RDF/XML als Java -Speicher-Format
Für Java -Anwendungen wird gelegentlich eine Speicherung des Zustandes gewünscht. So könnte es beispielsweise erwünscht sein, daß ein Programm zur Verwaltung einer Aufgabenliste, diese Aufgabenliste dauerhaft so speichert, daß sie nach dem Beenden des Programms erhalten bleibt und später wieder hergestellt werden kann.
Unter bestimmten Umständen kann es erwogen werden, XML als Speicherformat zu verwenden. In diesem Artikel wird vorausgesetzt, daß der Leser mit XML und dessen Vorteilen und Nachteilen für die Datenspeicherung bereits vertraut ist. Es wird angenommen, daß es erkannt wurde, daß eine Speicherung mit XML für den gewünschten Zweck vorteilhaft ist.
Unter diesen Umständen sollte RDF/XML verwendet werden, weil es all das bereitstellt, was meistens ohnehin mit „XML “ gemeint ist. So kann RDF/XML klarstellen, welche Elementtypen Datensätze und welche Elementtypen Felder von Datensätzen sein sollen. Die ganze Semantik der zu speichernden Daten wird besser dokumentiert als bei Verwendung von XML alleine. RDF/XML bietet viel von dem, was oft schon von XML erwartet wird. Einige Grundlagen von RDF/XML werden hier kurz erklärt, so daß der Artikel auch für Leser verständlich sein sollte, die RDF/XML bisher noch nicht kannten.
Jena
Jena ist eine Sammlung von Paketen zur Erleichterung des Zugriffs auf RDF -Daten mit Java.
Zur Beschaffung kann die folgende Quelle verwendet werden.
- Jena Semantic Web Toolkit Download
- http://www.hpl.hp.com/semweb/download.htm
Von dieser Seite kann ein Zip -Datei "http://www.hpl.hp.com/semweb/download/Jena-1.6.1.zip" kopiert werden.
Die Zip -Datei wird an einen beliebigen Ort entpackt. Die Pakete aus dem Verzeichnis "lib" können in ein geeignetes Verzeichnis kopiert werden, das im folgenden als das Verzeichnis "../l" angenommen wird.
Die Anwendung "taskbook"
In dieser Lektion wird eine Anwendung "taskbook" vorgestellt, die derzeit extrem trivial ist und später vielleicht noch ausgebaut wird. Es handelt sich um eine Aufgabenliste, die in der ersten Minimalversion nur Namen von Aufgaben enthalten kann. Die Grundstruktur dieser Anwendung ist das gleichnamige Aufgabenbuch "taskbook", dessen Inhalt eine Aufgabenliste "tasks" ist. Ein Eintrag in dieser Aufgabenliste ist eine Aufgabe "task", eine solche Aufgabe enthält nur ihren Namen. Die Aufgabenliste enthält hier die Aufgabe "Blumen giessen" und die Aufgabe "Waesche waschen".
taskbook [block structure]
.----------------------------------------------.
| taskbook : Taskbook |
| .----------------------------------------. |
| | tasks : Sequence | |
| | .---------------------------------. | |
| | | task0 : Task | | |
| | |---------------------------------| | |
| | | "Blumen giessen" : String | | |
| | '---------------------------------' | |
| | .---------------------------------. | |
| | | task1 : Task | | |
| | |---------------------------------| | |
| | | "Waesche waschen" : String | | |
| | '---------------------------------' | |
| '----------------------------------------' |
'----------------------------------------------'
Die Datenstruktur "taskbook" kann auch als Graph aufgefaßt werden.
taskbook [graph]
.--------------------. type .-----------------.
| taskbook |------------->| Taskbook |
'--------------------' '-----------------'
|
| tasks
V
.--------------------. type .------------------.
| tasks |------------->| Sequence |
'--------------------' '------------------'
|
'
/|
.-------' |
/ |
. |
| |
| |
| |
| |
| |
| |
| | 1
| V
| .--------------------. type .------------------.
| | task0 |------------->| Task |
| '--------------------' '------------------'
| | ^
| | name | type
| V |
| "Blumen giessen" |
. |
\ |
'-------. |
\ |
. |
| 2 |
V '
.--------------------. /
| task1 |----------------------'
'--------------------'
|
| name
V
"Waesche waschen"
Der Graph wird durch Elementaraussagen (“triples ”) dargestellt. Beispielsweise kann die Aussage „Die Ressource "taskbook-entity" hat den Typ "taskbook-class"“ als Tripel "taskbook-entity type-predicate taskbook-class" aufgefaßt werden. Durch eine Menge solcher Tripel (tripel set ) kann der gesamte Graph dargestellt werden.
taskbook [triple set]
taskbook-entity type-predicate taskbook-class
tasks-predicate tasks-entity
tasks-entity type-predicate sequence-class
_1-predicate task0-entity
_2-predicate task1-entity
task0-entity type-predicate task-class
name-predicate "Blumen giessen"
task1-entity type-predicate task-class
name-predicate "Waesche waschen"
Die folgende Beispieldatei zeigt, wie solch eine Tripelmenge in RDF formuliert werden kann. Die verwendeten Ressourcen und Relationen erhalten dabei durch die Verwendung von URI s weltweit eindeutige Namen.
taskbook.rdf
<rdf:RDF
xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'
xmlns:task='https://www.purl.org/stefan_ram/namespace/public/trp/task/predicate/'
xmlns:taskbook='https://www.purl.org/stefan_ram/namespace/public/trp/taskbook/predicate/'>
<rdf:Description rdf:about='https://www.purl.org/stefan_ram/namespace/private/trp/taskbook/entity'>
<rdf:type rdf:resource='https://www.purl.org/stefan_ram/namespace/public/trp/taskbook/class/'/>
<taskbook:tasks rdf:resource='https://www.purl.org/stefan_ram/namespace/private/trp/taskbook/tasks/entity'/>
</rdf:Description>
<rdf:Description rdf:about='https://www.purl.org/stefan_ram/namespace/private/trp/taskbook/tasks/entity'>
<rdf:type rdf:resource='http://www.w3.org/1999/02/22-rdf-syntax-ns#Seq'/>
<rdf:_1 rdf:resource='https://www.purl.org/stefan_ram/namespace/private/trp/task/task0/entity'/>
<rdf:_2 rdf:resource='https://www.purl.org/stefan_ram/namespace/private/trp/task/task1/entity'/>
</rdf:Description>
<rdf:Description rdf:about='https://www.purl.org/stefan_ram/namespace/private/trp/task/task0/entity'>
<rdf:type rdf:resource='https://www.purl.org/stefan_ram/namespace/public/trp/task/class/'/>
<task:name>Blumen giessen</task:name>
</rdf:Description>
<rdf:Description rdf:about='https://www.purl.org/stefan_ram/namespace/private/trp/task/task1/entity'>
<rdf:type rdf:resource='https://www.purl.org/stefan_ram/namespace/public/trp/task/class/'/>
<task:name>Waesche waschen</task:name>
</rdf:Description>
</rdf:RDF>
Im folgenden wird nun ein Java -Programm "Taskbook.java" angegeben, das die Datei "taskbook.rdf" einliest, verändert und wieder ausgibt, es zeigt folgende Vorgänge:
this.load( "taskbook.rdf" ); this.link();
Lesen der Datei "taskbook.rdf" und Bindung des Graphen an einige Felder der Klasse zum bequemen Zugriff.
this.print(); this.changeName();
Ausgeben des Graphen. Ändern des Namens einer Aufgabe vom Text "Blumen giessen" in den Text "Fenster putzen".
this.print(); this.addTask();
Ausgeben des Graphen. Eine Aufgabe "Heizkoerper entlueften" hinzufügen.
this.print(); removeTask();
Ausgeben des Graphen. Eine Aufgabe entfernen.
this.print(); save();
Ausgeben des Graphen. Schreiben des Graphen in die RDF -Datei "out.rdf".
Taskbook.java
class MyJena
{ // todo: hier auch "throws"?
final static com.hp.hpl.mesa.rdf.jena.model.Property property( final String l, final String r )
{ com.hp.hpl.mesa.rdf.jena.model.Property result = null; try
{ result = new com.hp.hpl.mesa.rdf.jena.common.PropertyImpl( l, r ); }
catch( Exception e ){} return result; }}
class TaskbookAso
{ int indentation = 0;
final private void space(){ java.lang.System.out.print( " " ); }
final private void indent(){ int i = 2 * indentation; while( i-- > 0 )space(); }
final private void line( final String s ){ indent(); java.lang.System.out.println( s ); }
final void start( final String s ){ this.line( s ); ++indentation; }
final void entry( final String s ){ this.line( s ); }
final void end( final String s ){ --indentation; }}
public final class Taskbook
{ final static String inFile = "taskbook.rdf";
final static TaskbookAso aso = new TaskbookAso();
final static String the = "https://www.purl.org/stefan_ram/namespace/public/trp/";
final static String my = "https://www.purl.org/stefan_ram/namespace/private/trp/";
final static com.hp.hpl.mesa.rdf.jena.model.Property theTaskNamePredicate =
MyJena.property( the + "task/predicate/", "name" );
final static com.hp.hpl.mesa.rdf.jena.model.Property theTaskbookTasksPredicate =
MyJena.property( the + "taskbook/predicate/", "tasks" );
com.hp.hpl.mesa.rdf.jena.model.Model graph;
com.hp.hpl.mesa.rdf.jena.model.Resource taskbook;
com.hp.hpl.mesa.rdf.jena.model.Resource tasks;
com.hp.hpl.mesa.rdf.jena.model.Seq tasksSeq;
Taskbook() throws Exception
{ if( theTaskNamePredicate == null || theTaskbookTasksPredicate == null )throw( new Exception() );
this.load( "taskbook.rdf" ); this.link();
this.print(); this.changeName();
this.print(); this.addTask();
this.print(); removeTask();
this.print(); save(); }
void load( final String path ) throws Exception
{ graph = new com.hp.hpl.mesa.rdf.jena.mem.ModelMem();
final java.io.InputStream source = Taskbook.class.getClassLoader().getResourceAsStream( path );
if( source != null )
{ graph.read( new java.io.InputStreamReader( source ), "" ); }}
void link() throws Exception
{ taskbook = getMy( "taskbook/entity" );
final com.hp.hpl.mesa.rdf.jena.model.Statement statement =
taskbook.getProperty( theTaskbookTasksPredicate );
tasks =( com.hp.hpl.mesa.rdf.jena.model.Resource )statement.getObject();
tasksSeq = graph.getSeq( tasks ); }
com.hp.hpl.mesa.rdf.jena.model.Resource getMy( final String s ) throws Exception
{ return graph.getResource( my + s ); }
com.hp.hpl.mesa.rdf.jena.model.Statement getStatement
( com.hp.hpl.mesa.rdf.jena.model.Resource res ) throws Exception
{ final com.hp.hpl.mesa.rdf.jena.model.Statement s = res.getProperty( theTaskNamePredicate ); return s; }
String getName( com.hp.hpl.mesa.rdf.jena.model.Resource res ) throws Exception
{ final com.hp.hpl.mesa.rdf.jena.model.Statement s = getStatement( res );
final com.hp.hpl.mesa.rdf.jena.model.RDFNode name =( com.hp.hpl.mesa.rdf.jena.model.RDFNode )s.getObject();
return name.toString(); }
// Seq getTasksSeq() throws Exception{ graph.getResource( my + s ); }
final void print() throws Exception
{ aso.start( "taskbook" ); aso.start( "tasks" );
com.hp.hpl.mesa.rdf.jena.model.NodeIterator iter = tasksSeq.iterator();
while( iter.hasNext() ){ aso.entry( getName( ( com.hp.hpl.mesa.rdf.jena.model.Resource )iter.next() ) ); }
aso.end( "tasks" ); aso.end( "taskbook" ); }
final void changeName() throws Exception
{ com.hp.hpl.mesa.rdf.jena.model.NodeIterator iter = tasksSeq.iterator();
final com.hp.hpl.mesa.rdf.jena.model.Statement statement =
getStatement( ( com.hp.hpl.mesa.rdf.jena.model.Resource )iter.next() );
statement.set( "Fenster putzen" ); }
final void addTask() throws Exception
{ // todo: hier auch "the" o.ae.?
com.hp.hpl.mesa.rdf.jena.model.Resource res = graph.createResource
( "https://www.purl.org/stefan_ram/namespace/private/trp/task/task2/entity" )
.addProperty( com.hp.hpl.mesa.rdf.jena.vocabulary.RDF.type,
"https://www.purl.org/stefan_ram/namespace/public/trp/task/class/" )
.addProperty( theTaskNamePredicate, "Heizkoerper entlueften" );
tasksSeq.add( 3, res ); }
final void removeTask() throws Exception
{ tasksSeq.remove( 1 ); }
final void save() throws Exception
{ java.io.OutputStream out = new java.io.FileOutputStream( "out.rdf" );
java.io.Writer w = new java.io.BufferedWriter( new java.io.OutputStreamWriter( out, "UTF-8" ));
graph.write( w ); /* graph.write( w, "RDF/XML-ABBREV" ); */ }
final public static void main( final String args[] )
{ try{ new Taskbook(); }catch( Exception e ){ java.lang.System.out.println( e ); } }}System.out
taskbook
tasks
Blumen giessen
Waesche waschen
taskbook
tasks
Fenster putzen
Waesche waschen
taskbook
tasks
Fenster putzen
Waesche waschen
Heizkoerper entlueften
taskbook
tasks
Waesche waschen
Heizkoerper entlueftenout.rdf
<rdf:RDF
xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'
xmlns:NS0='https://www.purl.org/stefan_ram/namespace/public/trp/taskbook/predicate/'
xmlns:NS1='https://www.purl.org/stefan_ram/namespace/public/trp/task/predicate/'
>
<rdf:Description rdf:about='https://www.purl.org/stefan_ram/namespace/private/trp/taskbook/entity'>
<rdf:type rdf:resource='https://www.purl.org/stefan_ram/namespace/public/trp/taskbook/class/'/>
<NS0:tasks rdf:resource='https://www.purl.org/stefan_ram/namespace/private/trp/taskbook/tasks/entity'/>
</rdf:Description>
<rdf:Description rdf:about='https://www.purl.org/stefan_ram/namespace/private/trp/task/task1/entity'>
<rdf:type rdf:resource='https://www.purl.org/stefan_ram/namespace/public/trp/task/class/'/>
<NS1:name>Waesche waschen</NS1:name>
</rdf:Description>
<rdf:Description rdf:about='https://www.purl.org/stefan_ram/namespace/private/trp/task/task0/entity'>
<rdf:type rdf:resource='https://www.purl.org/stefan_ram/namespace/public/trp/task/class/'/>
<NS1:name>Fenster putzen</NS1:name>
</rdf:Description>
<rdf:Description rdf:about='https://www.purl.org/stefan_ram/namespace/private/trp/task/task2/entity'>
<rdf:type>https://www.purl.org/stefan_ram/namespace/public/trp/task/class/</rdf:type>
<NS1:name>Heizkoerper entlueften</NS1:name>
</rdf:Description>
<rdf:Description rdf:about='https://www.purl.org/stefan_ram/namespace/private/trp/taskbook/tasks/entity'>
<rdf:type rdf:resource='http://www.w3.org/1999/02/22-rdf-syntax-ns#Seq'/>
<rdf:_1 rdf:resource='https://www.purl.org/stefan_ram/namespace/private/trp/task/task1/entity'/>
<rdf:_2 rdf:resource='https://www.purl.org/stefan_ram/namespace/private/trp/task/task2/entity'/>
</rdf:Description>
</rdf:RDF>
Die folgende Stapeldatei ist nur ein Beispiel, das zeigt, wie die Quelldatei "Taskbook.java" übersetzt werden kann. Diese Stapeldatei kann so praktisch nur auf Microsoft ®-Windows -Systemen verwendet werden, aber für viele andere Betriebssysteme kann eine ähnliche Datei erzeugt werden.
Taskbook.bat
SET NAME=Taskbook
SET JDK=C:\Programme\j2sdk1.4.2
SET BIN=%JDK%\BIN
SET JAVAC=%BIN%\javac.exe
SET JAVA=%BIN%\java.exe
SET CP=.;..\l\sax2.jar;..\l\xerces.jar;..\l\rdffilter.jar;..\l\icu4j.jar;..\l\jena.jar
%JAVAC% -classpath %CP% %NAME%.java
IF ERRORLEVEL 1 GOTO END
%JAVA% -cp %CP% %NAME% >taskbook.txt
type taskbook.txt
:END