Querying RDF Datasources

This section will describe how to lookup information in a datasource.

Query Methods

The interface nsIRDFDataSource provides a number of methods for querying an RDF datasource. The two common datasources in-memory-datasource and xml-datasource implement all of these methods. However, other datasources may not implement all features. If a method is not implemented by a datasource, an exception will be thrown when the method is called. This is true of many of Mozilla's built-in datasources, that is, those that begin with 'rdf:' that are provided with Mozilla. These methods are unimplemented as they are not necessary for the product.

Because RDF stores triples of data, you can query for data given a part of the triple. For instance, if you have the subject and predicate of the triple, you can query the datasource for the targets that are present. Similarly, if you have the predicate and target, you can retrieve the subjects.

The examples in this section use the Karen's family example RDF from a previous section. The RDF/XML representation of this RDF data is repeated below.

<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
         xmlns:wordnet="http://xmlns.com/wordnet/1.6/"
         xmlns:people="http://www.xulplanet.com/rdf/people/">
<wordnet:Person rdf:about="http://www.xulplanet.com/rdf/people/Karen" people:name="Karen">
  <people:children>
    <rdf:Seq rdf:about="http://www.xulplanet.com/rdf/people/KarensKids">
      <rdf:li>
        <wordnet:Person rdf:about="http://www.xulplanet.com/rdf/people/Sandra" people:name="Sandra"/>
      </rdf:li>
      <rdf:li>
        <wordnet:Person rdf:about="http://www.xulplanet.com/rdf/people/Kevin" people:name="Kevin"/>
      </rdf:li>
      <rdf:li>
        <wordnet:Person rdf:about="http://www.xulplanet.com/rdf/people/Jack" people:name="Jack"/>
      </rdf:li>
    </rdf:Seq>
  </people:children>
</wordnet:Person>
</rdf:RDF>

Listed below is a list of the query methods available in all RDF datasources. The table lists the function you would call when you have certain parts of a triple and you want another part of the triple. For example, the first row indicates that if you have the subject of the triple, and want to retrieve the predicates that point out of that subject resource, use the ArcLabelsOut function.

You have You want Method
Subject Predicate Target
X     Predicate ArcLabelsOut
X     Target ArcLabelsOut and then GetTarget(s)
X X   Target GetTarget or GetTargets
    X Predicate ArcLabelsIn
    X Subject ArcLabelsIn and then GetSource(s)
  X X Subject GetSource or GetSources
X X   Existence of Target hasArcOut
  X X Existence of Subject hasArcIn
X X X Existence HasAssertion

Retrieving Targets

The most commonly used method is GetTarget. This method will return a single target given a subject and a predicate. Let's say that we want to return the name of the Karen resource. Karen's resource URI is http://www.xulplanet.com/rdf/people/Karen. First, we get this resource using the RDF service.

var rdfService = Components.classes["@mozilla.org/rdf/rdf-service;1"].
                   getService(Components.interfaces.nsIRDFService);
var karen = rdfService.GetResource("http://www.xulplanet.com/rdf/people/Karen");

Remember that resources are global objects. If Karen appears in another datasource, both resources will be the same object. This makes it easy to combine two datasources together.

Next, we use the GetTarget method to retrieve Karen's name. We use this method because we have the subject -- the Karen resource we just got from the RDF service above -- and the predicate which is 'name'. We will need to qualify the predicate with the namespace. In the RDF/XML above, the people namespace prefix is used, but of course we can't use the prefix in code since it is just an XML shorthand. We will need to use the full URI which is http://www.xulplanet.com/rdf/people/name. Since the predicate is also a resource, we retrieve it from the RDF service just like the subject.

var name = rdfService.GetResource("http://www.xulplanet.com/rdf/people/name");
var target = datasource.GetTarget(karen, name, true);

The GetTarget method is passed the subject and the predicate resources. It returns the target as an RDF node. The method always returns objects which implement the nsIRDFNode interface, never the resource or literal interfaces directly. If you want these interfaces, you will need to to cast to the desired interface using QueryInterface. In the case of Karen, we will assume her name is a literal and get the name's value. Note that the returned value is not a string. None of the RDF query interfaces work directly on strings.

