Linked Data Enrichment with Self-Unfolding URIs - examples

Barnabás Szász*, Rita Fleiner**, András Micsik***

*University of Debrecen, Debrecen, Hungary

** Óbuda University, Budapest, Hungary

*** MTA, SZTAKI, Budapest, Hungary

 

This document explains the use of Self-Unfolding URI's through a real life example.
The first part of this page shows examples for the conceptual template describing the structure of generated triples.
Each template consist of a URI class and a set of triplets.
The second part contains three example SPARQL Insert implementations.

 

Template examples

Try it yourself!

 

Each self unfolding URI comes with a template which has the following structure:

<Base URI>/<type without namespace>;<Property1>=<Value1>;<Property2>=<Value2>...

<URI> rdf:type  <type with namespace>

      <property1> <value1> ;

      <property2> <value2> ;

      <property3> <calculated value> ;

      <property4> <related URI> .

 

The template for

<http://example.org/data/UnitMinuteInstant;year={year};month={month};day={day};hour={hour};minute={minute}.

 

is the following:

 

<http://example.org/data/UnitMinuteInstant;year={year};month={month};day={day};hour={hour};minute={minute}>

     rdf:type otime:UnitMinuteInstant ;
     time:inDateTime

<http://example.org/data/UnitMinuteDateTimeDescription;year={year};month={month};day={day};hour={hour};minute={minute}> .

 

 

<http://example.org/data/UnitMinuteDateTimeDescription;year={year};month={month};day={day};hour={hour};minute={minute}>

     rdf:type otime:unitMinuteDateTimeDescription ;
     time:hour "
{hour}"^^xsd:nonNegativeInteger ;
     time:minute "
{minute}"^^xsd:nonNegativeInteger ;
     time:month "
{month}"^^xsd:nonNegativeInteger ;
     time:day "
{day}" ;
     time:year "
{year}" .

 

 

The template for

 

<http://example.org/data/CourseTime;courseTerm={term};hour={hour};minute={minute};durationHour={durationHour};durationMinute={durationMinute};dayofweek={dayOfWeek}> .

 

is the following:

 

<http://example.org/data/CourseTime;courseTerm={term};hour={hour};minute={minute};durationHour={durationHour};durationMinute={durationMinute};dayofweek={dayOfWeek}>

     rdf:type otime:CourseTime ;
     ta:hasTemporalAggregateDescription

<http://example.org/data/StandardCourseTemporalAggregateDescription;year={year};month={month};day=({day}+{dayOfWeek}-1);hour={hour};minute={minute};durationHour={durationHour};durationMinute={durationMinute};dayofweek={dayOfWeek}> .

 

 

 

<http://example.org/data/StandardCourseTemporalAggregateDescription;year={year};month={month};day=({day}+{dayOfWeek}-1);hour={hour};minute={minute};durationHour={durationHour};durationMinute={durationMinute};dayofweek={dayOfWeek}>

     rdf:type      otime:StandardCourseTemporalAggregateDescription ;
     ta:hasithTemporalUnit
{dayOfWeek} ;
     ta:hasStart

<http://example.org/data/UnitMinuteInterval;year={year};month={month};day=({day}+{dayOfWeek}-1);hour={hour};minute={minute};durationHour={durationHour};durationMinute={durationMinute}> .

 

 

<http://example.org/data/UnitMinuteInterval;year={year};month={month};day=({day}+{dayOfWeek}-1);hour={hour};minute={minute};durationHour={durationHour};durationMinute={durationMinute}>

     rdf:type otime:UnitMinuteInterval ;
     time:hasDurationDescription

<http://example.org/data/DurationDescription;durationHour={durationHour};durationMinute={durationMinute}> ;
     time:hasBeginning <http://example.org/data/UnitMinuteInstant;year=
{year};month={month};day=({day}+{dayOfWeek}-1);hour={hour};minute={minute}> .

 

<http://example.org/data/DurationDescription;durationHour={durationHour};durationMinute={durationMinute}>

     rdf:type time:DurationDescription ;
     time:hours
{durationHour} ;
     time:minutes
{durationMinute} .

 

 

<http://example.org/data/UnitMinuteInstant;year={year};month={month};day=({day}+{dayOfWeek}-1);hour={hour};minute={minute}>

     rdf:type otime:UnitMinuteInstant ;
     time:inDateTime

<http://example.org/data/UnitMinuteDateTimeDescription;year={year};month={month};day=({day}+{dayOfWeek}-1);hour={hour};minute={minute}> .

 

 

<http://example.org/data/UnitMinuteDateTimeDescription;year={year};month={month};day=({day}+{dayOfWeek}-1);hour={hour};minute={minute}>

     rdf:type otime:unitMinuteDateTimeDescription ;
     time:hour "
{hour}"^^xsd:nonNegativeInteger ;
     time:minute "
{minute}"^^xsd:nonNegativeInteger ;
     time:month "
{month}"^^xsd:nonNegativeInteger ;
     time:day "(
{day}+{dayOfWeek}-1)" ;
     time:year "
{year}" .


