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.
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.
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.
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:
_viewClass
: the qname of the service to call_base
: the default graph to use in the SWP_withImports
: whether the default graph should include imports (yes)
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:
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>
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" }
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.
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
.