For one of our clients we needed to create multiple JSONP services with SOAP-backends in Datapower. JSON is supported by default in het Multi-Protocol gateway, and with JSONx, Datapower can handle it quite well. This post describes the fixes we did to extend JSONx and make it easy to create a JSONP-response in the same way you would do for a JSON-response.
For those of you who never heard of JSONP (JSON with Padding): it’s JSON wrapped in round brackets, preceded with a prefix. This makes it possible for javascript to use it as if it where a javascript function. It is used to allow a web page to request data from a server in a different domain (our datapower device).
Back to our case: the strenght of Datapower is its ability to handle XML content. Since JSON is no xml, IBM provided us with a language called JSONx. It is an XML-model that represents JSON-content. The idea is to work as long as possible with JSONx and after all mappings and validations are done the conversion to a proper JSON response can be done using the provided ‘jsonx2json.xsl’ style sheet. This stylesheet is by default available in the ‘store://’ directory on the Datapower appliance.
Since we wanted to use JSONP instead of JSON, we complemented the JSONX-language with an extra element <jsonp:callback> that will serve as a root for the normal JSONX content. The new name we used for it is JSONPx. It has one property: ‘name’. The value of this property will be used as the prefix for our JSONP-response. If ‘name’ is empty, the output will be normal JSON.
Here you can see of a sample of a JSONPx-file:
<jsonp:callback
xmlns:json="http://www.ibm.com/xmlns/prod/2009/jsonx"
xmlns:jsonp="http://www.i8c.be/xmlns/jsonpx" name="TestPrefix">
<json:object>
<json:number name="testValue">123</json:number>
<json:string name="testName">Foo</json:string>
</json:object>
</jsonp:callback>
Just like for a JSONx-file it is possible to validate this file against an XSD-schema. Instead of the default jsonx.xsd (located under ‘store://‘in Datapower), you now can use the XSD below and we called it jsonpx.xsd;
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://www.i8c.be/xmlns/jsonpx"
targetNamespace="http://www.i8c.be/xmlns/jsonpx"
elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:import namespace="http://www.ibm.com/xmlns/prod/2009/jsonx"
schemaLocation="store:///jsonx.xsd"/>
<xs:element name="callback" type="tns:callback"/>
<xs:complexType name="callback">
<xs:sequence>
<xs:any namespace="http://www.ibm.com/xmlns/prod/2009/jsonx"
minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="name" type="xs:string"/>
</xs:complexType>
</xs:schema>
For the transformation we use the XSLT called ‘jsonpx2json.xsl’ which imports the transformations from the ‘jsonx2json.xsl’ file, but adds the transformation for the jsonp:calback element to it.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0"
xmlns:json="http://www.ibm.com/xmlns/prod/2009/jsonx"
xmlns:jsonp="http://www.i8c.be/xmlns/jsonpx">
<xsl:output method="text" encoding="utf-8"
indent="no" media-type="application/javascript"/>
<xsl:import href="store:///jsonx2json.xsl"/>
<xsl:template match="jsonp:callback">
<xsl:if test="string-length(@name)>0">
<xsl:value-of select="@name"/>
<xsl:text>(</xsl:text>
</xsl:if>
<xsl:apply-templates select="*"/>
<xsl:if test="string-length(@name)>0">
<xsl:text>)</xsl:text>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Author: Tim
No comments:
Post a Comment