These are the steps to reproduce an environment where the self unfolding URI's can be applied to


Add the following definitions to your ontology:

 
PREFIX oloud: <http://lod.nik.uni-obuda.hu/oloud-base#>
PREFIX otime: <http://lod.nik.uni-obuda.hu/oloud-time#>
PREFIX ta: <http://ontology.ihmc.us/temporalAggregates.owl#>
PREFIX time: <http://www.w3.org/2006/time#>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
 
oloud:CourseTerm
      rdf:type owl:Class ;
      rdfs:subClassOf time:Interval .
 
otime:CourseTime
      rdf:type owl:Class ;
      rdfs:subClassOf ta:TemporalSeq.
 
otime:StandardCourseTemporalAggregateDescription a owl:Class ;  
         rdfs:subClassOf ta:TemporalAggregateDescription ;
         rdfs:subClassOf
          [ a owl:Restriction ;
            owl:hasValue 14 ;
            owl:onProperty ta:hasCount ] ,
          [ a owl:Restriction ;
            owl:hasValue time:unitDay ;
            owl:onProperty ta:hasTemporalUnit ] .
 
otime:UnitMinuteDateTimeDescription a owl:Class ;  
         rdfs:subClassOf time:DateTimeDescription ;
         rdfs:subClassOf
          [ a owl:Restriction ;
            owl:hasValue time:UnitMinute ;
            owl:onProperty time:unitType   ] .
           
otime:UnitMinuteInstant a owl:Class ;  
         rdfs:subClassOf time:Instant ;
         rdfs:subClassOf
          [ a owl:Restriction ;
            owl:allValuesFrom otime:UnitMinuteDateTimeDescription ;
                  owl:onProperty time:inDateTime   ] .
 
otime:UnitMinuteInterval a owl:Class ;  
         rdfs:subClassOf time:Interval ;
         rdfs:subClassOf
          [ a owl:Restriction ;
            owl:allValuesFrom oloud:UnitMinuteInstant ;
            owl:onProperty time:hasBeginning   ] .
           

Next, load the following data:

 
PREFIX oloud: <http://lod.nik.uni-obuda.hu/oloud-base#>
PREFIX otime: <http://lod.nik.uni-obuda.hu/oloud-time#>
PREFIX ta: <http://ontology.ihmc.us/temporalAggregates.owl#>
PREFIX time: <http://www.w3.org/2006/time#>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
 
<http://example.org/2015Fall> a oloud:CourseTerm;
      time:hasBeginning
            <http://example.org/UnitMinuteInstant;year=2015;month=9;day=7;hour=0;minute=0> .
<http://example.org/c001> a oloud:Course ;
      oloud:courseTerm <http://example.org/2015Fall> ;
      otime:courseTime <http://example.org/CourseTime;courseTerm=2015Fall;hour=10;minute=0;durationHour=1;durationMinute=30;dayofweek=2> .
 

Please note, that the following URI's are self unfolding and unfolding such a URI can trigger generating more self unfolding URIs. [1] and [3] is part of the inital data, [2] has been unfolded from [1], [4] from [3], [5] from [4], [6] and [7] from [5] and finally [8] from [7].

 

1.  <http://example.org/UnitMinuteInstant;year=2015;month=9;day=7;hour=0;minute=0>

2.  <http://example.org/UnitMinuteDateTimeDescription;year=2015;month=9;day=7;hour=0;minute=0>

3.  <http://example.org/CourseTime;courseTerm=2015Fall;hour=10;minute=0;durationHour=1;durationMinute=30;dayofweek=2>

4.  <http://example.org/StandardCourseTemporalAggregateDescription;year=2015;month=9;day=8;hour=10;minute=0;durationHour=1;durationMinute=30;dayofweek=2>

5.  <http://example.org/UnitMinuteInterval;year=2015;month=9;day=8;hour=10;minute=0;durationHour=1;durationMinute=30>

6.  <http://example.org/DurationDescription;durationHour=1;durationMinute=30>

7.  <http://example.org/UnitMinuteInstant;year=2015;month=9;day=8;hour=10;minute=0>

8.  <http://example.org/UnitMinuteDateTimeDescription;year=2015;month=9;day=8;hour=10;minute=0>
 

The Following INSERT statement is used to unfold [1], [2], [7] and [8] (for [7] and [8] run this statement again after the 3. - as [5] needs to already generated for [7]):

PREFIX oloud: <http://lod.nik.uni-obuda.hu/oloud-base#>

PREFIX otime: <http://lod.nik.uni-obuda.hu/oloud-time#>

PREFIX time: <http://www.w3.org/2006/time#>

PREFIX xsd:  <http://www.w3.org/2001/XMLSchema#>

 

INSERT

{

?uri a otime:UnitMinuteInstant;

       time:inDateTime ?desc_uri.

?desc_uri a otime:unitMinuteDateTimeDescription;

      time:minute ?minute ;

      time:hour ?hour ;

      time:day ?day ;

      time:month ?month ;

      time:year ?year .

}

WHERE {

  # matching any triplets

?anyobject ?anyproperty ?uri.

  # with a specific URI pattern

FILTER(STRSTARTS(STR(?uri), "http://example.org/UnitMinuteInstant")).

  # we need to generate a URI for the UnitMinuteDateTimeDescription entity

BIND(IRI(REPLACE(str(?uri),"/UnitMinuteInstant;","/UnitMinuteDateTimeDescription;")) AS ?desc_uri) .

  # extract the URI parameters

BIND(REPLACE(str(?uri), '^(.*)\\?', "") AS ?p)

BIND(xsd:nonNegativeInteger(REPLACE(REPLACE(str(?p), '^.*year=', "") , ';.*$', "")) AS ?year).

BIND(xsd:nonNegativeInteger(REPLACE(REPLACE(str(?p), '^.*month=', "") , ';.*$', "")) AS ?month).

BIND(xsd:nonNegativeInteger(REPLACE(REPLACE(str(?p), '^.*day=', "") , ';.*$', "")) AS ?day).

BIND(xsd:nonNegativeInteger(REPLACE(REPLACE(str(?p), '^.*hour=', "") , ';.*$', "")) AS ?hour).

BIND(xsd:nonNegativeInteger(REPLACE(REPLACE(str(?p), '^.*minute=', "") , ';.*$', "")) AS ?minute).

}

Which results:

 
<http://example.org/UnitMinuteInstant;year=2015;month=9;day=7;hour=0;minute=0>
      rdf:type otime:UnitMinuteInstant ;
      time:inDateTime
<http://example.org/UnitMinuteDateTimeDescription;year=2015;month=9;day=7;hour=0;minute=0> .
<http://example.org/UnitMinuteDateTimeDescription;year=2015;month=9;day=7;hour=0;minute=0>
      rdf:type otime:unitMinuteDateTimeDescription ;
      time:hour"0"^^xsd:nonNegativeInteger ;
      time:minute "0"^^xsd:nonNegativeInteger;
      time:month "9"^^xsd:nonNegativeInteger;
      time:day "7";
      time:year"2015" .
 
 
<http://example.org/UnitMinuteInstant;year=2015;month=9;day=8;hour=10;minute=0>
      rdf:type otime:UnitMinuteInstant ;

      time:inDateTime <http://example.org/UnitMinuteDateTimeDescription;year=2015;month=9;day=8;hour=10;minute=0> .
 
 
<http://example.org/UnitMinuteDateTimeDescription;year=2015;month=9;day=8;hour=10;minute=0>
     rdf:type otime:unitMinuteDateTimeDescription ;
     time:hour "10"^^xsd:nonNegativeInteger ;     
time:minute "0"^^xsd:nonNegativeInteger ;
     time:month "9"^^xsd:nonNegativeInteger ;
     time:day "8" ;
     time:year "2015" .
 

The Following INSERT statement is used to unfold [3] and [4]:

PREFIX oloud: <http://lod.nik.uni-obuda.hu/oloud-base#>

PREFIX otime: <http://lod.nik.uni-obuda.hu/oloud-time#>

PREFIX ta: <http://ontology.ihmc.us/temporalAggregates.owl#>

PREFIX time: <http://www.w3.org/2006/time#>

PREFIX xsd:  <http://www.w3.org/2001/XMLSchema#>

INSERT

{

?uri a otime:CourseTime;

            ta:hasTemporalAggregateDescription ?desc_uri.

?desc_uri a otime:StandardCourseTemporalAggregateDescription ;

      ta:hasStart ?interval_uri ;

      ta:hasithTemporalUnit ?dayofweek .

}

