Permalink
Browse files

Resolve namespaces correctly by ignoring "tns:", "targetNamespace", "…

…typedNamespace:", ... prefixes in child elements by default.

The ignored namespaces could be easily expanded/overriden by an `ignoredNamespaces` Object within the `options` parameter on `soap.createClient()`.
  • Loading branch information...
1 parent a71f2d2 commit 7cdc20aace4adaa9a1e7d9c7cab09218306e7fe3 @herom herom committed Jul 3, 2014
Showing with 327 additions and 7 deletions.
  1. +32 −0 Readme.md
  2. +23 −7 lib/wsdl.js
  3. +27 −0 test/request-response-samples/Dummy__should_ignore_custom_defined_namespaces/common.xsd
  4. +28 −0 test/request-response-samples/Dummy__should_ignore_custom_defined_namespaces/name.xsd
  5. +4 −0 test/request-response-samples/Dummy__should_ignore_custom_defined_namespaces/options.json
  6. +11 −0 test/request-response-samples/Dummy__should_ignore_custom_defined_namespaces/request.json
  7. +1 −0 test/request-response-samples/Dummy__should_ignore_custom_defined_namespaces/request.xml
  8. +12 −0 test/request-response-samples/Dummy__should_ignore_custom_defined_namespaces/response.json
  9. +14 −0 test/request-response-samples/Dummy__should_ignore_custom_defined_namespaces/response.xml
  10. +41 −0 test/request-response-samples/Dummy__should_ignore_custom_defined_namespaces/soap.wsdl
  11. +27 −0 test/request-response-samples/Dummy__should_ignore_defined_namespaces/common.xsd
  12. +28 −0 test/request-response-samples/Dummy__should_ignore_defined_namespaces/name.xsd
  13. +11 −0 test/request-response-samples/Dummy__should_ignore_defined_namespaces/request.json
  14. +1 −0 test/request-response-samples/Dummy__should_ignore_defined_namespaces/request.xml
  15. +12 −0 test/request-response-samples/Dummy__should_ignore_defined_namespaces/response.json
  16. +14 −0 test/request-response-samples/Dummy__should_ignore_defined_namespaces/response.xml
  17. +41 −0 test/request-response-samples/Dummy__should_ignore_defined_namespaces/soap.wsdl
