JSON Conversion Service (com.ibi.agents.XDJSONAgent)

Topics:

Syntax:

com.ibi.agents.XDJSONAgent

Description:

The JSON Conversion Service converts JSON to XML and vice-versa. This service offers a choice of two separate transformations that work in either of the following directions:

The iWay transformation is unusual because it does not have a preferred direction. It can take an arbitrary JSON object and convert it to XML, but it can also take an arbitrary XML document and convert it to JSON. A round-trip will often produce the same input, but this is not guaranteed. JSON field names are reused as XML element names. This makes XPath expressions look natural when they are evaluated against the resulting XML document.

The Standard transformation is described in section 22 of the XSLT3 specification. This algorithm is simple because it is designed to express JSON objects in a specialized XML form that conforms to a specific XML schema. This supports a perfect round trip of JSON objects to XML and back. XPath expressions to query the XML form is slightly more verbose because predicates are needed to match field names stored in attribute values.

Parameters:

Parameter

Description

Conversion

Chooses the conversion from JSON to XML, or XML to JSON using the Standard transformation described in the XSLT3 specification, or the iWay transformation.

Outer Tag

When converting from JSON to XML using the iWay transformation, the Outer Tag is the name of the root element wrapper in XML. When absent, only JSON objects with a single field can be converted to XML, with the field name promoted to the root element name. When converting from XML to JSON using the iWay transformation, this instructs to skip the root element if the name matches, thereby reversing the effect of the Outer Tag. This is ignored when using the Standard transformations.

JSON Literal Type

When converting from XML to JSON using the iWay transformation, this determines the data type of literal values in JSON. Dynamic will parse the XML text to discover the JSON type. This makes it convenient to use the values in JSON, but it assumes that everything that looks like a number is indeed a number. String will always quote the literal value. This always preserves the value without modification, but Boolean or numeric values may have to be converted explicitly in JSON expressions. This is ignored when using the Standard transformation.

Encoding

When converting from XML to JSON using the iWay transformation, this is the encoding used to convert the JSON string to bytes before storing in the document. This is ignored when using the Standard transformation.

Edges:

The following table lists and describes the edges that are returned by the JSON Conversion Service.

Line Edge

Description

success

The document was successfully converted.

fail_parse

An iFL expression could not be evaluated or a JSON document could not be parsed.

fail_format

The format of the message was invalid for the operation requested.

fail_operation

The operation could not be completed successfully.

iWay JSON to XML Transformation

The iWay transformation uses the JSON field names as XML element names and vice-versa.

The input of the JSON to XML iWay transformation can be a parsed JSON document or a flat document. A flat document will be parsed to a JSON value before being transformed. An XML input document is invalid and causes a fail_format error.

The output is a parsed XML document.

In JSON, a top level object is anonymous. The Outer Tag parameter (when specified) is the name generated for the corresponding top level Element in XML. It is always recommended to define an Outer Tag but it is possible to leave the Outer Tag empty for backwards compatibility. In that case, the service assumes the top level JSON object has a single field and promotes that field to top level. Without an Outer Tag, trying to convert a JSON object with zero or more than one fields causes an error.

An array is represented in XML with multiple consecutive elements of the same name. This requires an empty or singleton array be marked with the following attribute to indicate the array type for the round-trip:

json:force-array="true"

An array within an array is also anonymous and will be converted to a containing element called array to preserve the array structure.

The namespace prefix json stands for the http://json.org/ namespace. The prefix is automatically declared.

JSON accepts more valid characters than XML. The iWay transformation handles this by replacing an invalid character with the escape character underscore followed by a 4-digit hexadecimal string. The underscore was chosen because it is a valid start character in XML element names. When a field name must be escaped, it is marked with the following XML attribute:

json:escaped-key="true"

Similarly, when a string value must be escaped, it is marked with the following XML attribute:

json:escaped="true"

It is possible for an element to have both attributes. When absent, the default value of these attributes is false. The underscore character is not escaped, unless another character must be escaped within the same string.

iWay XML to JSON Transformation

The input of the XML to JSON iWay transformation must be a parsed XML document. A JSON document or a flat document is invalid and causes a fail_format error. The input can be any arbitrary XML document, but some conventions must be followed to produce desired JSON forms.

The output is a bytes document containing the serialized JSON object. The encoding used to convert the characters to bytes is given by the Encoding parameter.

The root element is skipped if the Outer Tag is defined and it matches the root element name. That reverses the effect of the Outer Tag.

A sub-element that appears once within its parent and is not marked with json:force-array="true" becomes a JSON field with a JSON object, number or Boolean value.

Conversely, a sub-element that appears more than once or is marked with json:force-array="true" becomes a JSON field with an array value. The sub-elements are gathered by name, they do not have to be consecutive.

Multiple text-nodes within a mixed-content parent Element are converted to a JSON field called content with an array value. This mapping is not reversible when going back to XML.

The JSON Literal Type parameter determines the data type of literal values in the JSON output. Setting the parameter to Dynamic will parse the XML text to discover the JSON type. String literals will be double-quoted whereas numbers and Booleans will not. This makes it convenient to use the values in JSON but it assumes that everything that looks like a number is indeed a number. Setting the parameter to String will always quote the literal value. This always preserves the value without modification, but boolean or numeric values may have to be converted explicitly in JSON expressions.

