29 January 2017
This version: http://ns.inria.fr/sparql-template
This document defines the syntax and semantics of the STTL language. STTL stands for SPARQL Template Transformation Language. In STTL transformations describe rules for transforming an RDF source graph into a text result. STTL is designed as an extension of the SPARQL 1.1 Query Language to build on standards and ease its adoption.
RDF provides us with a general purpose graph-oriented data model to represent and interchange data on the Web. However, the transformation and presentation of RDF data is still an open issue. Among the initiatives to answer this question there are extensive works for providing RDF with several varied syntaxes (XML, N-Triples, Turtle, RDFa, TriG, N-Quads, JSON-LD) and for linking it to other data sources (R2RML, CSV-LD, etc.). With the multiplication of data sources and data formats, developers of the Web of data now spend a lot of time and energy to build transformations to present RDF data to users and transform data from one source to another. Moreover, RDF is more and more used as a syntax to represent other languages (e.g. SPIN) and we consider that RDF can then be viewed as a pivot language to represent the abstract syntax trees of expressions of other languages.
For this reason, we propose the SPARQL Template Transformation Language (STTL) that enables Semantic Web developers to write specific yet compact RDF transformers toward other languages and formats. This document defines the syntax and semantics of STTL. A transformation expressed in STTL describes rules for transforming an RDF source graph into a text result. STTL is an extension of SPARQL 1.1 Query Language. To some extend STTL is to RDF what XSLT is to XML. An STTL engine takes an RDF graph and a transformation (a set of templates) as input and generates a textual output format as a character stream. Output format may be unstructured text such as natural language, or structured text such as Turtle, HTML, XML, Latex, CSV, etc. If the RDF graph represents the Abstract Syntax Tree of another language, e.g. SPIN, the transformation engine may generate a concrete syntax, e.g. SPARQL.
STTL is related with SPARQL, RDF and somehow with XSLT.
XSLT is a language for transforming XML documents into other XML documents.
STTL is similar to XSLT as it is a language for transforming RDF graphs into text formats such as RDF documents. However, STTL operates on the graph model of RDF, not on its syntax (that is, not on its RDF/XML syntax).
STTL is built on top of SPARQL 1.1 Query Language. It is an extension of SPARQL with an additional template query form and a set of extension functions.
STTL uses the prefix and namespaces shown below, which are omitted in the rest of the document:
prefix st: <http://ns.inria.fr/sparql-template/> prefix foaf: <http://xmlns.com/foaf/0.1/> prefix ex: <http://example.org/ns/>
A transformation is a set of templates. A template is a declarative rule with a condition part and a format part. A template is applied on a focus node. A focus node is an RDF term of the RDF graph that is currently processed by a transformation engine.
A transformation can be defined in two different formats.
In the process of finding the applicable template, more than one template may be eligible. However, in the general case, only one template will be applied. The first template in the transformation is chosen except if templates have priorities. In this case, the template with the highest priority is chosen.
SPARQL 1.1 Query Language proposes four query forms: select, construct, ask and describe. STTL proposes an additional query form: template. The template where query form is used to specify a text pattern that is instantiated with the results of the where clause. It is similar to the construct clause but generates text instead of generating RDF triples. The text pattern is made of constants (literals) and evaluable expressions (variables, function calls, etc.).
The where clause is executed as a SPARQL query where clause, with focus node bound to variable ?in if any, producing a solution sequence. It must be noted that the from, from named, order by, group by, having, limit, offset and values clauses are available for templates with the same syntax and semantics as SPARQL.
The template clause is instantiated for each solution of the where clause, producing a text for each solution. Variables in the template clause are replaced by their value from the solution, using by default the Turtle syntax. The result of a template is the concatenation of the text results produced by all the solutions. It must be noted that aggregates are available in the template clause with the same semantics as SPARQL. In the case of aggregates, the aggregate operations are performed, possibly with group by, thus producing a new solution sequence. The template clause is evaluated on the solution sequence resulting from the aggregate.
The example below lists all the triples linking URI in the current RDF graph in NTriple format.
template { ?in " " ?p " " ?o " ." } where { ?in ?p ?o filter (isURI(?in) && isURI(?o)) }
A template can have a name (an URI) and parameters. In the example shown below, the name of the template is ex:display and the parameter list is (?x).
template ex:display(?x) { st:apply-templates(?y) } where { ?x foaf:knows ?y }
The data model used by STTL is the same as the one used by SPARQL: RDF Dataset. The data model used by STTL is the RDF Dataset resulting from the parsing of the input RDF document(s) whatever their syntax is: RDF/XML, Turtle, N3, JSON-LD or RDFa. If the triple store is provided with an entailment regime (e.g. RDFS), STTL exploits the entailments in the same way than SPARQL.
The result of a transformation is a text, that is a character stream. The text can be structured (HTML, RDF/XML, XML, etc.), it can represent statements of a language (e.g. Turtle, SPARQL, OWL functional syntax, etc.), it can be natural language, etc.
In the process of finding the applicable template, more than one template may be eligible. In the general case, only one template will be applied. If no indication is given the first template applied following the order of the .rq files or the RDF document. Alternatively, if the possible templates have specified priorities, the template with the highest priority is chosen.
A template in a transformation may apply other templates. This is done using the st:apply-templates extension function. Below is an example of template which generates the functional syntax of an OWL allValuesFrom restriction statement.
template { "allValuesFrom(" st:apply-templates(?p) " " st:apply-templates(?c) ")" } where { ?in a owl:Restriction ; owl:onProperty ?p ; owl:allValuesFrom ?c . }
The previous template when applied to :
[] a owl:Restriction ; owl:onProperty foaf:knows ; owl:allValuesFrom foaf:Person .
generates the text below:
allValuesFrom(foaf:knows foaf:Person)
In the template above, two variables occur in the template clause: ?p and ?c. These variables are recursively processed by the st:apply-templates extension function using the set of templates of the transformation. If no template succeeds, a default format is generated which is the Turtle format. The where clause is the same as in SPARQL, except that variable ?in is bound to the focus node. The focus node is the node that is the argument of the current st:apply-templates function call.
The st:apply-templates function applies the first template in the transformation such that 1) the template were not already applied on the same focus node previously, 2) the where clause, with its ?in variable bound to the focus node, returns a solution sequence that is not empty and 3) the template clause does not raise an error.
Note that the st:apply-templates function can be called in the where part as shown below.
template { "allValuesFrom(" ?pp " " ?cc ")" } where { ?in a owl:Restriction ; owl:onProperty ?p ; owl:allValuesFrom ?c . bind (st:apply-templates(?p) as ?pp) bind (st:apply-templates(?c) as ?cc) }
A named template is called by name with parameter values using the st:call-template function. When several parameters occur, parameter passing is done by position (i.e. not by name).
template { st:call-template(ex:display, ?in) } where { ?in a foaf:Person }
The result of a template is the concatenation of the texts resulting from the instantiation of the template clause on every solution of the where clause. By default, a newline character is inserted as separator between text solutions. It is possible to overload the separator using the separator statement, similar to the SPARQL group_concat aggregate separator statement as shown below.
template { ?name ; separator = ", " } where { ?in foaf:name ?name }
In order to apply templates, the language provides a set of SPARQL extension functions. Running a transformation engine on a set of templates is done by an initial call to st:apply-templates-with in a SPARQL query (or a template) where the st-uri argument is the URI of the transformation. This function can also be used to apply another transformation within a transformation. Hence a complex transformation can be split into simpler ones. The uri argument of st:call-template is the name of a template. The term argument is the focus node, it is an RDF term.
In some cases, it is necessary to apply several templates in order to transform a focus node. In this case, the st:apply-templates-all function may be used. The result of st:apply-templates-all is the concatenation of the results of all the templates that succeed.
The st:apply-templates-graph functions enables the transformer to focus on a specific named graph. The graph-uri argument is the name of a graph.
The st:call-template functions enables the transformer to call a specific named template. The uri argument is the name of a named template.
st:apply-templates(term) st:apply-templates-with(st-uri) st:apply-templates-with(st-uri, term) st:apply-templates-all(term) st:apply-templates-with-all(st-uri, term) st:apply-templates-graph(graph-uri) st:apply-templates-with-graph(st-uri, graph-uri) st:call-template(uri, term_1, .., term_n) st:call-template-with(st-uri, uri, term_1, .., term_n)
There are aditional utility functions.
st:turtle(term) st:format(text-format, term, ...) st:number() st:nl()
st:turtle returns the Turtle format of an RDF term.
st:format given a text pattern with %s text variables and expressions, returns a formatted string.
st:number returns a number corresponding to the solution position.
st:nl returns a new line and take indentation defined by box into account.
SPARQL functions can be used in the template clause.
template { "The name of " xsd:string(?in) " is " xsd:string(?n) "." } where { ?in foaf:name ?n }
STTL provides a "hook" to define extension functions that are available within a transformation. To do so, STTL provides a simple formalism to define SPARQL extension functions. The function clause enables users to define a function with an URI as name and a list of parameter variables. The body of the function is defined using SPARQL filter language.
function ex:display(?x) { if (isURI(?x), concat("<", str(?x), ">"), str(?x)) } function ex:fac(?n) { if (?n = 0, 1, ?n * ex:fac(?n - 1)) }
As there are no natural root nodes in a graph, we provide the possibility to define a specific start template that determines the nodes to start with. The start template, if any, is the st:start named template. Otherwise, the first template of the transformation that succeeds is applied.
template st:start { st:apply-templates(?x) } where { ?x a foaf:Person }
The st:profile named template enables users to define extension functions. This template is not executed (this is why it is empty), it is a place holder for function definition and it is considered at compile time only. By convention, function definitions that are listed below the st:profile template are available for all templates of the transformation.
Function st:process is a predefined function that specifies the processing of variables in the template clause. The default behaviour is to call st:turtle to generate the Turtle format of the argument. This function can be overloaded.
In the example below, st:apply-templates is called on blank nodes and st:turtle is called on URIs and literals.
template st:profile {} where {} function st:process(?x) { if (isBlank(?x), st:apply-templates(?x), st:turtle(?x)) }
STTL provides a mechanism to attach a priority to templates. In the case where several templates may be applied, the one with the highest priority is chosen. In the case where several templates may succeed, it may be necessay to sort templates according to an explicit priority. Smaller numbers represent higher priority.
Pragma enables to define priority. It may be used in the future to define new features.
template { ... } where { ... } pragma { st:template st:priority 1 }
Conditional processing is done using SPARQL if then else filter expression.
template { if (?age >= 18, st:call-template(st:adult, ?in), st:call-template(st:child, ?in)) } where { ?in foaf:age ?age }
The combined use of if, st:call-template and recursion enables to implement powerful processing such as printing the development of n!.
template st:fac(?n) { if (?n = 0, 1, concat(?n, ".", st:call-template(st:fac, ?n - 1))) } where {}
Sorting is done using SPARQL order by clause.
template { st:apply-templates(?in) } where { ?in a foaf:Person ; foaf:name ?name } order by ?name
The group statement is syntactic sugar for group_concat() aggregate operation, except that it can have several arguments. In addition, it can have a separator which acts in the same way as SPARQL group_concat aggregate separator. Below is an example that concatenates the elements of a list.
template { "list(" group { ?elem } ")" } where { ?in rdf:rest*/rdf:first ?elem }
Box enable to increment the indentation of the output character stream when st:nl() is used.
template { "list(" box { group { ?elem st:nl() } } ")" } where { ?in rdf:rest*/rdf:first ?elem }
Format enable to specify a string pattern with text variables (%s) and a list of expressions. Text variables are replaced by the values of expressions.
template { format { "<h1>%s</h1><p>%s</p>" ?title ?text } } where { ?in ex:title ?title ; ex:text ?text }
We provide the syntax of SPARQL template, based on SPARQL 1.1 grammar.
Template ::= Prologue TemplateClause DatasetClause* WhereClause SolutionModifier ValuesClause Pragma Function* TemplateClause ::= 'template' NameArg ? '{' TExpression * Separator ? '}' TExpression ::= PrimaryExpression | Box | Format | Group NameArg ::= (iri VarList) | VarList VarList ::= '(' Var * ')' Group ::= 'group' ( 'distinct' ) ? '{' ( PrimaryExpression | Box | Format ) * Separator ? '}' Box ::= 'box' '{' TExpression * '}' Format ::= 'format' '{' PrimaryExpression TExpression + '}' Separator ::= ';' 'separator' '=' String Pragma ::= ( 'pragma' '{' Triple+ '}' ) ? Function ::= 'function' iri VarList '{' PrimaryExpression '}'
Syntax of the RDF document for tranformations is given in RDF/XML format. Each template must define its prefix and namespaces.
<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#' xmlns='http://ns.inria.fr/sparql-template/'> <rule> <body> <![CDATA[ prefix st: <http://ns.inria.fr/sparql-template/> template st:list(?l) { ?e } where { ?l rdf:rest*/rdf:first ?e } ]]> </body> </rule> <rule> <body> ... </body> </rule> </rdf:RDF>
SPARQL Templates are compiled as select-where SPARQL queries where variables in the template clause are replaced by a call to the st:process extension function. Its default behaviour is to call st:turtle. When st:process is bound to st:apply-templates in the profile, it implements the recursive call to the transformation engine. This function plays a similar role as the xsl:apply-templates clause in XSLT. Its behavior consists in executing templates one by one from the set of templates until one of them succeeds. The result of the st:apply-templates function call is the result of this successful template execution.
A template succeeds if the evaluation of the where clause returns solution(s) and if the evaluation of the template clause does not raise an error. An error may be caused by an unbound variable.
The focus node is the node that the transformation engine is processing at the current time. It is bound to a distinguished ?in variable the value of which is determined at run time by a process equivalent to the one shown below where the st:getFocusNode() function represents the focus node value determined from the environment.
The template below:
template { "allValuesFrom(" ?p " " ?c ")" } where { ?in a owl:Restriction ; owl:onProperty ?p ; owl:allValuesFrom ?c . }
is compiled into a select-where SPARQL query as shown below. The st:concat function is similar to the SPARQL concat function.
select (st:concat ( "allValuesFrom(", st:process(?p), " ", st:process(?c), ")") as ?out) where { bind (st:getFocusNode() as ?in) . ?in a owl:Restriction ; owl:onProperty ?p ; owl:allValuesFrom ?c . }
Executing a template consists first in executing the where part which results in a solution sequence (i. e. variable bindings). Then the select clause is executed, providing a solution sequence extended with the projected variable ?out. This is standard SPARQL query execution. To finish, an additional group_concat(?out) aggregate operation is performed on the SPARQL solution sequence, resulting into one solution where all values of the ?out variable are concatenated into a string value. This is the final result of the template and this is the result returned by the st:apply-templates function. Hence, it is possible to implement a STTL engine on top of a SPARQL interpreter using extension functions.
The group statement:
template { "list(" group { ?x ?y } ")" } where { ... }
is compiled as:
select (st:concat("list(", group_concat(concat(st:process(?x), st:process(?y))), ")") as ?out) where { ... }
We present some use cases for STTL.
List the content of a graph in Turtle syntax.
template { ?x " " ?p " " ?y "." } where { ?x ?p ?y } order by ?x ?p ?y
List the named graphs of a Dataset in Trig syntax.
template { "graph " ?g " {\n" group { ?x " " ?p " " ?y ".\n" } "}" } where { graph ?g { ?x ?p ?y } } group by ?g order by ?g
Generate an HTML table with the triples of the RDF graph.
template { format { """ <html> <body> <table>%s</table> </body> </html> """ group { format { "<tr><td>%s</td><td>%s</td><td>%s</td></tr>\n" ?s ?p ?o } } } } where { ?s ?p ?o } order by ?s ?p ?o
SPARQL Template Transformation Language aims at generating presentation format for RDF graphs. It is designed as an extension of SPARQL 1.1 Query Language. STTL is available in the Corese Semantic Web Factory and it is used in the Corese Web server. Preliminary works show that STTL can also be used to perform constraint checking with templates that return boolean values instead of text.