WHERE {

  # matching any triplets

?anyobject ?anyproperty ?uri.

  # with a specific URI pattern

FILTER(STRSTARTS(STR(?uri), "http://example.org/CourseTime")).

  # extract the URI parameters

BIND(REPLACE(str(?uri), '^(.*)\\?', "") AS ?p)

BIND(REPLACE(REPLACE(str(?p), '^.*courseTerm=', "") , ';.*$', "") AS ?ct).

BIND(IRI(CONCAT("http://example.org/", ?ct)) AS ?courseTerm).

  # extract the start date of the specific Course Term

?courseTerm time:hasBeginning ?b.

?b time:inDateTime ?d.

?d time:year ?year;

   time:month ?month;

   time:day ?startday.

  # calculate the first course occurance

BIND(REPLACE(REPLACE(str(?p), '^.*hour=', "") , ';.*$', "") AS ?hour).

BIND(REPLACE(REPLACE(str(?p), '^.*minute=', "") , ';.*$', "") AS ?minute).

BIND(REPLACE(REPLACE(str(?uri), '^.*dayofweek=', "") , ';.*$', "") AS ?dayofweek) .

BIND(xsd:integer(?startday)+xsd:integer(?dayofweek)-1 as ?day).

BIND(CONCAT(CONCAT(CONCAT(CONCAT(CONCAT(CONCAT(";year=",STR(?year)),";month="),STR(?month)),";day="),STR(?day),";"))AS ?u2).

  # Create a new UnitMinuteInterval entity representing the first course occurance

BIND(IRI(REPLACE(REPLACE(REPLACE(str(?uri),"/CourseTime;","/UnitMinuteInterval;"),';courseTerm=[^;]*(;|$)', ?u2),';dayofweek=[^;]*(;|$)', "")) AS ?interval_uri) .

  # we need to generate a URI for the StandardCourseTemporalAggregateDescription entity

BIND(IRI(REPLACE(REPLACE(str(?uri),"/CourseTime;","/StandardCourseTemporalAggregateDescription;"),';courseTerm=[^;]*(;|$)', ?u2)) AS ?desc_uri) .

}

Which results:

 
<http://example.org/CourseTime;courseTerm=2015Fall;hour=10;minute=0;durationHour=1;durationMinute=30;dayofweek=2>
      rdf:type otime:CourseTime ;      ta:hasTemporalAggregateDescription
<http://example.org/StandardCourseTemporalAggregateDescription;year=2015;month=9;day=8;hour=10;minute=0;durationHour=1;durationMinute=30;dayofweek=2> .
 
<http://example.org/StandardCourseTemporalAggregateDescription;year=2015;month=9;day=8;hour=10;minute=0;durationHour=1;durationMinute=30;dayofweek=2>
      rdf:type otime:StandardCourseTemporalAggregateDescription ;
      ta:hasithTemporalUnit 2 ;
      ta:hasStart <http://example.org/UnitMinuteInterval;year=2015;month=9;day=8;hour=10;minute=0;durationHour=1;durationMinute=30> .
 

The Following INSERT statement is used to unfold [5] and [6]:

PREFIX oloud: <http://lod.nik.uni-obuda.hu/oloud-base#>

PREFIX otime: <http://lod.nik.uni-obuda.hu/oloud-time#>

PREFIX time: <http://www.w3.org/2006/time#>

INSERT

{

?uri a otime:UnitMinuteInterval;

       time:hasBeginning ?instant_uri ;

       time:hasDurationDescription ?duration_uri .

?duration_uri a time:DurationDescription;

       time:minutes ?durationMinute ;

       time:hours ?durationHour .

} WHERE {

  # matching any triplets

?anyobject ?anyproperty ?uri.

  # with a specific URI pattern

FILTER(STRSTARTS(STR(?uri), "http://example.org/UnitMinuteInterval")).

  # extract the URI parameters

BIND(REPLACE(str(?uri), '^(.*)\\?', "") AS ?p)

BIND(REPLACE(REPLACE(str(?p), '^.*durationHour=', "") , ';.*$', "") AS ?durationHour).

BIND(REPLACE(REPLACE(str(?p), '^.*durationMinute=', "") , ';.*$', "") AS ?durationMinute).

  # we need to generate a URI for the DurationDescription entity

BIND(IRI(REPLACE(REPLACE(str(?uri),"/UnitMinuteInterval;","/DurationDescription;"),'(year=[^;]*(;|$))|(month=[^;]*(;|$))|(day=[^;]*(;|$))|(hour=[^;]*(;|$))|(minute=[^;]*(;|$))', "")) AS ?duration_uri) .

  # we need to generate a URI for the UnitMinuteInstant entity

BIND(IRI(REPLACE(REPLACE(REPLACE(str(?uri),"/UnitMinuteInterval;","/UnitMinuteInstant;"),'(durationHour=[^;]*(;|$))|(durationMinute=[^;]*(;|$))', ""),'([;]*$)', "")) AS ?instant_uri) .

}

Which results (see in action here):

 
<http://example.org/UnitMinuteInterval;year=2015;month=9;day=8;hour=10;minute=0;durationHour=1;durationMinute=30>
       rdf:type otime:UnitMinuteInterval ;
       time:hasDurationDescription <http://example.org/DurationDescription;durationHour=1;durationMinute=30> ;
       time:hasBeginning <http://example.org/UnitMinuteInstant;year=2015;month=9;day=8;hour=10;minute=0> .
 
<http://example.org/DurationDescription;durationHour=1;durationMinute=30>
      rdf:type time:DurationDescription ;
      time:hours 1 ;
      time:minutes 30 .