SPARQL Web Pages - Creating JSON

For TopBraid 5.0 and above, last updated on October 23, 2018

Authors:
Holger Knublauch <holger@topquadrant.com>

Abstract

This document explains how SPARQL Web Pages (SWP) can be used to produce JSON output and to parse JSON into RDF. SWP includes a library called SWON that provides elements for JSON structures such as objects, arrays and name-value-pairs. SWP services can use those SWON elements to create arbitrary JSON text in a reliable and structured manner.

This document is part of the SPARQL Web Pages Specification.


Table of Contents

 

1 Introduction

JSON is arguably the most widely used result format of modern web services. This tutorial describes how to create SPARQL Web Pages (SWP) web services that produce and parse JSON.

By following the tutorial you will learn about the SWON namespace (ontology) and the convenient SWP elements it provides for creating JSON. SWON abstracts away the low level syntax of JSON, so that web service developers can concentrate on the content. SWON also includes support for frequently needed design patterns such as turning SPARQL result sets into JSON objects or arrays.

This document is about handling arbitrarily structured JSON. TopBraid's GraphQL support provides an alternative technology for many JSON-based use cases.

2 Setting up a JSON Web Service

For the remainder of this document, we assume that you want to create a library of SWP web services that operate on the schemakennedys.ttl example as its domain model. To get started, run TopBraid Composer ME and go to File > New > RDF/SWP File:

Make sure to select the Extended Turtle format (.ttlx) because this will create more readable files than normal Turtle. Also make sure you import the SWON namespace which includes the SWP elements for JSON generation. In older versions, make sure that the check box is activated that gives the file a .ui.ttlx extension. This file extension will make sure that the web services declared in the file can be easily accessed via a TopBraid Live web server.

In that file, add your domain model (here: the Kennedys file) to the imports:

Now you can navigate to the class ui:JSONServices in the Classes view:

ui:JSONServices should be the base class of all JSON services, because it declares the correct mime type. Right-click on ui:JSONServices and create a subclass, e.g. json-kennedys:getPersonInfo for the service outlined in the next paragraph.

Note that if you have just created the .ui.ttlx file, you may need to tell TopBraid to update its SWP graph registry using System > Refresh TopBraid system registries.

3 Creating Objects (swon:Object and swon:Value)

Let's assume we want to create a web service that takes the URI of a given schema:Person as its argument and returns the person's given name and family name as a simple JSON object. Open the form of the class json-kennedys:getPersonInfo which is a subclass of ui:JSONServices. In the context menu behind spin:constraint, click on Create spl:Argument and fill in the dialog as follows:

You can open up the resulting Argument to change its spl:valueType to schema:Person to clarify the type of the expected input argument:

Now scroll down to ui:prototype to enter the SWP elements that shall be executed whenever the service is invoked:

<swon:Object>
    <swon:Value arg:name="givenName" arg:value="{= spl:object(?person, schema:givenName) }"/>
    <swon:Value arg:name="familyName" arg:value="{= spl:object(?person, schema:familyName) }"/>
</swon:Object>

Now you can test the web service against the personal TopBraid Live server that is built into TopBraid Composer ME. Open a browser and enter the following URL:

http://localhost:8083/tbl/swp?
        _viewClass=json-kennedys:getPersonInfo&
        _base=http://topbraid.org/examples/schemakennedys&
        _withImports=true&
        person=http://topbraid.org/examples/kennedys%23JohnKennedy

The output is a JSON object such as:

{
    "givenName":"John",
    "familyName":"Kennedy"
}

A quick overview of the arguments of the web service call:

The other argument(s) such as person are passed into the SWP service and are accessible there as pre-bound variables. In the ui:prototype above, the variable ?person points to the argument specified by the client. TopBraid's SWP editor will highlight the pre-bound variables in bold face as shown below:

The ui:prototype uses two elements from the SWON namespace. swon:Object can be used to represent a JSON object and basically prints out the curly brackets around whatever is defined inside of the swon:Object. swon:Value represents a name-value-pair (attribute) where arg:name becomes the name of the JSON attribute and arg:value specifies the actual value. The SWON elements will make sure that characters are escaped to correct JSON syntax, so you can focus on the logic.

You can combine the SWON elements with any other SWP control element including ui:forEach and ui:if...ui:else as illustrated in the following example that produces exactly the same output as the original one:

4 Creating Arrays (swon:Array and swon:Values)