var karensname;
var target = datasource.GetTarget(karen, name, true);
if (target instanceof Components.interfaces.nsIRDFLiteral){
  karensname = target.Value;
}

The instanceof operator checks if the value of 'target' is an RDF literal, and also has the side effect of casting the value to the interface if it is. This usage is also useful since we can both cast and check if the target is set in one step. If target is null, it means that the target did not exist. In this example, target will be null if Karen doesn't have a name specified. Inside the if-block, the value of the literal is retrieved as a string using the Value property.

You might have noticed that the GetTarget method has a third argument which is set to true above. This is used to indicate whether you want to retrieve a negative triple instead of a normal one. This is a special Mozilla-specific feature that allows an RDF statement to be false instead of true. Remember that when a piece of information is not supplied in the datasource, it means that the datasource does not know that information, not that the information is blank. For instance, if we hadn't specified Karen's name in the RDF/XML, it means that Karen's name is not known to the datasource. She may still have a name however.

A negative triple indicates that a particular statement is not true. For instance, we could add a statement that Karen's name is not 'Tracy'. Note that there is no way to actually specify this in the RDF/XML, only by directly manipulating the datasource. However, negative triples should generally be avoided. They don't really offer a lot of value and usually this kind of information is better specified in other ways.

However, if the third argument to the GetTarget method is false, it will return negative triples only. However, for almost all purposes, true should be supplied for this argument.

The GetTarget method will only return one of the targets that exist in the datasource. If Karen had several names, only one of them would be returned. The related method GetTargets will return a list of all the names. You should never rely on the order in which the names are returned, since RDF data isn't in any particular order. Although the GetTarget method will likely return the same value on each successive call, the value may be different each time your application is run.

The GetTargets method will return an enumeration which is an object which can be used to iterate over the results in sequence.

var targets = datasource.GetTargets(karen, name, true);
while (targets.hasMoreElements()){
  var name = targets.getNext();
  if (name instanceof Components.interfaces.nsIRDFLiteral){
    alert(name.Value);
  }
}

The enumeration implements the nsISimpleEnumeration interface and has two functions, hasMoreElements to check if all elements have been iterated over, and getNext to get the next element is sequence. The loop above will iterate over each name that exists. A cast must still be performed on each result. If no results exist, an empty enumeration will be returned, which means that the hasMoreElements call will always return false. Note that null is never returned from the GetTargets method.

Retrieving Subjects

There are also two methods GetSource and GetSources which work in the opposite direction. This means that we can get the Karen resource given her name as a literal. By combining the target and source retrieval methods, we can navigate anywhere in the RDF graph.

var rdfService = Components.classes["@mozilla.org/rdf/rdf-service;1"].
                   getService(Components.interfaces.nsIRDFService);
var karensname = rdfService.GetLiteral("Karen");
var name = rdfService.GetResource("http://www.xulplanet.com/rdf/people/name");
var subject= datasource.GetSource(name, karensname, true);

This code will find the Karen resource which is http://www.xulplanet.com/rdf/people/Karen. It works similarly to the target retrieval methods, except goes in the reverse direction. By supplying Karen's name, we can determine which resources have that name via the 'name' predicate. The GetSource method takes the predicate, target and truth value as arguments. The predicate is the first argument unlike the GetTarget method where it is the second argument. The GetSource method always returns an nsIRDFResource object since literals cannot have properties, so you can use the nsIRDFResource methods directly without casting the result.

There is also a GetSources method which will return an enumeration of all existing sources. This would be used in the case where several people had the name Karen.

Predicate Queries

Sometimes you will want to determine which predicates are specified for a given node in the datasource. For instance, given only the Karen resource, you would like to find out want properties it has. In the example, Karen has three properties, her name, her type and her children. The name has the value Karen The type is http://xmlns.com/wordnet/1.6/Person. The 'children' property is a resource http://www.xulplanet.com/rdf/people/KarensKids. It's possible that other properties might be added later as well.

If you want to determine which properties a resource has, use the GetArcsOut method of the datasource. It returns an enumeration of all the predicates that point out of a resource. If this method is called on the Karen resource, the enumeration will contain three values.

