diff --git a/src/types.ts b/src/types.ts index 896a0bf08..80396ab8b 100644 --- a/src/types.ts +++ b/src/types.ts @@ -99,6 +99,8 @@ export interface IWsdlBaseOptions { preserveWhitespace?: boolean; /** provides support for nonstandard array semantics. If true, JSON arrays of the form {list: [{elem: 1}, {elem: 2}]} are marshalled into xml as 1 2. If false, marshalls into 1 2 . Default: true. */ namespaceArrayElements?: boolean; + /** provides support for array with choice semantics. If array key matches, JSON arrays of the form {$sequence: [{elem: 1}, {elem: 2}]} are marshalled into xml as 12. Default: $sequence. */ + arrayWithChoiceTag?: string; useEmptyTag?: boolean; strict?: boolean; /** custom HTTP headers to be sent on WSDL requests. */ diff --git a/src/wsdl/index.ts b/src/wsdl/index.ts index 68fc61705..f80ee00a2 100644 --- a/src/wsdl/index.ts +++ b/src/wsdl/index.ts @@ -750,31 +750,36 @@ export class WSDL { for (i = 0, n = obj.length; i < n; i++) { const item = obj[i]; - const arrayAttr = this.processAttributes(item, nsContext); + const isArrayWithChoiceTagContainer = name === this.options.arrayWithChoiceTag; + const arrayAttr = isArrayWithChoiceTagContainer ? '' : this.processAttributes(item, nsContext); const correctOuterNsPrefix = nonSubNameSpace || parentNsPrefix || ns; // using the parent namespace prefix if given const body = this.objectToXML(item, name, nsPrefix, nsURI, false, null, schemaObject, nsContext); - let openingTagParts = ['<', name, arrayAttr, xmlnsAttrib]; - if (!emptyNonSubNameSpaceForArray) { - openingTagParts = ['<', appendColon(correctOuterNsPrefix), name, arrayAttr, xmlnsAttrib]; - } - - if (body === '' && this.options.useEmptyTag) { - // Use empty (self-closing) tags if no contents - openingTagParts.push(' />'); - parts.push(openingTagParts.join('')); + if (isArrayWithChoiceTagContainer) { + parts.push(body); } else { - openingTagParts.push('>'); - if (this.options.namespaceArrayElements || i === 0) { - parts.push(openingTagParts.join('')); + let openingTagParts = ['<', name, arrayAttr, xmlnsAttrib]; + if (!emptyNonSubNameSpaceForArray) { + openingTagParts = ['<', appendColon(correctOuterNsPrefix), name, arrayAttr, xmlnsAttrib]; } - parts.push(body); - if (this.options.namespaceArrayElements || i === n - 1) { - if (emptyNonSubNameSpaceForArray) { - parts.push([''].join('')); - } else { - parts.push([''].join('')); + + if (body === '' && this.options.useEmptyTag) { + // Use empty (self-closing) tags if no contents + openingTagParts.push(' />'); + parts.push(openingTagParts.join('')); + } else { + openingTagParts.push('>'); + if (this.options.namespaceArrayElements || i === 0) { + parts.push(openingTagParts.join('')); + } + parts.push(body); + if (this.options.namespaceArrayElements || i === n - 1) { + if (emptyNonSubNameSpaceForArray) { + parts.push([''].join('')); + } else { + parts.push([''].join('')); + } } } } @@ -939,7 +944,7 @@ export class WSDL { } } - value = this.objectToXML(child, name, nsPrefix, nsURI, false, null, null, nsContext); + value = this.objectToXML(child, name, nsPrefix, nsURI, false, null, name === this.options.arrayWithChoiceTag ? schemaObject : null, nsContext); } } else { value = this.objectToXML(child, name, nsPrefix, nsURI, false, null, null, nsContext); @@ -1178,6 +1183,7 @@ export class WSDL { } else { this.options.namespaceArrayElements = true; } + this.options.arrayWithChoiceTag = options.arrayWithChoiceTag || '$sequence'; // Allow any request headers to keep passing through this.options.wsdl_headers = options.wsdl_headers; diff --git a/test/wsdl-parse-test.js b/test/wsdl-parse-test.js index 87709f26f..d46fd0930 100644 --- a/test/wsdl-parse-test.js +++ b/test/wsdl-parse-test.js @@ -144,4 +144,151 @@ describe(__filename, function () { done(); }); }); + + it('should parse complex wsdls with mixed choice and minOccurs maxOccurs with custom $sequence', function (done) { + open_wsdl( + path.resolve(__dirname, 'wsdl/complex/mixed-sequence.wsdl'), + { + arrayWithChoiceTag: '$arrayChoice', + }, + function (err, def) { + if (err) { + return done(err); + } + + if (null === def.findSchemaType('getDataResponse', 'http://test-soap.com/api/mixedsequence')) { + return done('Unable to find "getDataResponse" complex type'); + } + + var requestBody = { + getDataResult: { + a: 0, + b: 10, + $arrayChoice: [ + { + c: { + id: '1', + value1: 'test 1', + }, + }, + { + d: { + id: '3', + value2: 'test 3', + }, + }, + { + c: { + id: '2', + value1: 'test 2', + }, + }, + ], + }, + }; + + var requestAsXML = def.objectToDocumentXML('getDataResponse', requestBody, 'acme', 'http://test-soap.com/api/mixedsequence', 'getDataResponse'); + + /** + * Expected XML: + * + * + * 0 + * 10 + * + * 1 + * test 1 + * + * + * 3 + * test 3 + * + * + * 2 + * test 2 + * + * + * + */ + assert.strictEqual( + requestAsXML, + '0101test 13test 32test 2', + ); + + done(); + }, + ); + }); + + it('should parse complex wsdls with mixed choice and minOccurs maxOccurs with default $sequence', function (done) { + open_wsdl( + path.resolve(__dirname, 'wsdl/complex/mixed-sequence.wsdl'), + function (err, def) { + if (err) { + return done(err); + } + + if (null === def.findSchemaType('getDataResponse', 'http://test-soap.com/api/mixedsequence')) { + return done('Unable to find "getDataResponse" complex type'); + } + + var requestBody = { + getDataResult: { + a: 0, + b: 10, + $sequence: [ + { + c: { + id: '1', + value1: 'test 1', + }, + }, + { + d: { + id: '3', + value2: 'test 3', + }, + }, + { + c: { + id: '2', + value1: 'test 2', + }, + }, + ], + }, + }; + + var requestAsXML = def.objectToDocumentXML('getDataResponse', requestBody, 'acme', 'http://test-soap.com/api/mixedsequence', 'getDataResponse'); + + /** + * Expected XML: + * + * + * 0 + * 10 + * + * 1 + * test 1 + * + * + * 3 + * test 3 + * + * + * 2 + * test 2 + * + * + * + */ + assert.strictEqual( + requestAsXML, + '0101test 13test 32test 2', + ); + + done(); + }, + ); + }); }); diff --git a/test/wsdl/complex/mixed-sequence.wsdl b/test/wsdl/complex/mixed-sequence.wsdl new file mode 100644 index 000000000..bcae576d8 --- /dev/null +++ b/test/wsdl/complex/mixed-sequence.wsdl @@ -0,0 +1,127 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +