XQuery/Simile Exhibit

Motivation edit

You want to create a Simile Exhibit output of an XML file. To do this we will need to convert XML to JSON file format.

Method edit

You have a file of contributors to a book and you would like to create a map of their locations.

<contributors>
    <contributor>
        <author-name>John Doe</author-name>
        <bio>John is a software developer interested in the semantic web.</bio>
        <location>New York, NY</location>
        <image-url>http://www.example.com/images/john-doe.jpg</image-url>
    </contributor>
    <contributor>
        <author-name>Sue Anderson</author-name>
        <bio>Sue is an XML consultant and is interested in XQuery.</bio>
        <location>San Francisco, CA</location>
        <image-url>http://www.example.com/images/sue-anderson.jpg</image-url>
    </contributor>
</contributors>

XQuery to Output JSON File edit

First we must transform our XML file into JSON format. This is a little tricky because JSON required the curly brace characters to be added to the output. The can be done by creating special variables that contain the strings.

In the XQuery header we also have to change the serialization method from our traditional XML to text/plain.

We also have to wrap our item output in a string-join() function to prevent the last comma from being serialized.

JSON files are just another file format for storing hierarchical data. Just like XML. JSON is used mostly by JavaScript developers that are not either not familiar with XML or don't have XML editing tools to validate file formats. JSON does allow for nesting of complex data but does not support many XML features such as namespaces.

Unlike XQuery, JSON file formats do not permit a "dash" character in the label unless you put quotes around the label. So note that the image-url property label has quotes around it.

xquery version "1.0";
declare option exist:serialize "method=text media-type=text/plain";

let $document := '/db/apps/exhibit/data/contributors.xml'
(: special characters such as left and right curly brace and newline  :)
let $lcb := '{', $rcb := '}', $nl := '
'
(: json file header and footer as well as item header and footers :)
let $json-header := concat($lcb, $nl, ' "items" : [ ')
let $json-footer := concat($nl, '  ]', $nl,$rcb)
let $item-header := concat($nl, '    ', $lcb, '  ')
let $item-footer := concat('    ', $rcb)
return
<results>{$json-header}
{
   string-join(
      for $contributor in doc($document)/contributors/contributor
      return
<item>{$item-header}label:       "{$contributor/author-name/text()}",
       location:     "{$contributor/location/text()}",
       "image-url":    "{$contributor/image-url/text()}"
{$item-footer}</item>
   , ', ')
}{$json-footer}</results>

Sample JSON Output edit

{
 "items" : [ 
    {  label:        "John Doe",
       location:     "New York, NY",
       "image-url":  "http://www.example.com/images/john-doe.jpg"
    }, 
    {  label:        "Sue Anderson",
       location:     "San Francisco, CA",
       "image-url":  "http://www.example.com/images/sue-anderson.jpg"
    }
  ]
}

Alternative Approach edit

An alternative is to use the fact that curly-braces can be escaped in XQuery by doubling. Since the output is being serialized as text, all elements will be serialised, so there is no need to serialise items separately.

xquery version "1.0";
declare option exist:serialize "method=text media-type=text/plain";
let $document := '/db/Wiki/JSON/contributors.xml'
return

<result>
{{
  "items" : [
{
   string-join(
      for $contributor in doc($document)/contributors/contributor
      return
<item>
       {{
label: "{$contributor/author-name}",
location: "{$contributor/location}",
"image-url":  "{$contributor/image-url}"
       }}
</item>
       , ', '
     )
}
     ]
}}
</result>

Execute