1. JSON

    Two of the most popular data exchange formats for structured data on the internet today are XML and JSON.

    JSON (pronounced 'Jason' ) stands for JavaScript Object Notation.

    Like XML, JSON is a human readable text format, but JSON is lightweight and requires less overhead than XML.

    To facilitate interoperability, XQuery version 3.1 introduces support for consuming JSON data.

    In addition, XQuery 3.1 introduces support for maps and arrays allowing for a more natural representation of JSON data in XQuery expressions.

    Both maps and arrays have been covered extensively in the XPath 3.0 and 3.1 training: see Maps and Arrays

    1. Consuming JSON

      XQuery 3.1 provides two built-in functions which are used to parse JSON data:

      • parse-json()
      • json-doc()

      1. parse-json()

        The parse-json() function parses a string supplied in JSON format and typically returns a map or array.

        parse-json() has two signatures:

        • a one argument signature in which only the string to be parsed is supplied.
        • a two argument signature in which the second argument is a map of options which can be used to parse the supplied string.

        example: Parsing a basic json string which returns a map

        let $j := parse-json( ' { "name": "mike" , "age": 34 , "department": "accounting" } ' )
        return  <age> { $j?age } </age>
        result:
        <age>34</age>
        • For clarity, the image in this example is a pretty printed version of the JSON being string passed to the parse-json() function.
        • The JSON data in this example consists of a map containing key / value pairs for name, age and department.
        • The let clause assigns the map returned from the call to the parse-json() function, to the variable $j.
        • The return clause uses a direct element constructor to construct an element named age, and an enclosed expression to compute the content of age.
        • The enclosed expression outputs the value in the map associated with the key named age by using the lookup operator ? i.e. { $j?age }.

        example: Parsing a json string which returns a map containing a nested map

        let $j := parse-json( ' { "employee": { "name": "mike" , "age": 34 , "department": "accounting"  } } ' )
        return  <age> { $j?employee?age } </age>
        result:
        <age>34</age>
        • For clarity, the image in this example is a pretty printed version of the JSON being string passed to the parse-json() function.
        • The JSON data in this example consists of a map with a key named employee. The value associated with the employee key is a nested map containing key / value pairs for name, age and department.
        • The let clause assigns the map returned from the call to the parse-json() function, to the variable $j.
        • The return clause uses a direct element constructor to construct an element named age, and an enclosed expression to compute the content of age.
        • The enclosed expression outputs the value associated with the key named age using the lookup operator ? i.e. { $j?employee?age }.

        example: Parsing a json string which returns a map containing nested maps and arrays

        let $j := parse-json( ' { "employees": { "employee": [{ "name": "mike" , "age": 34 , "department": "accounting" },{ "name": "sally" , "age": 24 , "department": "sales" }] }  } ' )
        let $s := array:size( $j?employees?employee )
        for $i in (1 to $s)
        return  <age> {  $j?employees?employee($i)?age  } </age>
        result:
        <age>34</age>
        <age>24</age>
        • For clarity, the image in this example is a pretty printed version of the JSON being string passed to the parse-json() function.
        • The JSON data in this example consists of a map with a key named employees. The value associated with the employees key is a nested map consisting of a key named employee.
        • The value associated with the employee key is an array of two members. Each array member is a map containing key / value pairs for name, age and department.
        • The first let clause in this example assigns the map returned by the call to the parse-json() function to the variable $j.
        • The second let clause uses the array:size() function to determine the number of members in the array i.e. array:size( $j?employees?employee ).
        • The for clause binds the variable $i to the integer range (1 to $s) which evaluates to (1 to 2) and the iterates over each item in the sequence .
        • The return clause uses a direct element constructor to construct an element named age, and an enclosed expression to compute the content of age.
        • Notice how $i is used as a placeholder for an index indicating which employee is being processed i.e. $j?employees?employee($i).
      2. json-doc()

        The json-doc() function parses an external resource containing JSON and typically returns a map or array.

        json-doc() has two signatures:

        • a one argument signature in which only the external resource is supplied.
        • a two argument signature in which the second argument is a map of options which can be used to parse the supplied resource.

        example: Parsing an external json resource which returns a simple map

        let $j := json-doc( 'https://qrng.anu.edu.au/API/jsonI.php?length=1&amp;type=uint8' )
        return <random> { $j?data  } </random>
        result:
        <random>200</random>
        • The let clause in this example parses an external JSON resource and returns a map which is assigned to the variable $j.
        • The external resource returns a map which contains four key / value pairs. The value associated with the key named data is a one byte random number.
        • The return clause uses a direct element constructor to create an element named random and an enclosed expression to compute the element content.
        • The enclosed expression retrieves the value of the key named data from the map stored in $j.