Saving RDF

This section will describe how to save RDF datasources to files or serialize them to strings.

Saving RDF/XML Files

An xml-datasource can be saved back to a file after modifications are made. In fact, RDF/XML loaded from a file URL tends to automatically save back to disk when the datasource itself is no longer being used. You shouldn't rely on this behaviour however, as this saving doesn't work relibably if the datasource is still in use when Mozilla exits. Therefore, you should always save the datasource manually if you need to.

Don't worry about the automatic saving occuring as well later. The datasource will only be saved if changes have been made, so a manual save followed by the automatic save will only cause the datasource to be saved once. This also means that manual saving does nothing if the datasource has not changed.

To save an RDF/XML file, use the Flush method of the nsIRDFRemoteDataSource interface. This method will save the changed RDF/XML back to the file it was loaded from. Only files loaded from file URLs can be saved in this manner. Remote files and files loaded from chrome URLs cannot be saved back.

var ds=rdfService.GetDataSourceBlocking("file:///main/animals.rdf");
var subject = rdfService.GetResource("http://www.some-fictitious-zoo.com/crustaceans");
var predicate = rdfService.GetResource("http://www.some-fictitious-zoo.com/rdf#name");
var name = rdfService.GetLiteral("Crustaceans");
ds.Assert(subject, predicate, name, true);
ds.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource);
ds.Flush();

This example loads an RDF/XML file, adds a statement to it, and then saves it back to disk. Since RDF is not ordered, the saved file will likely look quite different than it was originally.

A second method FlushTo may be used to save a datasource to a specific URL. As with the Flush method, currently only file URLs may be saved to. In the future, other types of URL may be supported for saving. However, it is possible to save from any type of URI. This means that while you can only save to a file URL, the FlushTo method can save a datasource that was loaded from another source. The FlushTo method takes one argument, the URL to save to. It doesn't modify the original datasource, nor its URL, and just writes a serialized version of the data in RDF/XML form. Since it writes to another file, you can use the FlushTo method even if you haven't modified the datasource.

The example below loads a datasource and saves it to another file.

var ds=rdfService.GetDataSourceBlocking("file:///main/animals.rdf");
ds.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource);
ds.FlushTo("file:///main/more-animals.rdf");

Serializing to a String

Note that only the xml-datasource supports saving as described above. For other types of datasources, you may wish to serialize the data into a string. You could then save the string to a file using Mozilla's file interfaces. You can also serialize an xml-datasource to a string, for example, if you wanted to display the RDF/XML to the user.

Serializing to a string involves two interfaces and a serializer component. This component is the reverse of the RDF parser component used to parse RDF. The serializer implements two interfaces, nsIRDFXMLSource and nsIRDFXMLSerializer. The former is used to initialize the serializer with a datasource to write out while the latter is used to do the conversion. If using the xml-datasource, the first part is handled for you and you can just call the Serialize method. The xml-datasource implements the nsIRDFXMLSerializer interface directly, so writing these datasources is more streamlined.

The Serialize method is used to write RDF/XML data to a stream. It doesn't write to a string directly -- instead we need to wrap the string to write to in a string. Naturally, if you want to write to a stream, you don't need to do this. The stream should implement the nsIOutputStream interface.

It's fairly easy to implement an output stream. There are only four methods and only one, write, has to do anything. This method will be called to write the serialized data to the stream. It won't be sent all at once, so you can use this to allow for asynchronous writing which doesn't block the user interface.

var outputStream = {
  data: "",
  close : function(){},
  flush : function(){},
  write : function (buffer,count){
    this.data += buffer;
    return count;
  },
  writeFrom : function (stream,count){},
  isNonBlocking: false
}
ds.QueryInterface(Components.interfaces.nsIRDFXMLSource);
ds.Serialize(outputStream);

In the above example, we create an output stream object. The XPConnect bridge which connects XPCOM and JavaScript is able to convert this into an implementation of the nsIOutputStream interface, simply by matching method names. The write method takes two arguments, the buffer of data and the length of the buffer. We simply append the buffer contents to a data property, which isn't part of the nsIOutputStream interface. After serialization is complete, the data property will hold the serialized RDF/XML string.

In the example above, we call the Serialize method directly on a datasource, after calling QueryInterface to cast it to the right interface. This works for fine for RDF/XML datasources, since they know how to do that. For other datasources, you must create a serializer first, as in the example below.

var serializer=Components.classes["@mozilla.org/rdf/xml-serializer;1"]
                         .createInstance(Components.interfaces.nsIRDFXMLSerializer);
serializer.init(ds);
serializer.QueryInterface(Components.interfaces.nsIRDFXMLSource);
serializer.Serialize(outputStream);

The serializer is created and initialized with the datasource by calling the init method. Then, we can call the Serialize method on the serializer directly after casting it. Most datasources can be serialized in this way. You cannot serialize a composite-datasource; you must serialize each datasource it contains separately.

When serializing, namespaces and prefixes will be determined automatically. The serializer uses a fairly simple mechanism whereby it assumes that the last hash mark (#) or forward slash is the separator between the namespace part and the value part. For example, http://www.xulplanet.com/rdf/people/name will have a namespace of 'http://www.xulplanet.com/rdf/people/' and a predicate value of 'name'. The serializer will make up a prefix to use. The behaviour may seem unusual and won't work if predicates don't follow that convention. Fortunately, the serializer has a means of controlling the namespaces that are used.

The serializer has a method addNameSpace which may be used to associate a prefix with a namespace URI. When serializing, the list of added namespaces is used when converting predicates to namespaces and values. The addNameSpace method takes two arguments, the prefix and the namespace URI. Although the namespace URI is a string, the prefix is an atom object instead. An atom is simply a string that is cached with a key and is efficient to compare. It's fairly similar to an RDF literal in purpose although atoms are built in to the XPCOM library which is convenient for Mozilla based applications which don't need RDF. Mozilla uses atoms internally to handle namespaces so that elements and attributes can be compared quickly. To create an atom, just use the atom service.

var atomService = Components.classes["@mozilla.org/atom-service;1"]
                    .createInstance(Components.interfaces.nsIAtomService);
var prefix = atomService.getAtom("people");
ser.addNameSpace(prefix,"http://www.xulplanet.com/rdf/people/");

In this example, the getAtom method of the atom service is used to get atom references. The atom service implements the nsIAtomService and the atoms implement the nsIAtom interface. The addNameSpace method is used to add a prefix 'people' to the namespace 'http://www.xulplanet.com/rdf/people/'. When serializing an RDF datasource, any predicates which begin with this namespace will be serialized using the namespace prefix 'people'. Note that the 'RDF' namespace is already added to the serializer so you don't have to add it manually.

Add a note User Contributed Notes
No comments available

Copyright © 1999 - 2005 XULPlanet.com