The SWON element swon:Array can be used to create JSON arrays. In a nutshell, this element renders [ ... ] around its child elements. The child elements of a swon:Array should be instances of either swon:Object or (from TopBraid 5.3 onwards) swon:Literal.

The following example extends the getPersonInfo web service so that it includes the children of the person:

The output of this is:

{
    "givenName":"John",
    "familyName":"Kennedy",
    "children":[
        {"fullName":"Patrick B. Kennedy"},
        {"fullName":"John Kennedy Jr"},
        {"fullName":"Caroline Kennedy"}
    ]
}

swon:Values (with an 's' at the end) can be used as a short form for swon:Value and swon:Array. The following prototype produces the same output as the one above:

The following example produces array members that are literals such as [42, true, "Hello"]:

<swon:Array>
    <swon:Literal arg:value="{= 42 }" />
    <swon:Literal arg:value="{= true }" />
    <swon:Literal arg:value="Hello" />
</swon:Array>

5 Creating JSON from ResultSets (swon:RSArray, swon:RSObject and swon:RSObjectArray)

If an array shall consist of plain JSON values such as strings, we can use swon:RSArray as shown below:

The output of this is:

{
    "givenName":"John",
    "familyName":"Kennedy",
    "children":["Patrick B. Kennedy","John Kennedy Jr","Caroline Kennedy"]
}

swon:RSObjectArray can be used to conveniently create complex objects. It takes a SPARQL result set as input and produces one object per row so that each variable becomes an attribute of the object:

The output of this is:

{
    "givenName":"John",
    "familyName":"Kennedy",
    "children":[
        {"givenName":"Caroline","familyName":"Kennedy"},
        {"givenName":"John","familyName":"Kennedy"},
        {"givenName":"Patrick","familyName":"Kennedy"}
    ]
}

Finally, swon:RSObject produces a single JSON object from a result set. This can be used to rewrite the original JSON to:

Which produces the same output as our original example:

{
    "givenName":"John",
    "familyName":"Kennedy"
}

6 Miscellaneous (swon:Comma, swon:Quote and swon:String)

The SWON namespace includes some helper elements that can help produce better structured SWP code.

swon:Comma and swon:Quote simply insert a comma or a quote character, respectively. While this appears to be trivial, it works around formatting issues with the SWP editor.

swon:String produces a correctly escaped JSON string including the quotes and (optionally) a comma, for cases where a JSON structure is produced "by hand" instead of with the built-in result set elements.

7 Parsing JSON (swon:parse)

This section is for TopBraid 5.3 onwards.

SWP can be used to process JSON, including JSON delivered by web service calls. The basic idea is that a JSON string is turned into RDF and the resulting RDF triples can be queried alongside other data. The built-in SWP element swon:parse can be used to perform this conversion while other TopBraid features such as sml:ImportTextFromURL can be used to retrieve JSON strings from a service.

swon:parse produces triples using the SWON RDF vocabulary. For example, if you have a JSON object { "arg" : "value" } you can parse it in SWP using

<swon:parse arg:text="{ 'arg' : 'value' }" />

and the resulting RDF triples (in Turtle notation) are:

[
    a swon:Object ;
    ui:child [
        a swon:Value ;
        arg:name "arg" ;
        arg:value "value" ;
        ui:childIndex 0 ;
    ]
] .

By default, swon:parse produces the result triples in the graph ui:tempGraph. This can be changed with the argument arg:graph. If you need to access the root resource (above, the blank node of type swon:Object, you can add child elements into the swon:parse elements and access the variable ?json, or any other variable specified by the argument arg:varName.

Here is a complete example that requests JSON from a given web service, parses the JSON and then walks all name-value pairs of the returned JSON object.

<sml:ImportTextFromURL sm:outputVariable="text" sml:url="https://jsonplaceholder.typicode.com/posts/1">
    <swon:parse arg:text="{= ?text }">
        <ui:forEach ui:resultSet="{#
                SELECT ?name ?value
                WHERE {
                    GRAPH ui:tempGraph {
                        ?json ui:child ?valueNode .
                        ?valueNode arg:name ?name .
                        ?valueNode arg:value ?value .
                    } .
                }
                ORDER BY (?name) }">
            <div>{= ?name } = {= ?value }</div>
        </ui:forEach>
    </swon:parse>
</sml:ImportTextFromURL>

As an alternative to swon:parse, see also ui:json.