JSON Module

This XQuery Module contains functions to parse and serialize JSON data JSON (JavaScript Object Notation) is a popular data exchange format for applications written in JavaScript. As there are notable differences between JSON and XML, or XQuery data types, no mapping exists that guarantees a lossless, bidirectional conversion between JSON and XML. For this reason, we offer various mappings, all of which are suited to different use cases.

=Conventions=

All functions and errors in this module are assigned to the  namespace, which is statically bound to the json prefix.

Conversion Formats
A little advice: in the Database Creation dialog of the GUI, if you select JSON Parsing and switch to the Parsing tab, you can see the effects of some of the conversion options.

Direct
The direct conversion format allows a lossless conversion from JSON to XML and back. The transformation is based on the following rules:


 * The resulting document has a root node.
 * Object pairs are represented via elements. The name of a pair is rewritten to an element name:
 * Empty names are represented by a single underscore (_). Existing underscores are rewritten to two underscores (__), and characters that are not valid in element names are rewritten to an underscore and the character’s four-digit Unicode.
 * If the lax option is set to true, invalid characters are simply replaced with underscores or (when invalid as first character of an element name) prefixed with an underscore. The resulting names are better readable, but cannot always be converted back to their original form.
 * Array entries are also represented via elements. _ is used as element name.
 * Object and array values are stored in text nodes.
 * The types of values are represented via type attributes:
 * The existing types are string, number, boolean, null, object, and array.
 * As most values are strings, the string type is by default omitted.

Attributes
The attributes format is lossless, too. The transformation based on the following rules:


 * The resulting document has a root node.
 * Object pairs are represented via elements. The name of a pair is stored in a name attribute.
 * Array entries are represented via elements.
 * Object and array values are stored in text nodes.
 * The types of values are represented via type attributes:
 * The existing types are string, number, boolean, null, object, and array.
 * As most values are strings, the string type is by default omitted.

Basic
The basic format is another lossless format. It converts a JSON document to an XML node and vice versa. The conversion rules are the same as for fn:json-to-xml.

JsonML
The jsonml format is designed to convert XML to JSON and back, using the JsonML dialect. JsonML allows the transformation of arbitrary XML documents, but namespaces, comments and processing instructions will be discarded in the transformation process. More details are found in the official JsonML documentation.

XQuery
The xquery format is lossless, too. It converts JSON data to an XQuery value (a map, array, string, number, boolean, or empty sequence) and vice versa. The conversion rules are the same as for fn:parse-json.

The resulting representation consumes less memory than XML-based formats, and values can be directly accessed without conversion. Thus, it is recommendable for very large inputs and for efficient ad-hoc processing.

Options
The following options are available (the Direction column indicates if an option applies to parsing, serialization, or both operations):

=Functions=

json:serialize
=Examples=

BaseX Format
Example 1: Adds all JSON documents in a directory to a database

Query:  let $database := "database" for $name in file:list('.', false, '*.json') let $file := file:read-text($name) let $json := json:parse($file) return db:add($database, $json, $name)

Example 2: Converts a simple JSON string to XML and back

Query:  json:parse('{}')

Result: 

Query:  (: serialize result as plain text :) declare option output:method 'text'; json:serialize

Result:  { }

Example 3: Converts a JSON string with simple objects and arrays

Query:  json:parse('{ "title": "Talk On Travel Pool",  "link": "http://www.flickr.com/groups/talkontravel/pool/",  "description": "Travel and vacation photos from around the world.",  "modified": "2014-02-02T11:10:27Z",  "generator": "http://www.flickr.com/" }')

Result:  Talk On Travel Pool http://www.flickr.com/groups/talkontravel/pool/ Travel and vacation photos from around the world. 2014-02-02T11:10:27Z http://www.flickr.com/

Example 4: Converts a JSON string with different data types

Query:  let $options := map { 'merge': true } return json:parse('{ "first_name": "John",  "last_name": "Smith",  "age": 25,  "address": {    "street": "21 2nd Street",    "city": "New York",    "code": 10021  },  "phone": [    {      "type": "home",      "number": "212 555-1234"    },    {      "type": "mobile",      "number": 1327724623    }  ] }', $options)

Result:   John Smith 25    21 2nd Street New York      home 212 555-1234              mobile 1327724623    

JsonML Format
Example 1: Converts all XML documents in a database to the JsonML format and writes them to disk

Query: <pre class="brush:xquery"> for $doc in collection('json') let $name := document-uri($doc) let $json := json:serialize($doc, map { 'format': 'jsonml' }) return file:write($name, $json)

Example 2: Converts an XML document with elements and text

Query: <pre class="brush:xquery"> json:serialize(doc('flickr.xml'), map { 'format': 'jsonml' })

flickr.xml: <pre class="brush:xml"> Talk On Travel Pool http://www.flickr.com/groups/talkontravel/pool/ Travel and vacation photos from around the world. 2014-02-02T11:10:27Z http://www.flickr.com/

Result: ["flickr", ["title", "Talk On Travel Pool"], ["link", "http://www.flickr.com/groups/talkontravel/pool/"], ["description", "Travel and vacation photos from around the world."], ["modified", "2014-02-02T11:10:27Z"], ["generator", "http://www.flickr.com/"]]

Example 3: Converts a document with nested elements and attributes to JsonML

Query: <pre class="brush:xquery"> json:serialize(doc('input.xml'), map { 'format': 'jsonml' })

input.xml: <pre class="brush:xml"> <address id='1'> <last_name>Smith</last_name> 25  <address xmlns='will be dropped as well'> 21 2nd Street New York <phone type='home'>212 555-1234

Result: ["address", {"id":"1"}, ["last_name", "Smith"], ["age", "25"], ["address", ["street", "21 2nd Street"], ["city", "New York"], ["code", "10021"]], ["phone", {"type":"home"}, "212 555-1234"]]

XQuery Format
Example 1: Converts a JSON string to XQuery

Query: <pre class="brush:xquery"> let $input := '{ "Title": "Drinks", "Author": [ "Jim Daniels", "Jack Beam" ] }' let $data := json:parse($input, map { 'format': 'xquery' }) return map:for-each($data, function($k, $v) { $k || ': ' || string-join($v, ', ') })

Result: Author: Jim Daniels, Jack Beam Title: Drinks

Example 2: Converts XQuery data to JSON

Query: <pre class="brush:xquery"> for $item in ( true,  'ABC',  array { 1 to 5 },  map { "Key": "Value" } ) return json:serialize( $item,  map { 'format': 'xquery', 'indent': 'no' } )

Result: true "ABC" [1,2,3,4,5] {"Key":"Value"}

=Errors=

=Changelog=


 * Version 9.1
 * Updated: json:parse can be called with empty sequence.


 * Version 9.0
 * Updated:  format renamed to.
 * Updated: error codes updated; errors now use the module namespace


 * Version 8.4
 * Updated:  changed to.


 * Version 8.2
 * Added: Conversion format.


 * Version 8.0
 * Updated: Serialization aligned with the json output method of the official specification.
 * Added: liberal option.
 * Removed: spec option.


 * Version 7.8
 * Removed: json:parse-ml, json:serialize-ml.
 * Updated: json:parse now returns a document node instead of an element, or an XQuery map if format is set to .map.


 * Version 7.7.2
 * Updated: $options argument added to json:parse and json:serialize.
 * Updated: json:parse-ml and json:serialize-ml are now deprecated.

The module was introduced with Version 7.0.