These pages are deprecated ; please go to the pages of our new team Edelweiss

Semtag: tutorial on the SeWeSe JSP library for Semantic web application using RDF, RDFS, OWL, Rules and SPARQL

updated 02/05/2007


About Description Downloads Documentation Tutorial Contacts

For remarks or questions on this tutorial contact Fabien Gandon

This semantic web application tutorial gives a quick tour of the Sewese JSP library to rapidly develop lightweight web application relying on RDF, RDFS, SPARQL and Rules. It was designed as a hand-on-keyboard introduction to the basics of the SEWESE libary. It uses RDF, RDFS and OWL Lite semantics for lightweight ontologies, SPARQL query language for RDF graph bases and production rules for knowledge factorisation in semantic web annotation bases.

TOC: Basics, Initializing, Querying RDF annotations, Querying RDFS/OWL ontologies, Editing RDF annotations.

This tutorial uses one web archive (WAR file for the tutorial available on the download page of SeWeSe) and requires that you have a container to deploy it that supports Servlet API 2.4 and JSP 2.0 like Tomcat 5.5.x. The tutorial web application also contains a sub-directory with the solutions of the questions of this tutorial.

For a complete javadoc of the Semtag library see the API.

For an introduction to RDF SPARQL and rules Corese Tutorial.

For an exhaustive introduction to OWL see the OWL Overview.

Initializing

Once you have deployed the (web archive) WAR file you can start editing the index.jsp page. (NB: one way to quickly deploy it in tomcat is to paste it in the webapp directory) The web application contains the same ontologies, annotations and rules than the Corese Tutorial. You will find them in the WEB-INF/data sub directory.

The first thing to do in an application using the Semtag lib is to initialize at least one Corese instance to load annotations and ontologies. The default instance is named defaultEngineWrapper and can be created by adding this to index.jsp:

See also: init

00
01
02
03
04
05
06
07
<h1>Semantic JSP Tag Library Tutorial</h1>
  <c:if test="${empty applicationScope['defaultEngineWrapper']}">
    <stl:init ontoDir="WEB-INF/data/schemas"
      annotDir="WEB-INF/data/annotations" 
      ruleDir="WEB-INF/data/rules"
      humans="http://www.inria.fr/2007/04/17/humans.rdfs#" />
    <h2>Initialisation</h2>
  </c:if>

The attributes that appear in lines 2, 3 and 4 specify the directories respectively containing ontologies, annotations and rules to load. Additional attributes like the one in line 5 may be used to declare namespaces which prefix can then directly be used in all the SPARQL queries.

Querying RDF annotations

There are several tags to run SPARQL queries but one of the most useful ones is a JSP loop tag to directly iterate over the results of a query. For instance to lists all the persons annotated in the loaded data just add these lines at the end of the index.jsp file.

See also: for-each-result

01
02
03
04
05
06
07
08
<h2>Query on persons</h2>
<div>
  <ul>
    <stl:for-each-result query="SELECT ?name WHERE { ?x humans:name ?name }">
      <li>${name}</li>
    </stl:for-each-result>
  </ul>
</div>

Line 4 uses the attribute query of the tag for-each-result to specify a query and the selected variables (here ?name). Line 5 directly references the variable in JSP ${name} accessing its value for each result.

Imagine you also want the age of the persons then you can just modify lines 4 and 5 like this:

04
05
06
<stl:for-each-result query="SELECT ?name ?age WHERE { ?x humans:name ?name . ?x humans:age ?age }">
  <li>${name} (${age})</li>
</stl:for-each-result>

Since not all the persons where specified with their age we are retrieving fewer answers. If we want to say that the age is an optional part of the query we can change the code to take that into account both in the query and in the display of its results when the age variable is not bound:

04
05
06
<stl:for-each-result query="SELECT ?name ?age WHERE { ?x humans:name ?name . OPTIONAL { ?x humans:age ?age } }">
  <li>${name} <c:if test="${!empty age}">(${age})</c:if></li>
</stl:for-each-result>

The Semtag lib also provides the equivalents of the classical if and choose tags but using SPARQL queries as test. For instance if you want to display males in blue and women in red you can change the above code like this:

04
05
06
07
08
09
10
11
12
13
<stl:for-each-result query="SELECT ?x ?name ?age WHERE { ?x humans:name ?name . OPTIONAL { ?x humans:age ?age } }">
 <li>
   <stl:choose>
     <stl:when test="ASK { &lt;${x}&gt; rdf:type humans:Female }"><span style="color: red">${name}</span></stl:when>
     <stl:when test="ASK { &lt;${x}&gt; rdf:type humans:Male }"><span style="color: blue">${name}</span></stl:when>
     <stl:otherwise>${name}</stl:otherwise>
   </stl:choose>
   <c:if test="${!empty age}"> (${age})</c:if>
 </li>
</stl:for-each-result>

In lines 7 and 8 a ASK query is used to test the type of the resource ?x returned in each result. Note the use of &lt; and &gt; to escape the < and > surrounding a URI in SPARQL.

There are other tags to query the base as you can see in the API. There is also a function to quickly send a query and obtain the first value of the first result:

01
02
03
04
05
<h2>Age of John</h2>
<div>
 <c:set var="myQuery" value="SELECT ?age WHERE { ?x humans:name 'John' . ?x humans:age ?age }" />
 John is ${stl:quickQuery(pageContext,myQuery)}-year old.
</div>

See also: quickQuery

Querying RDFS/OWL ontologies

Corese and Sewese can also be used to query the ontology. For instance to list all the sub-types of animals in the loaded ontology you can use the tag for-each-child:

See also: for-each-child

01
02
03
04
05
06
07
08
<h2>Get animal subtypes</h2>
<div>
  <ul>
    <stl:for-each-child root="http://www.inria.fr/2007/04/17/humans.rdfs#Animal" var="current">
    <li>${stl:label(pageContext, current, 'en', true)}</li>
    </stl:for-each-child>  
  </ul>
</div>

In line 4 the attribute root is used to specify the class for which we want the direct sub-types and the attribute var names the variable that will contain the URI of each child.

You could extend this code to display the number of instances for each one of the classes by calling the allInstanceNb function in line 5:

05
<li>${stl:label(pageContext, current, 'en', true)} (${stl:allInstanceNb(pageContext, current)})</li>

See also: label allInstanceNb

There are also two handy functions to generate check boxes and lists from the children of a class:

01
02
03
04
05
<h2>Select animal types</h2>
<div>
  <stl:select name="animal_type" root="http://www.inria.fr/2007/04/17/humans.rdfs#Animal"
  header="Choose a notion:" lang="en" />
</div>

See also: select

01
02
03
04
05
<h2>Select person types</h2>
<div>
  <stl:input-list name="person_type"
  root="http://www.inria.fr/2007/04/17/humans.rdfs#Person" multiple="true" lang="en" />
</div>

See also: input-list

Using functions and tags from the library one can rapidly develop a web-based ontology browser. First add this link at the end of the index.jsp file.

01
02
03
04
<h2>Browse the ontology</h2>
<div>
  Open a page to <a href="browse.jsp">browse ontology.</a>
</div>

Then make a copy of the index.jsp, name it browse.jsp and leave it at the root of the web application with the index.jsp file. Edit the file browse.jsp and replace the content of its body with the following code:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<c:choose>
  <c:when test="${!empty param['uri']}">
    <h1>
      <stl:for-each-label uri="${stl:decode(param['uri'])}" var="currentLabel" lang="en" varStatus="myStatus">
        ${currentLabel} 
        <c:if test="${!myStatus.last}"> - </c:if>
      </stl:for-each-label>
    </h1>
    <h2>Comments:</h2>
    <stl:for-each-comment uri="${stl:decode(param['uri'])}" var="currentComment" lang="en" varStatus="myStatus">
      <p>${currentComment}</p>
    </stl:for-each-comment>        
    <h2>Parents:</h2>
    <ul>
      <stl:for-each-parent root="${stl:decode(param['uri'])}" var="current">
      <li><a href="?uri=${stl:encode(current)}">${stl:label(pageContext, current, 'en', true)}</a></li>
      </stl:for-each-parent>  
    </ul>           
    <h2>Children:</h2>
    <ul>
      <stl:for-each-child root="${stl:decode(param['uri'])}" var="current">
      <li><a href="?uri=${stl:encode(current)}">${stl:label(pageContext, current, 'en', true)}</a></li>
      </stl:for-each-child>  
    </ul>
    <h2><a href="?uri=">back to roots</a></h2>
  </c:when>
  <c:otherwise>
    <h1>Roots</h1>
    <h2>concepts:</h2>
    <ul>
      <stl:for-each-root-concept var="current">
        <c:set var="label" value="${stl:label(pageContext, current, 'en', true)}" />
        <c:if test="${!empty label}"><li><a href="?uri=${stl:encode(current)}">${label}</a></li></c:if>
      </stl:for-each-root-concept>
    </ul>
    <h2>properties:</h2>
    <ul>
      <stl:for-each-root-property var="current">
      <c:set var="label" value="${stl:label(pageContext, current, 'en', true)}" />
        <c:if test="${!empty label}"><li><a href="?uri=${stl:encode(current)}">${label}</a></li></c:if>
      </stl:for-each-root-property>
    </ul>
  </c:otherwise>
</c:choose>

Test this page by clicking on the link you added to the index.jsp file. This new page is divided in two parts:

  1. if a parameter URI is passed to the page then lines 03 to 25 use different tags of the library to labels, comments and hierarchical links of the class or property identified by this URI.
  2. if no parameter URI is passed to the page then lines 28 to 42 display the root classes and root properties of the loaded ontologies.

