XML-Verarbeitung in Java

Transcription

XML-Verarbeitung in Java
Content
..
.......
... .....
...
...
..
...
...
...
...
...
...
...
...
...
.
...
..
...
...
.
.
...
.
...
...
...
...
.
...
...
...
...
...
.
...
...
...
...
.
...
...
...
...
...
.
...
...
...
...
.
...
...
...
...
...
.
...
...
...
...
.
...
..
Information
Concept
Topic
XML-Verarbeitung in Java
Praktikum zur Vorlesung Intelligente Informationssysteme
WS 2004/05
Gunar Fiedler ([email protected])
Question1 : When should I use XML?
Answer: When you need a buzzword in your resume.
1 XML
Die EXtensible Markup Language ist eine Sprache zur Beschreibung von Daten.
Dabei bedient man sich einer Menge von Markierungselementen, den sogenannten
Tags. Anders als bei HTML ist die Menge der Tags nicht vorbestimmt, jeder kann
sich seine eigenen Tags definieren.
Die Syntax eines XML-Dokuments ist einfach:
<?xml version="1.0" encoding="ISO-8859-1"?>
<tour>
<artist>R.E.M.</artist>
<title>Tour 2005</title>
<event>
<place name="ColorLine Arena">
<address>Sylvesterallee, 22525 Hamburg</address>
</place>
<date day="17" month="2" year="2005" hour="20" minute="0" />
</event>
</tour>
Jedes Dokument beginnt mit der XML declaration, welche die XML-Version und die
Zeichencodierung der Datei angibt:
<?xml version="1.0" encoding="ISO-8859-1"?>
Momentan wird immer XML-Version 1.0 verwendet, ISO-8859-1 bezeichnet den
Zeichensatz Latin 1/West European.
1
www.w3schools.com/xml/xml_whatis.asp
1 XML
XML-Verarbeitung
<tour>
Das erste Tag bezeichnet das Wurzelelement des Dokuments, in das alle anderen
Elemente eingebettet sind. Jedes XML-Dokument hat genau 1 Wurzelelement. Im
Unterschied zu HTML wird in XML bei der Definition von Bezeichnern zwischen
Groß- und Kleinschreibung unterschieden.
Da jeder seine eigenen Tags definieren kann, würde bald großes Chaos herrschen,
und niemand könnte unterscheiden, wer ein bestimmtes Tag mit welcher Bedeutung
definiert hat. Aus diesem Grund werden Tagnamen in Namensräume eingeteilt. Ein
Namensraum ist ein weltweit eindeutiger Bezeichner, also eine URI2 . Dieser URI
wird im Wurzelelement ein symbolischer Bezeichner zugewiesen:
<tour xmlns="http://www.is.informatik.uni-kiel.de/events"
xmlns:h="http://www.w3.org/1999/xhtml">
<artist><h:h1>R.E.M.</h:h1></artist>
</tour>
Namespaces werden durch xmlns:XX-Attribute festgelegt, wobei XX dem symbolischen Bezeichner entspricht. Dem eigentlichen Tag-Namen wird dieser Bezeichner
vorangestellt, im Beispiel wurde aus dem HTML-Tag h1 ein Tag h:h1, da der
XHTML-Namespace, in dem h1 definiert ist, mit dem symbolischen Bezeichner h
versehen wurde. Tags ohne explizite Namespace-Angabe werden dem StandardNamespace zugeordnet. Dessen Definition erfolgt durch das xmlns-Attribut des Wurzelknotens.
<artist>R.E.M.</artist>
Das Element artist wird Kindelement des ihm übergeordneten Elements tour genannt. Analog sind title und event Kinder von tour; place und date sind Kinder von event. Jedes öffnende“ Tag (<tour>, <artist>, <date>, ...) muss wieder
”
geschlossen werden. Dies geschieht durch Angabe des Tag-Namens mit einem vorangestellten Schrägstrich (/), z.B. </tour>. Besitzt das Element keine Kindelemente,
wie z.B. das Element date, so kann der Schrägstrich auch vor die schließende Klammer des öffnenden Tags geschrieben werden (<date />), diese Schreibweise ist zu
<date></date> äquivalent.
Ein Kind-Element muss sich vollständig innerhalb des Eltern-Elements befinden, d.h.
es wird nach dem öffnenden Tag des Eltern-Elements definiert und vor dem schließenden Tag des Eltern-Elements geschlossen. Durch diese Konstruktionsvorschrift
bilden die Elemente eines XML-Dokuments einen Baum, dessen Wurzelknoten gerade das Wurzelelement des Dokuments ist.
Besitzt ein XML-Element mehrere Kinder, so bilden die Kind-Elemente eine Liste
und keine Menge oder Multimenge.
<date day="17" month="2" year="2005" hour="20" minute="0" />
2
2
wobei es sich um einen URN und nicht um eine URL handelt
WS 2004/05, Gunar Fiedler, ISE@CAU
XML-Verarbeitung in Java
2 XML-Verarbeitung
Jedes Element kann Attribute haben. Attribute besitzen einen Namen und einen
Wert aus dem Wertebereich eines atomaren Datentyps, z.B. eine Zeichenkette oder
eine Zahl. Attribute werden innerhalb der Klammern des öffnenden Tags eines Elements durch die Angabe name="value" definiert. Der Wert des Attributs muss stets
in Hochkommata eingeschlossen werden. Ein Element kann beliebig viele Attribute
besitzen. Auch Attribute werden in Namespaces eingeteilt.
<artist>R.E.M.</artist>
Jedes Element kann Text beinhalten. Es ist möglich, Kind-Elemente und TextAbschnitte zu mischen. Falls der Text eines Elements selbst Tags enthält, die aber
nicht interpretiert werden sollen (wie <pre>-Abschnitte in HTML bzw. die verbatimUmgebung in LATEX), so muss er in eine CDATA-Section eingeschlossen werden:
<event>
<!-- ... -->
<travelinfo>
<![CDATA[ <strong>PKW</strong><br />Fahren Sie ...]]>
</travelinfo>
</event>
Neben den vorgestellten Strukturierungselementen gibt es noch zwei weitere: Kommentare und Processing Instructions. Ein Kommentar wird durch die Markierungen
<!-- und --> eingeschlossen:
<!-- Das ist ein Kommentar -->
Eine Processing Instruction ist, wie der Name schon sagt, eine Verarbeitungsanweisung für die Anwendung, welche das XML-Dokument liest und verarbeitet. Sie wird
in <? und ?> Markierungen eingeschlossen. Eine wichtige Processing Instruction ist
z.B. die Angabe eines fest zugeordneten Stylesheets (siehe auch Abschnitt 4.1):
<?xml-stylesheet type="text/xsl" href="renderAsHTML.xsl"?>
Ein XML-Dokument heißt well formed“, wenn es die dargestellte Syntax einhält.
”
Falls es zusätzlich einem gegebenen Schema bzw. einer DTD3 entspricht, nennt man
es valid“.
”
2 XML-Verarbeitung
XML-Dokumente sind zunächst einmal reine Textdateien. Um mit den Informationen in diesen Dateien arbeiten zu können, muss ein Programm den Inhalt der Datei
3
Document Type Definition, eine alternative Möglichkeit, die Struktur festzulegen, siehe auch
Abschnitt 3
WS 2004/05, Gunar Fiedler, ISE@CAU
3
2 XML-Verarbeitung
XML-Verarbeitung
analysieren und die kodierten Informationen extrahieren. Vor dieser Aufgabe steht
jedes Programm, das XML-Daten verarbeitet, deshalb existieren diverse Laufzeitbibliotheken, die diese Schritte unterstützen.
Für die Verarbeitung von XML-Daten haben sich zwei wesentliche Ansätze durchgesetzt: SAX und DOM. Die Simple API for XML“ (SAX) stellt eine API bereit,
”
mit deren Hilfe das Programm während des Parsens der Datei auf gefundene Token (öffnende und schließende Tags, Textelemente, ...) reagieren kann. Im Gegensatz
dazu stellt das Document Object Model“ (DOM) eine objektorientierte Datenstruk”
tur bereit, die das Dokument als Baum darstellt und Funktionen zum Traversieren
anbietet.
SAX und DOM sind sprachunabhängige Spezifikationen, es existieren Implementierungen für alle in der Praxis eingesetzten Programmiersprachen. Wir konzentrieren
uns hier auf die Java API for XML und die Bibliothek Xerces“.
”
2.1 Einlesen von XML-Dokumenten mittels SAX
SAX bietet dem Programmierer ein ereignisgesteuertes Zugriffsmodell auf XMLDatenströme. Ein Parser analysiert das XML-Dokument und erzeugt bei Auftreten
eines bestimmten Tokens ein Ereignis, auf welches das Programm reagiert.
Folgende Ereignisse werden durch den SAX-Parser erzeugt:
• startDocument: Beginn des Parsens eines Dokuments
• endDocument: Ende des Parsens eines Dokuments
• startElement(namespace, name, qname, attrs): Ein öffnendes Tag wurde
gefunden. Der Parser teilt dem Programm den Namespace, den Namen, den
qualifizierten Namen4 und die Attributliste mit.
• endElement(namespace, name, qname): ein schließendes Tag wurde gefunden
• characters(buf[], offset, len): Liefert len Zeichen im Puffer buf[] an
der Stelle offset
• ... analoge Ereignisse für die restlichen Elemente
2.1.1 Das Grundgerüst eines SAX-basierten Programms
Der SAX-Parser braucht ein Handler-Objekt, an das er seine Ereignisse schicken
kann. Die Klasse dieses Objekts muss das ContentHandler-Interface implementieren. Dieses Interface stellt zu den Ereignissen korrespondierende Methoden bereit.
Die Klasse DefaultHandler entspricht diesen Anforderungen, sie implementiert leere Methoden für alle SAX-Ereignisse. Man kann seine eigenen Handler-Klassen von
DefaultHandler ableiten:
4
4
Die Kombination aus Namespace und Namen, falls der Parser Namespaces nicht bearbeitet, sind
die Parameter namespace und name leer.
WS 2004/05, Gunar Fiedler, ISE@CAU
XML-Verarbeitung in Java
2 XML-Verarbeitung
p u b l i c c l a s s MyHandler extends D e f a u l t H a n d l e r
{
/∗ . . . ∗/
}
Als nächstes müssen die Methoden für die gewünschten Ereignisse überschrieben
werden. Angenommen, wir wollen unser Beispiel-XML-Dokument bearbeiten und die
Namen aller Veranstaltungsorte ausgeben. Wir müssen also das Ereignis startElement
abfangen und das name-Attribut ausgeben:
p u b l i c c l a s s MyHandler extends D e f a u l t H a n d l e r
{
p u b l i c v o i d s t a r t E l e m e n t ( S t r i n g namespaceURI ,
S t r i n g sName ,
S t r i n g qName ,
Attributes attrs )
throws SAXException
{
// Element−Name
S t r i n g eName = sName ;
// F a l l s Namespaces n i c h t v e r a r b e i t e t werden , nehmen w i r qName
i f ( ”” . e q u a l s ( eName ) ) eName = qName ;
i f ( ( ”p l a c e ” . e q u a l s ( eName ) && ( n u l l != a t t r s ) )
{
// name−A t t r i b u t s u c h e n
f o r ( i n t i = 0 ; i < a t t r s . g e t L e n g t h ( ) ; i ++)
{
S t r i n g aName = a t t r s . getLocalName ( i ) ;
i f ( ”” . e q u a l s ( aName ) ) aName = a t t r s . getQName ( i ) ;
i f ( ”name ” . e q u a l s ( aName ) )
{
// Ausgabe d e s Wertes
System . o u t . p r i n t l n ( a t t r s . g e t V a l u e ( i ) ) ;
}
}
}
}
}
Auch die anderen SAX-Ereignisse werden durch Überschreiben der jeweils korrespondierenden Methoden behandelt, nähere Hinweise sind in der Dokumentation
der API des Java Web Service Development Packs“ unter ContentHandler und
”
DefaultHandler zu finden.
WS 2004/05, Gunar Fiedler, ISE@CAU
5
2 XML-Verarbeitung
XML-Verarbeitung
Soll ein XML-Dokument verarbeitet werden, müssen folgende Schritte unternommen
werden:
1. Ein geeigneter Handler ist zu implementieren.
2. Ein Parser ist zu instanziieren. Es existieren verschiedene Parser-Implementierungen,
jeweils mit eigenen Stärken und Schwächen. Die Instanziierung erfolgt nach
dem Factory-Prinzip5 .
3. Durch den Aufruf der Methode parse wird der Vorgang gestartet.
// D i e s e B i b l i o t h e k e n und K l a s s e n werden t y p i s c h e r w e i s e b e n o e t i g t
import o r g . xml . s a x . ∗ ;
import o r g . xml . s a x . h e l p e r s . D e f a u l t H a n d l e r ;
import j a v a x . xml . p a r s e r s . S A X P a r s e r F a c t o r y ;
import j a v a x . xml . p a r s e r s . P a r s e r C o n f i g u r a t i o n E x c e p t i o n ;
import j a v a x . xml . p a r s e r s . SAXParser ;
/∗ . . . ∗/
p u b l i c v o i d parseDocument ( F i l e f )
{
try
{
// i n s t a n z i i e r e n d e s H a n d l e r s
D e f a u l t H a n d l e r h a n d l e r = new MyHandler ( ) ;
// F a c t o r y e r z e u g e n
SAXParserFactory f a c t o r y = SAXParserFactory . newInstance ( ) ;
// P a r s e r −I n s t a n z e r z e u g e n
SAXParser p a r s e r = f a c t o r y . newSAXParser ( ) ;
// p a r s e n m it unserem H a n d l e r
parser . parse ( f , handler )
}
catch ( E x c e p t i o n e )
{
e . printStackTrace ( ) ;
/∗ . . . ∗/
}
}
/∗ . . . ∗
5
6
siehe Software-Pattern
WS 2004/05, Gunar Fiedler, ISE@CAU
XML-Verarbeitung in Java
2 XML-Verarbeitung
2.2 Verarbeiten von XML-Dokumenten mit DOM
Im Gegensatz zum parsenden Ansatz von SAX ist DOM ein speicherinternes Format
zum Bearbeiten von XML-Daten. DOM definiert eine Reihe von Interfaces, mit deren
Hilfe man sich durch die Baumstruktur des Dokuments bewegen kann.
2.2.1 Die Elemente von DOM
DOM stellt ein Dokument als eine Hierarchie von Node-Objekten dar. Je nach Knotentyp implementieren diese Objekte auch spezialisierte Interfaces. Die wichtigsten
Interfaces sind:
Document
DocumentFragment
Element
Attr
Text
Comment
repräsentiert
repräsentiert
repräsentiert
repräsentiert
repräsentiert
repräsentiert
ein XML-Dokument
einen Teilwald“ des Dokumenten-Baums
”
ein Element des XML-Dokuments
ein Attribut eines Elements
einen Textabschnitt
einen Kommentar
Diese Interfaces definieren Methoden zum Durchmustern der Hierarchie. Nähere Informationen zum Datenmodell findet man unter http://www.w3.org/DOM/DOMTR.
2.2.2 Die Arbeit mit DOM
Die Arbeit mit DOM-Strukturen impliziert folgende Teilaufgaben:
Einlesen / Erstellen eines Dokuments Es existieren zwei Wege, eine DOM-Struktur
zu erzeugen: from scratch“ oder durch Einlesen bestehender XML-Daten. Beiden
”
Methoden ist gemeinsam, dass ein Dokumenten-Baum durch einen sogenannten
DocumentBuilder initialisiert wird:
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Ein neues, leeres Dokument wird durch den Aufruf der Methode newDocument erzeugt:
Document doc = builder.newDocument();
Ein bestehendes Dokument, z.B. eine XML-Datei oder ein XML-Datenstrom aus
einer anderen beliebigen Quelle, kann über einen Parser in einen DOM-Baum überführt werden. Im Standardfall geschieht dies über den Aufruf der Methode parse:
Document doc = builder.parse( new File("inputfile.xml"));
Neben Objekten der Klasse File sind auch InputStreams, InputSources und URIs
mögliche Datenquellen für den Parser.
WS 2004/05, Gunar Fiedler, ISE@CAU
7
2 XML-Verarbeitung
XML-Verarbeitung
Traversieren und Verändern Die Knoten-Objekte eines DOM-Baums sind diesem
Baum fest zugeordnet. Neue Knoten werden über die entsprechenden createXXXMethoden des Dokumentenobjekts erzeugt:
Element tour = doc.createElement("tour");
Element artist = doc.createElement("artist");
Text artistValue = doc.createTextNode("R.E.M.");
/* ... */
Für Attribute eines Elements existiert im Interface Element die setAttributeMethode:
Element place = doc.createElement("place");
place.setAttribute("name","ColorLine Arena");
Nach ihrer Definition müssen die Elemente zu einem Baum zusammengefügt werden:
artist.appendChild(artistValue);
tour.appendChild(artist);
doc.appendChild(tour); // das Wurzelelement
Weiterhin stellen die DOM Interfaces Methoden zum Traversieren des Baumes zur
Verfügung:
getDocumentElement
getAttribute
getElementsByTagName
getChildNodes
getPreviousSibling
getNextSibling
getParentNode
...
gibt den Wurzelelement des Baumes zurück
gibt den Wert eines Attributs zurück
liefert eine Liste aller Kindelemente mit einem bestimmten
Tag-Namen
gibt eine Liste aller Kindelemente zurück
gibt den Knoten zurück, der den gleichen Vaterknoten hat
und in der Liste der Kinder des Vaters vor dem Ausgangsknoten liegt
analog
gibt den Vaterknoten zurück
Zum Verändern des Baumes stehen ebenfalls Methoden bereit:
insertBefore
setAttribute
removeAttribute
removeChild
replaceChild
importNode
fügt einen neuen Knoten ein
setzt ein Attribut eines Elements
entfernt ein Attribut
entfernt einen Knoten aus der Liste der Kinder
ersetzt einen Knoten in der Liste der Kinder
importiert einen Knoten aus einem anderen Dokument, der
Knoten kann anschließend in die Struktur eingefügt werden
...
8
WS 2004/05, Gunar Fiedler, ISE@CAU
XML-Verarbeitung in Java
2 XML-Verarbeitung
Ausschreiben / Serialisieren Eine DOM-Hierarchie ist eine interne Speicherstruktur. Zum Abspeichern oder für den Datenaustausch ist es notwendig, das DOMDokument wieder in ein XML-Dokument, also eine Textdatei bzw. einen Zeichenstrom, umzuwandeln. Dies kann auf verschiedene Art und Weise geschehen; z.B. zu
Fuß, indem man den Baum traversiert und entsprechende Ausgaben tätigt.
Da diese Aufgabe für XML-verarbeitende Programme häufig anfällt, bietet die XercesBibliothek vorgefertigte Klassen, um den Prozess der Serialisierung zu automatisieren. Durch ein Objekt der Klasse XMLSerializer kann man sich aus einem DOMDokument einen XML-Datenstrom erzeugen lassen. Mit Hilfe der Klasse OutputFormat
stellt man notwendige Format-Parameter ein:
OutputFormat format = new OutputFormat(doc);
format.setEncoding("UTF-8"); // Kodierung setzen
format.setIndenting(true); // Einrückung aktivieren
format.setIndent(2); // 2 Zeichen einrücken
format.setLineWidth(75); // maximale Zeilenbreite
FileOutputStream f = new FileOutputStream("outputfile.xml");
XMLSerializer out = new XMLSerializer(f,format);
out.serialize(doc);
f.close();
Notwendige Packages Um mit DOM zu arbeiten, werden typischerweise folgende
Packages benötigt:
javax.xml.parsers.*
org.xml.sax.*
java.io.*
org.w3c.dom.*
org.apache.xml.serialize.*
DocumentBuilder, DocumentBuilderFactory, etc.
parser-spezifische Klassen
Ein- und Ausgabe
die DOM Interfaces
Serialisierung (Xerces-spezifisch)
2.2.3 Ein zusammenhängendes Beispiel
Das folgende Listing zeigt ein Codefragment, das ein DOM-Dokument einliest, um
einen Teilbaum erweitert und ausschreibt. Zu Begin habe die Datei diesen Inhalt:
<?xml version="1.0" encoding="UTF-8"?>
<tour>
<artist>R.E.M.</artist>
<title>Tour 2005</title>
<event>
<place name="ColorLine Arena">
<address>Sylvesterallee, 22525 Hamburg</address>
</place>
WS 2004/05, Gunar Fiedler, ISE@CAU
9
2 XML-Verarbeitung
XML-Verarbeitung
<date day="17" hour="20" minute="0" month="2" year="2005"/>
</event>
</tour>
Das Listing:
import
import
import
import
import
j a v a x . xml . p a r s e r s . ∗ ;
o r g . xml . s a x . ∗ ;
java . io . ∗ ;
o r g . w3c . dom . ∗ ;
o r g . a p a c h e . xml . s e r i a l i z e . ∗ ;
/∗ . . . ∗/
// E r z e u g e n d e s Dokuments
DocumentBuilderFactory f a c t o r y = DocumentBuilderFactory . newInstance ( ) ;
D o c u m e n t B u i l d e r b u i l d e r = f a c t o r y . ne w D o c um e ntBuilde r ( ) ;
Document doc = b u i l d e r . newDocument ( ) ;
// t o u r i s t d a s W u r z e l e l e m e n t
E le m e nt t o u r = doc . getDocumentElement ( ) ;
// E r z e u g e n d e r E l e m e n t e und E r s t e l l u n g d e s T e i l b a u m s
E le m e nt e v e n t = doc . c r e a t e E l e m e n t ( ”e v e n t ” ) ;
E le m e nt p l a c e = doc . c r e a t e E l e m e n t ( ”p l a c e ” ) ;
p l a c e . s e t A t t r i b u t e ( ”name ” , ”Arena L e i p z i g ” ) ;
E le m e nt a d d r e s s = doc . c r e a t e E l e m e n t ( ”a d d r e s s ” ) ;
a d d r e s s . a p p e n d C h i l d ( doc . c r e a t e T e x t N o d e ( ”Am S p o r t f o r u m , 04105 L e i p z i g ” ) ) ;
place . appendChild ( address ) ;
event . appendChild ( place ) ;
E le m e nt d a t e = doc . c r e a t e E l e m e n t ( ”d a t e ” ) ;
d a t e . s e t A t t r i b u t e ( ”day ” , ”13 ” ) ;
d a t e . s e t A t t r i b u t e ( ”month ” , ”2 ” ) ;
d a t e . s e t A t t r i b u t e ( ”y e a r ” , ”2005 ” ) ;
d a t e . s e t A t t r i b u t e ( ”h o u r ” , ”20 ” ) ;
d a t e . s e t A t t r i b u t e ( ”m i n u t e ” , ”0 ” ) ;
event . appendChild ( date ) ;
// w i r f u e g e n d a s neue E l e m e n t v o r dem e r s t e n ”e v e n t ” e i n
// f a l l s b i s h e r k e i n ”e v e n t ” e x i s t i e r t , w i r d d a s neue E r e i g n i s
// am Ende d e r K i n d l i s t e e i n g e f u e g t
N o d e L i s t e v e n t s = t o u r . getElementsByTagName ( ”e v e n t ” ) ;
i f ( events . getLength () > 0 )
{
tour . i n s e r t B e f o r e ( event , ev ent s . item ( 0 ) ) ;
}
else
{
tour . i n s e r t B e f o r e ( event , n u l l ) ;
10
WS 2004/05, Gunar Fiedler, ISE@CAU
XML-Verarbeitung in Java
3 XML Schema
}
// A u s s c h r e i b e n d e r D a t e i
OutputFormat f o r m a t = new OutputFormat ( doc ) ;
f o r m a t . s e t E n c o d i n g ( ”UTF−8 ” ) ;
format . s e t I n d e n t i n g ( true ) ;
format . s e t I n d e n t ( 2 ) ;
format . setLineWidth ( 7 5 ) ;
format . setPreserveSpace ( f a l s e ) ;
F i l e O u t p u t S t r e a m f o s = new F i l e O u t p u t S t r e a m ( ” o u t p u t f i l e . xml ” ) ;
X M L S e r i a l i z e r o u t p u t = new X M L S e r i a l i z e r ( f o s , f o r m a t ) ;
o u t p u t . s e r i a l i z e ( doc ) ;
fos . close ();
/∗ . . . ∗/
Die Datei outputfile.xml hat anschließend diesen Inhalt:
<?xml version="1.0" encoding="UTF-8"?>
<tour>
<artist>R.E.M.</artist>
<title>Tour 2005</title>
<event>
<place name="Arena Leipzig">
<address>Am Sportforum, 04105 Leipzig</address>
</place>
<date day="13" hour="20" minute="0" month="2" year="2005"/>
</event>
<event>
<place name="ColorLine Arena">
<address>Sylvesterallee, 22525 Hamburg</address>
</place>
<date day="17" hour="20" minute="0" month="2" year="2005"/>
</event>
</tour>
3 XML Schema
In den ersten Abschnitten haben wir XML allgemein als Datenbeschreibungssprache
eingeführt. Damit ein Programm XML-Daten verarbeiten kann, muss es allerdings
wissen, welche Tags an welcher Stelle welche Bedeutung haben. Zumindest für die
Beschreibung der Syntax eines XML-Dokuments gibt es explizite Beschreibungsmittel: Document Type Defintions (DTDs) und XML-Schemata. Mit letzterem wollen
wir uns hier beschäftigen.
WS 2004/05, Gunar Fiedler, ISE@CAU
11
3 XML Schema
XML-Verarbeitung
Ein XML-Schema ist selbst wieder ein XML-Dokument, in dem festgehalten wird,
welche Elemente auf welche Art und Weise innerhalb eines Instanz-Dokuments vorkommen dürfen. Der Tag-Name des Wurzelelements des Schema-Dokuments ist
schema aus dem Namespace http://www.w3.org/2001/XMLSchema:
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.is.informatik.uni-kiel.de/events"
xmlns="http://www.is.informatik.uni-kiel.de/events">
<!-- ... -->
</xsd:schema>
Mittels des Attributs targetNamespace wird der Namespace angegeben, dessen Elemente hier beschrieben werden. Mit Hilfe von xsd:element-Tags werden einzelne
Elemente definiert. Es wird unterschieden zwischen einfachen und komplexen Typen. Ein Element mit einem einfachen Typ enthält genau einen Textwert aus dem
Wertebereich des Typs, z.B. eine Zeichenkette oder eine Zahl. Elemente mit komplexem Typ enthalten Attribute, Unterelemente und / oder gemischten Inhalt. Für
Unterelemente und Attribute lassen sich Kardinalitätsbedingungen und Standardwerte angeben. Um die Wiederverwendung von Schema-Elementen zu unterstützen,
bietet XML-Schema diverse Mechanismen zur Definition und Verwaltung von Typen
an.
Eine Möglichkeit, das Schema unseres Beispieldokuments zu beschreiben, ist die
folgende:
<? xml v e r s i o n=”1 . 0 ” e n c o d i n g=”UTF−8 ”?>
<x s d : s c h e m a x m l n s : x s d=” h t t p : //www . w3 . o r g /2001/XMLSchema ”
t a r g e t N a m e s p a c e=” h t t p : //www. i s . i n f o r m a t i k . u n i − k i e l . de / e v e n t ”
x m lns=” h t t p : //www. i s . i n f o r m a t i k . u n i − k i e l . de / e v e n t ”>
<!−− e i n w i e d e r v e r w e n d b a r e r k o m p l e x e r Typ −−>
<x s d : c o m p l e x T y p e name=”e v e n t T y p e ”>
<!−− d i e E l e m e n t e s o l l e n i n d e r a n g e g e b e n e n
R e i h e n f o l g e a u f t r e t e n −−>
<x s d : s e q u e n c e>
<!−− 1 . K i n d e l e m e n t : p l a c e −−>
<x s d : e l e m e n t name=”p l a c e ”>
<!−− e i n anonymer k o m p l e x e r Typ −−>
<x s d : c o m p l e x T y p e>
<x s d : s e q u e n c e>
<!−− 1 . K i n d e l e m e n t von p l a c e : a d d r e s s −−>
<x s d : e l e m e n t name=”a d d r e s s ” t y p e=” x s d : s t r i n g ” />
</ x s d : s e q u e n c e>
<!−− A t t r i b u t : name −−>
< x s d : a t t r i b u t e name=”name ” t y p e=” x s d : s t r i n g ”
u s e=” r e q u i r e d ” />
12
WS 2004/05, Gunar Fiedler, ISE@CAU
XML-Verarbeitung in Java
3 XML Schema
</ x s d : c o m p l e x T y p e>
</ x s d : e l e m e n t>
<!−− 2 . K i n d e l e m e n t : d a t e −−>
<x s d : e l e m e n t name=”d a t e ”>
<x s d : c o m p l e x T y p e>
<!−− A t t r i b u t : day −−>
< x s d : a t t r i b u t e name=”day ”>
<x s d : s i m p l e T y p e>
<!−− e i n e I n t e g e r −Z a h l von 1 b i s 31 −−>
< x s d : r e s t r i c t i o n b a s e=” x s d : i n t e g e r ”>
< x s d : m i n I n c l u s i v e v a l u e=”1 ” />
<x s d : m a x I n c l u s i v e v a l u e=”31 ” />
</ x s d : r e s t r i c t i o n>
</ x s d : s i m p l e T y p e>
</ x s d : a t t r i b u t e>
<!−− A t t r i b u t month , w i r l a s s e n d i e E i n s c h r a e n k u n g
d e r U e b e r s i c h t l i c h k e i t wegen weg −−>
< x s d : a t t r i b u t e name=”month ” t y p e=” x s d : i n t e g e r ” />
<!−− A t t r i b u t e y e a r −−>
< x s d : a t t r i b u t e name=”y e a r ” t y p e=” x s d : i n t e g e r ” />
<!−− A t t r i b u t h o u r −−>
< x s d : a t t r i b u t e name=”h o u r ” t y p e=” x s d : i n t e g e r ” />
<!−− A t t r i b u t m i n u t e −−>
< x s d : a t t r i b u t e name=”m i n u t e ” t y p e=” x s d : i n t e g e r ” />
</ x s d : c o m p l e x T y p e>
</ x s d : e l e m e n t>
</ x s d : s e q u e n c e>
</ x s d : c o m p l e x T y p e>
<!−− d a s W u r z e l e l e m e n t t o u r −−>
<x s d : e l e m e n t name=”t o u r ”>
<x s d : c o m p l e x T y p e>
<x s d : s e q u e n c e>
<!−− z u n a e c h s t e i n K i n d e l e m e n t a r t i s t −−>
<x s d : e l e m e n t name=” a r t i s t ” t y p e=” x s d : s t r i n g ” />
<!−− danach e i n K i n d e l e m e n t t i t l e −−>
<x s d : e l e m e n t name=” t i t l e ” t y p e=” x s d : s t r i n g ”
minOccurs=”1 ” maxOccurs=”1 ” />
<!−− e i n e L i s t e von e v e n t −E l e m e n t e n −−>
<x s d : e l e m e n t name=”e v e n t ” t y p e=”e v e n t T y p e ”
minOccurs=”0 ” maxOccurs=”unbounded ” />
</ x s d : s e q u e n c e>
</ x s d : c o m p l e x T y p e>
</ x s d : e l e m e n t>
</ x s d : s c h e m a>
WS 2004/05, Gunar Fiedler, ISE@CAU
13
4 XSL Transformationen
XML-Verarbeitung
4 XSL Transformationen
Aufbauend auf dem XML-Standard ist die EXtensible Stylesheet Language eine
Sprache, um Transformationen von XML-Dokumenten zu beschreiben. In sogenannten Stylesheets werden Regeln angegeben, wie ein XML-Dokument einer bestimmten
Struktur in ein Dokument mit einer anderen Struktur überführt wird. Das AusgabeDokument ist entweder wieder ein XML- oder Text-Dokument, bei Nutzung von
Formating Objects (FOs) kann aber z.B. auch ein PDF-Dokument gerendert werden.
4.1 Stylesheets
Ein Stylesheet ist selbst eine XML-Datei, welche die Transformationsregeln beschreibt. Das Wurzelelement jedes Stylesheets ist ein stylesheet-Element aus dem
Namespace http://www.w3.org/1999/XSL/Transform:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html"/>
<!-- ... -->
</xsl:stylesheet>
Mit Hilfe des Elements xsl:output wird der Typ des Ausgabedokuments bestimmt,
z.B. html oder xml. Im Anschluss können die Transformationsregeln definiert werden. Dies geschieht über Templates. Einem Template wird ein XPath-Ausdruck6
zugeordnet. Erfüllt ein zu verarbeitendes Element mit seinen Eigenschaften diesen
Ausdruck, so wird das Template für dieses Element ausgeführt und erzeugt eine
Ausgabe. Was ausgegeben werden soll, wird in den Rumpf des Templates geschrieben. Beispielsweise soll das Wurzelelement tour unseres Dokuments transformiert
werden. Dafür definieren wir ein Template, das bei Auftreten von /tour - also tour
direkt an der Wurzel - aufgerufen wird.
<xsl:template match="/tour">
<html>
<head><title>Veranstaltungskalender</title></head>
<body>
<h1>
<xsl:apply-templates select="artist" />:
<xsl:apply-templates select="title" />
</h1>
6
siehe Abschnitt 4.2
14
WS 2004/05, Gunar Fiedler, ISE@CAU
XML-Verarbeitung in Java
4 XSL Transformationen
<xsl:apply-templates select="event" />
</body>
</html>
</xsl:template>
Die xsl-Elemente veranlassen den Stylesheet-Prozessor zu bestimmten Aktionen.
Alles, was nicht dem xsl-Namespace entstammt, wird in die Ausgabe kopiert. Im
obigen Beispiel sehen wir ein wichtiges xsl-Tag: xsl:apply-templates. Mit Hilfe
dieses Tags werden kontext-abhängig weitere Templates aufgerufen. Das selectAttribut enthält einen XPath-Ausdruck, der relativ zum aktuellen Element die zu
bearbeitenden Elemente auswählt.
<xsl:template match="artist">
<xsl:value-of select "text()" />
</xsl:template>
Mit Hilfe des xsl-Elements value-of kann der Wert eines Ausdrucks bestimmt werden. Dies kann z.B. ein Element, ein Attribut, der Aufruf einer xsl-Funktion, aber
auch eine komplexere Berechnung sein.
<xsl:value-of select="date/@day" />.
Dieser Ausdruck gibt zum Beispiel den Wert des Attributs day des Unterelements
date zurück. Attributnamen wird stets das @-Zeichen vorangestellt.
XSL definiert eine Reihe von Tags zur Ablaufsteuerung, die wichtigsten sind in der
nachfolgenden Tabelle zusammengestellt:
<xsl:if test=""></xsl:if>
<xsl:for-each select="">
<xsl:choose>
<xsl:text>
<xsl:comment>
WS 2004/05, Gunar Fiedler, ISE@CAU
wenn der Ausdruck im Attribut test wahr ist,
wird der eingeschlossene Teil des XSL-Codes
ausgeführt. <xsl:if> unterstützt kein else. Mit
Hilfe von test="XPath-Ausdruck" lässt sich die
Existenz eines Elements (oder Atributs) überprüfen: <xsl:if test="artist"> prüft, ob ein
Unterelement artist existiert.
iteriert über eine Menge von Elementen.
analog zu switch- oder case-Statements
wird ein bestimmter Code-Block abhängig von einer Bedingung ausgeführt. Die
einzelnen Bedingungen und Blöcke werden
durch <xsl:when test="">-Blöcke definiert.
<xsl:otherwise> definiert den else“-Block.
”
Man beachte, dass ein if-then-else-Block mit
Hilfe von xsl:choose formuliert werden muss.
erzeugt Ausgabetext
erzeugt einen Kommentar
15
4 XSL Transformationen
<xsl:copy>
<xsl:copy-of select="" />
XML-Verarbeitung
kopiert das aktuelle Element in den Ausgabestrom
kopiert einen Teilbaum, der per XPath im
select-Attribut ausgewählt wird, in die Ausgabe
Darüber hinaus bietet XSL einige weitere Möglichkeiten, z.B. für die Parametrisierung und Wiederverwendung von Stylesheets und Templates. Es sei auf weiterführende Literatur verwiesen.
4.2 XPath
4.2.1 Grundlagen der Adressierung
Eine häufige Aufgabenstellung innerhalb von XSL-Stylesheets ist das Selektieren
von Elementen. Dies geschieht navigierend über die Definition von relativen oder
absoluten Pfaden.
XPath-Ausdrücke erinnern stark an Verzeichnisnamen und sind folgendermaßen aufgebaut:
• der Schrägstrich / wird als Separator zwischen Bezeichnern benutzt: event/place
• absolute Pfade, die beim Wurzelelement starten, beginnen mit einem Schrägstrich: /tour/artist, alle anderen Pfade sind relativ zum aktuellen Element
(dem aktuellen Kontext) definiert.
• zwei Punkte verweisen auf das Elternelement des aktuellen Elements: ../place
• ein Punkt referenziert das aktuelle Element: ./date
Ein Ausdruck wie event/place selektiert alle place-Elemente unter allen eventElementen. Möchte man in dieser Liste ein bestimmtes Element referenzieren, so
fügt man den Index in eckigen Klammern an den Bezeichner an. event[1]/place
selektiert alle place-Elemente des ersten event-Elements. Falls weitere Operationen
Eindeutigkeit erfordern, wird jeweils das erste Element der Liste genutzt.
Attributen wird das @-Zeichen vorangestellt: event/place/@name selektiert das nameAttribut des Elements unter event/place.
4.2.2 XPath-Ausdrücke und Wildcards
Bedingungen an Elemente werden in eckigen Klammern dem Bezeichner angehängt.
place[@name=’ColorLine Arena’] selektiert das place-Element, dessen Attribut
name den Wert ColorLine Arena hat. event[date] selektiert alle event-Elemente,
die ein date-Unterelement haben.
Ein Stern (*) anstelle eines Bezeichners fungiert als Wildcard, er selektiert alle Bezeichner. Analog selektiert @* alle Attribute. Der Ausdruck /*/* selektiert jedes Element auf der zweiten Hierarchieebene. Möchte man ein Element auf einer beliebigen
16
WS 2004/05, Gunar Fiedler, ISE@CAU
XML-Verarbeitung in Java
4 XSL Transformationen
Ebene selektieren, so schreibt man //: .//place selektiert alle place-Elemente, die
irgendwo im aktuellen Teilbaum stehen.
4.3 Ein zusammenhängendes Beispiel
Das folgende Listing zeigt ein Stylesheet, das für unser Beispieldokument eine HTMLAusgabe erzeugt:
<? xml v e r s i o n=”1 . 0 ” e n c o d i n g=”UTF−8 ” ?>
< x s l : s t y l e s h e e t v e r s i o n=”1 . 0 ”
x m l n s : x s l=” h t t p : //www. w3 . o r g /1999/XSL/ T r a n s f o r m ”>
< x s l : o u t p u t method=”html ”/>
< x s l : t e m p l a t e match=”/ ”>
< x s l : a p p l y −t e m p l a t e s s e l e c t=”t o u r ” />
</ x s l : t e m p l a t e>
< x s l : t e m p l a t e match=”t o u r ”>
<html>
<head>< t i t l e >V e r a n s t a l t u n g s k a l e n d e r</ t i t l e ></ head>
<body>
<h1>
< x s l : a p p l y −t e m p l a t e s s e l e c t=” a r t i s t ” /> :
< x s l : a p p l y −t e m p l a t e s s e l e c t=” t i t l e ” />
</ h1>
< t a b l e c o l s=”3 ”>
< x s l : a p p l y −t e m p l a t e s s e l e c t=”e v e n t ” />
</ t a b l e>
</ body>
</ html>
</ x s l : t e m p l a t e>
< x s l : t e m p l a t e match=” a r t i s t ”>
< x s l : v a l u e −o f s e l e c t=” t e x t ( ) ” />
</ x s l : t e m p l a t e>
< x s l : t e m p l a t e match=” t i t l e ”>
< x s l : v a l u e −o f s e l e c t=” t e x t ( ) ” />
</ x s l : t e m p l a t e>
< x s l : t e m p l a t e match=”e v e n t ”>
< t r>
<t d>
< x s l : v a l u e −o f s e l e c t=”d a t e / @day ” /> .
< x s l : v a l u e −o f s e l e c t=”d a t e /@month ” /> .
< x s l : v a l u e −o f s e l e c t=”d a t e / @ y e a r ” />
</ t d>
WS 2004/05, Gunar Fiedler, ISE@CAU
17
4 XSL Transformationen
XML-Verarbeitung
<t d>
< x s l : v a l u e −o f s e l e c t=”d a t e / @hour ” /> :
< x s l : v a l u e −o f s e l e c t=”d a t e / @minute ” />
</ t d>
<t d>
< x s l : v a l u e −o f s e l e c t=”p l a c e /@name ” />
</ t d>
</ t r>
</ x s l : t e m p l a t e>
</ x s l : s t y l e s h e e t>
4.4 XSLT mit Xalan
Die Xalan-Bibliothek bietet Klassen, mit deren Hilfe XSL Transformationen durchgeführt werden können. Die zentrale Klasse ist javax.xml.transform.Transformer.
Sie erzeugt aus einem Eingabedokument und einem Stylesheet ein Ausgabedokument:
// d i e
import
import
import
b e n o e t i g t e n Packages
j a v a x . xml . t r a n s f o r m . ∗ ;
j a v a x . xml . t r a n s f o r m . s t r e a m . ∗ ;
j a v a x . xml . t r a n s f o r m . dom . ∗ ;
/∗ . . . ∗/
// d i e E i n g a b e d a t e i e n
StreamSource s t y l e s h e e t =
new S t r e a m S o u r c e ( new F i l e ( ” s t y l e s h e e t . x s l ” ) ) ;
StreamSource i n F i l e =
new S t r e a m S o u r c e ( new F i l e ( ”i n p u t . xml ” ) ) ;
// A u s g a b e d a t e i
S t r e a m R e s u l t o u t F i l e = new S t r e a m R e s u l t ( new F i l e ( ”o u t p u t . html ” ) ) ;
// E r z e u g e n d e s T r a n s f o r m e r s u e b e r e i n e F a c t o r y
TransformerFactory factory = TransformerFactory . newInstance ( ) ;
Transformer t r a n s f o r m e r = f a c t o r y . newTransformer ( s t y l e s h e e t ) ;
transformer . transform ( inFile , outFile );
Anstelle der StreamSources und StreamResults können auch DOMSources und DOMResults
genutzt werden, um DOM-Dokumente zu verarbeiten.
Die Xalan-Bibliothek bietet auch einen XSL-Prozessor für die Kommandozeile, der
folgendermaßen aufgerufen werden kann:
java org.apache.xalan.xslt.Process -IN inFile.xml \
-XSL stylesheet.xsl -OUT outFile.html
18
WS 2004/05, Gunar Fiedler, ISE@CAU
XML-Verarbeitung in Java
5 Weiterführende Literatur
5 Weiterführende Literatur
• http://www.w3schools.com eine Menge guter Tutorials rund ums Thema
XML
• http://www.w3.org/TR/REC-xml W3C XML Recommendation
• http://www.w3.org/TR/xmlschema-0 W3C XML Schema Recommendation
• http://www.w3.org/TR/xsl W3C XSL Recommendation
• http://java.sun.com/xml/jaxp/docs.html Dokumentation zu JAXP
• http://xml.apache.org Dokumentation zu Xerces und Xalan
WS 2004/05, Gunar Fiedler, ISE@CAU
19