"use strict"; /* * Copyright (c) 2011 Vinay Pulim * MIT Licensed * */ /*jshint proto:true*/ exports.__esModule = true; exports.open_wsdl = exports.WSDL = void 0; var assert_1 = require("assert"); var debugBuilder = require("debug"); var fs = require("fs"); var _ = require("lodash"); var path = require("path"); var sax = require("sax"); var stripBom = require("strip-bom"); var url = require("url"); var http_1 = require("../http"); var nscontext_1 = require("../nscontext"); var utils_1 = require("../utils"); var elements = require("./elements"); var debug = debugBuilder('node-soap'); var XSI_URI = 'http://www.w3.org/2001/XMLSchema-instance'; var trimLeft = /^[\s\xA0]+/; var trimRight = /[\s\xA0]+$/; function trim(text) { return text.replace(trimLeft, '').replace(trimRight, ''); } function deepMerge(destination, source) { return _.mergeWith(destination, source, function (a, b) { return Array.isArray(a) ? a.concat(b) : undefined; }); } function appendColon(ns) { return (ns && ns.charAt(ns.length - 1) !== ':') ? ns + ':' : ns; } function noColonNameSpace(ns) { return (ns && ns.charAt(ns.length - 1) === ':') ? ns.substring(0, ns.length - 1) : ns; } var WSDL = /** @class */ (function () { function WSDL(definition, uri, options) { var _this = this; this.ignoredNamespaces = ['tns', 'targetNamespace', 'typedNamespace']; this.ignoreBaseNameSpaces = false; this.valueKey = '$value'; this.xmlKey = '$xml'; var fromFunc; this.uri = uri; this.callback = function () { }; this._includesWsdl = []; // initialize WSDL cache this.WSDL_CACHE = {}; if (options && options.WSDL_CACHE) { this.WSDL_CACHE = options.WSDL_CACHE; } this._initializeOptions(options); if (typeof definition === 'string') { definition = stripBom(definition); fromFunc = this._fromXML; } else if (typeof definition === 'object') { fromFunc = this._fromServices; } else { throw new Error('WSDL constructor takes either an XML string or service definition'); } process.nextTick(function () { try { fromFunc.call(_this, definition); } catch (e) { return _this.callback(e); } _this.processIncludes(function (err) { var name; if (err) { return _this.callback(err); } try { _this.definitions.deleteFixedAttrs(); var services = _this.services = _this.definitions.services; if (services) { for (name in services) { services[name].postProcess(_this.definitions); } } var complexTypes = _this.definitions.complexTypes; if (complexTypes) { for (name in complexTypes) { complexTypes[name].deleteFixedAttrs(); } } // for document style, for every binding, prepare input message element name to (methodName, output message element name) mapping var bindings = _this.definitions.bindings; for (var bindingName in bindings) { var binding = bindings[bindingName]; if (typeof binding.style === 'undefined') { binding.style = 'document'; } if (binding.style !== 'document') { continue; } var methods = binding.methods; var topEls = binding.topElements = {}; for (var methodName in methods) { if (methods[methodName].input) { var inputName = methods[methodName].input.$name; var outputName = ''; if (methods[methodName].output) { outputName = methods[methodName].output.$name; } topEls[inputName] = { methodName: methodName, outputName: outputName }; } } } // prepare soap envelope xmlns definition string _this.xmlnsInEnvelope = _this._xmlnsMap(); _this.callback(err, _this); } catch (e) { _this.callback(e); } }); }); } WSDL.prototype.onReady = function (callback) { if (callback) { this.callback = callback; } }; WSDL.prototype.processIncludes = function (callback) { var schemas = this.definitions.schemas; var includes = []; for (var ns in schemas) { var schema = schemas[ns]; includes = includes.concat(schema.includes || []); } this._processNextInclude(includes, callback); }; WSDL.prototype.describeServices = function () { var services = {}; for (var name_1 in this.services) { var service = this.services[name_1]; services[name_1] = service.description(this.definitions); } return services; }; WSDL.prototype.toXML = function () { return this.xml || ''; }; WSDL.prototype.getSaxStream = function (xml) { var saxStream = sax.createStream(true, null); xml.pipe(saxStream); return saxStream; }; WSDL.prototype.xmlToObject = function (xml, callback) { var _this = this; var p = typeof callback === 'function' ? {} : sax.parser(true, null); var objectName = null; var root = {}; var schema = { Envelope: { Header: { Security: { UsernameToken: { Username: 'string', Password: 'string' } } }, Body: { Fault: { faultcode: 'string', faultstring: 'string', detail: 'string' } } } }; var stack = [{ name: null, object: root, schema: schema }]; var xmlns = {}; var refs = {}; var id; // {id:{hrefs:[],obj:}, ...} p.onopentag = function (node) { var nsName = node.name; var attrs = node.attributes; var name = utils_1.splitQName(nsName).name; var attributeName; var top = stack[stack.length - 1]; var topSchema = top.schema; var elementAttributes = {}; var hasNonXmlnsAttribute = false; var hasNilAttribute = false; var obj = {}; var originalName = name; if (!objectName && top.name === 'Body' && name !== 'Fault') { var message = _this.definitions.messages[name]; // Support RPC/literal messages where response body contains one element named // after the operation + 'Response'. See http://www.w3.org/TR/wsdl#_names if (!message) { try { // Determine if this is request or response var isInput = false; var isOutput = false; if ((/Response$/).test(name)) { isOutput = true; name = name.replace(/Response$/, ''); } else if ((/Request$/).test(name)) { isInput = true; name = name.replace(/Request$/, ''); } else if ((/Solicit$/).test(name)) { isInput = true; name = name.replace(/Solicit$/, ''); } // Look up the appropriate message as given in the portType's operations var portTypes = _this.definitions.portTypes; var portTypeNames = Object.keys(portTypes); // Currently this supports only one portType definition. var portType = portTypes[portTypeNames[0]]; if (isInput) { name = portType.methods[name].input.$name; } else { name = portType.methods[name].output.$name; } message = _this.definitions.messages[name]; // 'cache' this alias to speed future lookups _this.definitions.messages[originalName] = _this.definitions.messages[name]; } catch (e) { if (_this.options.returnFault) { p.onerror(e); } } } topSchema = message.description(_this.definitions); objectName = originalName; } if (attrs.href) { id = attrs.href.substr(1); if (!refs[id]) { refs[id] = { hrefs: [], obj: null }; } refs[id].hrefs.push({ par: top.object, key: name, obj: obj }); } if (id = attrs.id) { if (!refs[id]) { refs[id] = { hrefs: [], obj: null }; } } // Handle element attributes for (attributeName in attrs) { if (/^xmlns:|^xmlns$/.test(attributeName)) { xmlns[utils_1.splitQName(attributeName).name] = attrs[attributeName]; continue; } hasNonXmlnsAttribute = true; elementAttributes[attributeName] = attrs[attributeName]; } for (attributeName in elementAttributes) { var res = utils_1.splitQName(attributeName); if (res.name === 'nil' && xmlns[res.prefix] === XSI_URI && elementAttributes[attributeName] && (elementAttributes[attributeName].toLowerCase() === 'true' || elementAttributes[attributeName] === '1')) { hasNilAttribute = true; break; } } if (hasNonXmlnsAttribute) { obj[_this.options.attributesKey] = elementAttributes; } // Pick up the schema for the type specified in element's xsi:type attribute. var xsiTypeSchema; var xsiType; for (var prefix in xmlns) { if (xmlns[prefix] === XSI_URI && (prefix + ":type" in elementAttributes)) { xsiType = elementAttributes[prefix + ":type"]; break; } } if (xsiType) { var type = utils_1.splitQName(xsiType); var typeURI = void 0; if (type.prefix === utils_1.TNS_PREFIX) { // In case of xsi:type = "MyType" typeURI = xmlns[type.prefix] || xmlns.xmlns; } else { typeURI = xmlns[type.prefix]; } var typeDef = _this.findSchemaObject(typeURI, type.name); if (typeDef) { xsiTypeSchema = typeDef.description(_this.definitions); } } if (topSchema && topSchema[name + '[]']) { name = name + '[]'; } stack.push({ name: originalName, object: obj, schema: (xsiTypeSchema || (topSchema && topSchema[name])), id: attrs.id, nil: hasNilAttribute }); }; p.onclosetag = function (nsName) { var cur = stack.pop(); var obj = cur.object; var top = stack[stack.length - 1]; var topObject = top.object; var topSchema = top.schema; var name = utils_1.splitQName(nsName).name; if (typeof cur.schema === 'string' && (cur.schema === 'string' || cur.schema.split(':')[1] === 'string')) { if (typeof obj === 'object' && Object.keys(obj).length === 0) { obj = cur.object = ''; } } if (cur.nil === true) { if (_this.options.handleNilAsNull) { obj = null; } else { return; } } if (_.isPlainObject(obj) && !Object.keys(obj).length) { obj = null; } if (topSchema && topSchema[name + '[]']) { if (!topObject[name]) { topObject[name] = []; } topObject[name].push(obj); } else if (name in topObject) { if (!Array.isArray(topObject[name])) { topObject[name] = [topObject[name]]; } topObject[name].push(obj); } else { topObject[name] = obj; } if (cur.id) { refs[cur.id].obj = obj; } }; p.oncdata = function (text) { var originalText = text; text = trim(text); if (!text.length) { return; } if (/<\?xml[\s\S]+\?>/.test(text)) { var top_1 = stack[stack.length - 1]; var value = _this.xmlToObject(text); if (top_1.object[_this.options.attributesKey]) { top_1.object[_this.options.valueKey] = value; } else { top_1.object = value; } } else { p.ontext(originalText); } }; p.onerror = function (e) { p.resume(); throw { Fault: { faultcode: 500, faultstring: 'Invalid XML', detail: new Error(e).message, statusCode: 500 } }; }; p.ontext = function (text) { var originalText = text; text = trim(text); if (!text.length) { return; } var top = stack[stack.length - 1]; var name = utils_1.splitQName(top.schema).name; var value; if (_this.options && _this.options.customDeserializer && _this.options.customDeserializer[name]) { value = _this.options.customDeserializer[name](text, top); } else { if (name === 'int' || name === 'integer' || name === 'short') { value = parseInt(text, 10); } else if (name === 'double' || name === 'float' || name === 'decimal') { value = Number(text); } else if (name === 'bool' || name === 'boolean') { value = text.toLowerCase() === 'true' || text === '1'; } else if (name === 'dateTime' || name === 'date') { value = new Date(text); } else { if (_this.options.preserveWhitespace) { text = originalText; } // handle string or other types if (typeof top.object !== 'string') { value = text; } else { value = top.object + text; } } } if (top.object[_this.options.attributesKey]) { top.object[_this.options.valueKey] = value; } else { top.object = value; } }; if (typeof callback === 'function') { // we be streaming var saxStream = sax.createStream(true, null); saxStream.on('opentag', p.onopentag); saxStream.on('closetag', p.onclosetag); saxStream.on('cdata', p.oncdata); saxStream.on('text', p.ontext); xml.pipe(saxStream) .on('error', function (err) { callback(err); }) .on('end', function () { var r; try { r = finish(); } catch (e) { return callback(e); } callback(null, r); }); return; } p.write(xml).close(); return finish(); function finish() { // MultiRef support: merge objects instead of replacing for (var n in refs) { var ref = refs[n]; for (var _i = 0, _a = ref.hrefs; _i < _a.length; _i++) { var href = _a[_i]; Object.assign(href.obj, ref.obj); } } if (root.Envelope) { var body = root.Envelope.Body; if (body && body.Fault) { var code = body.Fault.faultcode && body.Fault.faultcode.$value; var string = body.Fault.faultstring && body.Fault.faultstring.$value; var detail = body.Fault.detail && body.Fault.detail.$value; code = code || body.Fault.faultcode; string = string || body.Fault.faultstring; detail = detail || body.Fault.detail; var error = new Error(code + ': ' + string + (detail ? ': ' + JSON.stringify(detail) : '')); error.root = root; throw error; } return root.Envelope; } return root; } }; /** * Look up a XSD type or element by namespace URI and name * @param {String} nsURI Namespace URI * @param {String} qname Local or qualified name * @returns {*} The XSD type/element definition */ WSDL.prototype.findSchemaObject = function (nsURI, qname) { if (!nsURI || !qname) { return null; } var def = null; if (this.definitions.schemas) { var schema = this.definitions.schemas[nsURI]; if (schema) { if (qname.indexOf(':') !== -1) { qname = qname.substring(qname.indexOf(':') + 1, qname.length); } // if the client passed an input element which has a `$lookupType` property instead of `$type` // the `def` is found in `schema.elements`. def = schema.complexTypes[qname] || schema.types[qname] || schema.elements[qname]; } } return def; }; /** * Create document style xml string from the parameters * @param {String} name * @param {*} params * @param {String} nsPrefix * @param {String} nsURI * @param {String} type */ WSDL.prototype.objectToDocumentXML = function (name, params, nsPrefix, nsURI, type) { // If user supplies XML already, just use that. XML Declaration should not be present. if (params && params._xml) { return params._xml; } var args = {}; args[name] = params; var parameterTypeObj = type ? this.findSchemaObject(nsURI, type) : null; return this.objectToXML(args, null, nsPrefix, nsURI, true, null, parameterTypeObj); }; /** * Create RPC style xml string from the parameters * @param {String} name * @param {*} params * @param {String} nsPrefix * @param {String} nsURI * @returns {string} */ WSDL.prototype.objectToRpcXML = function (name, params, nsPrefix, nsURI, isParts) { var parts = []; var defs = this.definitions; var nsAttrName = '_xmlns'; nsPrefix = nsPrefix || utils_1.findPrefix(defs.xmlns, nsURI); nsURI = nsURI || defs.xmlns[nsPrefix]; nsPrefix = nsPrefix === utils_1.TNS_PREFIX ? '' : (nsPrefix + ':'); parts.push(['<', nsPrefix, name, '>'].join('')); for (var key in params) { if (!params.hasOwnProperty(key)) { continue; } if (key !== nsAttrName) { var value = params[key]; var prefixedKey = (isParts ? '' : nsPrefix) + key; var attributes = []; if (typeof value === 'object' && value.hasOwnProperty(this.options.attributesKey)) { var attrs = value[this.options.attributesKey]; for (var n in attrs) { attributes.push(' ' + n + '=' + '"' + attrs[n] + '"'); } } parts.push(['<', prefixedKey].concat(attributes).concat('>').join('')); parts.push((typeof value === 'object') ? this.objectToXML(value, key, nsPrefix, nsURI) : utils_1.xmlEscape(value)); parts.push([''].join('')); } } parts.push([''].join('')); return parts.join(''); }; WSDL.prototype.isIgnoredNameSpace = function (ns) { return this.options.ignoredNamespaces.indexOf(ns) > -1; }; WSDL.prototype.filterOutIgnoredNameSpace = function (ns) { var namespace = noColonNameSpace(ns); return this.isIgnoredNameSpace(namespace) ? '' : namespace; }; /** * Convert an object to XML. This is a recursive method as it calls itself. * * @param {Object} obj the object to convert. * @param {String} name the name of the element (if the object being traversed is * an element). * @param {String} nsPrefix the namespace prefix of the object I.E. xsd. * @param {String} nsURI the full namespace of the object I.E. http://w3.org/schema. * @param {Boolean} isFirst whether or not this is the first item being traversed. * @param {?} xmlnsAttr * @param {?} parameterTypeObject * @param {NamespaceContext} nsContext Namespace context */ WSDL.prototype.objectToXML = function (obj, name, nsPrefix, nsURI, isFirst, xmlnsAttr, schemaObject, nsContext) { var schema = this.definitions.schemas[nsURI]; var parentNsPrefix = nsPrefix ? nsPrefix.parent : undefined; if (typeof parentNsPrefix !== 'undefined') { // we got the parentNsPrefix for our array. setting the namespace-variable back to the current namespace string nsPrefix = nsPrefix.current; } parentNsPrefix = noColonNameSpace(parentNsPrefix); if (this.isIgnoredNameSpace(parentNsPrefix)) { parentNsPrefix = ''; } var soapHeader = !schema; var qualified = schema && schema.$elementFormDefault === 'qualified'; var parts = []; var prefixNamespace = (nsPrefix || qualified) && nsPrefix !== utils_1.TNS_PREFIX; var xmlnsAttrib = ''; if (nsURI && isFirst) { if (this.options.overrideRootElement && this.options.overrideRootElement.xmlnsAttributes) { this.options.overrideRootElement.xmlnsAttributes.forEach(function (attribute) { xmlnsAttrib += ' ' + attribute.name + '="' + attribute.value + '"'; }); } else { if (prefixNamespace && !this.isIgnoredNameSpace(nsPrefix)) { // resolve the prefix namespace xmlnsAttrib += ' xmlns:' + nsPrefix + '="' + nsURI + '"'; } // only add default namespace if the schema elementFormDefault is qualified if (qualified || soapHeader) { xmlnsAttrib += ' xmlns="' + nsURI + '"'; } } } if (!nsContext) { nsContext = new nscontext_1.NamespaceContext(); nsContext.declareNamespace(nsPrefix, nsURI); } else { nsContext.pushContext(); } // explicitly use xmlns attribute if available if (xmlnsAttr && !(this.options.overrideRootElement && this.options.overrideRootElement.xmlnsAttributes)) { xmlnsAttrib = xmlnsAttr; } var ns = ''; if (this.options.overrideRootElement && isFirst) { ns = this.options.overrideRootElement.namespace; } else if (prefixNamespace && (qualified || isFirst || soapHeader) && !this.isIgnoredNameSpace(nsPrefix)) { ns = nsPrefix; } var i; var n; // start building out XML string. if (Array.isArray(obj)) { var nonSubNameSpace = ''; var emptyNonSubNameSpaceForArray = false; var nameWithNsRegex = /^([^:]+):([^:]+)$/.exec(name); if (nameWithNsRegex) { nonSubNameSpace = nameWithNsRegex[1]; name = nameWithNsRegex[2]; } else if (name[0] === ':') { emptyNonSubNameSpaceForArray = true; name = name.substr(1); } for (i = 0, n = obj.length; i < n; i++) { var item = obj[i]; var arrayAttr = this.processAttributes(item, nsContext); var correctOuterNsPrefix = nonSubNameSpace || parentNsPrefix || ns; // using the parent namespace prefix if given var body = this.objectToXML(item, name, nsPrefix, nsURI, false, null, schemaObject, nsContext); var 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('')); } 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('')); } } } } } else if (typeof obj === 'object') { var currentChildXmlnsAttrib = ''; for (name in obj) { // Happens when Object.create(null) is used, it will not inherit the Object prototype if (!obj.hasOwnProperty) { obj = Object.assign({}, obj); } if (!obj.hasOwnProperty(name)) { continue; } // don't process attributes as element if (name === this.options.attributesKey) { continue; } // Its the value of a xml object. Return it directly. if (name === this.options.xmlKey) { nsContext.popContext(); return obj[name]; } // Its the value of an item. Return it directly. if (name === this.options.valueKey) { nsContext.popContext(); return utils_1.xmlEscape(obj[name]); } var child = obj[name]; if (typeof child === 'undefined') { continue; } var attr = this.processAttributes(child, nsContext); var value = ''; var nonSubNameSpace = ''; var emptyNonSubNameSpace = false; var nameWithNsRegex = /^([^:]+):([^:]+)$/.exec(name); if (nameWithNsRegex) { nonSubNameSpace = nameWithNsRegex[1] + ':'; name = nameWithNsRegex[2]; } else if (name[0] === ':') { emptyNonSubNameSpace = true; name = name.substr(1); } if (isFirst) { value = this.objectToXML(child, name, nsPrefix, nsURI, false, null, schemaObject, nsContext); } else { if (this.definitions.schemas) { if (schema) { var childSchemaObject = this.findChildSchemaObject(schemaObject, name); // find sub namespace if not a primitive if (childSchemaObject && ((childSchemaObject.$type && (childSchemaObject.$type.indexOf('xsd:') === -1)) || childSchemaObject.$ref || childSchemaObject.$name)) { /*if the base name space of the children is not in the ingoredSchemaNamspaces we use it. This is because in some services the child nodes do not need the baseNameSpace. */ var childNsPrefix = ''; var childName = ''; var childNsURI = void 0; var childXmlnsAttrib = ''; var elementQName = childSchemaObject.$ref || childSchemaObject.$name; if (elementQName) { elementQName = utils_1.splitQName(elementQName); childName = elementQName.name; if (elementQName.prefix === utils_1.TNS_PREFIX) { // Local element childNsURI = childSchemaObject.$targetNamespace; childNsPrefix = nsContext.registerNamespace(childNsURI); if (this.isIgnoredNameSpace(childNsPrefix)) { childNsPrefix = nsPrefix; } } else { childNsPrefix = elementQName.prefix; if (this.isIgnoredNameSpace(childNsPrefix)) { childNsPrefix = nsPrefix; } childNsURI = schema.xmlns[childNsPrefix] || this.definitions.xmlns[childNsPrefix]; } var unqualified = false; // Check qualification form for local elements if (childSchemaObject.$name && childSchemaObject.targetNamespace === undefined) { if (childSchemaObject.$form === 'unqualified') { unqualified = true; } else if (childSchemaObject.$form === 'qualified') { unqualified = false; } else { unqualified = schema.$elementFormDefault !== 'qualified'; } } if (unqualified) { childNsPrefix = ''; } if (childNsURI && childNsPrefix) { if (nsContext.declareNamespace(childNsPrefix, childNsURI)) { childXmlnsAttrib = ' xmlns:' + childNsPrefix + '="' + childNsURI + '"'; if (!xmlnsAttrib.includes(childNsPrefix)) { currentChildXmlnsAttrib = childXmlnsAttrib; xmlnsAttrib += childXmlnsAttrib; } } } } var resolvedChildSchemaObject = void 0; if (childSchemaObject.$type) { var typeQName = utils_1.splitQName(childSchemaObject.$type); var typePrefix = typeQName.prefix; var typeURI = schema.xmlns[typePrefix] || this.definitions.xmlns[typePrefix]; childNsURI = typeURI; if (typeURI !== 'http://www.w3.org/2001/XMLSchema' && typePrefix !== utils_1.TNS_PREFIX) { // Add the prefix/namespace mapping, but not declare it nsContext.addNamespace(typePrefix, typeURI); } resolvedChildSchemaObject = this.findSchemaType(typeQName.name, typeURI) || childSchemaObject; } else { resolvedChildSchemaObject = this.findSchemaObject(childNsURI, childName) || childSchemaObject; } if (childSchemaObject.$baseNameSpace && this.options.ignoreBaseNameSpaces) { childNsPrefix = nsPrefix; childNsURI = nsURI; } if (this.options.ignoreBaseNameSpaces) { childNsPrefix = ''; childNsURI = ''; } ns = childNsPrefix; if (Array.isArray(child)) { // for arrays, we need to remember the current namespace childNsPrefix = { current: childNsPrefix, parent: ns }; childXmlnsAttrib = childXmlnsAttrib && childXmlnsAttrib.length ? childXmlnsAttrib : currentChildXmlnsAttrib; } else { // parent (array) already got the namespace childXmlnsAttrib = null; } value = this.objectToXML(child, name, childNsPrefix, childNsURI, false, childXmlnsAttrib, resolvedChildSchemaObject, nsContext); } else if (obj[this.options.attributesKey] && obj[this.options.attributesKey].xsi_type) { // if parent object has complex type defined and child not found in parent var completeChildParamTypeObject = this.findChildSchemaObject(obj[this.options.attributesKey].xsi_type.type, obj[this.options.attributesKey].xsi_type.xmlns); nonSubNameSpace = obj[this.options.attributesKey].xsi_type.prefix; nsContext.addNamespace(obj[this.options.attributesKey].xsi_type.prefix, obj[this.options.attributesKey].xsi_type.xmlns); value = this.objectToXML(child, name, obj[this.options.attributesKey].xsi_type.prefix, obj[this.options.attributesKey].xsi_type.xmlns, false, null, null, nsContext); } else { if (Array.isArray(child)) { if (emptyNonSubNameSpace) { name = ':' + name; } else { name = nonSubNameSpace + name; } } value = this.objectToXML(child, name, nsPrefix, nsURI, false, null, null, nsContext); } } else { value = this.objectToXML(child, name, nsPrefix, nsURI, false, null, null, nsContext); } } } ns = noColonNameSpace(ns); if (prefixNamespace && !qualified && isFirst && !this.options.overrideRootElement) { ns = nsPrefix; } else if (this.isIgnoredNameSpace(ns)) { ns = ''; } var useEmptyTag = !value && this.options.useEmptyTag; if (!Array.isArray(child)) { // start tag parts.push(['<', emptyNonSubNameSpace ? '' : appendColon(nonSubNameSpace || ns), name, attr, xmlnsAttrib, (child === null ? ' xsi:nil="true"' : ''), useEmptyTag ? ' />' : '>', ].join('')); } if (!useEmptyTag) { parts.push(value); if (!Array.isArray(child)) { // end tag parts.push([''].join('')); } } } } else if (obj !== undefined) { parts.push((this.options.escapeXML) ? utils_1.xmlEscape(obj) : obj); } nsContext.popContext(); return parts.join(''); }; WSDL.prototype.processAttributes = function (child, nsContext) { var attr = ''; if (child === null || child === undefined) { child = []; } var attrObj = child[this.options.attributesKey]; if (attrObj && attrObj.xsi_type) { var xsiType = attrObj.xsi_type; var prefix = xsiType.prefix || xsiType.namespace; // Generate a new namespace for complex extension if one not provided if (!prefix) { prefix = nsContext.registerNamespace(xsiType.xmlns); } else { nsContext.declareNamespace(prefix, xsiType.xmlns); } xsiType.prefix = prefix; } if (attrObj) { for (var attrKey in attrObj) { // handle complex extension separately if (attrKey === 'xsi_type') { var attrValue = attrObj[attrKey]; attr += ' xsi:type="' + attrValue.prefix + ':' + attrValue.type + '"'; attr += ' xmlns:' + attrValue.prefix + '="' + attrValue.xmlns + '"'; continue; } else { attr += ' ' + attrKey + '="' + utils_1.xmlEscape(attrObj[attrKey]) + '"'; } } } return attr; }; /** * Look up a schema type definition * @param name * @param nsURI * @returns {*} */ WSDL.prototype.findSchemaType = function (name, nsURI) { if (!this.definitions.schemas || !name || !nsURI) { return null; } var schema = this.definitions.schemas[nsURI]; if (!schema || !schema.complexTypes) { return null; } return schema.complexTypes[name]; }; WSDL.prototype.findChildSchemaObject = function (parameterTypeObj, childName, backtrace) { if (!parameterTypeObj || !childName) { return null; } if (!backtrace) { backtrace = []; } if (backtrace.indexOf(parameterTypeObj) >= 0) { // We've recursed back to ourselves; break. return null; } else { backtrace = backtrace.concat([parameterTypeObj]); } var found = null; var i = 0; var child; var ref; if (Array.isArray(parameterTypeObj.$lookupTypes) && parameterTypeObj.$lookupTypes.length) { var types = parameterTypeObj.$lookupTypes; for (i = 0; i < types.length; i++) { var typeObj = types[i]; if (typeObj.$name === childName) { found = typeObj; break; } } } var object = parameterTypeObj; if (object.$name === childName && object.name === 'element') { return object; } if (object.$ref) { ref = utils_1.splitQName(object.$ref); if (ref.name === childName) { return object; } } var childNsURI; // want to avoid unecessary recursion to improve performance if (object.$type && backtrace.length === 1) { var typeInfo = utils_1.splitQName(object.$type); if (typeInfo.prefix === utils_1.TNS_PREFIX) { childNsURI = parameterTypeObj.$targetNamespace; } else { childNsURI = this.definitions.xmlns[typeInfo.prefix]; } var typeDef = this.findSchemaType(typeInfo.name, childNsURI); if (typeDef) { return this.findChildSchemaObject(typeDef, childName, backtrace); } } // handle $base (e.g. for ExtensionElement) like $type if (object.$base && (!Array.isArray(object.children) || !object.children.length)) { var baseInfo = utils_1.splitQName(object.$base); childNsURI = parameterTypeObj.$targetNamespace; if (baseInfo.prefix !== utils_1.TNS_PREFIX) { childNsURI = this.definitions.xmlns[baseInfo.prefix]; } var baseDef = this.findSchemaType(baseInfo.name, childNsURI); if (baseDef) { return this.findChildSchemaObject(baseDef, childName, backtrace); } } if (Array.isArray(object.children) && object.children.length > 0) { for (i = 0, child; child = object.children[i]; i++) { found = this.findChildSchemaObject(child, childName, backtrace); if (found) { break; } if (child.$base) { var baseQName = utils_1.splitQName(child.$base); var childNameSpace = baseQName.prefix === utils_1.TNS_PREFIX ? '' : baseQName.prefix; childNsURI = child.xmlns[baseQName.prefix] || child.schemaXmlns[baseQName.prefix]; var foundBase = this.findSchemaType(baseQName.name, childNsURI); if (foundBase) { found = this.findChildSchemaObject(foundBase, childName, backtrace); if (found) { found.$baseNameSpace = childNameSpace; found.$type = childNameSpace + ':' + childName; break; } } } } } if (!found && object.$name === childName) { return object; } return found; }; WSDL.prototype._initializeOptions = function (options) { this._originalIgnoredNamespaces = (options || {}).ignoredNamespaces; this.options = {}; var ignoredNamespaces = options ? options.ignoredNamespaces : null; if (ignoredNamespaces && (Array.isArray(ignoredNamespaces.namespaces) || typeof ignoredNamespaces.namespaces === 'string')) { if (ignoredNamespaces.override) { this.options.ignoredNamespaces = ignoredNamespaces.namespaces; } else { this.options.ignoredNamespaces = this.ignoredNamespaces.concat(ignoredNamespaces.namespaces); } } else { this.options.ignoredNamespaces = this.ignoredNamespaces; } this.options.valueKey = options.valueKey || this.valueKey; this.options.xmlKey = options.xmlKey || this.xmlKey; if (options.escapeXML !== undefined) { this.options.escapeXML = options.escapeXML; } else { this.options.escapeXML = true; } if (options.returnFault !== undefined) { this.options.returnFault = options.returnFault; } else { this.options.returnFault = false; } this.options.handleNilAsNull = !!options.handleNilAsNull; if (options.namespaceArrayElements !== undefined) { this.options.namespaceArrayElements = options.namespaceArrayElements; } else { this.options.namespaceArrayElements = true; } // Allow any request headers to keep passing through this.options.wsdl_headers = options.wsdl_headers; this.options.wsdl_options = options.wsdl_options; if (options.httpClient) { this.options.httpClient = options.httpClient; } // The supplied request-object should be passed through if (options.request) { this.options.request = options.request; } var ignoreBaseNameSpaces = options ? options.ignoreBaseNameSpaces : null; if (ignoreBaseNameSpaces !== null && typeof ignoreBaseNameSpaces !== 'undefined') { this.options.ignoreBaseNameSpaces = ignoreBaseNameSpaces; } else { this.options.ignoreBaseNameSpaces = this.ignoreBaseNameSpaces; } // Works only in client this.options.forceSoap12Headers = options.forceSoap12Headers; this.options.customDeserializer = options.customDeserializer; if (options.overrideRootElement !== undefined) { this.options.overrideRootElement = options.overrideRootElement; } this.options.useEmptyTag = !!options.useEmptyTag; }; WSDL.prototype._processNextInclude = function (includes, callback) { var _this = this; var include = includes.shift(); if (!include) { return callback(); } var includePath; if (!/^https?:/i.test(this.uri) && !/^https?:/i.test(include.location)) { var isFixed = (this.options.wsdl_options !== undefined && this.options.wsdl_options.hasOwnProperty('fixedPath')) ? this.options.wsdl_options.fixedPath : false; if (isFixed) { includePath = path.resolve(path.dirname(this.uri), path.parse(include.location).base); } else { includePath = path.resolve(path.dirname(this.uri), include.location); } } else { includePath = url.resolve(this.uri || '', include.location); } if (this.options.wsdl_options !== undefined && typeof this.options.wsdl_options.overrideImportLocation === 'function') { includePath = this.options.wsdl_options.overrideImportLocation(includePath); } var options = Object.assign({}, this.options); // follow supplied ignoredNamespaces option options.ignoredNamespaces = this._originalIgnoredNamespaces || this.options.ignoredNamespaces; options.WSDL_CACHE = this.WSDL_CACHE; open_wsdl_recursive(includePath, options, function (err, wsdl) { if (err) { return callback(err); } _this._includesWsdl.push(wsdl); if (wsdl.definitions instanceof elements.DefinitionsElement) { _.mergeWith(_this.definitions, wsdl.definitions, function (a, b) { return (a instanceof elements.SchemaElement) ? a.merge(b) : undefined; }); } else { return callback(new Error('wsdl.defintions is not an instance of elements.DefinitionsElement')); } _this._processNextInclude(includes, function (err) { callback(err); }); }); }; WSDL.prototype._parse = function (xml) { var _this = this; var p = sax.parser(true, null); var stack = []; var root = null; var types = null; var schema = null; var schemaAttrs = null; var options = this.options; p.onopentag = function (node) { var nsName = node.name; var attrs = node.attributes; var top = stack[stack.length - 1]; var name = utils_1.splitQName(nsName).name; if (name === 'schema') { schemaAttrs = attrs; } if (top) { try { top.startElement(stack, nsName, attrs, options, schemaAttrs); } catch (e) { if (_this.options.strict) { throw e; } else { stack.push(new elements.Element(nsName, attrs, options, schemaAttrs)); } } } else { if (name === 'definitions') { root = new elements.DefinitionsElement(nsName, attrs, options); stack.push(root); } else if (name === 'schema') { // Shim a structure in here to allow the proper objects to be created when merging back. root = new elements.DefinitionsElement('definitions', {}, {}); types = new elements.TypesElement('types', {}, {}); schema = new elements.SchemaElement(nsName, attrs, options); types.addChild(schema); root.addChild(types); stack.push(schema); } else { throw new Error('Unexpected root element of WSDL or include'); } } }; p.onclosetag = function (name) { var top = stack[stack.length - 1]; assert_1.ok(top, 'Unmatched close tag: ' + name); top.endElement(stack, name); }; p.write(xml).close(); return root; }; WSDL.prototype._fromXML = function (xml) { this.definitions = this._parse(xml); this.definitions.descriptions = { types: {}, elements: {} }; this.xml = xml; }; WSDL.prototype._fromServices = function (services) { }; WSDL.prototype._xmlnsMap = function () { var xmlns = this.definitions.xmlns; var str = ''; for (var alias in xmlns) { if (alias === '' || alias === utils_1.TNS_PREFIX) { continue; } var ns = xmlns[alias]; switch (ns) { case 'http://xml.apache.org/xml-soap': // apachesoap case 'http://schemas.xmlsoap.org/wsdl/': // wsdl case 'http://schemas.xmlsoap.org/wsdl/soap/': // wsdlsoap case 'http://schemas.xmlsoap.org/wsdl/soap12/': // wsdlsoap12 case 'http://schemas.xmlsoap.org/soap/encoding/': // soapenc case 'http://www.w3.org/2001/XMLSchema': // xsd continue; } if (~ns.indexOf('http://schemas.xmlsoap.org/')) { continue; } if (~ns.indexOf('http://www.w3.org/')) { continue; } if (~ns.indexOf('http://xml.apache.org/')) { continue; } str += ' xmlns:' + alias + '="' + ns + '"'; } return str; }; return WSDL; }()); exports.WSDL = WSDL; function open_wsdl_recursive(uri, p2, p3) { var fromCache; var WSDL_CACHE; var options; var callback; if (typeof p2 === 'function') { options = {}; callback = p2; } else { options = p2; callback = p3; } WSDL_CACHE = options.WSDL_CACHE; if (fromCache = WSDL_CACHE[uri]) { return callback.call(fromCache, null, fromCache); } return open_wsdl(uri, options, callback); } function open_wsdl(uri, p2, p3) { var options; var callback; if (typeof p2 === 'function') { options = {}; callback = p2; } else if (typeof p3 === 'function') { options = p2; callback = p3; } // initialize cache when calling open_wsdl directly var WSDL_CACHE = options.WSDL_CACHE || {}; var request_headers = options.wsdl_headers; var request_options = options.wsdl_options; var wsdl; if (!/^https?:/i.test(uri)) { debug('Reading file: %s', uri); fs.readFile(uri, 'utf8', function (err, definition) { if (err) { callback(err); } else { wsdl = new WSDL(definition, uri, options); WSDL_CACHE[uri] = wsdl; wsdl.WSDL_CACHE = WSDL_CACHE; wsdl.onReady(callback); } }); } else { debug('Reading url: %s', uri); var httpClient = options.httpClient || new http_1.HttpClient(options); httpClient.request(uri, null /* options */, function (err, response, definition) { if (err) { callback(err); } else if (response && response.statusCode === 200) { wsdl = new WSDL(definition, uri, options); WSDL_CACHE[uri] = wsdl; wsdl.WSDL_CACHE = WSDL_CACHE; wsdl.onReady(callback); } else { callback(new Error('Invalid WSDL URL: ' + uri + '\n\n\r Code: ' + response.statusCode + '\n\n\r Response Body: ' + response.body)); } }, request_headers, request_options); } return wsdl; } exports.open_wsdl = open_wsdl; //# sourceMappingURL=index.js.map