var karen = rdfService.GetResource("http://www.xulplanet.com/rdf/people/Karen");
var targets = datasource.ArcLabelsOut(karen);
while (targets.hasMoreElements()){
  var predicate = targets.getNext();
  if (predicate instanceof Components.interfaces.nsIRDFResource){
    alert(predicate.Value);
  }
}

The enumeration returns three predicate resources, not the values of the predicates. So the values returned would be resources with the values http://www.xulplanet.com/rdf/people/name, http://www.xulplanet.com/rdf/people/children, and http://www.w3.org/1999/02/22-rdf-syntax-ns#type. Remember that RDF in unordered so the results will not be returned in any particular order. The enumeration always returns generic nsISupports objects, so you will need to cast the returned results from the getNext method. In the case of the enumerations created from the ArcLabelsOut method, the values will always be nsIRDFResources, since predicates are always resources.

Once you have the predicate resource, you can supply it as an argument to GetTarget to get the value of the predicate for that resource. For example, the following code will get the value of the found predicates.

var karen = rdfService.GetResource("http://www.xulplanet.com/rdf/people/Karen");
var targets = datasource.ArcLabelsOut(karen);
while (targets.hasMoreElements()){
  var predicate = targets.getNext();
  if (predicate instanceof Components.interfaces.nsIRDFResource){
    var target = datasource.GetTarget(karen, predicate, true);
    if (target instanceof Components.interfaces.nsIRDFResource){
      alert("Resource is: " + target.Value);
    }
    else if (target instanceof Components.interfaces.nsIRDFLiteral){
      alert("Literal is: " + target.Value);
    }
  }
}

In this case, we need to check for both the nsIRDFResource and nsIRDFLiteral interfaces after the call to GetTarget, since one of the results, the name, will be a literal, while the other two, the type and the children, are resources, and we don't know the order in which they will be returned. It's a good idea to do this check anyway unless you are absolutely sure what kind of node will be returned.

Note that if two 'name' predicates point out from a resource, for instance, if Karen has two names, only one 'name' predicate will be returned in the enumeration. The enumerations will never contain duplicates. In this case, you will need to use the GetTargets method to retrieve the values.

The ArcLabelsIn method is similar to the ArcLabelsOut method but operates in the reverse direction. For instance, given the literal 'Karen', we could determine which predicates are used to point to the value. In the example, only one value will be returned in the enumeration, the 'name' predicate. But imagine that someone had the name 'April'. This would be used to indicate someone's name, but might also be used elsewhere in the datasource to specify the month of something using a 'month' predicate. In this situation, both predicates will be returned, even though they aren't part of the same resource. It is this feature which makes navigation of the RDF graph quite powerful.

Queries for Existence

Three additional datasource methods allow you to check for the existence of data in the RDF. The hasArcOut method may be used to check if a node has a certain predicate pointing out of it. This method is similar to the GetTarget method except that it does not return the actual target, only a boolean indicating whether the predicate exists or not. This method might be more efficient for some datasources. For instance, we could check if Karen has a name or not using the following code:

var karen = rdfService.GetResource("http://www.xulplanet.com/rdf/people/Karen");
var name = rdfService.GetResource("http://www.xulplanet.com/rdf/people/name");
var hasName = datasource.hasArcOut(karen, name);

The result of the hasArcOut method will be either true or false. In this example, the result will be true. There is also the related hasArcIn method for checking for the existence of a predicate pointing in to a node. Note that these two methods begin with a lower case letter which is not true of the other datasource methods.

The HasAssertion method may be used to check for a triple in the datasource given all three parts of the triple. This would allow you to check if Karen has a specific name. This method will return true if the triple exists, and false if it does not.

Finally, datasources supply a GetAllResources method which will return an enumeration of all of the resources that are used as subjects in the datasource. In the example, five values will be returned. There is no equivalent method for returning all of the literals. To do this, you will need to iterate over each resource using GetAllResources, call ArcLabelsOut on each resource, and then call GetTargets to get each target. This effectively iterates through all of the data in the datasource.

Add a note User Contributed Notes
No comments available

Copyright © 1999 - 2005 XULPlanet.com