See also: for-each-label for-each-comment for-each-child for-each-parent for-each-root-concept for-each-root-property

Editing RDF annotations

Using tags from the library one can also rapidly develop a web-based editor for the RDF data. Let us prototype an small interface to add, edit and remove persons.

See also: modify-annot

First add this form at the end of the index.jsp file:

01
02
03
04
05
06
07
<h2>Add a person</h2>
<div>
  <form action="add_person.jsp" method="post">
    Add a person named: <input type="TEXT" name="name" size="30"></input>
    <input type="SUBMIT" name="Submit"></input>
  </form>
</div>

Then make a copy of the index.jsp, name it add_person.jsp and leave it at the root of the web application with the index.jsp file. Edit the file add_person.jsp and replace the content of its body with the following code:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
<c:if test="${!empty param['name']}">  
  <stl:modify-annot kind="add"
    xpath="/rdf:RDF"
    forceUpdate="true"
    file="human_2007_04_17.rdf"
    humans="http://www.inria.fr/2007/04/17/humans.rdfs#"
    rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
    <humans:Person rdf:ID="${stl:encode(param['name'])}"
     xmlns:humans="http://www.inria.fr/2007/04/17/humans.rdfs#"
       xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
      <humans:name>${param['name']}</humans:name>
    </humans:Person>
  </stl:modify-annot>
  <p>A new person named "${param['name']}" was created.</p> 
</c:if>

Line 2 uses the tag modify-annot and the attribute kind with the value add to specify that we want to add some RDF. Line 5 gives the file and line 3 gives the XPath where the RDF should be added. Line 04 indicates we want the engine to load this change. Line 6 and 7 declare namespaces and 8 to 12 specify the RDF to add.

Now to change the name of a person add this form at the end of the index.jsp file:

01
02
03
04
05
06
07
08
<h2>Edit a person</h2>
<div>
  <form action="edit_person.jsp" method="post">
    Actual name: <input type="TEXT" name="name_before" size="30"></input>
    New name: <input type="TEXT" name="name_after" size="30"></input>
    <input type="SUBMIT" name="Submit"></input>
  </form>
</div>

Then make a copy of the index.jsp, name it edit_person.jsp and leave it at the root of the web application with the index.jsp file. Edit the file edit_person.jsp and replace the content of its body with the following code:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
<c:if test="${!empty param['name_before'] and !empty param['name_after']}">
 <p>Parameters found "${param['name_before']}" and "${param['name_after']}".</p>
  <c:set var="myQuery">ASK { ?x humans:name "${param['name_before']}" }</c:set>
  <stl:if test="${myQuery}">
    <p>Person found.</p>
    <stl:modify-annot kind="replace"
      xpath="/rdf:RDF/humans:Person/humans:name[text()='${param['name_before']}']"
      forceUpdate="true"
      file="human_2007_04_17.rdf"
      humans="http://www.inria.fr/2007/04/17/humans.rdfs#"
      rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
      <humans:name xmlns:humans="http://www.inria.fr/2007/04/17/humans.rdfs#">${param['name_after']}</humans:name>
    </stl:modify-annot>
    <p>The name "${param['name_before']}" was changed to "${param['name_after']}".</p>
  </stl:if>
</c:if>

Line 66 uses the tag modify-annot and the attribute kind with the value replace to specify that we want to modify some RDF. Line 9 gives the file and line 7 gives the XPath of the RDF/XML node that should be changed. Line 8 indicates we want the engine to load this change. Line 10 and 11 declare namespaces and line 11 specify the RDF to replace the selected node.

Finally to remove a person add this form at the end of the index.jsp file:

01
02
03
04
05
06
07
<h2>Delete a person</h2>
<div>
  <form action="delete_person.jsp" method="post">
    Delete the person named: <input type="TEXT" name="name" size="30"></input>
    <input type="SUBMIT" name="Submit"></input>
  </form>
</div>

Then make a copy of the index.jsp, name it delete_person.jsp and leave it at the root of the web application with the index.jsp file. Edit the file delete_person.jsp and replace the content of its body with the following code:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
<c:if test="${!empty param['name']}">
  <c:set var="myQuery">ASK { ?x humans:name "${param['name']}" }</c:set>
  <p>Parameter found "${param['name']}".</p>
  <stl:if test="${myQuery}">
    <p>Person found.</p>
    <stl:modify-annot kind="del"
      xpath="//*[child::humans:name='${param['name']}']"
      forceUpdate="true"
      file="human_2007_04_17.rdf"
      humans="http://www.inria.fr/2007/04/17/humans.rdfs#"
      rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" /> 
    <p>"${param['name']}" was deleted.</p>
  </stl:if>
</c:if>

Line 6 uses the tag modify-annot and the attribute kind with the value del to specify that we want to delete some RDF. Line 9 gives the file and line 7 gives the XPath of the RDF/XML node that should be deleted. Line 8 indicates we want the engine to load this change. Line 10 and 11 declare namespaces.