Skip to content

Commit

Permalink
fix: handle xsi:type for subtype mappng from json to xml
Browse files Browse the repository at this point in the history
See #141
  • Loading branch information
raymondfeng committed Jan 24, 2018
1 parent 153acf6 commit 07b0d30
Show file tree
Hide file tree
Showing 9 changed files with 156 additions and 4 deletions.
4 changes: 2 additions & 2 deletions src/client.js
Expand Up @@ -19,7 +19,7 @@ class Client extends Base {
constructor(wsdl, endpoint, options) {
super(wsdl, options);
options = options || {};
this.xmlHandler = new XMLHandler(options);
this.xmlHandler = new XMLHandler(wsdl.definitions.schemas, options);
this._initializeServices(endpoint);
this.httpClient = options.httpClient || new HttpClient(options);
}
Expand Down Expand Up @@ -175,7 +175,7 @@ class Client extends Base {


var nsContext = this.createNamespaceContext(soapNsPrefix, soapNsURI);
var xmlHandler = this.xmlHandler || new XMLHandler(options);
var xmlHandler = this.xmlHandler || new XMLHandler(this.wsdl.schemas, options);
var envelope = Client.createSOAPEnvelope(soapNsPrefix, soapNsURI);

var soapHeaderElement = envelope.header;
Expand Down
42 changes: 41 additions & 1 deletion src/parser/xmlHandler.js
Expand Up @@ -17,7 +17,8 @@ var Set = helper.Set;


class XMLHandler {
constructor(options) {
constructor(schemas, options) {
this.schemas = schemas || {};
this.options = options || {};
this.options.valueKey = this.options.valueKey || '$value';
this.options.xmlKey = this.options.xmlKey || '$xml';
Expand Down Expand Up @@ -191,6 +192,41 @@ class XMLHandler {
return node;
}

/**
* Check if the attributes have xsi:type and return the xsi type descriptor if exists
* @param {*} descriptor The current descriptor
* @param {*} attrs An object of attribute values
*/
getXsiType(descriptor, attrs) {
var xsiTypeDescriptor;
if (attrs != null && typeof attrs === "object") {
for (let p in attrs) {
let child = attrs[p];
// if field is $xsiType add xsi:type attribute
if (p === this.options.xsiTypeKey) {
let xsiType;
if (typeof child === "object" && typeof child.type !== "undefined") {
// $xsiType has two fields - type, xmlns
xsiType = QName.parse(child.type, child.xmlns);
} else {
xsiType = QName.parse(child);
}
var schema = this.schemas[xsiType.nsURI];
if (schema) {
var xsiTypeInfo =
schema.complexTypes[xsiType.name] ||
schema.simpleTypes[xsiType.name];
// The type might not be described
// describe() takes wsdl definitions
xsiTypeDescriptor = xsiTypeInfo && xsiTypeInfo.describe({schemas: this.schemas});
}
break;
}
}
}
return xsiTypeDescriptor;
}

/**
* Map a JSON object into an XML type
* @param {XMLElement} node The root node
Expand All @@ -206,6 +242,10 @@ class XMLHandler {
return node;
}

// First try to see if a subtype should be used
var xsiType = this.getXsiType(descriptor, attrs);
descriptor = xsiType || descriptor;

var elements = {}, attributes = {};
if (descriptor != null) {
for (let i = 0, n = descriptor.elements.length; i < n; i++) {
Expand Down
3 changes: 2 additions & 1 deletion src/server.js
Expand Up @@ -25,12 +25,13 @@ class Server extends Base {
options = options || {};
this.path = path;
this.services = services;
this.xmlHandler = new XMLHandler(this.wsdl.options);

debug('Server parameters: path: %s services: %j wsdl: %j', path, services, wsdl);
if (path[path.length - 1] !== '/')
path += '/';
wsdl.load(function(err) {
if (err) throw err;
self.xmlHandler = new XMLHandler(self.wsdl.definitions.schemas, self.wsdl.options);
var listeners = server.listeners('request').slice();

server.removeAllListeners('request');
Expand Down
11 changes: 11 additions & 0 deletions test/request-response-samples/addList__xsi_type/request.json
@@ -0,0 +1,11 @@
{
"record": [
{
"id": "1",
"name": "John",
"$attributes": {
"$xsiType": "{urn:example}NameRecord"
}
}
]
}
@@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Header/><soap:Body><ns1:addList xmlns:ns1="urn:example"><ns1:record xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns2="urn:example" xsi:type="ns2:NameRecord"><ns1:id>1</ns1:id><ns1:name>John</ns1:name></ns1:record></ns1:addList></soap:Body></soap:Envelope>
9 changes: 9 additions & 0 deletions test/request-response-samples/addList__xsi_type/response.json
@@ -0,0 +1,9 @@
{
"record": {
"$attributes": {
"$xsiType": { "type": "UserRecord", "xmlns": "urn:example" }
},
"id": "2",
"name": "Mary"
}
}
11 changes: 11 additions & 0 deletions test/request-response-samples/addList__xsi_type/response.xml
@@ -0,0 +1,11 @@
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" >
<soapenv:Header/>
<soapenv:Body>
<ns1:addListResponse xmlns:ns1="urn:example" xmlns:ns2="urn:example">
<ns1:record xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns2:UserRecord">
<ns1:id>2</ns1:id>
<ns1:name>Mary</ns1:name>
</ns1:record>
</ns1:addListResponse>
</soapenv:Body>
</soapenv:Envelope>
38 changes: 38 additions & 0 deletions test/request-response-samples/addList__xsi_type/soap.messages.xsd
@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:msgs="urn:example"
targetNamespace="urn:example"
elementFormDefault="qualified" attributeFormDefault="qualified">

<complexType name="AddListResponse">
<sequence>
<element name="record" minOccurs="1" maxOccurs="unbounded" type="msgs:Record"/>
</sequence>
</complexType>

<element name="addListResponse" type="msgs:AddListResponse"/>

<complexType name="AddListRequest">
<sequence>
<element name="record" type="msgs:Record" minOccurs="1" maxOccurs="unbounded"/>
</sequence>
</complexType>

<complexType name="Record">
<sequence>
<element name="id" type="string"/>
</sequence>
</complexType>

<complexType name="NameRecord">
<complexContent>
<extension base="msgs:Record">
<sequence>
<element name="name" type="string"/>
</sequence>
</extension>
</complexContent>
</complexType>

<element name="addList" type="msgs:AddListRequest"/>
</schema>
41 changes: 41 additions & 0 deletions test/request-response-samples/addList__xsi_type/soap.wsdl
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns:tns="urn:urn:example:ws"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:msgs="urn:example"
targetNamespace="urn:urn:example:ws">
<types>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xsd:import namespace="urn:example" schemaLocation="soap.messages.xsd"/>
</xsd:schema>
</types>
<message name="addListRequest">
<part name="parameters" element="msgs:addList"/>
</message>
<message name="addListResponse">
<part name="parameters" element="msgs:addListResponse"/>
</message>
<portType name="NetSuitePortType">
<operation name="addList">
<input name="addListRequest" message="tns:addListRequest"/>
<output name="addListResponse" message="tns:addListResponse"/>
</operation>
</portType>
<binding name="NetSuiteBinding" type="tns:NetSuitePortType">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="addList">
<soap:operation soapAction="addList"/>
<input name="addListRequest">
<soap:body use="literal"/>
</input>
<output name="addListResponse">
<soap:body use="literal"/>
</output>
</operation>
</binding>
<service name="NetSuiteService">
<port name="NetSuitePort" binding="tns:NetSuiteBinding">
<soap:address location="http://localhost:1509"/>
</port>
</service>
</definitions>

0 comments on commit 07b0d30

Please sign in to comment.