This turorial is part of the RAP - Rdf API for PHP documentation.
Radoslaw Oldakowski <firstname.lastname@example.org>
In this tutorial I will explain the syntax of the RDQL query language implemented in RDF API for PHP and show how to query RDF models created within the API. The exact RDQL grammar for RAP's RDQL Engine, described in Bacus Naur Form (BNF), is provided here.
The general form of an RDQL query, shown below, resembles an SQL statement:
Every successful query returns a set of variable bindings. In the
SELECT clause we define a list of variables to be returned.
Each variable is introduced by a question mark (?) and can be named using alphanumerical characters combined with an underscore (_).
Multiple variables are separated by a space and/or an optional comma (,), for example:
In case that we want to specify all query variables, we can use the SQL-like shortcut in form of a star (*):
FROM clause we specify the path or URL of the RDF document
to be queried. However, this tutorial focuses on querying RDF models created
within RAP (MemModels or DbModels) by passing the RDQL query string to the method
rdqlQuery(). In this case the query is performed on a particular
model, thus there is no need to specify it once again. If the passed string
FROM clause, it will then be ignored by the query engine.
WHERE clause we indicate a list of triple patterns which
have to be matched by each valid query result set. All patterns representing
an RDF statement have the form
(subject, predicate, object) where
the subject, predicate, and object can either be a
?variable. The object can moreover be a
This will match any statement of an RDF model with a predicate indicated
by the above URIref (vCard's email property) and an object represented by
"email@example.com". Furthermore, we can specify the language
and datatype of a literal:
"literal string"@lang^^<datatypeURI>. Note that the language
tag has no effect when the literal is datatyped, except for
plain literals. Correspondingly to the
SELECT clause, using commas
(,) is also optional.
In addition to the triple patterns of the
WHERE clause, in the
AND part of an query we can specify Boolean expressions over values
of URIs and literals. RAP's implementation of RDQL shows the real expressive
power of this query language. And so, we can use:
arithmetic conditions (including multiplicative and additive operators), for instance:
(multiple expressions are separated by commas)
string equality expressions, where
EQ stands for "equal" and
NE for "not equal":
Perl-style regular expressions, where "~~" | "=~" stands for "match" and "!~" for "not match", for example, return only HTML documents:
We can also combine multiple filter expressions using logical operators "&&" (AND), "||" (OR):
as well as use negation indicated by the exclamation mark (!):
To make the query easier to read and write for humans, RDQL provides a way
to shorten the length of URIs (used in the
AND clauses) by defining a string prefix. Every prefix is
defined in the
USING clause as demonstrated below:
Note that since RAP V0.8 QNames (e.g. vCard:EMAIL) in contrast to full URI's
need not to be surrounded by '<' and '>'. However, the RDQL parser is also
with earlier versions of the RDQL grammar (RAP V0.6 - RAP V0.7.1). Moreover,
RAP supports default prefixes (e.g.
that can be used without an explicit definition.
While writing very long and complicated RDQL queries, it is often of great benefit to comment the code. For this purpose RAP allows us to use two kinds
of comment syntaxes. The first one is the one-line comment introduced by "//", the second has the form of
/* this is a comment */.
At this point it is time to put together all the pieces explained so far and present RAP's RDQL Engine in action. In the following part of this section we will be querying an RDF document describing employees of an example corporation (employees.rdf). The working code for the examples that will be demonstrated in this RDQL tutorial is rdql_tutorial.php.
We shall start with including all RAP classes needed and loading the document into a MemModel:
Once the model has been created, we can perform our first query which will be: "find the full name of all employees".
So, we create a variable
$query1 and assign it the corresponding query string:
To execute the query, we simply call the method
rdqlQuery() on the MemModel and pass the variable holding the query string as parameter:
The result returned is an array of variable bindings with the values of these variables being RAP objects (
BlankNode). This enables us to use these objects for model update or other API calls.
We can, of course, print out the result on the screen as well. For this purpose, RAP's RDQL engine offers a very convenient method
writeQueryResultAsHtmlTable(). All we have to do is to pass the query result to this method:
This will result in the following output in the browser window:
Literal: Bill Parker
Literal: George Simpson
Literal: Monica Murphy
If we did not want to have objects being returned as variable values but their string serialization instead,
we would call the method
rdqlQeury() and pass
FALSE as the second parameter:
Note that in this case the resulting array could not be passed to the method
writeQueryResultAsHtmlTable() so that we had to iterate it
using PHP's built-in
As you can see querying RDF models in RAP is extremely easy. Similarly we also query persisted models by passing the RDQL string to the method
rdqlQuery() called on a DbModel. Hence, from this point on I will only explain how to formulate a query and show its corresponding result.
In our next query: "find the given name of all employees over 30" we have to use a filter expression. Moreover, in order to find out the given name we must specify the corresponding path in the graph leading through a Blank Node (marked bold):
In the above example, I have also demonstrated a possible way to insert comments. Here, the variable
?blank is only used to link the resource
to the given name. We did not specify
?blank in the
SELECT clause, consequently we get:
Literal: 33 (rdf:datatype="http://www.w3.org/TR/xmlschema-2/integer")
Literal: 41 (rdf:datatype="http://www.w3.org/TR/xmlschema-2/integer")
Note that the value of
?age is a datatyped literal. Yet another even more complex example might be: "find the private telephone number
of the person whose office number is '+1 111 2222 668' and additionally return his given name and age". In this query we have to specify several paths in the graph.
Furthermore, we use a string equality expression in the
AND clause to filter the office number:
As shown in this example we can leave out commas. Note also that we make use of the default prefix
rdf:type) supported by RAP's RDQL engine. This query returns one matching set of variable bindings:
Literal: 33 (rdf:datatype="http://www.w3.org/TR/xmlschema-2/integer")
Literal: +1 111 2212 431
So far, the values of all variables returned were literals. However, we can ask for resources as well. Consider the following query: "find the resources that represent employees whose family name starts with 'M' and additionally return the corresponding office email address". This can be written in RDQL as shown below:
In this case we use a regular expression to indicate the first letter of the family name
and once again apply the default prefix
rdf. This results in:
For more query examples see Documentation included in RAP documentation. You can additionally visit the website with the Interactive RDQL Demonstration allowing you to practice with your own documents and queries. Furthermore, RDQL Test Cases give you an even deeper insight into RAP implementation of RDQL by providing the opportunity to go through 77 queries testing different aspects of the language implementation, performed in real time on both a memory and a persisted model.