View
@@ -250,6 +250,38 @@ soap.createClient(__dirname + '/wsdl/default_namespace.wsdl', {attributesKey: '$
});
```
+## Handling "ignored" namespaces
+If an Element in a `schema` definition depends on an Element which is present in the same namespace, normally the `tns:`
+namespace prefix is used to identify this Element. This is not much of a problem as long as you have just one `schema` defined
+(inline or in a separate file). If there are more `schema` files, the `tns:` in the generated `soap` file resolved mostly to the parent `wsdl` file,
+ which was obviously wrong.
+
+ `node-soap` now handles namespace prefixes which shouldn't be resolved (because it's not necessary) as so called `ignoredNamespaces`
+ which default to an Array of 3 Strings (`['tns', 'targetNamespace', 'typedNamespace']`).
+
+ If this is not sufficient for your purpose you can easily add more namespace prefixes to this Array, or override it in its entirety
+ by passing an `ignoredNamespaces` object within the `options` you pass in `soap.createClient()` method.
+
+ A simple `ignoredNamespaces` object, which only adds certain namespaces could look like this:
+ ```
+ var options = {
+ ignoredNamespaces: {
+ namespaces: ['namespaceToIgnore', 'someOtherNamespace']
+ }
+ }
+ ```
+ This would extend the `ignoredNamespaces` of the `WSDL` processor to `['tns', 'targetNamespace', 'typedNamespace', 'namespaceToIgnore', 'someOtherNamespace']`.
+
+ If you want to override the default ignored namespaces you would simply pass the following `ignoredNamespaces` object within the `options`:
+ ```
+ var options = {
+ ignoredNamespaces: {
+ namespaces: ['namespaceToIgnore', 'someOtherNamespace'],
+ override: true
+ }
+ }
+ ```
+ This would override the default `ignoredNamespaces` of the `WSDL` processor to `['namespaceToIgnore', 'someOtherNamespace']`. (This shouldn't be necessary, anyways).
[downloads-image]: http://img.shields.io/npm/dm/soap.svg
[npm-url]: https://npmjs.org/package/soap
View
@@ -86,11 +86,12 @@ function findKey(obj, val) {
return n;
}
-var Element = function(nsName, attrs) {
+var Element = function(nsName, attrs, ignoredNamespaces) {
var parts = splitNSName(nsName);
this.nsName = nsName;
this.namespace = parts.namespace;
+ this.ignoredNamespaces = ignoredNamespaces;
this.name = parts.name;
this.children = [];
this.xmlns = {};
@@ -115,15 +116,15 @@ Element.prototype.deleteFixedAttrs = function() {
Element.prototype.allowedChildren = [];
-Element.prototype.startElement = function(stack, nsName, attrs) {
+Element.prototype.startElement = function(stack, nsName, attrs, ignoredNamespaces) {
if (!this.allowedChildren)
return;
var ChildClass = this.allowedChildren[splitNSName(nsName).name],
element = null;
if (ChildClass) {
- stack.push(new ChildClass(nsName, attrs));
+ stack.push(new ChildClass(nsName, attrs, ignoredNamespaces));
}
else {
this.unexpected(nsName);
@@ -563,7 +564,7 @@ MessageElement.prototype._createLookupTypeObject = function (nsString, xmlns) {
*/
MessageElement.prototype._getNestedLookupTypeString = function (element) {
var resolvedType = '^',
- excluded = ['xs']; // do not process $type values wich start with
+ excluded = this.ignoredNamespaces.concat('xs'); // do not process $type values wich start with
if (element.hasOwnProperty('$type') && typeof element.$type === 'string') {
if (excluded.indexOf(element.$type.split(':')[0]) === -1) {
@@ -921,13 +922,25 @@ ServiceElement.prototype.description = function(definitions) {
var WSDL = function(definition, uri, options) {
var self = this,
- fromFunc;
+ fromFunc,
+ ignoredNamespaces;
this.uri = uri;
this.callback = function() {
};
this.options = options || {};
+ ignoredNamespaces = this.options.ignoredNamespaces;
+
+ if (ignoredNamespaces &&
+ (Array.isArray(ignoredNamespaces.namespaces) || typeof ignoredNamespaces.namespaces === 'string')) {
+ if (ignoredNamespaces.override) {
+ this.ignoredNamespaces = ignoredNamespaces.namespaces;
+ } else {
+ this.ignoredNamespaces.concat(ignoredNamespaces.namespaces);
+ }
+ }
+
if (typeof definition === 'string') {
fromFunc = this._fromXML;
}
@@ -994,6 +1007,8 @@ var WSDL = function(definition, uri, options) {
});
};
+WSDL.prototype.ignoredNamespaces = ['tns', 'targetNamespace', 'typedNamespace'];
+
WSDL.prototype.onReady = function(callback) {
if (callback)
this.callback = callback;
@@ -1496,7 +1511,8 @@ WSDL.prototype._parse = function(xml) {
var self = this,
p = sax.parser(true),
stack = [],
- root = null;
+ root = null,
+ ignoredNamespaces = this.ignoredNamespaces;
p.onopentag = function(node) {
var nsName = node.name;
@@ -1506,7 +1522,7 @@ WSDL.prototype._parse = function(xml) {
var name;
if (top) {
try {
- top.startElement(stack, nsName, attrs);
+ top.startElement(stack, nsName, attrs, ignoredNamespaces);
} catch (e) {
if (self.options.strict) {
throw e;
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xs:schema xmlns:someIgnoredNamespace="http://www.Dummy.com/Common/Types" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.Dummy.com/Common/Types" elementFormDefault="qualified" attributeFormDefault="unqualified">
+ <xs:complexType name="DummyResult">
+ <xs:sequence>
+ <xs:element name="DummyList" type="someIgnoredNamespace:DummyList" minOccurs="0"/>
+ </xs:sequence>
+ <xs:attribute name="code" type="xs:string" use="optional"/>
+ </xs:complexType>
+ <xs:complexType name="Dummy">
+ <xs:simpleContent>
+ <xs:extension base="xs:string">
+ <xs:attribute name="language" type="xs:language" use="optional"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <xs:complexType name="DummyList">
+ <xs:sequence>
+ <xs:element name="DummyElement" type="someIgnoredNamespace:Dummy" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="DummyFilter">
+ <xs:sequence>
+ <xs:element name="DummyIntFilter" type="xs:string" minOccurs="0"/>
+ <xs:element name="DummyStringFilter" type="xs:string" minOccurs="0"/>
+ </xs:sequence>
+ </xs:complexType>
+</xs:schema>
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xs:schema xmlns:tns="http://www.Dummy.com/Name/Types" xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ targetNamespace="http://www.Dummy.com/Name/Types" elementFormDefault="qualified"
+ attributeFormDefault="unqualified" xmlns:c="http://www.Dummy.com/Common/Types">
+ <xs:import namespace="common.xsd" schemaLocation="common.xsd"/>
+ <xs:element name="DummyRequest">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="DummyField1" type="xs:string" minOccurs="0"/>
+ <xs:element name="DummyFilter" type="c:DummyFilter" minOccurs="0"/>
+ <xs:element name="Account" type="tns:DummyAccount" minOccurs="0"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="DummyResponse">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="DummyResult" type="c:DummyResult"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:complexType name="DummyAccount">
+ <xs:sequence>
+ <xs:element name="DummyName" type="xs:string"/>
+ <xs:element name="DummyPassword" type="xs:string" minOccurs="0"/>
+ </xs:sequence>
+ </xs:complexType>
+</xs:schema>
@@ -0,0 +1,4 @@
+{
+ "namespaces": ["someIgnoredNamespace"],
+ "override": false
+}
@@ -0,0 +1,11 @@
+{
+ "DummyField1": "Humpty",
+ "DummyFilter": {
+ "DummyFilterString": "Dumpty"
+ },
+ "DummyAccount": {
+ "DummyName": "Dummy",
+ "DummyPassword": "1234"
+ }
+
+}
@@ -0,0 +1 @@
+<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tns="http://www.Dummy.com" xmlns:n="http://www.Dummy.com/Name/Types"><soap:Header></soap:Header><soap:Body><n:DummyRequest xmlns:n="http://www.Dummy.com/Name/Types" xmlns="http://www.Dummy.com/Name/Types"><n:DummyField1>Humpty</n:DummyField1><n:DummyFilter><c:DummyFilterString xmlns:c="http://www.Dummy.com/Common/Types">Dumpty</c:DummyFilterString></n:DummyFilter><n:DummyAccount><n:DummyName>Dummy</n:DummyName><n:DummyPassword>1234</n:DummyPassword></n:DummyAccount></n:DummyRequest></soap:Body></soap:Envelope>
@@ -0,0 +1,12 @@
+{
+ "DummyResult": {
+ "DummyList": {
+ "DummyElement": {
+ "attributes": {
+ "language": "en-US"
+ },
+ "$value": "Dummy Element Entry"
+ }
+ }
+ }
+}
@@ -0,0 +1,14 @@
+<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tns="http://www.Dummy.com" xmlns:n="http://www.Dummy.com/Name/Types">
+ <soap:Header></soap:Header>
+ <soap:Body>
+ <n:DummyResponse>
+ <n:DummyResult>
+ <c:DummyList xmlns:c="http://www.Dummy.com/Common/Types">
+ <c:DummyElement language="en-US">
+ Dummy Element Entry
+ </c:DummyElement>
+ </c:DummyList>
+ </n:DummyResult>
+ </n:DummyResponse>
+ </soap:Body>
+</soap:Envelope>
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
+ xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ xmlns:tns="http://www.Dummy.com" xmlns:n="http://www.Dummy.com/Name/Types" xmlns:ns="http://schemas.xmlsoap.org/soap/encoding/" targetNamespace="http://www.Dummy.com">
+ <wsdl:types>
+ <xs:schema>
+ <xs:import namespace="http://www.Dummy.com/Common/Types" schemaLocation="common.xsd"/>
+ <xs:import namespace="http://www.Dummy.com/Name/Types" schemaLocation="name.xsd"/>
+ </xs:schema>
+ </wsdl:types>
+ <wsdl:message name="DummyRequest">
+ <wsdl:part name="DummyRequest" element="n:DummyRequest"/>
+ </wsdl:message>
+ <wsdl:message name="DummyResponse">
+ <wsdl:part name="DummyResponse" element="n:DummyResponse"/>
+ </wsdl:message>
+ <wsdl:portType name="DummyPortType">
+ <wsdl:operation name="Dummy">
+ <wsdl:input message="tns:DummyRequest"/>
+ <wsdl:output message="tns:DummyResponse"/>
+ </wsdl:operation>
+ </wsdl:portType>
+ <wsdl:binding name="DummyBinding" type="tns:DummyPortType">
+ <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
+ <wsdl:operation name="Dummy">
+ <soap:operation soapAction="http://www.Dummy.com#Dummy" style="document"/>
+ <wsdl:input>
+ <soap:body use="literal"/>
+ </wsdl:input>
+ <wsdl:output>
+ <soap:body use="literal"/>
+ </wsdl:output>
+ </wsdl:operation>
+ </wsdl:binding>
+ <wsdl:service name="DummyService">
+ <wsdl:port name="DummyPortType" binding="tns:DummyBinding">
+ <soap:address location="http://www.Dummy.com/"/>
+ </wsdl:port>
+ </wsdl:service>
+</wsdl:definitions>
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xs:schema xmlns:tns="http://www.Dummy.com/Common/Types" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.Dummy.com/Common/Types" elementFormDefault="qualified" attributeFormDefault="unqualified">
+ <xs:complexType name="DummyResult">
+ <xs:sequence>
+ <xs:element name="DummyList" type="tns:DummyList" minOccurs="0"/>
+ </xs:sequence>
+ <xs:attribute name="code" type="xs:string" use="optional"/>
+ </xs:complexType>
+ <xs:complexType name="Dummy">
+ <xs:simpleContent>
+ <xs:extension base="xs:string">
+ <xs:attribute name="language" type="xs:language" use="optional"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <xs:complexType name="DummyList">
+ <xs:sequence>
+ <xs:element name="DummyElement" type="tns:Dummy" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="DummyFilter">
+ <xs:sequence>
+ <xs:element name="DummyIntFilter" type="xs:string" minOccurs="0"/>
+ <xs:element name="DummyStringFilter" type="xs:string" minOccurs="0"/>
+ </xs:sequence>
+ </xs:complexType>
+</xs:schema>
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xs:schema xmlns:tns="http://www.Dummy.com/Name/Types" xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ targetNamespace="http://www.Dummy.com/Name/Types" elementFormDefault="qualified"
+ attributeFormDefault="unqualified" xmlns:c="http://www.Dummy.com/Common/Types">
+ <xs:import namespace="common.xsd" schemaLocation="common.xsd"/>
+ <xs:element name="DummyRequest">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="DummyField1" type="xs:string" minOccurs="0"/>
+ <xs:element name="DummyFilter" type="c:DummyFilter" minOccurs="0"/>
+ <xs:element name="Account" type="tns:DummyAccount" minOccurs="0"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="DummyResponse">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="DummyResult" type="c:DummyResult"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:complexType name="DummyAccount">
+ <xs:sequence>
+ <xs:element name="DummyName" type="xs:string"/>
+ <xs:element name="DummyPassword" type="xs:string" minOccurs="0"/>
+ </xs:sequence>
+ </xs:complexType>
+</xs:schema>
@@ -0,0 +1,11 @@
+{
+ "DummyField1": "Humpty",
+ "DummyFilter": {
+ "DummyFilterString": "Dumpty"
+ },
+ "DummyAccount": {
+ "DummyName": "Dummy",
+ "DummyPassword": "1234"
+ }
+
+}
@@ -0,0 +1 @@
+<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tns="http://www.Dummy.com" xmlns:n="http://www.Dummy.com/Name/Types"><soap:Header></soap:Header><soap:Body><n:DummyRequest xmlns:n="http://www.Dummy.com/Name/Types" xmlns="http://www.Dummy.com/Name/Types"><n:DummyField1>Humpty</n:DummyField1><n:DummyFilter><c:DummyFilterString xmlns:c="http://www.Dummy.com/Common/Types">Dumpty</c:DummyFilterString></n:DummyFilter><n:DummyAccount><n:DummyName>Dummy</n:DummyName><n:DummyPassword>1234</n:DummyPassword></n:DummyAccount></n:DummyRequest></soap:Body></soap:Envelope>
@@ -0,0 +1,12 @@
+{
+ "DummyResult": {
+ "DummyList": {
+ "DummyElement": {
+ "attributes": {
+ "language": "en-US"
+ },
+ "$value": "Dummy Element Entry"
+ }
+ }
+ }
+}
@@ -0,0 +1,14 @@
+<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tns="http://www.Dummy.com" xmlns:n="http://www.Dummy.com/Name/Types">
+ <soap:Header></soap:Header>
+ <soap:Body>
+ <n:DummyResponse>
+ <n:DummyResult>
+ <c:DummyList xmlns:c="http://www.Dummy.com/Common/Types">
+ <c:DummyElement language="en-US">
+ Dummy Element Entry
+ </c:DummyElement>
+ </c:DummyList>
+ </n:DummyResult>
+ </n:DummyResponse>
+ </soap:Body>
+</soap:Envelope>
Oops, something went wrong.

0 comments on commit 7cdc20a

Please sign in to comment.