An element with the following attribute will have its name unescaped to produce the JSON field name:

json:escaped-key="true"

An element with the following attribute will have its value unescaped to produce the JSON string value.

json:escaped="true"

iWay Transformation Examples

The following table shows the correspondence between JSON and XML. The Outer Tag is assumed to be JSON, and the JSON Literal Type is set to Dynamic.

Concept

JSON

XML

Non-object

1

<json>1</json>

Empty Object

0

<json/>

Null

{"null1": null}

<json><null1>null</null1></json>

Number

{"num1": 1}

<json><num1>1</num1></json>

String

{"str1":"abc"}

<json><str1>abc</str1></json>

Boolean

{"bool1":true}

<json><bool1>true</bool1></json>

Multiple Fields

{"key1": "val1", "key2": "val2"}

<json><key1>val1</key1><key2>val2</key2></json>

Subobject

{"obj1":{"sub1":1}}

<json><obj1><sub1>1</sub1></obj1></json>

Empty Array

{"array0":[]}

<json xmlns:json="http://json.org/"><array0 json:force-array="true"/></json>

Singleton Array

{"array1":[1]}

<json xmlns:json="http://json.org/"><array1 json:force-array="true">1</array1></json>

Array

{"array3":[1,2,3]}

<json><array3>1</array3><array3>2</array3>
<array3>3</array3></json>

Subarray

{"array2d":[[11,12],[21,22]]}

<json><array2d><array>11</array>
<array>12</array></array2d>
<array2d><array>21</array>
<array>22</array></array2d></json>

Regular Underscore

{"a_b":1}

<json><a_b>1</a_b></json>

Escaped Key

{"a:b":1}

<json xmlns:json="http://json.org/"><a_003ab json:escaped-key="true">1</a_003ab></json>

Escaped Underscore

{"a_\u0003":1}

<json xmlns:json="http://json.org/"><a_005f_0003 json:escaped-key="true">1</a_005f_0003></json>

Regular Underscore

{"a":"a_b"}

<json><a>a_b</a></json>

Escaped Value

{"a":"a_\u0003"}

<json xmlns:json="http://json.org/"><a json:escaped="true">a_005f_0003</a></json>

Both Attributes

{"a:b":"a_\u0003"}

{"a:b":"a_\u0003"}	<json xmlns:json="http://json.org/"><a_003ab json:escaped-key="true" json:escaped="true">a_005f_0003</a_003ab></json>

The following table shows how JSON is transformed to XML when the Outer Tag is absent. The conversion succeeds only when the input JSON object has a single field. To avoid this error, it is recommended to always define an Outer Tag.

Concept

JSON

XML

Non-Object

1

Error document with fail_operation

Empty Object

{}

Error document with fail_operation

Single Field

{"key1": "val1"}

<key1>val1</key1>

Multiple Fields

{"key1": "val1", "key2": "val2"}

Error document with fail_operation

The following table shows how XML is transformed to JSON when the JSON Literal Type is set to String. The Outer Tag is assumed to be JSON. All primitive literals become quoted strings.

Concept

XML

JSON

Null

<json><null1>null</null1></json>

{"null1":"null"}

Number

<json><num1>1</num1></json>

{"num1":"1"}

String

<json><str1>abc</str1></json>

{"str1":"abc"}

Boolean

<json><bool1>true</bool1></json>

{"bool1":"true"}

The following table shows some notable cases when XML is transformed to JSON. The Outer Tag is assumed to be JSON.

Concept

XML

JSON

Simple Type

<json><obj>abc</obj></json>

{"obj":"abc"}

Mixed Content

<json><obj>abc<sub>xyz</sub>def</obj></json>

{"obj":{"content": ["abc","def"],"sub":"xyz"}}

Not Consecutive

<json><a>a1</a><b>b1</b><a>a2</a></obj></json>

{"a":["a1","a2"],"b":"b1"}

iWay Transformation XPath Example

The iWay transformation produces XML documents that are intuitive to query with XPath. For example, the following JSON object:

{"obj":{"list":[11,22,33]}}

is transformed into:

<json><obj><list>11</list><list>22</list><list>33</list></obj></json>.

The XPath expression to extract the value 33 can be written as follows:

/json/obj/list[3]

Standard JSON to XML Transformation

The Standard transformation is described in section 22 of the XSLT3 specification. It supports perfect round-trips from JSON to XML and back.

The input must be a parsed JSON document. An XML or a flat input document is invalid and causes a fail_format error. The output is a parsed XML document.

JSON values are mapped to XML elements in the http://www.w3.org/2005/xpath-functions namespace based on the JSON data type, as defined in the following table.

JSON Type

XML Element Name

Object

map

Array

array

String

string

Number

number

Boolean

boolean

A JSON object is mapped to an element called map as indicated in this table. Each field is mapped to an XML subelement named according to this table. The field name is stored in the key attribute of the subelement.

An array item is mapped to an element called array. Each array item is mapped to an XML subelement named according to this table.

