JSON Module

From BaseX Documentation
Revision as of 18:21, 24 September 2013 by CG (talk | contribs) (→‎json:serialize)
Jump to navigation Jump to search

This XQuery Module contains functions to parse and serialize JSON documents. JSON (JavaScript Object Notation) is a popular data exchange format for applications written in JavaScript. As there are notable differences between JSON and XML, no mapping exists that guarantees a lossless, bidirectional conversion between JSON and XML. For this reason, we offer two sets of functions in this module:

Conventions

All functions in this module are assigned to the http://basex.org/modules/json namespace, which is statically bound to the json prefix.
All errors are assigned to the http://basex.org/errors namespace, which is statically bound to the bxerr prefix.

Formats

BaseX

The standard BaseX JSON format facilitates a lossless conversion from JSON to XML and back. The transformation is based on the following rules:

  1. The resulting document has a <json/> root node.
  2. Names (keys) of objects are represented as elements:
    1. Empty names are represented by a single underscore (<_>...</_>).
    2. Underscore characters are rewritten to two underscores (__).
    3. A character that cannot be represented as NCName character is rewritten to an underscore and its four-digit Unicode.
  3. As the members of arrays have no names, <value/> is used as element name.
  4. JSON values are represented as text nodes.
  5. The types of values are represented in attributes:
    1. The value types number, boolean, null, object and array are represented by a type attribute.
    2. The string type is omitted, as it is treated as default type.
    3. If a name has the same type throughout the document, the type attribute will be omitted. Instead, the name will be listed in additional, type-specific attributes in the root node. The attributes are named by their type in the plural (numbers, booleans, nulls, objects and arrays), and the attribute value contains all names with that type, separated by whitespaces.

JsonML

The JsonML format can be used to transform 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.

Functions

json:parse

Version 7.7.2: $options argument added

Signatures json:parse($input as xs:string) as element(json)
json:parse($input as xs:string, $options as item()) as element(json)
Summary Converts the JSON document specified by $input to XML, and returns the result as element(json) instance. The converted XML document is both well readable and lossless, i.e., the converted document can be serialized back to the original JSON representation.
The $options argument can be used to control the way the input is converted. The following options are available (they bear resemblance to the ones specified in XSLT 3.0):
  • spec determines the used JSON specification. Allowed values are RFC4627, ECMA-262, and liberal; the default is (RFC4627).
  • unescape determines whether escape sequences (marked by a backslash) in the input are expanded. The default is true.
  • format determines the conversion format. Allowed values are json, jsonml, and map; the default is json.

Options can either be specified

  • as children of an <json:options/> element; e.g.:
<json:options>
  <json:format value='jsonml'/>
  ...
</json:options>
  • or as map, which contains all key/value pairs:
{ 'format' : 'jsonml', ... }
Errors BXJS0001: the specified input cannot be parsed as JSON document.
BXJS0003: a specified option cannot be parsed.

json:serialize

Version 7.7.2: $options argument added

Signatures json:serialize($input as node()) as xs:string
json:serialize($input as node(), $options as item()) as xs:string
Summary Serializes the node specified by $input as JSON, and returns the result as xs:string instance. The serialized node must conform to the syntax specified by the json:parse() function.
XML documents can also be serialized as JSON if the Serialization Option method is set to json.
The $options argument can be used to control the way the input is serialized. The following options are available (they bear resemblance to the ones specified in XSLT 3.0):
  • spec determines the used JSON specification. Allowed values are RFC4627, ECMA-262, and liberal; the default is (RFC4627).
  • unescape determines whether escape sequences (marked by a backslash) in the input are expanded. The default is true.
  • format determines the conversion format. Allowed values are json and jsonml; the default is json.

Options can either be specified

  • as children of an <json:options/> element; e.g.:
<json:options>
  <json:format value='jsonml'/>
  ...
</json:options>
  • or as map, which contains all key/value pairs:
{ 'format' : 'jsonml', ... }
Errors BXJS0002: the specified node cannot be serialized as JSON document.

json:serialize-ml

Version 7.7.2: deprecated; please use json:serialize instead.

Signatures json:serialize-ml($input as node()) as xs:string
Summary Serializes the node specified by $input and returns the result as xs:string instance.
XML documents can also be output in the JsonML format by setting the Serialization Option "method" to "jsonml".
Errors BXJS0002: the specified value cannot be serialized.

json:parse-ml

Version 7.7.2: deprecated; please use json:parse instead.

Signatures json:parse-ml($input as xs:string) as element()
Summary Converts the JsonML document specified by $input to XML, and returns the result as element() instance. The JSON input must conform to the JsonML specification to be successfully converted.
Errors BXJS0001: the specified input cannot be parsed as JsonML instance.

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, document { $json }, $name) 

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

Query:

json:parse('{}')

Result:

<json objects="json"/>

Query:

(: serialize result as plain text :)
declare option output:method 'text';
json:serialize(<json objects="json"/>)

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": "2009-02-02T11:10:27Z",
  "generator": "http://www.flickr.com/"
}')

Result:

<json objects="json">
  <title>Talk On Travel Pool</title>
  <link>http://www.flickr.com/groups/talkontravel/pool/</link>
  <description>Travel and vacation photos from around the world.</description>
  <modified>2009-02-02T11:10:27Z</modified>
  <generator>http://www.flickr.com/</generator>
</json>

Example 4: Converts a JSON string with different data types

Query:

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
    }
  ]
}')

Result:

<json numbers="age code" arrays="phone" objects="json address value">
  <first__name>John</first__name>
  <last__name>Smith</last__name>
  <age>25</age>
  <address>
    <street>21 2nd Street</street>
    <city>New York</city>
    <code>10021</code>
  </address>
  <phone>
    <value>
      <type>home</type>
      <number>212 555-1234</number>
    </value>
    <value>
      <type>mobile</type>
      <number type="number">1327724623</number>
    </value>
  </phone>
</json>

JsonML Format

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

Query:

for $doc in collection('json')
let $name := document-uri($doc)
let $json := json:serialize($doc)
return file:write($name, $json)

Example 2: Converts a simple XML fragment to the JsonML format

Query:

json:serialize(<xml/>, { 'format': 'jsonml' })

Result:

["xml"]

Example 3: Converts an XML document with elements and text

Query:

json:serialize(doc('flickr.xml'), { 'format': 'jsonml' })

flickr.xml:

<flickr>
  <title>Talk On Travel Pool</title>
  <link>http://www.flickr.com/groups/talkontravel/pool/</link>
  <description>Travel and vacation photos from around the world.</description>
  <modified>2009-02-02T11:10:27Z</modified>
  <generator>http://www.flickr.com/</generator>
</flickr>

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",
    "2009-02-02T11:10:27Z"],
  ["generator",
    "http:\/\/www.flickr.com\/"]]

Example 4: Converts a document with nested elements and attributes

Query:

json:serialize(doc('input.xml'), { 'format': 'jsonml' })

input.xml:

<address id='1'>
  <!-- comments will be discarded -->
  <last_name>Smith</last_name>
  <age>25</age>
  <address xmlns='will be dropped as well'>
    <street>21 2nd Street</street>
    <city>New York</city>
    <code>10021</code>
  </address>
  <phone type='home'>212 555-1234</phone>
</address>

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"]]

Errors

Code Description
BXJS0001 The specified input cannot be parsed as JSON document.
BXJS0002 The specified node cannot be serialized as JSON document.
BXJS0003 A specified option cannot be parsed.

Changelog

Version 7.7.2

The module was introduced with Version 7.0.