LDOM (Name and Acronym TBD) Templates
For the ongoing discussion about the potential name of this technology, see the W3C wiki page.
TODO: This section needs work - templates are used but not introduced yet at this stage. The problem is that we want non-SPARQL experts to still be able to use those templates even if they don't understand how they work internally.
In addition to constraints defined in SPARQL, LDOM makes it possible to define constraints
using higher-level elements called Templates.
(How to define your own Templates is introduced later.)
The following example demonstrates the use of the Template ldom:ShapeConstraint
which links a property with a "shape" that it needs to fulfill:
ex:Rectangle ldom:constraint [ a ldom:ShapeConstraint ; ldom:predicate ex:creator ; ldom:some [ ldom:property [ ldom:predicate schema:email ; ldom:minCount 1 ; ] ; ] ; ] ;
The above means that at least one of the values of the property ex:creator
must be an object that has at least one schema:email value.
This constraint gets evaluated together with the constraints defined by the property
declarations, which means that the ex:creator must also be an instance
of schema:Person.
The property ldom:some means "at least one" - use ldom:all
to specify that all values of the property must match the given shape.
Note that the matching values do not have to be instances of the given shape,
i.e. no rdf:type triple is required.
Shapes can be nested, e.g. using additional ldom:constraint values.
Templates can also be used as values of ldom:property, as long as
the template is a subclass of the system template ldom:PropertyConstraint.
The LDOM core includes two such templates:
ldom:DerivedPropertyConstraint
and ldom:PrimaryKeyProperty.
Here is an example of the latter, declaring that the values of the property
ex:isoCode must be unique for each instance of ex:Country.
ex:Country
a rdfs:Class ;
rdfs:subClassOf rdfs:Resource ;
rdfs:label "Country" ;
ldom:property [
a ldom:PrimaryKeyPropertyConstraint ;
ldom:predicate ex:isoCode ;
ldom:valueType xsd:string ;
ldom:uriStart "http://example.org/country-" ;
rdfs:label "ISO code" ;
] ...
This type of constraint also specifies how the URIs of instances need to
be constructed, by concatenating the provided ldom:uriStart
with the value of the primary key.
Tools can use this information to automatically create URIs for newly
created instances, and for data imported from external non-RDF sources
such as relational databases.
Another built-in template is ldom:OrConstraint which can be
used to combine multiple other constraint templates to express that at least one
of two conditions need to be satisfied.
The following example expresses that a ex:RectangleWithArea must either
have ex:width and ex:height, or a value for
ex:area:
ex:RectangleWithArea a rdfs:Class ; rdfs:subClassOf ex:Rectangle ; ldom:constraint [ a ldom:OrConstraint ; ldom:shape1 [ ldom:property [ ldom:predicate ex:width ; ldom:minCount 1 ; ] ; ldom:property [ ldom:predicate ex:height ; ldom:minCount 1 ; ] ] ; ldom:shape2 [ ldom:property [ ldom:predicate ex:area ; ldom:minCount 1 ; ] ] ] ; .
The SPARQL query behind the ldom:OrConstraint uses a built-in
helper function ldom:violatesConstraints to recursively evaluate
the nested shapes. Based on this function, similar templates (such as exclusive-or)
could be defined.
Many other kinds of templates can be used from third-party template libraries that provide high-level vocabularies for common design patterns.
LDOM Templates are "boxed" queries that can be used as values of
ldom:constraint and ldom:property
(as well as ldom:rule if that gets included into the standard).
The role of a template is to encapsulate a reusable piece of SPARQL logic
so that users do not need to reinvent the wheel.
Templates hide the complexity of the underlying SPARQL query and are therefore
suitable for people who are not familiar with SPARQL.
The following example declares a LDOM template that can be used for
constraints to express that the values of a given property shall be
greater than 0.
ex:PositivePropertyValueConstraint
a ldom:ConstraintTemplate ;
rdfs:subClassOf ldom:TemplateConstraint ;
rdfs:label "Positive property value constraint" ;
ldom:labelTemplate "Values of property {?property} must be > 0" ;
rdfs:comment """
A template that can be used to define a LDOM constraint on a given property
(ex:property) to make sure that the values of that property are > 0.
""" ;
ldom:argument [
ldom:predicate ex:property ;
ldom:valueType rdf:Property ;
rdfs:comment "The property to constrain (e.g. ex:width or ex:height)." ;
] ;
ldom:sparql """
SELECT (?property AS ?path) ?message
WHERE {
?this ?property ?value .
FILTER (?value <= 0) .
BIND (CONCAT("Property ", ldom:label(?property),
" must only have positive values, but found ",
xsd:string(?value)) AS ?message) .
}
""" ;
.
In the example above, the template takes an argument, as specified by the
ldom:argument. This argument is represented by a value of
the property ex:property which is mapped to the variable
?property when the query executes.
Here is an example that instantiates, or "calls", the template to
define constraints on the properties ex:width and ex:height for all instances
of the class ex:Rectangle.
ex:Rectangle ... ldom:constraint [ a ex:PositivePropertyValueConstraint ; ex:property ex:height ; ] ; ldom:constraint [ a ex:PositivePropertyValueConstraint ; ex:property ex:width ; ] .
When a LDOM engine encounters such a constraint definition, it will
execute the ldom:sparql body of the template and pre-bind the declared
argument variables with the values specified in the template call.
In the case of ex:height, the template's body basically becomes the following,
where every appearance of the variable ?property has been replaced with
the constant ex:height.
SELECT (ex:height AS ?path) ?message
WHERE {
?this ex:height ?value .
FILTER (?value <= 0) .
BIND (CONCAT("Property ", ldom:label(ex:height),
" must only have positive values, but found ", xsd:string(?value)) AS ?message) .
}
LDOM templates make it possible to create libraries of reusable constraints
and rules (and other use cases), so that users do not need to learn SPARQL.
The LDOM standard comes with several of such reusable constraints including
ldom:PropertyConstraint and ldom:Argument
which is used by LDOM itself to declare the arguments of templates.
The example above highlights that LDOM templates can be used to create higher-level
modeling languages that introduce constructs such as the
ex:PositivePropertyValueConstraint above together
with semantics that are executable by any LDOM-compliant engine.
At the same time, high-level elements such as the property declarations can also be used by
other engines that do not necessarily rely on SPARQL.
Some applications may only support certain templates as a controlled
vocabulary. For example, a JavaScript client form engine may only
support property definitions with value type and min/max cardinality.
The class ldom:Profile can represent such sets of templates,
as illustrated in the following example.
Here, an application could use the profile ex:SimpleFormProfile
to display warnings if an incoming LDOM model uses features outside of
its profile.
ex:SimpleFormProfile a ldom:Profile ; ldom:member ldom:AbstractCountPropertyConstraint ; # defines ldom:min/maxCount ldom:member ldom:AbstractValueTypePropertyConstraint . # defines ldom:valueType
LDOM Functions are similar to Templates in their syntax, but they are used to
declare new SPARQL functions based on an encapsulated, reusable query.
The following snippet defines a function ex:computeArea that takes
a Rectangle as its argument and returns an integer that is the result of
multiplying the Rectangle's width with its height.
ex:computeArea
a ldom:Function ;
rdfs:subClassOf ldom:Functions ;
rdfs:label "compute area" ;
rdfs:comment "Computes the area of a given rectangle (?arg1) as the product of its width and height." ;
ldom:argument [
ldom:predicate ldom:arg1 ;
ldom:valueType ex:Rectangle ;
rdfs:comment "The rectangle whose area to compute." ;
] ;
ldom:sparql """
SELECT ((?width * ?height) AS ?result)
WHERE {
?arg1 ex:width ?width .
?arg1 ex:height ?height .
}
""" ;
ldom:returnType xsd:integer ;
.
In LDOM-compliant SPARQL processors, this new function can be used such as in the following example:
SELECT *
WHERE {
?rectangle a ex:Rectangle .
FILTER (ex:computeArea(?rectangle) >= 100) .
}
LDOM functions have a SELECT query as their body, and this query needs to have one
result variable (here: ?result). The first binding of this variable will be used
as result of the function execution. The execution mechanism is illustrated in the
following diagram.
LDOM includes a special kind of property constraints for properties that
are computed (or derived or inferred) from other values.
A good example of this is the ex:area property for rectangles:
ex:Rectangle ... ldom:property [ a ldom:DerivedPropertyConstraint ; ldom:predicate ex:area ; ldom:maxCount 1 ; ldom:sparql "ex:computeArea(?this)" ; ldom:valueType xsd:integer ; rdfs:label "area" ; rdfs:comment "The area of the Rectangle, defined as the product of width x height." ; ] ;
The ldom:DerivedPropertyConstraint above will flag a constraint
violation if the value of ex:area is not equal to the result
of the provided SPARQL expression.
Some LDOM implementations may also chose to use constraints of this type in a constructive way, to automatically compute missing values (but this is not covered by the standard).
(Unclear whether the WG will include inferencing, so this feature is at risk)
LDOM makes it possible to attach executable rules to classes.
Rules are represented as SPARQL CONSTRUCT queries that apply to all instances
of the associated class and its subclasses.
In those rules, the variable ?this refers to each instance of those classes.
A LDOM execution engine will make sure that ?this has the correct values.
The triples that are constructed by such a rule become "inferred" and are added
to the RDF graph, so that other rules can "see" the new triples.
In the following example, the value of ex:area gets computed by multiplying
the values of ex:width and ex:height.
ex:Rectangle
ldom:rule [
ldom:sparql """
CONSTRUCT {
?this ex:area ?area . # Infer ?area as a value of ex:area
}
WHERE {
?this ex:width ?width . # Get the width of ?this Rectangle
?this ex:height ?height . # Get the height of ?this Rectangle
BIND ((?width * ?height) AS ?area) . # Compute area := width * height
}
""" ;
] .
The property ldom:rule is used to link a class with a rule.
The values of this property must be either CONSTRUCT queries or template calls
that wrap a CONSTRUCT query.
LDOM constraints can be grouped into contexts - URIs that have the type
ldom:Context.
This makes it possible to indicate that certain constraints shall not
apply by default, but only for certain applications or user communities.
The property ldom:context links an ldom:Constraint
with a context:
ex:Rectangle ldom:property [ ldom:predicate dct:publisher ; ldom:minCount 1 ; ldom:context <http://example.org/trackable> ] .
In the example above, the class ex:Rectangle has been extended
with a minimum cardinality constraint on the property dct:publisher.
This constraint is applicable in the provided ldom:context only,
which means that it does not apply by default.
However, certain applications that process ex:Rectangle instances
can trigger the constraint checking in a context that includes all default
constraints plus the extra constraints from the http://example.org/trackable
context.
The operation that triggers the constraint checking can take included and excluded
contexts as argument. Contexts can be organized into hierarchies using
ldom:subContextOf, which means that whenever a super-context is requested
then all constraints from its sub-contexts also apply.
The built-in URI ldom:DefaultContext can be used to specify the default
context, and that is also the default value if ldom:context is unspecified.