wOTTR: Web Reasonable Ontology Templates
top
examples:
/
SHACL:
/
Table of Contents
Web Reasonable Ontology Templates (wOTTR)
RDF serialisation format for OTTR templates and instances
- Version
- 0.4.6
- Published
Tue Aug 18 15:16:48 2026- Authors
- Martin G. Skjæveland
- Issues
- https://gitlab.com/ottr/language/wOTTR/issues
1. Introduction
This specification defines the RDF serialisation of Reasonable Ontology Templates (OTTR), called Web Reasonable Ontology Templates (wOTTR).
With wOTTR it is possible to express templates and template instances in an RDF format that is designed to be compact and readable. Given that wOTTR is defined for RDF it is possible to leverage the existing W3C stack of languages and tools to work with OTTR templates.
The vocabulary of the wOTTR language is specified by an OWL ontology presented in section 3.5.2 and the grammar is defined by a SHACL shape specification presented in section 2.2. The appendix (section 3) contains unit tests.
This example of a template serialised in wOTTR gives a reasonable
complete introduction to the syntax without further explanation. The
example shows the NamedPizza template which specifies three parameters
(on lines 4, 7 and 11) typed as respectively
owl:Class, owl:NamedIndividual and a list of owl:Class-es. The
second parameter is set as optional.
The template's pattern contains 5 template instances (lines
15, 18, 26, 30 and 34). The
pattern instance of the template ax:SubObjectSomeValuesFrom (line
18) takes three arguments, where the third argument is "list
expanded" (line 23) using the cross modifier (line
24).
The template is annotated by an annotation instance (line 40).
This template is explained in more detail in section 3.2.
1: pizza:NamedPizza a ottr:Template ; 2: ottr:parameters ( 3: 4: [ ottr:type owl:Class; 5: ottr:variable _:pizza ] 6: 7: [ ottr:type owl:NamedIndividual; 8: ottr:variable _:country; 9: ottr:modifier ottr:optional ] 10: 11: [ ottr:type ( rdf:List owl:Class ); 12: ottr:variable _:toppings; ] ) ; 13: 14: ottr:pattern 15: [ ottr:of ax:SubClassOf ; 16: ottr:values ( _:pizza p:NamedPizza ) ] , 17: 18: [ ottr:of ax:SubObjectSomeValuesFrom ; 19: ottr:arguments ( 20: [ ottr:value _:pizza ] 21: [ ottr:value p:hasTopping ] 22: [ ottr:value _:toppings; 23: ottr:modifier ottr:listExpand ] ) ; 24: ottr:modifier ottr:cross ] , 25: 26: [ ottr:of ax:SubObjectHasValue ; 27: ottr:values 28: ( _:pizza p:hasCountryOfOrigin _:country ) ] , 29: 30: [ ottr:of ax:SubObjectAllValuesFrom ; 31: ottr:values 32: ( :pizza p:hasTopping _:alltoppings ) ] , 33: 34: [ ottr:of rstr:ObjectUnionOf ; 35: ottr:values 36: ( _:alltoppings _:toppings ) ] ; # end pattern 37: 38: ## new feature 39: ottr:annotation 40: [ ottr:of <http://example.net/ns#TemplateAnnotation> ; 41: ottr:values ( pizza:NamedPizza "A pizza template" ) ] .
1.1. Documents
This specification consists of the following files:
- ./core-vocabulary.owl.ttl
- Ontology declaring the core vocabulary of wOTTR.
- ./core-grammar.shacl.ttl
- Shape definitions of wOTTR grammar rules.
- ./all.owl.ttl
- Ontology that imports all OTTR specifications, including the above.
- ./index.html
- This file.
Other files:
- ./examples.zip
- all the examples in this document
- ./tests.zip
- all the unit tests in this document
- ./std-tokens.shacl.ttl
- Shape definitions that restrict the
rdf:,rdfs:,owl:andsh:namespace to the standard respective vocabularies. - ./ottr-tokens.shacl.ttl
- Shape definitions that restrict the
ottr:namespace to the vocabulary defined in this specification.
1.2. Changelog
- 0.4.6
- Typo fixes.
- 0.4.4
- Fixed internal template in tpl/ used to generate vocabulary: use the same URL to publish as the templates own URL.
- 0.4.3
- Fixed basic unit tests and remove them from the set of wOTTR unit tests. Added some change notes to the ontology.
- 0.4.2
- Added ottr:NullableTriple as a base template. Added ottr:Status a set of instances of this class. Changed unit test implementation to using jena-shacl.
1.3. Document conventions
1.3.1. Notation
This is a defined term.
This is a mention of a defined term.
This is an example box. Examples are informative.
Examples are standalone and makes no reference to external resources unless explicitly stated. The examples are meant to illustrate use of the syntax, and not necessarily to display interesting or useful templates.
This is a box containing a normative SHACL shape snippet.
1.3.2. Prefixes
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> . @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . @prefix owl: <http://www.w3.org/2002/07/owl#> . @prefix skos: <http://www.w3.org/2004/02/skos/core#> . @prefix vann: <http://purl.org/vocab/vann/> . @prefix dc: <http://purl.org/dc/elements/1.1/> . @prefix foaf: <http://xmlns.com/foaf/0.1/> . @prefix dcterms: <http://purl.org/dc/terms/> . @prefix cc: <http://creativecommons.org/ns#> . @prefix sh: <http://www.w3.org/ns/shacl#> . @prefix shsh: <http://www.w3.org/ns/shacl-shacl#> . @prefix ex: <http://example.net/ns#> . @prefix ottr: <http://ns.ottr.xyz/0.4/> . @prefix o-wottr: <http://spec.ottr.xyz/wOTTR/0.4.4/tpl/> .
1.3.3. Diagrams
The diagrams in this document are informal, but should be understood in the following way:
- Arrows with open heads indicate subclass relationships—pointing to the superclass
- Dotted arrows indicate type relationships—pointing to the class
- Other arrows indicate domain and possibly range restrictions to
properties—pointing from the domain (arrow source) to the
range (arrow target):
- A regular arrowhead indicates a regular domain and range restriction
- A diamond arrowhead indicates that the range is a list of the target class
- An empty blue target indicates that the range is unspecified
2. wOTTR language
First we give an overview of the wOTTR vocabulary, then present each shape in detail.
In order make the presentation more readable, we will frequently
write, "a Class", e.g., "a ottr:Template", and take this to mean
a resource of type ottr:Template. Also, we will write, e.g., "a
ClassX has a property which is a ClassY" and take this to mean
that there must be a triple (x, property , y), where x has
the type ClassX and y has the type ClassY, e.g., "an
ottr:Argument has a ottr:value which is an RDF resource". The
type information need not be explicitly stated, but can be inferred.
2.1. Vocabulary
The wOTTR vocabulary lies close to the formal vocabulary established in mOTTR
[1] and rOTTR [2]. We will therefore not explicitly
establish the (reasonably obvious) connection between these vocabularies, e.g.,
that the wOTTR vocabulary element ottr:Template represents a
template as defined in mOTTR [1].
The wOTTR language makes frequent use of RDF lists as a means to represent an ordering of resources. We do this since RDF lists have a succinct serialisation in RDF Turtle, as seen in the above example, which makes template instances syntactically similar to ordinary function calls and predicates. A consequence of using RDF lists is that wOTTR goes beyond the OWL 2 DL language fragment, since RDF lists are used for the serialisation of OWL.
A schematic overview of the ontology is given in Figure 2.
The classes, properties and individuals of the wOTTR vocabulary are presented in the next sections. Each section contains a table. The wOTTR ontology is produced from these tables by converting the tables into OTTR template instances whose expansion, plus some additional ontology metadata, gives the ontology. This process is shown in the appendix.
The tables use the following formatting rules:
- Column headers with a trailing question mark indicate that a value in this column is optional.
- Table cells with a trailing
*are not translated into the ontology. This is done in the following cases:- Cells that contain lists.
- Cells that contain the value
rdfs:Resource.
2.1.1. Classes
The classes of the vocabulary are listed in Table 1.
Each row represents a owl:Class with optional superclass
relationship (using rdfs:subClassOf), textual definition
(skos:definition) and optional note (skos:note).
2.1.2. Properties
The properties of the vocabulary are listed in Table 2.
Each row represents an
owl:AnnotationProperty with optional domain (rdfs:domain) and
optional range (rdfs:range), textual definition (skos:definition) and
optional node (skos:note).
The reasons for using owl:AnnotationProperty to represent the
properties (and not owl:ObjectProperty and
owl:DatatypeProperty) is that
- many of the properties take RDF lists as values, which places the vocabulary outside the OWL 2 DL fragment anyway, and
- some of the properties,
ottr:value,ottr:defaultandottr:parameter, need to take both literals and IRIs as values, which disqualifies the use ofowl:ObjectPropertyorowl:DatatypeProperty.
The domains and ranges for ottr:modifier are not translated into
the ontology. This is because these should be represented as a
"locally scoped" domain and range, but complex axioms on annotation
properties are not supported in OWL.
2.1.3. Individuals
The individuals of the vocabulary are listed in Table 3.
Each row represents
a owl:Thing with type relationship to a class (rdf:type),
textual definition (skos:definition) and optional note
(skos:note).
2.2. Grammar
2.2.1. Fundamentals
ottr:RDFListShape a sh:NodeShape ; sh:targetSubjectsOf rdf:first , rdf:rest ; sh:node shsh:ListShape ; sh:name "RDF lists" ; sh:message "RDF lists must be regular linked lists." .
2.2.2. Instances
It is optional to explicitly type the resources used to specify an
instance, e.g., it is not required to explicitly add the statement that an
instance has the type ottr:Instance or ottr:Argument.
An ottr:Instance must be associated with the (single)
ottr:Signature, ottr:Template and ottr:BaseTemplate it is an
instance of using the ottr:of property. (Note that
ottr:Template or ottr:BaseTemplate are disjoint subclasses of
ottr:Signature.)
An ottr:Instance may have one ottr:modifier which is an
ottr:ExpansionModifier. An ottr:ExpansionModifier is either
ottr:cross, ottr:zipMax or ottr:zipMin.
An ottr:Instance must specify a list of arguments.
This can be done in two
ways: the canonical or the compact way. The canonical way is to state that an ottr:Instance has
ottr:arguments which is an RDF list of
ottr:Argument-s. The compact way is to directly state that an
ottr:Instance has (attribute-) ottr:values which is an RDF list
of RDF resources. However, as explained in the next paragraph, the
reduced expressivity of the
compact way does not cover all cases.
The canonical way covers all cases.
This is the shape expression for ottr:Instance-s.
ottr:InstanceShape a sh:NodeShape ;
sh:targetSubjectsOf ottr:of , ottr:arguments , ottr:values ;
sh:targetObjectsOf ottr:pattern, ottr:annotation ;
sh:property
[ sh:path ottr:of ;
sh:minCount 1 ;
sh:maxCount 1 ;
sh:nodeKind sh:IRI ;
sh:name "Instance's reference to signature" ;
sh:message "An instance must have exactly one reference to a signature, which must be an IRI."
] ,
[ sh:path ottr:modifier ;
sh:maxCount 1 ;
sh:node _:instanceModifierInList ;
sh:name "Instance modifier" ;
sh:message "An instance can only have one modifier, which must be either ottr:cross, ottr:zipMin or ottr:zipMax."
];
sh:xone
(
[ sh:property
[ sh:path ottr:arguments ;
sh:minCount 1 ;
sh:maxCount 1 ;
sh:node shsh:ListShape ;
sh:property [
sh:path ( [ sh:zeroOrMorePath rdf:rest ] rdf:first ) ;
sh:node ottr:ArgumentShape ;
] ;
sh:name "Instance argument list" ;
sh:message "An instance must have exactly (possibly empty) one argument list or argument value list. The argument list must contain arguments---and not argument values."
]
]
[ sh:property
[ sh:path ottr:values ;
sh:minCount 1;
sh:maxCount 1 ;
sh:node shsh:ListShape
] ;
sh:name "Instance argument value list" ;
sh:message "An instance must have exactly one (possibly empty) argument list or argument value list."
]
) ;
## instance has listExpander if and only if exists argument with modifier.
## modelled as (( not A or B ) and ( not B or A))
sh:and (
[ sh:or ( [ sh:not _:hasPropertyInstanceModifier ] _:hasPropertyArgumentWithListExpander ) ]
[ sh:or ( [ sh:not _:hasPropertyArgumentWithListExpander ] _:hasPropertyInstanceModifier ) ]
)
.
### Some shapes represented by named blank nodes to avoid repetition:
# legal instance modifiers:
_:instanceModifierInList sh:in ( ottr:cross ottr:zipMin ottr:zipMax ) .
# instance has a modifier:
_:hasPropertyInstanceModifier
sh:property [
sh:path ottr:modifier ;
sh:minCount 1 ;
sh:node _:instanceModifierInList ] .
# instance has an argument with a modifier:
_:hasPropertyArgumentWithListExpander
sh:property [
sh:path ( ottr:arguments [ sh:zeroOrMorePath rdf:rest ] rdf:first ottr:modifier ) ;
sh:minCount 1 ;
sh:hasValue ottr:listExpand ] .
An ottr:Argument must have one ottr:value which is any RDF
resource. The resource ottr:none can be used to explicitly specify
that an ottr:Argument has no value.
An ottr:Argument may have a ottr:modifier which is an
ottr:ArgumentModifier. The only ottr:ArgumentModifier is
ottr:listExpand. An ottr:Argument which has a
ottr:listExpand modifier, must have a ottr:value which is compatible with a
list type.
Canonical vs. Compact arguments
Since the compact way of specifying an instance's arguments does not
include any ottr:Argument-s, it cannot be used if it is necessary
to associate information on any of the ottr:Argument-s, for
instance marking an ottr:Argument with an
ottr:ArgumentModifier.
The use of ottr:none is required when stating "no value" in the
compact way. This is due to how lists are represented in RDF Turtle.
This is the shape expression for an ottr:Argument.
ottr:ArgumentShape a sh:NodeShape ;
sh:targetSubjectsOf ottr:value ;
## sh:nodeKind sh:BlankNode ; ## only in strict mode?
sh:property
[ sh:path ottr:modifier ;
sh:maxCount 1;
sh:node [ sh:in ( ottr:listExpand ) ] ;
sh:name "Argument modifier" ;
sh:message "An argument can only have the modifier ottr:listExpand."
] ,
[ sh:path ottr:value ;
sh:minCount 1;
sh:maxCount 1;
sh:name "Argument value" ;
sh:message "An argument can only have one value."
] ;
## if listExpander, then must be blanknode/list
## modelled as not A or B.
sh:or (
[ sh:not [ sh:path ottr:modifier ; sh:hasValue ottr:listExpand ] ]
[ sh:path ottr:value ;
sh:nodeKind sh:BlankNode ;
sh:message "An argument with a ottr:listExpand modifier must have a blanknode (possibly representing a list) as value.";
]
)
.
The two instances below are equivalent. Each specifies an instance of
the signature ex:template with four arguments that have
respectively the values _:A, (no value), _:C and _:D.
# 1. instance, canonical arguments
[] ottr:of ex:template ;
ottr:arguments (
[ ottr:value _:A ]
[ ottr:value ottr:none ]
[ ottr:value _:C ]
[ ottr:value _:D ] ) .
# 2. instance, compact argument values
[] ottr:of ex:template ;
ottr:values ( _:A ottr:none _:C _:D ) .
The first instance uses the canonical way of specifying arguments,
while the second uses the compact form.
ottr:none is used to specify the missing value for the second argument.
Note that none of the ottr:Instance-s or ottr:Argument-s are typed as
that.
This example shows the use of instance modifiers and argument
modifiers. The instance is marked with the instance modifier
ottr:cross and the second argument is marked with the argument
modifier ottr:listExpand.
[] ottr:of ex:template ;
ottr:modifier ottr:cross ;
ottr:arguments (
[ ottr:value ( 1 2 3 4 ) ; ottr:modifier ottr:listExpand ]
[ ottr:value ( ex:a ex:b ex:c ) ]
[ ottr:value "string" ]
[ ottr:value ottr:none ]
[ ottr:value rdfs:subClassOf ] ) .
This instance cannot be specified the compact way, using argument value
syntax and ottr:values, since it is necessary to mark one of the
arguments with an argument modifier.
2.2.3. Signatures
The ottr:Signature class has two subclasses, ottr:Template and
ottr:BaseTemplate, which are disjoint. We require that instances of
these classes are explicitly typed with at least the most specific
class.
A ottr:Signature must be identifiable by a concrete IRI (and
not a blank node).
A ottr:Signature must have ottr:parameters which is a
(possibly empty) RDF list of ottr:Parameter-s.
A ottr:Signature may have any number of ottr:annotation-s
which are ottr:Instance-s.
This is the shape definition of a ottr:Signature.
ottr:SignatureShape a sh:NodeShape ;
sh:targetClass ottr:Signature ;
sh:targetSubjectsOf ottr:parameters, ottr:annotation ;
sh:class ottr:Signature ;
sh:nodeKind sh:IRI ;
sh:message "A signature must have the type ottr:Signature or one of its subclasses, and be identified by an IRI." ;
sh:property
[ sh:path ottr:parameters ;
sh:minCount 1 ;
sh:maxCount 1 ;
sh:node shsh:ListShape ;
sh:property [
sh:path ( [ sh:zeroOrMorePath rdf:rest ] rdf:first ) ;
sh:node ottr:ParameterShape ;
] ;
sh:name "Signature parameter list" ;
sh:message "A signature must declare exactly one parameter list, which must contain parameters."
]
.
This is a signature with no parameters, as seen by the empty RDF list
of ottr:parameters. The signature is annotated by two instances of the templates ex:templateA and ex:templateB.
ex:signature a ottr:Signature ; ottr:parameters ( ); ottr:annotation [ ottr:of ex:templateA ; ottr:values ( ex:signature "this an annotation" ) ] , [ ottr:of ex:templateB ; ottr:values ( ex:signature "this is also an annotation" ) ] .
A ottr:Parameter must have a ottr:variable which is a RDF resource.
The RDF resource representing the
variable can be any resource type, i.e., IRI, blank node or literal,
but we recommend using a blank node as their semantics lie close to
the intention of a variable.
A ottr:Parameter can have a ottr:name which is an xsd:token.
A ottr:Parameter can have a ottr:type. How types are specified is
described below.
A ottr:Parameter can have a ottr:default value which is an RDF resource.
A ottr:Parameter can have several ottr:modifier-s which are
ottr:ParameterModifier-s. A ottr:ParameterModifier is either
ottr:optional or ottr:nonBlank.
This is the shape definition of a ottr:Parameter.
ottr:ParameterShape a sh:NodeShape ;
sh:targetSubjectsOf ottr:variable, ottr:type, ottr:default ;
## sh:nodeKind sh:BlankNode ; ## only in strict mode?
sh:property
[ sh:path ottr:variable ;
##REMOVED sh:nodeKind sh:BlankNode ; ## only in strict mode?
sh:minCount 1 ;
sh:maxCount 1 ;
sh:name "Parameter variable" ;
sh:message "A parameter must have exactly one variable.";
] ,
[ sh:path ottr:type ;
sh:node ottr:TypeListShape ;
sh:maxCount 1 ;
sh:name "Parameter type" ;
sh:message "A parameter can only have one type, which must be a permissible type value."
] ,
[ sh:path ottr:name ;
sh:maxCount 1 ;
sh:name "Parameter name" ;
sh:datatype xsd:token ;
sh:message "A parameter can only have one name."
] ,
[ sh:path ottr:default ;
sh:maxCount 1 ;
sh:name "Parameter default value" ;
sh:message "A parameter can only have one default value."
] ,
[ sh:path ottr:modifier ;
sh:node [ sh:in ( ottr:optional ottr:nonBlank ) ] ;
sh:name "Parameter modifier" ;
sh:message "A parameter can only have the modifiers ottr:optional or ottr:nonBlank."
]
.
This is the shape expression for ottr:modifier which restricts its
use to only instances, arguments and parameters.
ottr:ModifierShape a sh:NodeShape ;
sh:targetObjectsOf ottr:modifier ;
sh:xone
(
[ sh:path [ sh:inversePath ottr:modifier ] ;
sh:node ottr:InstanceShape
]
[ sh:path [ sh:inversePath ottr:modifier ] ;
sh:node ottr:ArgumentShape
]
[ sh:path [ sh:inversePath ottr:modifier ] ;
sh:node ottr:ParameterShape
]
) .
This is a signature that declares three parameters with respectively the variables
_:class, _:property and _:string.
The second parameter is marked by the modifier ottr:nonBlank,
and the third parameter is marked as optional.
ex:signature a ottr:Signature ;
ottr:parameters (
[ ottr:variable _:class ]
[ ottr:variable _:property; ottr:modifier ottr:nonBlank ]
[ ottr:variable _:string; ottr:modifier ottr:optional ]
) .
2.2.4. Types
Parameter types are specified using an RDF list, where the last
element in the list must be a basic type, the least upper bound type
ottr:LUB can only occur as the next to last element (which may also
be the first), and the list types
identifiers rdf:List or ottr:NEList can not be the last element.
This RDF list (written in RDF Turtle syntax): ( rdf:List ottr:NEList ottt:LUB
xsd:string ) represents the type List<NEList<LUB<xsd:string>>>. If
the type of a ottr:Parameter is a basic type, it can be specified
using (just) the type IRI (and not a singleton RDF list containing
the type).
This is the shape definition of parameter types.
ottr:TypeListShape a sh:NodeShape ;
sh:targetObjectsOf ottr:type ;
sh:xone
(
[ sh:node shsh:ListShape ;
sh:property
[ sh:path ( [ sh:zeroOrMorePath rdf:rest ] rdf:first ) ;
sh:node ottr:TypeShape ;
sh:minCount 1;
] ;
sh:name "Complex parameter type" ;
sh:message """Unrecognised complex type. A type is specified either as a list of types,
where the last item in the list must be a basic type, the second last can be a 'least upper bound'
type, and the types preceeding it can be list types."""
]
[ sh:node ottr:BasicTypeShape ;
sh:name "Basic parameter type" ;
sh:message "Unrecognised basic type. A type is specified either as an RDF list of types or a single basic type."
]
)
.
These are examples of complex types:
# A list of xsd:int-s -- List<xsd:int> (rdf:List xsd:int) # A non-empty list of xsd:int-s -- NEList<xsd:int>: (ottr:NEList xsd:int) # A list of list of owl:Class-es -- List<List<owl:Class>>: (rdf:List rdf:List owl:Class) # The least upper bound of owl:ObjectProperty -- LUB<owl:ObjectProperty>: (ottr:LUB owl:ObjectProperty) # A list of least upper bounds of owl:ObjectProperty -- List<LUB<owl:ObjectProperty>>: (rdf:List ottr:LUB owl:ObjectProperty)
2.2.5. Template
The class ottr:Template is a subclass of ottr:Signature. A ottr:Template must therefore also follow
the shape specification for ottr:Signature-s.
A ottr:Template may have a ottr:patten which is composed by any
number of ottr:Instance-s.
ottr:TemplateShape a sh:NodeShape ; sh:targetClass ottr:Template ; sh:targetSubjectsOf ottr:pattern ; sh:class ottr:Template .
This is a template with three parameters and a pattern consisting of two template instances.
ex:template a ottr:Template ;
ottr:parameters (
[ ottr:variable _:thing ]
[ ottr:variable _:label; ottr:type xsd:string; ottr:modifier ottr:optional ]
[ ottr:variable _:comment; ottr:type xsd:string; ottr:modifier ottr:optional ]
) ;
ottr:pattern
[ ottr:of ottr:Triple; ottr:values ( _:thing rdfs:label _:label ) ] ,
[ ottr:of ottr:Triple; ottr:values ( _:thing rdfs:comment _:comment ) ]
.
2.2.6. Base template
The class ottr:BaseTemplate is a subclass of ottr:Signature. A ottr:BaseTemplate must therefore also follow
the shape specification for ottr:Signature-s.
A ottr:BaseTemplate cannot have a ottr:pattern.
ottr:BaseTemplateShape a sh:NodeShape ;
sh:targetClass ottr:BaseTemplate ;
sh:class ottr:BaseTemplate ;
sh:property
[ sh:path ottr:pattern ;
sh:maxCount 0 ;
sh:message "A base template cannot have a pattern."
] .
This is a base template which represents a regular RDF triple pattern.
ottr:Triple a ottr:BaseTemplate ;
ottr:parameters (
[ ottr:type ottr:IRI; ottr:variable _:subject ]
[ ottr:type ottr:IRI; ottr:variable _:predicate; ottr:modifier ottr:nonBlank ]
[ ottr:type rdfs:Resource; ottr:variable _:object ] ) .
2.3. Base Templates
The base template ottr:Triple is serialised in wOTTR as follows:
ottr:Triple a ottr:BaseTemplate ;
ottr:parameters (
[ ottr:type ottr:IRI; ottr:variable _:subject ]
[ ottr:type ottr:IRI; ottr:variable _:predicate; ottr:modifier ottr:nonBlank ]
[ ottr:type rdfs:Resource; ottr:variable _:object ] ) .
The base template ottr:Triple is serialised in wOTTR as follows:
ottr:NullableTriple a ottr:BaseTemplate ;
ottr:parameters (
[ ottr:type ottr:IRI; ottr:variable _:subject; ottr:modifier ottr:optional ]
[ ottr:type ottr:IRI; ottr:variable _:predicate; ottr:modifier ottr:nonBlank, ottr:optional ]
[ ottr:type rdfs:Resource; ottr:variable _:object; ottr:modifier ottr:optional ] ) .
3. Appendix
3.1. JSON-LD context
This JSON-LD context is helpful for formatting JSON-LD serialisations of OTTR templates.
3.2. NamedPizza example
We now walk through a complete template and explain each piece before it is listed. We point to some of the changes from the previous version of the vocabulary; these statements are put in parenthesis.
A template is identified by its IRI, which must be a concrete IRI, and must be typed as a ottr:Template.
1: pizza:NamedPizza a ottr:Template ;
Parameters are given as an RDF list. (This removes the need for
using the old ottr:index for each of the parameters to ensure an
order of the parameters.)
2: ottr:parameters (
This is the first parameter, represented as a blank node. The type
of the parameter, and thus the type of the variable, is given with
the ottr:type property. The variable is given with the
ottr:variable property. We recommend to use a blank node for
representing the variable to avoid clashes with other variables.
3: [ ottr:type owl:Class; 4: ottr:variable _:pizza ]
Optional parameters are marked as such by giving the value
ottr:optional for the ottr:modifier predicate.
5: [ ottr:type owl:NamedIndividual; 6: ottr:variable _:country; 7: ottr:modifier ottr:optional ]
List type parameters are given using RDF lists. The type given here
( rdf:List owl:Class ) is a list of classes: List<Class>. (The
types for the first and second parameter could have been given as a
singular list, i.e,. ( owl:Class ) and ( owl:NamedIndividual ),
however, we allow non-list types like these to be given just using
the IRI of the type alone. (Variables that represent lists are no
longer given as lists, but as a single resource, again, preferably
as a blank node.)
8: [ ottr:type ( rdf:List owl:Class ); 9: ottr:variable _:toppings; ] ) ;
The ottr:pattern property explicitly points to the set of the
instances of the pattern. (Ordinary triples must be given as
instances of the Triple template.)
10: ottr:pattern
(A template instance is specified as before, but we have introduced
new property IRIs; we now use ottr:of instead of
ottr:templateRef, and ottr:values instead of ottr:withValues.)
11: [ ottr:of ax:SubClassOf ; 12: ottr:values ( _:pizza p:NamedPizza ) ] ,
If an instance requires additional information about the arguments,
the arguments need to be explicitly represented (not just the
values). In the template instance above, a list expander is specified
(with ottr:modifier ottr:cross) and the arguments that are selected
for list expansion must be indicated with the use of ottr:modifier
ottr:listExpand. This modifier can only be applied to arguments which
are of "list type".
13: [ ottr:of ax:SubObjectSomeValuesFrom ; 14: ottr:arguments ( 15: [ ottr:value _:pizza ] 16: [ ottr:value p:hasTopping ] 17: [ ottr:value _:toppings; 18: ottr:modifier ottr:listExpand ] ) ; 19: ottr:modifier ottr:cross ] ,
20: [ ottr:of ax:SubObjectHasValue ; 21: ottr:values 22: ( _:pizza p:hasCountryOfOrigin _:country ) ] , 23: 24: [ ottr:of ax:SubObjectAllValuesFrom ; 25: ottr:values 26: ( :pizza p:hasTopping _:alltoppings ) ] , 27: 28: [ ottr:of rstr:ObjectUnionOf ; 29: ottr:values 30: ( _:alltoppings _:toppings ) ] ; # end pattern
Annotations are a new feature of templates. Technically an annotation is a ground template instance, ground meaning variables are not allowed as arguments. Annotation instances are typically used to associate information with the template itself, such as a description. A template may have any number of annotation instances.
31: ## new feature 32: ottr:annotation
33: [ ottr:of <http://example.net/ns#TemplateAnnotation> ; 34: ottr:values ( pizza:NamedPizza "A pizza template" ) ] .
We show the differences between the old and new wOTTR vocabulary with an example where the matching parts are aligned side by side.
Previous version
pizza:NamedPizza a ottr:Template ;
ottr:hasParameter
[ ottr:index 1 ;
ottr:classVariable :pizza ] ,
[ ottr:index 2 ;
ottr:individualVariable :country;
ottr:optional true ] ,
[ ottr:index 3 ;
ottr:listVariable (:toppings) ] .
# body:
[] ottr:templateRef ax:SubClassOf ;
ottr:withValues ( :pizza p:NamedPizza ) .
[] ottr:templateRef ax:SubObjectSomeValuesFrom ;
ottr:hasArgument
[ ottr:index 1; ottr:value :pizza ] ,
[ ottr:index 2; ottr:value p:hasTopping ] ,
[ ottr:index 3;
ottr:eachValue (:toppings) ] .
[] ottr:templateRef ax:SubObjectHasValue ;
ottr:withValues
( :pizza p:hasCountryOfOrigin :country ) .
[] ottr:templateRef ax:SubObjectAllValuesFrom ;
ottr:withValues
( :pizza p:hasTopping _:alltoppings ) .
[] ottr:templateRef rstr:ObjectUnionOf ;
ottr:withValues
( _:alltoppings (:toppings) ) .
This version
pizza:NamedPizza a ottr:Template ; ottr:parameters ( [ ottr:type owl:Class; ottr:variable _:pizza ] [ ottr:type owl:NamedIndividual; ottr:variable _:country; ottr:modifier ottr:optional ] [ ottr:type ( rdf:List owl:Class ); ottr:variable _:toppings; ] ) ; ottr:pattern [ ottr:of ax:SubClassOf ; ottr:values ( _:pizza p:NamedPizza ) ] , [ ottr:of ax:SubObjectSomeValuesFrom ; ottr:arguments ( [ ottr:value _:pizza ] [ ottr:value p:hasTopping ] [ ottr:value _:toppings; ottr:modifier ottr:listExpand ] ) ; ottr:modifier ottr:cross ] , [ ottr:of ax:SubObjectHasValue ; ottr:values ( _:pizza p:hasCountryOfOrigin _:country ) ] , [ ottr:of ax:SubObjectAllValuesFrom ; ottr:values ( :pizza p:hasTopping _:alltoppings ) ] , [ ottr:of rstr:ObjectUnionOf ; ottr:values ( _:alltoppings _:toppings ) ] ; # end pattern ## new feature ottr:annotation [ ottr:of <http://example.net/ns#TemplateAnnotation> ; ottr:values ( pizza:NamedPizza "A pizza template" ) ] .
3.3. wOTTR Templates
These are the templates used to construct the wOTTR vocabulary ontology from the tables in this document.
3.3.1. Term template
o-wottr:Term a ottr:Template ;
ottr:parameters (
[ ottr:variable _:IRI; ottr:type ottr:IRI ]
[ ottr:variable _:definition; ottr:type xsd:string; ottr:modifier ottr:optional ]
[ ottr:variable _:note; ottr:type xsd:string; ottr:modifier ottr:optional ]
) ;
ottr:pattern
[ ottr:of ottr:Triple; ottr:values ( _:IRI skos:definition _:definition ) ] ,
[ ottr:of ottr:Triple; ottr:values ( _:IRI skos:note _:note ) ] .
3.3.2. Class template
o-wottr:Class a ottr:Template ;
ottr:parameters (
[ ottr:variable _:IRI; ottr:type owl:Class ]
[ ottr:variable _:super; ottr:type owl:Class; ottr:modifier ottr:optional ]
[ ottr:variable _:definition; ottr:type xsd:string; ottr:modifier ottr:optional ]
[ ottr:variable _:note; ottr:type xsd:string; ; ottr:modifier ottr:optional ]
) ;
ottr:pattern
[ ottr:of ottr:Triple; ottr:values (_:IRI rdfs:subClassOf _:super ) ] ,
[ ottr:of o-wottr:Term ; ottr:values ( _:IRI _:definition _:note ) ] .
3.3.3. Property template
o-wottr:Property a ottr:Template ;
ottr:parameters (
[ ottr:variable _:IRI; ottr:type owl:AnnotationProperty ]
[ ottr:variable _:domain; ottr:type owl:Class; ottr:modifier ottr:optional ]
[ ottr:variable _:range; ottr:type owl:Class; ottr:modifier ottr:optional ]
[ ottr:variable _:definition; ottr:type xsd:string; ottr:modifier ottr:optional ]
[ ottr:variable _:note; ottr:type xsd:string; ottr:modifier ottr:optional ]
) ;
ottr:pattern
[ ottr:of ottr:Triple; ottr:values ( _:IRI rdf:type owl:AnnotationProperty ) ] ,
[ ottr:of ottr:Triple; ottr:values ( _:IRI rdfs:domain _:domain ) ] ,
[ ottr:of ottr:Triple; ottr:values ( _:IRI rdfs:range _:range ) ] ,
[ ottr:of o-wottr:Term; ottr:values ( _:IRI _:definition _:note ) ] .
3.3.4. Instance template
o-wottr:Instance a ottr:Template ;
ottr:parameters (
[ ottr:variable _:IRI; ottr:type owl:NamedIndividual ]
[ ottr:variable _:type; ottr:type owl:Class; ottr:modifier ottr:optional ]
[ ottr:variable _:definition; ottr:type xsd:string; ottr:modifier ottr:optional ]
[ ottr:variable _:note; ottr:type xsd:string; ottr:modifier ottr:optional ]
) ;
ottr:pattern
[ ottr:of ottr:Triple ; ottr:values ( _:IRI rdf:type _:type ) ] ,
[ ottr:of o-wottr:Term ; ottr:values ( _:IRI _:definition _:note ) ] .
3.4. Unit tests
A unit test is either a syntactically correct or an incorrect RDF snippet. Syntactically correct snippets are put in green boxes, while syntactically incorrect snippets are put in red boxes.
# CORRECT
# INCORRECT
Basic
"Basic" tests are not specific to the wOTTR specification.
# INCORRECT: rdf:asdf in an incorrect IRI. [] rdf:asdf [] .
# INCORRECT: rdfs:asdf in an incorrect IRI. [] rdfs:asdf [] .
# INCORRECT: owl:asdf in an incorrect IRI. [] owl:asdf [] .
# INCORRECT: sh:asdf in an incorrect IRI. [] sh:asdf [] .
# INCORRECT: ottr:asdf in an incorrect IRI. [] ottr:asdf [] .
# INCORRECT: An RDF list cannot have two firsts. [ rdf:first 1 ; rdf:first 2 ; rdf:rest rdf:nil ]
# INCORRECT: An RDF list cannot have two rests. [ rdf:first 1 ; rdf:rest 2, rdf:nil ]
# INCORRECT: An RDF list cannot be a loop.
_:A rdf:first 1 ;
rdf:rest [ rdf:first 2 ; rdf:rest _:A ] .
Instance
# CORRECT: This is an instance with no arguments. [] ottr:of ex:template ; ottr:arguments () .
# CORRECT: This is an instance with no argument values. [] ottr:of ex:template ; ottr:values () .
# INCORRECT: an instance's reference to signature, via ottr:of, must be to a concrete IRI. [] ottr:of _:signature ; ottr:arguments () .
# INCORRECT: an instance cannot have both ottr:arguments and ottr:values. [] ottr:of ex:signature ; ottr:arguments () ; ottr:values () .
# INCORRECT: an instance cannot be instance of two different signatures. [] ottr:of ex:signatureA , ex:templateB ; ottr:values () .
# INCORRECT: an instance can only have one modifier. [] ottr:of ex:signature ; ottr:values () ; ottr:modifier ottr:cross, ottr:zipMin .
# INCORRECT: ottr:optional is not a permissible instance modifier. [] ottr:of ex:signature ; ottr:values () ; ottr:modifier ottr:optional .
# CORRECT: ottr:cross is a permissible instance modifier. [] ottr:of ex:signature ; ottr:arguments ( [ ottr:value ( 1 2 ); ottr:modifier ottr:listExpand ] ) ; ottr:modifier ottr:cross .
# INCORRECT: ottr:valus, ottr:modfer and ottr:cros are typos and not correct vocabulary elements. [] ottr:of ex:signature ; ottr:valus () ; ottr:modfer ottr:cros .
# INCORRECT: arguments with listExpander modifier must have list as value.
[] ottr:of ex:template ;
ottr:modifier ottr:cross ;
ottr:arguments (
[ ottr:value ex:not-a-list ; ottr:modifier ottr:listExpand ]
)
.
# INCORRECT: An argument has a listExpand modifier iff the instance must has a modifier. [] ottr:of ex:signature ; ottr:arguments ( [ ottr:value ( 1 2 ); ottr:modifier ottr:listExpand ] ) .
# INCORRECT: A argument has a listExpand modifier iff then the instance has a modifier. [] ottr:of ex:signature ; ottr:arguments ( [ ottr:value ( 1 2 ) ] ) ; ottr:modifier ottr:cross .
Argument
# INCORRECT: an argument list must contain arguments (and not values). [] ottr:of ex:template ; ottr:arguments (_:val1 _:val2 ) .
# CORRECT: This is a template that uses the canonical way of representing arguments. [] ottr:of ex:template ; ottr:arguments ( [ ottr:value _:val1 ] [ ottr:value _:val2 ] ) .
# CORRECT: This is a template that uses the compact way of representing argument values. [] ottr:of ex:template ; ottr:values (_:val1 _:val2 ) .
Signature
# INCORRECT: a signature must have parameters. ex:signature a ottr:Signature .
# CORRECT: This is a signaure with an empty parameter list. ex:signature a ottr:Signature ; ottr:parameters () .
# INCORRECT: a signature must be identified by an IRI and not a blank node. [] a ottr:Signature ; ottr:parameters () .
# INCORRECT: A signature cannot have multiple parameter lists ex:signature a ottr:Signature ; ottr:parameters ( [ ottr:variable _:a ] ) ; ottr:parameters ( [ ottr:variable _:b ] ) .
# CORRECT: This is a signature with two parameters. ex:signature a ottr:Signature ; ottr:parameters ( [ ottr:variable _:a ] [ ottr:variable _:b ]) .
# INCORRECT: A signature must be typed as one. ex:signature ottr:parameters ( ) .
# CORRECT: typing with subclasses of ottr:Signature is OK. ex:template a ottr:Template ; ottr:parameters ( ) . ex:baseTemplate a ottr:BaseTemplate ; ottr:parameters ( ) .
# INCORRECT: The parameter list must be a list (and not a parameter). ex:signature a ottr:Signature ; ottr:parameters [ ottr:variable _:a ] .
# INCORRECT: The parameter list must be a list of parameters (and not resources). ex:signature a ottr:Signature ; ottr:parameters ( ex:param ) ;
# CORRECT: This is a signature with an annotation instance. ex:signature a ottr:Signature ; ottr:parameters ( ) ; ottr:annotation [ ottr:of ex:template ; ottr:values () ] .
# CORRECT: This is a signature with multiple annotation instances.
ex:signature a ottr:Signature ;
ottr:parameters ( ) ;
ottr:annotation
[ ottr:of ex:tb ; ottr:values (1 2 3) ] ,
[ ottr:of ex:tc ; ottr:values (ex:a 1 2) ] ,
[ ottr:of ex:td ; ottr:values (true false) ] ,
[ ottr:of ex:te ; ottr:values (((0))) ] ,
[ ottr:of ex:tf ; ottr:arguments ([ ottr:value 2 ] [ ottr:value "asdf"] ) ] ,
[ ottr:of ex:tg ;
ottr:modifier ottr:cross;
ottr:arguments ([ ottr:value (1 2 3); ottr:modifier ottr:listExpand ] [ ottr:value "asdf"] ) ] .
# INCORRECT: a signature annotations are not given as a list. ex:signature a ottr:Signature ; ottr:parameters ( ) ; ottr:annotation ( [ ottr:of ex:tb ; ottr:values () ] [ ottr:of ex:tc ; ottr:values () ] )
Parameter
# INCORRECT: a parameter must have a variable . ex:signature a ottr:Signature ; ottr:parameters ([]) .
# CORRECT: This is a signature with a parameter. ex:signature a ottr:Signature ; ottr:parameters ([ ottr:variable _:a ]) .
# INCORRECT: a parameter cannot have two types. ex:signature a ottr:Signature ; ottr:parameters ([ ottr:variable _:a ; ottr:type rdfs:Resource, owl:Class ]) .
# INCORRECT: a parameter cannot have two default values. ex:signature a ottr:Signature ; ottr:parameters ([ ottr:variable _:a ; ottr:default "one", "two" ]) .
# INCORRECT: parameter modifiers can only be ottr:optional or ottr:nonBlank ex:signature a ottr:Signature ; ottr:parameters ([ ottr:variable _:a ; ottr:modifier ottr:cross ]) .
# CORRECT
ex:signature a ottr:Signature ;
ottr:parameters (
[ ottr:variable _:a ]
[ ottr:variable _:b ; ottr:type rdfs:Resource ]
[ ottr:variable _:c ; ottr:type owl:Class ; ottr:default "value" ]
[ ottr:variable _:d ; ottr:type xsd:int ; ottr:default 2 ; ottr:modifier ottr:nonBlank ]
[ ottr:variable _:e ; ottr:type owl:ObjectProperty ; ottr:modifier ottr:optional, ottr:nonBlank ]
) .
# INCORRECT: a parameter cannot have more than one name. ex:signature a ottr:Signature ; ottr:parameters ([ ottr:variable _:a ; ottr:name "a"^^xsd:token, "b", 3 ]) .
# CORRECT: a parameter with a name. ex:signature a ottr:Signature ; ottr:parameters ([ ottr:variable _:a ; ottr:name "a"^^xsd:token ]) .
Type
# CORRECT: This is a signature with one parameter typed as owl:Class.
ex:signature a ottr:Signature ;
ottr:parameters (
[ ottr:variable _:a; ottr:type owl:Class ]
) .
# CORRECT: This is a signature with one parameter typed as xsd:string.
ex:signature a ottr:Signature ;
ottr:parameters (
[ ottr:variable _:a; ottr:type xsd:string ]
) .
# CORRECT: This is a signature with one parameter typed as ottt:LUB<xsd:string>.
ex:signature a ottr:Signature ;
ottr:parameters (
[ ottr:variable _:a; ottr:type ( ottr:LUB xsd:string ) ]
) .
# INCORRECT: types must be taken from rOTTR, and cannot be blank.
ex:signature a ottr:Signature ;
ottr:parameters (
[ ottr:variable _:a ; ottr:type _:blank ]
) .
@prefix skos: <http://www.w3.org/2004/02/skos/core#> .
# INCORRECT: types must be taken from rOTTR
ex:signature a ottr:Signature ;
ottr:parameters (
[ ottr:variable _:a; ottr:type skos:Concept ]
) .
# INCORRECT: if a "single resource" type cannot be a complex type
ex:signature a ottr:Signature ;
ottr:parameters (
[ ottr:variable _:a; ottr:type rdf:List ]
) .
# INCORRECT
ex:signature a ottr:Signature ;
ottr:parameters (
[ ottr:variable _:a; ottr:type (rdf:List xsd:int) ]
[ ottr:variable _:b; ottr:type (ottr:NEList xsd:int) ]
[ ottr:variable _:c; ottr:type (rdf:List rdf:List owl:Class) ]
[ ottr:variable _:d; ottr:type (ottr:LUB owl:ObjectProperty) ]
[ ottr:variable _:e; ottr:type (rdf:List ottr:LUB owl:ObjectProperty) ]
) .
Template
# INCORRECT: a template (being a subclass of Signature) must have parameters. ex:template a ottr:Template .
# CORRECT: This is a template with no pattern. ex:template a ottr:Template ; ottr:parameters () .
# CORRECT
ex:template a ottr:Template ;
ottr:parameters () ;
ottr:pattern
[ ottr:of ex:tb ; ottr:values (1 2 3) ] ,
[ ottr:of ex:tc ; ottr:values (ex:a 1 2) ] ,
[ ottr:of ex:td ; ottr:values (true false) ] ,
[ ottr:of ex:te ; ottr:values ( ( ( 0 ) ) ) ] ,
[ ottr:of ex:tf ; ottr:arguments ([ ottr:value 2 ] [ ottr:value "asdf"] ) ] ,
[ ottr:of ex:tg ;
ottr:modifier ottr:cross;
ottr:arguments ([ ottr:value (1 2 3); ottr:modifier ottr:listExpand ] [ ottr:value "asdf"] ) ] .
# INCORRECT: a pattern is not given as a list.
ex:template a ottr:Template ;
ottr:parameters () ;
ottr:pattern (
[ ottr:of ex:tb ; ottr:values (1 2 3) ]
[ ottr:of ex:tc ; ottr:values (ex:a 1 2) ]
[ ottr:of ex:td ; ottr:values (true false) ]
[ ottr:of ex:te ; ottr:values ( ( ( 0 ) ) ) ]
[ ottr:of ex:tf ; ottr:arguments ([ ottr:value 2 ] [ ottr:value "asdf"] ) ]
[ ottr:of ex:tg ;
ottr:modifier ottr:cross;
ottr:arguments ([ ottr:values (1 2 3); ottr:modifier ottr:listExpand ] [ ottr:value "asdf"] ) ] ) .
BaseTemplate
# INCORRECT: a base template (being a subclass of Signature) must have parameters. ex:template a ottr:BaseTemplate .
# INCORRECT: a base template cannot have a pattern. ex:template a ottr:BaseTemplate ; ottr:parameters () ; ottr:pattern [ ottr:of ex:b; ottr:values (1 2 3) ] .
# CORRECT: This is a base template with an annotation instance. ex:template a ottr:BaseTemplate ; ottr:parameters () ; ottr:annotation [ ottr:of ex:b; ottr:values ( 1 2 3 ) ] .
3.5. Unit test validation
3.5.1. SHACL shapes
Validate SHACL shapes against the SHACL-SHACL http://www.w3.org/ns/shacl-shacl shape description.
Error: Could not find or load main class Tester Caused by: java.lang.ClassNotFoundException: Tester3.5.2. Vocabulary
Validate vocabulary shapes against vocabulary token SHACL descriptions and the wOTTR SHACL description.
Error: Could not find or load main class Tester Caused by: java.lang.ClassNotFoundException: Tester3.5.3. Basic tests
Validate incorrect basic unit tests shapes against vocabulary token SHACL descriptions and the wOTTR SHACL description.
Error: Could not find or load main class Tester Caused by: java.lang.ClassNotFoundException: Tester3.5.4. Examples
Validate correct unit tests shapes against vocabulary token SHACL descriptions and the wOTTR SHACL description.
Error: Could not find or load main class Tester Caused by: java.lang.ClassNotFoundException: Tester3.5.5. Correct unit tests
Validate correct unit tests shapes against vocabulary token SHACL descriptions and the wOTTR SHACL description.
Error: Could not find or load main class Tester Caused by: java.lang.ClassNotFoundException: Tester3.5.6. Incorrect unit tests
Validate incorrect unit tests shapes against vocabulary token SHACL descriptions and the wOTTR SHACL description.
Error: Could not find or load main class Tester Caused by: java.lang.ClassNotFoundException: Tester3.5.7. Implementation
This is the implementation used for checking the correctness of the examples and the unit tests.
import java.io.IOException; import java.io.StringWriter; import java.nio.file.Files; import java.nio.file.Path; import java.util.Arrays; import java.util.stream.Collectors; import org.apache.jena.rdf.model.Model; import org.apache.jena.rdf.model.ModelFactory; import org.apache.jena.riot.Lang; import org.apache.jena.riot.RDFDataMgr; import org.apache.jena.shacl.ShaclValidator; import org.apache.jena.shacl.Shapes; import org.apache.jena.shacl.ValidationReport; import org.apache.jena.shacl.lib.ShLib; public class RDFUtils { public static String readFile(String filePath) { try { return Files.readString(Path.of(filePath)); } catch (IOException ex) { return filePath; } } public static String removePrefixes(String ttlString) { return Arrays.stream(ttlString.split(System.lineSeparator())) .filter(s -> !s.startsWith("@prefix ")) .collect(Collectors.joining(System.lineSeparator())) .trim(); } public static Model loadModel(String... urls) { Model model = ModelFactory.createDefaultModel(); for (String url : urls) { RDFDataMgr.read(model, url); } return model; } public static String writeModel(Model model) { StringWriter writer = new StringWriter(); RDFDataMgr.write(writer, model, Lang.TTL); return writer.toString(); } public static ValidationReport getValidationReport(Model shape, Model data) { Shapes shaclShapes = Shapes.parse(shape.getGraph()); ValidationReport report = ShaclValidator.get().validate(shaclShapes, data.getGraph()); return report; } }
import static j2html.TagCreator.*; import j2html.tags.DomContent; import picocli.CommandLine; import picocli.CommandLine.*; import java.util.concurrent.Callable; import java.util.Arrays; // Inspired by https://picocli.info/#_example_application public class Tester implements Callable<Integer> { @Option(names = {"-s", "--shape"}, required = true, description = "SHACL shape file/URL") private String[] shapeFile; @Option(names = {"-v", "--vocab"}, required = false, description = "Vocabulary RDF file/URL") private String[] vocabFiles = {}; @Parameters(description = "RDF data files/URL") private String[] dataFiles = {}; @Override public Integer call() throws Exception { var shapeModel = RDFUtils.loadModel(shapeFile); var vocabModel = RDFUtils.loadModel(vocabFiles); var container = div(); for (String dataFile : dataFiles) { var dataModel = RDFUtils.loadModel(dataFile); var dataModelString = RDFUtils.removePrefixes(RDFUtils.readFile(dataFile)); dataModel.add(vocabModel); var report = RDFUtils.getValidationReport(shapeModel, dataModel); var conforms = Boolean.toString(report.conforms()); var reportContainer = li(); container.with(reportContainer); reportContainer.with(span(conforms + ": " + dataFile).withClass(conforms), details(summary("Data"), pre(dataModelString)), details(summary("Validation report"), pre(RDFUtils.removePrefixes(RDFUtils.writeModel(report.getModel())))) ); } System.out.println(container.render()); return 0; } public static void main(String... args) { int exitCode = new CommandLine(new Tester()).execute(args); System.exit(exitCode); } }
4. References
- mOTTR
- https://spec.ottr.xyz/mOTTR/0.1.0/
- rOTTR
- https://spec.ottr.xyz/rOTTR/0.2.0/
- RDF 1.1 Turtle
- https://www.w3.org/TR/turtle/