A string, number, or Boolean is converted to an element with a text node.

JSON accepts more valid characters than XML. The Standard transformation handles this by replacing an invalid character with the escape character backslash followed by a 4-digit hexadecimal string. When a field name must be escaped, it is marked with the following XML attribute:

escaped-key="true"

Similarly, when a string value must be escaped, it is marked with the following XML attribute:

 escaped="true"

These attributes are not within a namespace. It is possible for an element to have both attributes. When absent, the default value of these attributes is false. The backslash character is not escaped, unless another character must be escaped within the same string.

Standard XML to JSON Transformation

The input of the Standard XML to JSON transformation must be a parsed XML document in a specific form, which means it must satisfy the expected XML schema. A parsed JSON or a flat input document is invalid and generates a fail_format error.

The output is a parsed JSON document.

A JSON value is created based on the XML element name according to the table above. For more information, see Standard JSON to XML Transformation.

Each sub-element of a map element corresponds to a field. The name of the field is given by the key attribute. If the attribute escaped-key="true" is present, then the value of the key attribute is unescaped first to produce the field name. It is an error if the key attribute is missing.

Each sub-element of an array element corresponds to an item in the array.

An element with the following attribute, will have its name unescaped to produce the JSON field name.

escaped-key="true"

An element with the following attribute, will have its value unescaped to produce the JSON string value:

escaped="true"

Standard Transformation Examples

The following table shows the correspondence between JSON and XML and back. The examples are perfectly symmetric.

Concept

JSON

XML

Non-Object

1

<number xmlns="http://www.w3.org/2005/xpath-functions">4</number>

Empty Object

{}

<map xmlns="http://www.w3.org/2005/xpath-functions"/>

Null

{"null1": null}

<map xmlns="http://www.w3.org/2005/xpath-functions"><null key="null1"/></map>

Number

{"num1": 1}

<map xmlns="http://www.w3.org/2005/xpath-functions"><number key="num1">1</number></map>

String

{"str1":"abc"}

<map xmlns="http://www.w3.org/2005/xpath-functions"><string key="str1">abc</string></map>

Boolean

{"bool1":true}

<map xmlns="http://www.w3.org/2005/xpath-functions"><boolean key="bool1">true</boolean></map>

Multiple Fields

{"key1": "val1", "key2": "val2"}

<map xmlns="http://www.w3.org/2005/xpath-functions"><string key="key1">val1</string><string key="key2">val2</string></map>

Subobject

{"obj1":{"sub1":1}}

<map xmlns="http://www.w3.org/2005/xpath-functions"><map key="obj1"><number key="sub1">1</number></map></map>

Empty Array

{"array0":[]}

<map xmlns="http://www.w3.org/2005/xpath-functions"><array key="array0"/></map>

Singleton Array

{"array1":[1]}

<map xmlns="http://www.w3.org/2005/xpath-functions"><array key="array1"><number>1</number></array></map>

Array

{"array3":[1,2,3]}

<map xmlns="http://www.w3.org/2005/xpath-functions">
<array key="array3"><number>1</number>
<number>2</number>
<number>3</number></array></map>

Subarray

{"array2d":[[11,12],[21,22]]}

<map xmlns="http://www.w3.org/2005/xpath-functions">
<array key="array2d"><array><number>11</number>
<number>12</number></array>
<array><number>21</number>
<number>22</number></array></array></map>

Regular Backslash

{"a\\b":1}

<map xmlns="http://www.w3.org/2005/xpath-functions"><number key="a\b">1</number></map>

Escaped Key

{"a\u0003":1}

<map xmlns="http://www.w3.org/2005/xpath-functions"><number key="a\u0003" escaped-key="true">1</number></map>

Escaped Backslash

{"a\\\u0003":1}

<map xmlns="http://www.w3.org/2005/xpath-functions"><number key="a\\\u0003" escaped-key="true">1</number></map>

Regular Backslash

{"a":"a\\b"}

<map xmlns="http://www.w3.org/2005/xpath-functions"><string key="a">a\b</string></map>

Escaped Value

{"a":"a_\u0004"}

<map xmlns="http://www.w3.org/2005/xpath-functions"><string key="a" escaped="true">a_\u0004</string></map>

Both Attributes

{"a\u0003":"a\u0004"}

<map xmlns="http://www.w3.org/2005/xpath-functions"><string key="a\u0003" escaped-key="true" escaped="true">a\u0004</string></map>

Standard Transformation XPath Example

The Standard transformation produces XML documents that require slightly verbose expressions to query with XPath. For example, the following JSON object:

{"str1":"abc","list":[11,22,33]}}

is transformed into:

<map xmlns="http://www.w3.org/2005/xpath-functions"><string key="str1">abc</string><array key="list"><number>11</number><number>22</number><number>33</number></array></map>

A fully developed XPath expression to extract the value 33 can be written as follows:

/json:map/json:array[@key="list"]/json:number[3]

Notice how a predicate is needed to test the key attribute against the desired field name.

This expression assumes the json prefix is declared in an XML Namespace provider with the following value:

http://www.w3.org/2005/xpath functions