LDT templates

This guide explains how to use LDT templates to change the way your application operates

Template is a core concept in an Linked Data Templates application ontology. It defines what SPARQL command gets executed when on the application's service when a certain URI is requested on that application. The service is usually backed by a triplestore.

When Linked Data is served from a triplestore, the RDF descriptions returned when URIs are dereferenced are often results of the same default SPARQL query template. A common one is DESCRIBE ?this, which returns all known triples about a resource identified here as ?this. The final query is obtained from this template by setting the requested URI as the value of the ?this variable.

Templates allow you to customize this mechanism by only mapping a certain class of URIs to a certain SPARQL command. Moreover, they support write mode as well, by allowing mapping to SPARQL update. This means that different parts of your application's URI address space can change the dataset and respond in different ways when a software client interacts with them. This is a common requirement for real-world end-user applications backed by SPARQL services.

Use case

Lets reuse a geospatial RDF dataset from the CSV import example: any number of countries with coordinates. It could look like this in a Trig syntax (the base URI is not relevant in this context):

@base        <https://linkeddatahub.com/demo/city-graph/>
@prefix nsdd: <ns/domain/default#>
@prefix ns:  <ns#>

{

    <countries/AD/> a nsdd:Item ;
        dct:title "Andorra" ;
        dh:slug "AD" ;
        foaf:primaryTopic <countries/AD/#this> .

    <countries/AD/#this> a ns:Country ;
        foaf:isPrimaryTopicOf <countries/AD/#this> ;
        dct:identifier "AD" ;
        geo:lat 42.5 ;
        geo:long 1.6 ;
        dct:title "Andorra" .

}

By default, the resource URIs will match a default template, which depends on what LDT ontologies your application imports. But lets say that we want to override it with our own country-specific template, which:

  • matches country document resources
  • includes descriptions of nearby countries when dereferenced
  • removes document as well as country when deleted

Template structure

Use case requirements above translate directly into main LDT template components:

Match
Use /countries/{id}/ URI template to match only country document URIs and not others
Query
A proper solution would be to use GeoSPARQL here, but for the sake of this example we can retrieve nearby countries by filtering coordinates that are within a bounding box:
PREFIX  geo:  <http://www.w3.org/2003/01/geo/wgs84_pos#>
PREFIX  dct:  <http://purl.org/dc/terms/>
PREFIX  foaf: <http://xmlns.com/foaf/0.1/>

DESCRIBE ?this ?country ?nearbyCountry
WHERE
  { GRAPH ?g
      { ?this     foaf:primaryTopic  ?country .
        ?country  geo:lat            ?lat ;
                  geo:long           ?long
        OPTIONAL
          { GRAPH ?nearbyCountryGraph
              { ?nearbyCountry
                          geo:lat   ?nearbyLat ;
                          geo:long  ?nearbyLong
                FILTER ( ?country != ?nearbyCountry )
              }
          }
        FILTER ( ( ?nearbyLat > ( ?lat - 10 ) ) && ( ?nearbyLat < ( ?lat + 10 ) ) )
        FILTER ( ( ?nearbyLong > ( ?long - 10 ) ) && ( ?nearbyLong < ( ?long + 10 ) ) )
      }
  }
Update
PREFIX  foaf: <http://xmlns.com/foaf/0.1/>

DELETE {
  GRAPH ?graph {
    ?this ?p ?o .
    ?country ?countryP ?countryO .
  }
}
WHERE
  { GRAPH ?graph
      { ?this ?p ?o
        OPTIONAL
          { ?this foaf:primaryTopic ?country .
            ?country ?countryP ?countryO
          }
      }
  }
Super-template
Templates inherit properties from super-templates, to which they must be linked using the subclass relationship. If you know of an existing template that already defines the URI pattern, query/update etc. that you need, you may define your template as a sub-template of it. For example, an update analogous to the one above is defined on thgt:Document template in the THGT ontology.

Execution

Now lets consider GET and DELETE requests to our country document URI https://linkeddatahub.com/demo/city-graph/countries/AD/. The URI will be set as the value of the variable ?this before the query or update is executed. In other words, a variable binding (?this, <https://linkeddatahub.com/demo/city-graph/countries/AD/>) will be applied on the query/update string before execution.

GET request will invoke execution of this query:

PREFIX  geo:  <http://www.w3.org/2003/01/geo/wgs84_pos#>
PREFIX  dct:  <http://purl.org/dc/terms/>
PREFIX  foaf: <http://xmlns.com/foaf/0.1/>

DESCRIBE <https://linkeddatahub.com/demo/city-graph/countries/AD/> ?country ?nearbyCountry
WHERE
  { GRAPH ?g
      { <https://linkeddatahub.com/demo/city-graph/countries/AD/>     foaf:primaryTopic  ?country .
        ?country  geo:lat            ?lat ;
                  geo:long           ?long
        OPTIONAL
          { GRAPH ?nearbyCountryGraph
              { ?nearbyCountry
                          geo:lat   ?nearbyLat ;
                          geo:long  ?nearbyLong
                FILTER ( ?country != ?nearbyCountry )
              }
          }
        FILTER ( ( ?nearbyLat > ( ?lat - 10 ) ) && ( ?nearbyLat < ( ?lat + 10 ) ) )
        FILTER ( ( ?nearbyLong > ( ?long - 10 ) ) && ( ?nearbyLong < ( ?long + 10 ) ) )
      }
  }

The RDF result of the query will be returned as the Linked Data response body.

DELETE request will invoke execution of this update:

PREFIX  foaf: <http://xmlns.com/foaf/0.1/>

DELETE {
  GRAPH ?graph {
    <https://linkeddatahub.com/demo/city-graph/countries/AD/> ?p ?o .
    ?country ?countryP ?countryO .
  }
}
WHERE
  { GRAPH ?graph
      { <https://linkeddatahub.com/demo/city-graph/countries/AD/> ?p ?o
        OPTIONAL
          { <https://linkeddatahub.com/demo/city-graph/countries/AD/> foaf:primaryTopic ?country .
            ?country ?countryP ?countryO
          }
      }
  }