extensible Markup Language

Werbung
XML
extensible Markup Language
www.w3.org/XML
Dr. Beatrice Amrhein
2
Inhaltsverzeichnis
1 XML Grundlagen...........................................................................................................................................5
1.1 Die wichtigsten Punkte.........................................................................................................................5
1.2 XML Sprachen und Anwendungen........................................................................................................7
1.3 Der Aufbau eines XML Dokuments.......................................................................................................7
1.4 Elemente...............................................................................................................................................8
1.5 Attribute.............................................................................................................................................10
1.6 Zeichen- und Entity-Referenzen..........................................................................................................11
1.7 Kommentare und Verarbeitungsanweisungen....................................................................................11
1.8 Die XML Deklaration...........................................................................................................................11
1.9 XML Knotentypen und Nachfolger......................................................................................................12
1.10 Wohlgeformtheit: Zusammenfassung...............................................................................................12
2 Namespaces................................................................................................................................................13
2.1 Wozu dienen Namespaces?................................................................................................................13
2.2 Definition eines Namespaces..............................................................................................................14
2.3 Qualifizierte Element-Namen.............................................................................................................15
3 XSD: XML Schema Definition.......................................................................................................................18
3.1 Deklarationen <--> Definitionen..........................................................................................................20
3.2 Deklaration von einfachen Typen........................................................................................................22
3.3 Vordefinierte primitive Schema Typen................................................................................................23
3.4 Attribut Deklarationen........................................................................................................................25
3.5 Komplexe Schema Typen....................................................................................................................26
3.6 Spezielle Schema Elemente................................................................................................................29
3.7 Schlüssel.............................................................................................................................................32
4 SAX: Simple Application Interface for XML..................................................................................................38
4.1 Was ist SAX?........................................................................................................................................38
4.2 Wofür ist SAX geeignet?......................................................................................................................38
4.3 Wie funktioniert SAX?.........................................................................................................................38
4.4 Übersicht über das SAX API.................................................................................................................39
4.5 Implementation des Default Handlers................................................................................................40
4.6 Fehlerbehandlung: ErrorHandler........................................................................................................42
Ein SAX Beispiel.........................................................................................................................................43
5 DOM: Das Document Object Model............................................................................................................45
Was ist DOM?...........................................................................................................................................45
Die DOM Node Typen...............................................................................................................................45
5.1 Die org.w3c.dom Java Interfaces.........................................................................................................46
5.2 Benutzen des DOM Parsers.................................................................................................................48
6 StAX: Streaming API for XML.......................................................................................................................50
6.1 Was ist StAX?......................................................................................................................................50
7 JAXB: Java Architecture for XML Binding.....................................................................................................54
7.1 Die JAXB Architektur...........................................................................................................................54
7.2 Das Binding.........................................................................................................................................55
7.3 Übersetzung verschiedener Basis-Datentypen....................................................................................56
7.4 Erzeugen der Java Klassen...................................................................................................................57
7.5 Einlesen der XML Daten......................................................................................................................58
7.6 Schreiben der Daten in ein XML File...................................................................................................58
7.7 Anpassen der generierten Java Klassen und Member Variablen.........................................................59
7.8 Externe Binding-Deklaration...............................................................................................................60
7.9 Erzeugen von Schematas....................................................................................................................61
7.10 Schreiben von XML Daten ohne ObjectFactory.................................................................................63
8 Die Transformations-Sprache XSLT..............................................................................................................68
3
8.1 Wie funktioniert XSLT?........................................................................................................................68
8.2 Der Aufbau eines Stylesheets: Templates...........................................................................................70
8.3 Die wichtigsten XSLT Befehle...............................................................................................................72
9 Grundlegendes zu XSLT...............................................................................................................................81
9.1 Default Template Regeln.....................................................................................................................81
9.2 Template Driven vs. Data Driven Stylesheets......................................................................................83
10 XPath: Die XSL Adressierungssprache.......................................................................................................84
10.1 Die XPath Syntax...............................................................................................................................84
10.2 Adressierungs-Achsen.......................................................................................................................88
10.3 Die wichtigsten XPath Funktionen....................................................................................................89
11 XSL-FO Einführung....................................................................................................................................94
11.2 Die wichtigsten FO Elemente............................................................................................................95
11.3 Die wichtigsten Attribute................................................................................................................104
4
1 XML Grundlagen
1.1 Die wichtigsten Punkte
XML ist dazu gemacht, Informationen auszutauschen, zu speichern und zu übertragen, aber nicht um Daten
darzustellen. In HTML sind Daten und deren Darstellung vermischt. In XML sind die Daten von deren
Präsentation getrennt.
XML wird benutzt, um Daten zwischen verschiedenen Applikationen, Datenbanken, Computer Systemen
und auch über das Internet auszutauschen.
•
•
•
•
XML ist keine Programmiersprache, sondern ein Standard, um Informationen zu strukturieren, zu
verschicken oder zu speichern.
XML trennt Information von deren Darstellung -- im Gegensatz zu HTML
XML vereinfacht den Daten Austausch zwischen inkompatiblen Systemen.
XML vereinfacht den Austausch von Informationen über das Internet (B2B).
XML Dokumente sind Unicode Text Files, einfach lesbar und somit einfach benutzbar.
•
Aus XML entstehen neue Sprachen: SVG, WAP (Wireless Application Protocol ), WML (Wireless
Markup Language), CML (Chemical Markup Language ), MathML, ...
•
Immer mehr Applikationen haben XML Schnittstellen, (Datenbanken, MSExcel, MSWord, SAP...), was
den einfachen Austausch von Informationen erlaubt.
XML wurde 1998 von einer Arbeitsgruppe des World Wide Web Consortium (W3C) definiert, um
Informationen im World Wide Web bereitzustellen.
•
•
extensible: Die Tag-Menge ist erweiterbar (Metasprache)
•
markup: Die Tags enthalten Metadaten
Ein HTML Beispiel
<html>
<h1>People</h1>
<table border="1">
<tr>
<th>Name</th>
<th>Profession</th>
</tr>
<tr>
<td>Alan Turing</td>
<td>computer scientist</td>
</tr>
<tr>
<td>Richard M. Feynman</td>
<td>physicist</td>
</tr>
</table>
</html>
5
Ein XML Beispiel
XML Dokumente sind reine Datenfiles und enthalten im Gegensatz zu HTML normalerweise keine
Präsentations-Hinweise.
<?xml version="1.0"?>
<!-- file people.xml -->
<people>
<person>
<name>Alan Turing</name>
<profession>computer scientist</profession>
</person>
<person>
<name>Richard M. Feynman</name>
<profession>physicist</profession>
</person>
</people>
Der Unterschied von XML zu HTML
HTML ist endliche Menge von Formatierungselementen wie
Überschriften, Absätze, Listen, Tabellen usw. und dient zur
Darstellung von Informationen
XML ist eine erweiterbare Menge struktureller und inhaltlicher
Elemente und enthält die Beschreibung und die Struktur der
Informationen
6
1.2 XML Sprachen und Anwendungen
Durch Vereinbaren gewisser Tags, wird eine gemeinsame (Austausch-) Sprache für mathematische oder
chemische Formeln, Bilder, Ressourcen, ... definiert.
•
•
•
•
•
•
•
•
•
•
Extensible HyperText Markup Language (XHTML)
Scalable Vector Graphics (SVG)
Mathematical Markup Language (MathML)
XML Schema Definition (XSD)
Wireless Markup Language (WML)
Chemical Markup Language (CML)
Financial Products Markup Language (FpML)
User Interface Markup Language (UIML)
Geography Markup Language (GML)
Bean Markup Language (BML)
...
Obwohl XML zunächst vor allem für Internet Applikationen definiert wurde, wird XML heute für
verschiedenste Anwendungen eingesetzt. Die Standards werden darum laufend den neuen Bedürfnissen
angepasst.
•
Elektronischer Datenaustausch zwischen Firmen (B2B)
•
Konfigurationsfiles von Software
•
•
•
Erstellen und Verarbeiten von Textdokumenten (vgl. DocBook)
Definition von Netzwerk- oder Internet Protokollen (SOAP, WSDL, ...)
•
Schnittstelle zu Datenbanken
Deklarative Programmierung
•
...
•
1.3 Der Aufbau eines XML Dokuments
XML-Dokumente müssen wohlgeformt sein. Das heisst, sie müssen nach gewissen Regeln aufgebaut sein.Ein
XML-Dokument heisst wohlgeformt, wenn es die syntaktischen Regeln der Spezifikation einhält, bzw. wenn
ein XML-Parser das Dokument ohne Fehler einlesen kann.
XML-Dokument
XML-Parser
Applikation
Einige der Regeln sind:
•
Es gibt im XML-Dokument genau ein äusserstes Element (Root Element).
•
•
Jedes Element hat ein Start- und ein passendes End-Tag.
Die Elemente sind korrekt geschachtelt.
...
Dieses Kapitel behandelt im Folgenden die vollständigen Regeln für die Wohlgeformtheit.
•
7
Ein Beispiel
<?xml version="1.0"?>
<!-- file people.xml -->
<people>
<person>
<name>Alan Turing</name>
<profession>
computer scientist
</profession>
</person>
Prolog
optionaler Kommentar
Root / Document
-element
<person>
<name>Richard M. Feynman</name>
<profession>
physicist
</profession>
</person>
</people>
•
<people> ist das Root-Element oder Document-Element des XML Dokuments.
Die zwei <person> Elemente sind Kind-Elemente von <people>
•
Das <name> Element hat als Kind einen Text-Knoten.
•
1.4 Elemente
Die Struktur eines Elements
Start-Tag
<person>
<name>Alan Turing</name>
<profession>
computer scientist
</profession>
</person>
Inhalt
End-Tag
Jedes Element beginnt mit einem Start-Tag (hier <person>) und endet mit einem End-Tag </person>. StartTag und End-Tag müssen identisch sein (case-sensitiv) bis auf den Slash im End-Tag.
Gültige Element Namen
•
•
•
Elementnamen dürfen Buchstaben, Ziffern, Unterstriche (_), Bindestriche (-) und Punkte (.)
enthalten
Elementnamen müssen mit einem Buchstaben oder einem Unterstrich beginnen
Doppelpunkte sind für Namespaces reserviert
Gültige Namen
<Drivers_License_Number>
<year-month-day>
<firstName>
Ungültige Namen
<Driver's_License_Number>
<year/month/day>
<first Name>
8
Der Element-Inhalt
Der Inhalt eines Elementes kann aus Zeichendaten oder aus weiteren Elementen bestehen:
<person>
<name>
<firstName>Alan</firstName>
<lastName>Turing</lastName>
</name>
<profession>computer scientist</profession>
<profession>mathematician</profession>
<profession>cryptographer</profession>
</person>
•
•
<firstName> und <lastName> sind Elemente, welche als Kinder nur Zeichendaten (Text-Knoten)
enthalten.
<name> und <person> enthalten weitere Kind-Elemente.
Der folgende Baum entspricht (hier) gerade dem DOM (Document Object Model).
Die Blätter eines XML-Baums sind entweder Text-Knoten (Zeichendaten, Strings) oder leere Knoten.
Man unterscheidet im Baum zwischen Kindern (d.h. direkten Nachfolgern) und allgemeinen Nachfolgern auf
beliebigen Stufen (Kinder, Enkel, Urenkel, ...)
Elemente mit gemischten Inhalt
Textorientierte XML-Dokumente enthalten oft Elemente mit gemischtem Inhalt. Beispiele davon sind Briefe,
Reports, Bücher, Artikel, ...
<biography>
<name>Alan Turing</name> was one of the first people to truly
deserve the name
<profession>computer scientist</profession>
</biography>
Das <biography> Element ist ein sog. "mixed element". Es enthält sowohl Zeichendaten (Text-Knoten) als
auch Element-Knoten.
9
Im zugehörigen XML Baum hat das biography Kinder darum Elemente und Text-Knoten als Kinder.
biography
name
was one
of the ...
profession
Alan
Turing
computer
scientist
Leere Elemente
Leere Elemente sind solche ohne Inhalt.
<image></image>
Bei leeren Elementen darf der End-Tag fehlen, die Darstellung verkürzt sich auf den Start-Tag.
<image/>
1.5 Attribute
Das Start-Tag eines Elements kann ein oder mehrere Attribute enthalten
<person born="1912/06/23" died="1954/06/07">
<name>Alan Turing</name>
<image src="turing.jpg"/>
</person>
•
•
•
•
•
•
•
•
Nur das Start Tag darf Attribute enthalten.
Attribut Werte müssen in Anführungszeichen (") oder in Apostrophe (') eingeschlossen werden
Attribut Werte dürfen das Zeichen, in das sie eingeschlossen sind, nicht enthalten
Attribut Werte dürfen das Zeichen < nicht enthalten
Attribut Werte dürfen das Zeichen & nur am Anfang einer Zeichen- oder Entity-Referenz enthalten
Ein Element darf nicht zwei Attribute mit dem gleichen Namen haben
Attribute können nicht verschachtelt werden
Die Reihenfolge der Attribute ist unwesentlich
Attribute sind darum eher für Metadaten, Elemente für die eigentlichen Daten zu verwenden. Die
Unterscheidung zwischen Daten und Metadaten ist allerdings nicht immer einfach.
10
1.6 Zeichen- und Entity-Referenzen
Sonderzeichen können als Zeichen Referenzen (Entity) mit dem entsprechenden Unicode eingefügt werden:
<copyright> Copyright © 2001</copyright>
Beispiele von Zeichen Referenzen:
©
©
(Copyright)
€
€
(Euro)
Für die Zeichen &, <, >, ', " gibt es spezielle Entity Referenzen
Zeichen
Entity-Referenz
&
&
<
<
>
>
'
'
"
"
<publisher>
O'Reilly & Associates
</publisher>
Durch Angabe des entsprechenden Zeichensatzes wie zum Beispiel
<?xml version="1.0" encoding="ISO-8859-1"?>
werden die Umlaute ä, ö, ü als Zeichen erkannt und müssen nicht als Referenzen angegeben werden.
1.7 Kommentare und Verarbeitungsanweisungen
Kommentare
dienen der Dokumentation des XML Codes und können überall ausser innerhalb eines Tags stehen
<!-- These links need to be verified -->
Kommentare dürfen ausser am Anfang (<!--) und am Ende (-->) keine "--" Sequenz enthalten.
Verarbeitungsanweisungen (Processing Instructions)
liefern Informationen für bestimmte Anwendungen und stehen normalerweise im Prolog des XMLDokuments
<?robots index="yes" follow="no"?>
Eine spezielle Verarbeitungsanweisung ist die XML Deklaration zu Beginn des Dokumentes
<?xml version="1.0" encoding="ISO-8859-1"?>
Eine andere Verarbeitungsanweisung wird zum Verknüpfen eines XSL-Stylesheets verwendet
<?xml-stylesheet href="stl.xsl" type="text/xsl"?>
1.8 Die XML Deklaration
Die XML-Deklaration ist optional, muss aber - falls vorhanden - ganz am Anfang des XML-Dokuments stehen
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="ISO-8859-1"?>
Das Encoding gibt die für das XML Dokument verwendete Codierung an.
11
1.9 XML Knotentypen und Nachfolger
Wenn man in XML von Knoten redet, meint man die Bestandteile der Dokument-Baumstruktur.
Die verschiedenen XML Knotentypen sind
•
Elemente --> <firstName> ... </firstName>
•
Attribute --> date="1912"
•
Textknoten --> Alan
•
Kommentarknoten --> <!-- Kommentar -->
•
Verarbeitungsanweisungen --> <? processing introduction ?>
Wir betrachten das folgende Beispiel:
<people>
<!-- Personenbeschreibung-->
<person>
<name>
<firstName>Alan</firstName>
<lastName>Turing</lastName>
</name>
<born date=”1912/06/23”>
<profession>computer scientist</profession>
<profession>cryptographer</profession>
</person>
<people>
Jedes XML-Dokument beginnt mit einem Wurzelknoten. Dieser hat jedoch keine konkrete Ausprägung,
sondern ist nur der abstrakte "Ursprung" der Daten und wird oft mit einem Slash (/) bezeichnet.
Erst sein unmittelbarer Abkömmling in der Baumstruktur hat eine konkrete Ausprägung: nämlich das RootElement oder Dokument-Element, also das äusserste, den gesamten Inhalt umfassende Element (hier
<people>).
Das Root-Element hat in unserem Beispiel zwei Kind-Knoten (bzw. direkte Nachfolger): einen KommentarKnoten und ein person Element. Aus Sicht des person Elements ist der Knoten people der Elternknoten,
oder das Elternelement. Der person Knoten hat vier Kind-Knoten, nämlich ein name Element, ein born
Elemen und zwei profession Elemente. Das born Element hat einen assoziierten Knoten, nämlich ein
Attribut namens date. Der Kind-Knoten von firstName ist der Text-Knoten “Alan”.
Die (direkten und indirekten) Nachfolger des person-Elementes sind dessen Kinder (name, born, profession)
sowie die indirekten Nachfolger firstName und lastName.
1.10 Wohlgeformtheit: Zusammenfassung
XML-Dokumente müssen wohlgeformt sein. Das heisst, sie müssen nach folgenden Regeln aufgebaut sein:
•
•
•
•
•
•
•
•
•
Es gibt im XML-Dokument genau ein äusserstes Element (Document- oder Root-Element)
Jedes Element hat ein Start- und ein passendes End-Tag (case-sensitive!)
Die Elementnamen bestehen aus Buchstaben, Ziffern und den Zeichen Punkt, Unterstrich,
Bindestrich und Doppelpunkt (für Namespaces)
Elementnamen beginnen mit einem Buchstaben oder einem Unterstrich
Die Elemente sind korrekt geschachtelt
Alle Attribut-Werte stehen im Start-Tag eines Elements und in Anführungszeichen (Single oder
Double Quotes)
Ein Element hat nicht mehrere Attribute mit demselben Namen
Kommentare und Verarbeitungsanweisungen stehen nicht innerhalb von Tags
Attribut-Werte dürfen die Zeichen < nicht enthalten und & nur für Entities
12
2 Namespaces
2.1 Wozu dienen Namespaces?
Namespaces werden benötigt um:
•
Namenskonflikte bei Elementen und Attributen zu vermeiden.
•
Elemente und Attribute einer bestimmten XML-Anwendung zuzuordnen (XSL, SVG, MathML, FO, ...).
Browser können diese automatisch erkennen und umsetzen.
•
die gewohnten Namen (title, name, type, ...) für verschiedene Anwendungen benutzen zu können.
Ein SVG Beispiel
<svg:svg xmlns:svg="http://www.w3.org/2000/svg" ... >
<svg:g font-family="Helvetica" font-size="6">
<svg:rect x="10" y="33" width="10" height="10" fill="#FFCCCC"/>
<svg:text x="7" y="50">0 sec.</svg:text>
<svg:rect x="60" y="20" width="10" height="10" fill="#FFCCCC"/>
<svg:text x="52" y="40">3 sec.</svg:text>
<svg:path d="M-5,0 L0,-10 L5,0 z" fill="blue" stroke="red">
<svg:animateMotion from="15,43" to="65,30" begin="0s" dur="3s"/>
</svg:path>
</svg:g>
</svg:svg>
Ein MathML Beispiel
MathML wird in diesem Beispiel innerhalb von einer HTML Seite benutzt.
<html xmlns="http://www.w3.org/1999/xhtml">
<body>
<h4>Can your browser display Presentation MathML?</h4>
<p>
<m:math xmlns:m="http://www.w3.org/1998/Math/MathML">
<m:mrow>
<m:msup>
<m:mfenced open="[" close="]">
<m:mrow>
<m:mi>a</m:mi>
<m:mo>+</m:mo>
<m:mi>b</m:mi>
</m:mrow>
</m:mfenced>
<m:mn>260</m:mn>
...
</p>
...
13
Beispiel eines Namenskonflikts
Namen wie date, title, name, description will man oft in verschiedenstem Kontext benutzen können:
<?xml version="1.0"?>
<catalog>
<description>
<title>Impressionist Paintings</title>
<creator>Elliotte Rusty Harold</creator>
<date>2000-08-22</date>
</description>
<painting>
<title>Memory of the Garden at Etten</title>
<artist>Vincent van Gogh</artist>
<date>
<month>November</month>
<year>1888</year>
</date>
</painting>
</catalog>
2.2 Definition eines Namespaces
Durch Definieren eines Namespaces werden die Namen eindeutig
description
creator
painting
title
date
artist
day
month
year
description
dc:creator
dc:title
dc:date
painting
pt:artist
pt:title
pt:day
pt:date
pt:month
pt:year
Ein Namespace wird durch einen URI definiert:
xmlns:dc=“http://purl.org/dc“
xmlns:m="http://www.w3.org/1998/Math/MathML"
•
•
Der URI zeigt nicht unbedingt auf eine existierende HTML-Seite.Wichtig ist bloss, dass der
Namespace eindeutig ist.
Parser vergleichen Namespace-URIs zeichenweise. Der Präfix dient als dessen Abkürzung.
Für Namespaces werden URL's benutzt, weil diese weltweit eindeutig festgelegt sind.
So benutzt zum Beispiel Microsoft für ihre Anwendungen Namespaces der Form
http://schemas.microsoft.com/... oder OpenOffice die Namespaces http://openoffice.org/...
14
2.3 Qualifizierte Element-Namen
Um Elemente in einen Namespace einzufügen, werden sie mit dem entsprechenden Präfix qualifiziert:
<dc:title>Impressionist Paintings</dc:title>
Mit einem xmlns-Attribut kann einem Namespace-URI ein Präfix zugeordnet werden:
<description xmlns:dc="http://purl.org/dc" >
Der Präfix ist nur innerhalb des Elements gültig, in dem er definiert wird.
Damit ein Präfix im ganzen Dokument gültig ist, muss er also im Root-Element definiert werden.
Die definierten Namespaces werden dann im XML Dokument verwendet, um die Namenskonflikte
aufzulösen.
<?xml version="1.0"?>
<catalog xmlns:dc="http://purl.org/dc" xmlns:pt="http://vangoghgallery.com/pt">
<dc:description >
<dc:title>Impressionist Paintings</dc:title>
<dc:creator>Elliotte Rusty Harold</dc:creator>
<dc:date>2000-08-22</dc:date>
</dc:description>
<pt:painting>
<pt:title>Memory of the Garden at Etten</pt:title>
<pt:artist>Vincent van Gogh</pt:artist>
<pt:date>
<pt:month>November</pt:month>
<pt:year>1888</pt:year>
</pt:date>
</pt:painting>
</catalog>
Default Namespaces
Wird ein Namespace ohne Präfix definiert, so gehören alle Elemente ohne qualifizierten Namen innerhalb
dieses Bereichs zu diesem Namespace.
<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>Presentation Examples</title></head>
<body>
<h4>This is a Presentation of MathML</h4>
<math xmlns="http://www.w3.org/1998/Math/MathML">
<mrow>
<msubsup><mi>x</mi><mn>1</mn><mi>a</mi></msubsup>
<mo>+</mo>
<msubsup><mi>x</mi><mn>2</mn><mi>b</mi></msubsup>
</mrow>
</math>
</body>
</html>
15
16
XSD
XML Schema Definition
www.w3.org/XML/Schema
17
3 XSD: XML Schema Definition
Was ist ein Schema?
•
•
•
•
XML Schema ist eine XML basierte Alternative für ein DTD.
Ein XML Schema beschreibt die Struktur eines XML Dokuments.
XML Schema ist eine W3C Recommendation
Statt XML Schema wird oft die Abkürzung XSD (XML Schema Definition) benutzt.
Ein Schema definiert
•
•
•
•
•
•
•
•
die Elemente, welche im Dokument vorkommen dürfen
die Attribute, welche vorkommen dürfen
welche Elemente Kind-Elemente sind
die Reihenfolge der Elemente
die Anzahl der Kind-Elemente
ob ein Element leer ist oder Text enthalten kann
Datentypen für Elemente und Attribute
Default Werte und feste Werte für Elemente und Attribute
Die Vorteile von XML Schema
XML Schema unterstützt Datentypen
•
Einfache und exakte Beschreibung der erlaubten Werte
•
Einfache Verifizierbarkeit der Korrektheit der Daten
•
Einfaches Definieren von Einschränkungen (facets) an die Daten
•
Einfaches Definieren von Datenformaten (pattern)
•
Einfaches Konvertieren der Daten in andere Datentypen
•
Einfaches Arbeiten mit Daten aus Datenbanken
XML Schema benutzt XML Syntax
•
Keine neue Sprache muss erlernt werden.
•
Editieren, transformieren und parsen der Schema Files kann durch die selben Editoren oder Tools
erfolgen wie für „normale“ XML Dateien.
XML Schemas sind erweiterbar
•
Eigene Datentypen können von den vordefinierten Datentypen hergeleitet werden
•
Schemas (die darin definierte Typen) können in anderen Schemas wieder verwendet werden
•
Ein beliebiges XML Dokument kann mehrere Schemas referenzieren.
18
Ein Beispiel Schema
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.note.org"
elementFormDefault="qualified">
<xs:element name="note">
<xs:complexType>
<xs:sequence>
<xs:element name="to" type="xs:string"/>
<xs:element name="from" type="xs:string"/>
<xs:element name="heading" type="xs:string"/>
<xs:element name="body" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Das Schema definiert ein neues Vokabular. Alle im Schema definierten Elemente (und ev. Attribute) gehören
dann zum Target- Namespace (www.note.org).
Ein dazu passendes Instanz Dokument
<?xml version="1.0"?>
<note xmlns="http://www.note.org"
xmlns:xsdi="http://www.w3.org/2001/XMLSchema-instance"
xsdi:schemaLocation="http://www.note.org note.xsd">
<to> Bill </to>
<from> Jani </from>
<heading> Reminder </heading>
<body>
Don't forget the book!
</body>
</note>
Das XML-Dokument benutzt das im Schema definierte Vokabular.
Verknüpfen des Schemas mit dem Instanz Dokument
xmlns="http://www.note.org"
ist der vom Schema definierte Namespace (hier als Default Namespace gesetzt).
xmlns:xsdi="http:// ... /XMLSchema-instance"
definiert den xsdi Namespace (für alle xsdi- Befehle).
xsdi:schemaLocation= "http://www.note.org note.xsd"
gibt das Schema File an: im File note.xsd wird die im Instanz-Dokument benutzte Sprache
(zum Namespace http://www.note.org) definiert.
19
Die Teile eines Schemas
Eine Element-Deklaration bestimmt den Namen und den Typ eines Elementes.
Eine Typ-Definition bestimmt den Namen eines Typs und die Beschreibung (Zusammensetzung) dieses Typs.
3.1 Deklarationen <--> Definitionen
Elementdeklarationen sind entweder lokal oder global:
Globale Elementdeklarationen sind Kind-Elemente von <schema> und können als Dokumentelement eines
Instanz-Dokuments vorkommen.
<xs:schema ...>
<xs:element name="note">
<xs:complexType>
. . .
</xs:complexType>
</xs:element>
. . .
</xs:schema>
Lokale Elementdeklarationen sind Kind-Elemente einer Typ-Definition und somit nicht global bekannt.
<xs:complexType name="addressType">
<xs:sequence>
<xs:element name="to" type="xs:string"/>
. . .
</xs:sequence>
. . .
Eine Deklaration beschreibt ein Element oder Attribut, welches im Instanz-Dokument vorkommen darf. So
wird ein <age>, bzw. ein <product> Element deklariert.
<xs:element name="age" type="xs:short"/>
<xs:element name="product">
. . .
</xs:element>
20
Eine Definition definiert einen Typ (hier productType), welcher dann in einer Element- oder AttributDeklaration verwendet werden kann.
<xs:complexType name="productType">
. . .
</xs:complexType>
Lokale Typen (die in eine Typ-Definition eingebettet sind und also keinen Namen haben) nennt man auch
anonyme Typen.
Eine Typ-Definition hat immer ein name-Attribut (sonst kann der Typ nirgendwo verwendet werden). Ein
solcher Typ nennt man darum benannter Typ.
In der Deklaration kann ein Element entweder einen vordefinierten (benannten) Typ verwenden (shoeType)
<xs:element name="shoeSize" type="shoeSizeType"/>
... oder einen anonymen Typ definieren
<xs:element name="shoeSize">
<xs:complexType>
<xs:simpleContent>
....
</xs:simpleContent>
</xs:complexType>
</xs:element>
aber nicht beides gleichzeitig!
Das Schema Typ-System
Einfache Typen sind Strings, Zahlen, Zeittypen oder Listen, bzw. Vereinigungen davon.
Elemente mit komplexen Typen können selber wieder Elemente und/oder Attribute enthalten.
21
3.2 Deklaration von einfachen Typen
Beispiele von einfachen Elementen mit atomaren Typen
<lastName>Schmid</lastName>
<age>34</age>
<born>1968-03-27</born>
Die entsprechenden Deklarationen:
<xs:element name="lastName" type="xs:string"/>
<xs:element name="age" type="xs:short"/>
<xs:element name="born" type="xs:date"/>
Elemente mit atomaren (einfachen) Typen können einen Default Wert oder einen festen Wert haben:
<xs:element name="color" type="xs:string" default="red"/>
<xs:element name="color" type="xs:string" fixed="red"/>
Wiederholungen minOccurs/maxOccurs
Die Anzahl möglicher Wiederholungen eines Elementes wird mit den Attributen minOccurs und maxOccurs
angegeben:
<xs:complexType name="familyType">
<xs:sequence>
<xs:element name="lastName" type="xs:string"/>
<xs:element name="childName" type="xs:string"
maxOccurs="10" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
Fehlt das minOccurs oder maxOccurs Attribut, dann gilt automatisch der Defaultwert 1.
Die allgemeine Syntax für einfache Elemente:
<xs:element name="Elementname" type="Elementtyp"
minOccurs="min" maxOccurs="max" default/fixed="Vorgabe" />
22
3.3 Vordefinierte primitive Schema Typen
Es gibt in der Schema Sprache bereits vordefinierte primitive Typen:
•
Mögliche boolean Werte sind: true, false, 1, 0
•
date ist von der Form 2001-03-28 (Jahr-Monat-Tag)
•
time ist von der Form 21:36:54 (Stunde:Minute:Sekunde)
•
gYearMonth besteht bloss aus Jahr und Monat
•
gMonthDay besteht bloss aus Monat und Tag
•
dateTime ist date und time getrennt durch ein Trenn-Zeichen T (2001-03-28T21:36:54)
Abgeleitete String Typen
•
•
•
•
•
•
•
string: Ein beliebiger String
normalizedString: Ein String ohne Tabs oder Newlines
token: Ein normalizedString ohne Anfangs-, End- oder aufeinander folgende Spaces
anyURI: Ein URI, z.B. http://www.isbe.ch
Name: Ein Elementname mit Namespace
NCName: Ein Name ohne Namespace
language: Ein gültiger xml:lang Wert
z.B. DE, EN, FR, ...
ID, IDREF, ENTITY, ...
sind aus Kompatibilitätsgründen
aus der Sprache DTD übernommen.
23
Numerische Datentypen
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
integer: Eine (beliebig grosse) ganze Zahl
nonPositiveInteger: Eine negative Zahl (inklusive 0)
negativeInteger: Eine negative Zahl (ohne 0)
long: Der Bereich von -9223372036854775808 bis 9223372036854775807
int: Der Bereich von -2147483648 bis 2147483647
short: Der Bereich von 32768 bis 32767
byte: Der Bereich von -128 bis 127
nonNegativeInteger: Von 0 bis unendlich
unsignedLong: Von 0 bis 18446744073709551615
unsignedInt: Von 0 bis 4294967295
unsignedShort: Von 0 bis 65536
unsignedByte: Von 0 bis 255
positiveInteger: Von 1 bis unendlich
decimal: Eine beliebig lange Zahl der Form 117.08, -98, +24.5, ...
float: 32 bit Zahlen der Form 12.56E3, 1.356, INF, -INF, NAN, ...
double: 64 bit Zahlen der Form 12.56E3, 12560, 0, INF, -INF, NAN, ...
24
3.4 Attribut Deklarationen
Attribute können nicht verschachtelt werden, sie haben also immer einen einfachen Typ.
Elemente, welche Attribute enthalten, haben hingegen immer einen komplexen Typ.
Ein Beispiel
<person gender="male">Peter Muster</person>
die Attribut-Deklaration:
<xs:attribute name="gender" type="xs:string"/>
Wie ein Attribut einem Element zugefügt wird, sehen wir im Kapitel über die Komplexen Typen.
Beispiele von Attribut Deklarationen
Ein Attribut mit Default Wert:
<xs:attribute name="lang" type="xs:string" default="EN"/>
Ein Attribut mit fixem Wert:
<xs:attribute name="lang" type="xs:string" fixed="EN"/>
Ein optionales Attribut:
<xs:attribute name="lang" type="xs:string" use="optional"/>
Das Attribut muss vorhanden sein:
<xs:attribute name="lang" type="xs:string" use="required"/>
Vorsicht: Attribute sind optional, ausser sie sind mit use="required" deklariert!
List und Union Typen
Ein List-Typ definiert eine Liste von einfachen Typen:
Beispiel: Liste von ganzen Zahlen
<xs:simpleType name="regNumberType">
<xs:list itemType="xs:int"/>
</xs:simpleType>
Liste von ganzen Zahlen der Länge 4:
<xs:simpleType name="shortRegNumberType">
<xs:restriction base="regNumberType">
<xs:length value="4"/>
</xs:restriction>
</xs:simpleType>
Eine Liste von ganzen Zahlen: <regNumber> 4 35 45 213 34 24 12 </regNumber>
Eine Liste der Länge 4: <shortRegNumber> 5 13 63 14 </shortRegNumber>
Ein Union-Typ ist eine Vereinigung von einfachen Typen:
<xs:simpleType name="UnoType">
<xs:union memberTypes="xs:int
</xs:simpleType>
xs:boolean"/>
Elemente vom Typ UnoType wären also zum Beispiel
<unoElem>41</unoElem>
oder
<unoElem>true</unoElem>
25
3.5 Komplexe Schema Typen
Ein komplexes Element ist ein XML Element mit einem komplexen Typ.
Es gibt vier Arten von komplexen Elementen
•
leere Elemente (die nur Attribute enthalten),
•
Elemente, welche nur andere Elemente enthalten,
•
gemischte Elemente enthalten sowohl andere Elemente als auch Text.
•
Elemente mit beliebigem Inhalt
Elemente mit komplexen Typen können also andere Elemente, Text-Knoten und/oder Attribute enthalten.
Leere Elemente
Ein leeres Element
<product productId="1345" />
Ein mögliches XML Schema:
<xs:complexType name="productType">
<xs:attribute name="productId" type="xs:positiveInteger"/>
</xs:complexType>
<xs:element name="product" type="productType"/>
Eine analoge Elementdeklarationen (mit anonymem Typ):
<xs:element name="product">
<xs:complexType>
<xs:attribute name="prodid" type="xs:positiveInteger"/>
</xs:complexType>
</xs:element>
Ein einfaches Element mit Attribut
Zum Beispiel
<shoeSize country="france">35</shoeSize>
Ein mögliches XML Schema:
<xs:complexType name="shoeSizeType" >
<xs:simpleContent>
<xs:extension base="xs:positiveInteger">
<xs:attribute name="country" type="xs:string"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
26
Elemente mit einer Sequenz von Kind-Elementen
<person>
<firstName>John</firstName>
<lastName>Smith</lastName>
</person>
Ein XML Schema
<xs:complexType name="personType">
<xs:sequence>
<xs:element name="firstName" type="xs:string"/>
<xs:element name="lastName" type="xs:string"/>
</xs:sequence>
</xs:complexType>
Durch Definieren eines benannten Typs kann dieser für Elementdeklarationen wiederverwendet werden
<xs:element name="person" type="personType"/>
<xs:element name="employee" type="personType"/>
Sequenz von Kind-Elementen erweitert um ein Attribut
<person gender="male">
<firstName>John</firstName>
<lastName>Smith</lastName>
</person>
Das XML Schema
<xs:complexType name="personType">
<xs:sequence>
<xs:element name="firstName" type="xs:string"/>
<xs:element name="lastName" type="xs:string"/>
</xs:sequence>
<xs:attribute name="gender" type="xs:string"/>
</xs:complexType>
Attribute werden immer nach den Kind-Elementen (sequence, choice oder all) aufgeführt.
Elemente mit einer unsortierten Folge von Kind-Elementen
Der all Indikator gibt an, dass die Kind-Elemente in beliebiger Reihenfolge, aber jedes Kind nur (höchstens)
einmal vorkommen darf:
<xs:complexType name="personType">
<xs:all>
<xs:element name="firstName" type="xs:string"/>
<xs:element name="lastName" type="xs:string"/>
</xs:all>
</xs:complexType>
Innerhalb des all Indikators kann minOccurs nur die Werte 0 oder 1 annehmen.
maxOccurs kann nur den Wert 1 haben.
27
Elemente mit einer Auswahl von Kind-Elementen
Der Choice Indikator bestimmt, dass entweder das eine oder das andere Kind vorkommen soll:
<xs:complexType name="personType" >
<xs:choice>
<xs:element name="employee" type="employeeType"/>
<xs:element name="member" type="memberType"/>
</xs:choice>
</xs:complexType>
Eine Person ist also entweder ein employee oder ein member (nicht beides).
Elemente mit gemischtem Inhalt
Das letter Element ist ein Element mit gemischtem Inhalt.
<letter> Dear Mr.<name>J. Smith</name>.
Your order <orderid>1032</orderid> will be shipped on <shipdate>2001-07-13
</shipdate>.</letter>
Dies wird durch mixed=”true” deklariert:
<xs:element name="letter">
<xs:complexType mixed="true">
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="orderid" type="xs:positiveInteger"/>
<xs:element name="shipdate" type="xs:date"/>
</xs:sequence>
</xs:complexType>
</xs:element>
Die Reihenfolge und Anzahl der Kind-Elemente ist dadurch fest vorgegeben.
Mixed Elemente werden vor allem für Text-Dokumente und weniger für Daten-Dokumente verwendet.
28
3.6 Spezielle Schema Elemente
Wir behandeln in diesem Kurs nur die wichtigsten Schema Elemente. Für eine vollständige Behandlung
sämtlicher Schema Elemente (Element- oder Attribut-Gruppen, Substitutionen, Typ-Referenzen, ...) siehe
z.B. http://www.w3.org/TR/xmlschema-0.
Facetten
Einfache Typ-Elemente lassen sich weiter einschränken durch sogenannte Facetten (facets). Mögliche
Restriktionen können maximale oder minimale Länge, ein Pattern (reg. Ausdruck), eine Aufzählung der
gültigen Werte (enumeration) oder ein minimaler/maximaler Wert sein.
Facetten für Strings:
length, maxLength, minLength
Facetten für numerische Werte:
totalDigits, fractionDigits, maxExclusive, minExclusive, maxInclusive, minInclusive
Facetten für Zeit-Typen:
maxExclusive (<), minExclusive (>), maxInclusive (<=), minInclusive (>=)
Für alle Typen:
enumeration, pattern, whiteSpace
Einige Beispiele
Erlaubte Wochentage sind Montag, Mittwoch und Samstag.
<xs:simpleType name="weekDayType">
<xs:restriction base="xs:string">
<xs:enumeration value="Montag"/>
<xs:enumeration value="Mittwoch"/>
<xs:enumeration value="Samstag"/>
</xs:restriction>
</xs:simpleType>
Eine Publisher ID ist entweder von der Form P-ABC oder von der Form P-321:
<xs:simpleType name="publisherIdType">
<xs:restriction base="xs:string">
<xs:pattern value="P-[A-Z]+"/>
<xs:pattern value="P-[0-9]+"/>
<xs:maxLength value="5"/>
</xs:restriction>
</xs:simpleType>
Falls mehrere Pattern angegeben sind, werden diese einfach der Reihe nach probiert. Zuletzt wird hier noch
zusätzlich die Länge geprüft.
29
Die Bedeutung der verschiedenen Facetten
enumeration
Definiert eine Liste von möglichen Werten
fractionDigits Spezifiziert die maximal erlaubte Anzahl Dezimalstellen (grösser oder gleich null)
length
Spezifiziert die (exakte!) Anzahl Buchstaben oder Listenelemente (grösser oder gleich null)
maxExclusive
Spezifiziert eine obere Schranke für numerische Werte (Werte sind kleiner!)
maxInclusive
minExclusive
Spezifiziert eine obere Schranke für numerische Werte (kleiner oder gleich)
Spezifiziert die maximal erlaubte Anzahl Buchstaben oder Listenelemente (grösser oder
gleich null)
Spezifiziert eine untere Schranke für numerische Werte (Werte sind grösser!)
minInclusive
Spezifiziert eine untere Schranke für numerische Werte (grösser oder gleich)
minLength
Spezifiziert die minimale Anzahl Buchstaben oder Listenelemente (grösser oder gleich null)
pattern
Definiert ein Muster für die erlaubten Werte
totalDigits
Spezifiziert die maximale Anzahl Ziffern (grösser oder gleich null)
whiteSpace
Spezifiziert, wie Whitespaces (newlines, tabs, ...) behandelt werden sollen
maxLength
Beispiele von Facetten
Ein letter Wert besteht aus genau einem kleinen Buchstaben (von a bis z)
<xs:simpleType name="letterType">
<xs:restriction base="xs:string">
<xs:pattern value="[a-z]"/>
</xs:restriction>
</xs:simpleType>
Ein threeInitials Wert besteht aus genau drei Buchstaben (von A bis Z)
<xs:simpleType name="threeInitialsType”>
<xs:restriction base="xs:string">
<!--oder [a-zA-Z]{3} -->
<xs:pattern value="[a-zA-Z][a-zA-Z][a-zA-Z]"/>
</xs:restriction>
</xs:simpleType>
Oder vier Buchstaben aus a,T und x
<xs:restriction base="xs:string">
<xs:pattern value="[aTx] {4} "/>
</xs:restriction>
Eine product Id besteht aus 4 Ziffern
<xs:simpleType name="productIdType">
<xs:restriction base="xs:int">
<xs:pattern value="[0-9][0-9][0-9][0-9]"/>
</xs:restriction>
</xs:simpleType>
<!--oder [0-9]{4} -->
30
myString besteht aus 5 bis acht kleinen Buchstaben und Zahlen
<xs:simpleType name="myStringType">
<xs:restriction base="xs:string">
<xs:pattern value="([a-z0-9])*"/>
<xs:minLength value="5"/>
<xs:maxLength value="8"/>
</xs:restriction>
</xs:simpleType>
Oder einem Grossbuchstaben gefolgt von mindestens einem kleinen Buchstaben
<xs:restriction base="xs:string">
<xs:pattern value="[A-Z]([a-z])+"/>
</xs:restriction>
Der XML-Parser soll die Leer-Zeichen mitzählen
<xs:simpleType name="addressType">
<xs:restriction base="xs:string">
<xs:minLength value="5"/>
<xs:whiteSpace value="preserve"/>
</xs:restriction>
</xs:simpleType>
Nur Werte von 0 bis 100
<xs:simpleType name="ageType">
<xs:restriction base="xs:int">
<xs:minInclusive value="0"/>
<xs:maxInclusive value="100"/>
</xs:restriction>
</xs:simpleType>
oder ohne "Rand" (1 bis 99 )
<xs:restriction base="xs:int">
<xs:minExclusive value="0"/>
<xs:maxExclusive value="100"/>
</xs:restriction>
Die wichtigsten regulären Ausdrücke
Bedeutung
\
.
x
^x
[x]
()
|
{x}
{x,}
{x,y}
?
*
+
\d \D
\s \S
Escape, um Instanzen von Zeichen zu finden, welche als Metazeichen benutzt werden (wie Punkt,
Klammer, ... )
Ein beliebiges Zeichen (ausser newline)
Eine Instanz von x
Jedes Zeichen ausser x
Alle Zeichen in diesem Bereich ( z.Bsp. [abuv] die Buchstaben a, b, u oder v, [a-z] alle Kleinbuchstaben)
Runde Klammern dienen für die Gruppierung
Der OR Operator (Auswahl) (a|A)
Der Ausdruck muss genau x Mal vorkommen
Der Ausdruck muss mindestens x Mal vorkommen
Der Ausdruck kommt mindestens x Mal und höchstens y Mal vor.
Abkürzung für {0,1}
Abkürzung für {0, }
Abkürzung für {1, }
\d : Abkürzung für [0-9] (digits) \D : alles ausser Ziffern
\s : Whitespace (spaces, tabs, newlines, ...) \S : kein Whitespace
31
3.7 Assertions (Zusicherungen)
Mit Hilfe von Zusicherungen können weitere Einschränkungen an Werte von Elementen oder Attributen
definiert werden. Werte von Elementen oder Attributen können Verglichen oder in Beziehung gesetzt
werden. Es können auch komplexe Bedingungen an Werte definiert werden.
Beispiele mit xs:assert
Die Namen (Vorname und Nachname) sollen verschieden sein.
<xs:complexType name="nameType">
<xs:sequence>
<xs:element name="first_name" type="xs:string"/>
<xs:element name="last_name" type="xs:string"/>
</xs:sequence>
<xs:assert test="first_name != last_name"/>
</xs:complexType>
Das Start-Datum soll nach dem End-Datum liegen (soll grösser sein).
<xs:complexType name="pType">
<xs:sequence>
<xs:element name="name" type="nameType"/>
</xs:sequence>
<xs:attribute name="startDate" type="xs:date"/>
<xs:attribute name="endDate" type="xs:date"/>
<xs:assert test="@startDate > @endDate"/>
</xs:complexType>
Die Anzahl Eigenschaften (profession und hobby) sollen dem Wert des properties Attributs entsprechen.
<xs:complexType name="personType">
<xs:sequence>
<xs:element name="name" type="nameType"/>
<xs:element name="profession" type="xs:string" maxOccurs="9"/>
<xs:element name="hobby" type="xs:string" maxOccurs="9"/>
</xs:sequence>
<xs:attribute name="properties" type="xs:int"/>
<xs:assert test="@properties eq count(profession | hobby)"/>
</xs:complexType>
Ein gültiges Instanz-Dokument
<person properties="2">
<name>
<first_name>Richard</first_name>
<middle_name>P.</middle_name>
<last_name>Feynman</last_name>
</name>
<born addressRef="unq" date="1918"/>
<died date="1988"/>
<profession>physicist</profession>
<hobby>African drum music</hobby>
</person>
32
Beispiele mit xs:assertion
Für komplexe (inhaltliche) Einschränkungen an einfache Datentypen gibt es das xs:assertion Element.
Der Wert soll kleiner als 1800 oder grösser als 1900 sein, aber ungleich null.
<xs:simpleType name="spezType">
<xs:restriction base="xs:int">
<xs:assertion test="($value < 1800 or $value > 1900) and $value != 0"/>
</xs:restriction>
</xs:simpleType>
Der (integer) Wert soll ungerade sein.
<xs:simpleType name="oddType">
<xs:restriction base="xs:int">
<xs:assertion test="($value mod 2 != 0)"/>
</xs:restriction>
</xs:simpleType>
33
3.8 Schlüssel
Mit Hilfe von keys können Elemente oder Attribute als Schlüssel definiert und damit die Eindeutigkeit
innerhalb eines Instanzdokuments garantiert werden
<xs:key name="departmentId">
<xs:selector xpath="department"/>
<xs:field xpath="@id"/>
</xs:key>
Die Schlüsseldefinition befindet sich normalerweise in der Deklaration des Root-Elements des XMLDokuments.
Der xs:selector enthält die Adresse, wo sich das Schlüsselfeld befindet (hier im department Element direkt
unter dem Root Element). Ein oder mehrere xs:field Elemente definieren die Schlüsselfelder (hier ein
Attribut namens id).
Ein analoges Konstrukt ist die unique Definition. Auch damit kann die Eindeutigkeit von Elementen
festgelegt werden.
<xs:unique name="nameUnique">
<xs:selector xpath="name"/>
<xs:field xpath="@id"/>
</xs:unique>
Referenzen auf Schlüssel
Mittels keyref können Referenzen auf Schlüssel (key) definiert werden
<xs:keyref name="departmentRef" refer="departmentId">
<xs:selector xpath="employee/department"/>
<xs:field xpath="@ref"/>
</xs:keyref>
Die Schlüssel-Referenz-Definition befindet sich normalerweise direkt bei der Schlüsseldefinition.
Der xs:selector enthält die Adresse, wo sich die Schlüsselreferenz befindet (hier im employee/department
Element unter dem Root Element). Das xs:field definiert die Felder der Schlüsselreferenzen (hier ein Attribut
namens ref).
Ein Beispiel Schema mit Schlüsseldefinition
In den Elementen person/born und person/died gibt es je eine Referenz auf eine Adresse.
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="people">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" name="person" type="personType"/>
<xs:element maxOccurs="unbounded" name="address" type="addressType"/>
</xs:sequence>
</xs:complexType>
<xs:key name="addressID">
<xs:selector xpath="address"/>
<xs:field xpath="@id"/>
</xs:key>
<-- alle Adress-Ids sind verschieden -->
34
<xs:keyref name="bornRef" refer="addressID">
<xs:selector xpath="person/born"/>
<xs:field xpath="@addressRef"/>
</xs:keyref>
<-- addressRef bezieht sich
auf eine Adress-Id
-->
<xs:keyref name="diedRef" refer="addressID">
<xs:selector xpath="person/died"/>
<xs:field xpath="@addressRef"/>
</xs:keyref>
</xs:element>
<xs:complexType name="personType">
. . .
</xs:complexType>
<xs:complexType name="addressType">
<xs:sequence>
<xs:element name="country" type="xs:string"/>
<xs:element name="city" type="xs:string"/>
</xs:sequence>
<xs:attribute name="id" type="xs:string"/>
</xs:complexType>
<xs:complexType name="bdType">
<xs:attribute name="addressRef" type="xs:string"/>
<xs:attribute name="date" type="xs:positiveInteger"/>
</xs:complexType>
</xs:schema>
Ein mögliches Instanzdokument
<?xml version="1.0" encoding="UTF-8"?>
<people xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="People.xsd">
<person>
<name>
<firstName>Alan</firstName>
<lastName>Turing</lastName>
</name>
<born date="1912" addressRef="gbl"/>
<!-- Referenz auf eine Adresse-->
<died date="1954" addressRef="gbc"/>
<!-- Referenz auf eine Adresse-->
<profession>computer scientist</profession>
<profession>mathematician</profession>
<profession>cryptographer</profession>
<hobby>philosophy</hobby>
<hobby>biology</hobby>
</person>
<address id="gbl">
<!-- Schlüssel -->
<country>Great Britain</country>
<city>London</city>
</address>
<address id="gbc">
<!-- Schlüssel -->
<country>Great Britain</country>
<city>Cambridge</city>
</address>
</people>
35
Any-Elemente und Attribute
Ein <any> Element erlaubt uns, das XML Dokument zu einem späteren Zeitpunkt um beliebige Elemente zu
erweitern. Das selbe bewirkt ein <anyAttribute> für Attribute.
<xs:element name="person">
<xs:complexType>
<xs:sequence>
<xs:element name="firstName" type="xs:string"/>
<xs:element name="lastName" type="xs:string"/>
<xs:any minOccurs="0"/>
</xs:sequence>
<xs:anyAttribute/>
</xs:complexType>
</xs:element>
Eine mögliche Erweiterung, zum Beispiel um ein Children Element und ein gender Attribut:
<xs:element name="children">
<xs:complexType>
<xs:sequence>
<xs:element name="childName" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:attribute name="gender">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:pattern value="male | female"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
Ein gültiges (erweitertes) Instanz-Dokument
Das person Element kann so um ein gender Attribut und ein children Element erweitert werden.
<person gender="female">
<firstName>Maria</firstName>
<lastName>Stuard</lastName>
<children>
<childName>Jakob</childName>
<childName>Cecilia</childName>
</children>
</person>
36
Schema Dokumentation
Anmerkungen (xs:annotation) enthalten Informationen für den Benutzer (xs:documentation) oder für eine
Applikation (xs:appinfo)
<xs:annotation>
<xs:documentation xml:lang="en">
This is a schema for address books
</xs:documentation>
</xs:annotation>
Einfügen von Schemas
Mittels include kann ein anderes Schema eingefügt werden, welches denselben Target-Namespace hat:
<xs:include schemaLocation="address.xsd"/>
Mittels import kann ein Schema eingefügt werden, welches einen andern Target-Namespace hat:
<xs:import
namespace="http://www.example.org/address"
schemaLocation="address.xsd"/>
Include erweitert also das Schema um weitere Typen desselben Namespaces.
Import hingegen erlaubt das Benutzen von Typen aus anderen Namespaces.
Typen überschreiben: xs:override
Ab Schema Version 1.1 können (einzelne) Schema Typen in einem anderen Schema überschrieben und dadurch neu
definiert werden.
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"#
xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"
vc:minVersion="1.1">
<xs:override schemaLocation="OverrideBase.xsd">
<xs:simpleType name="DressSizeType">
<xs:restriction base="xs:integer">
<xs:minInclusive value="2"/>
<xs:maxInclusive value="16"/>
</xs:restriction>
</xs:simpleType>
</xs:override>
<xs:element name="newSize" type="DressSizeType"/>
</xs:schema>
37
38
Verarbeiten von XML Dokumenten
SAX: Simple Application Interface for XML
org.xml.sax
DOM: Document Object Model
www.w3.org/DOM
StAX: Streaming API for XML
javax.xml.stream
39
4 SAX: Simple Application Interface for XML
4.1 Was ist SAX?
SAX definiert ein einfaches API für einen Event basierten Parser.
Event basiert heisst, der Parser liest ein XML Dokument von Anfang bis Ende und benachrichtigt bei jeder
erkannten syntaktischen Struktur (Element, Prozess Instruktion, Kommentar, Namespace-Definition, ...) die
Applikation.
Die Benachrichtigung erfolgt durch Aufruf der entsprechenden Funktionen
•
startDocument
•
startElement
•
endElement
•
endDocument
•
....
SAX funktioniert wie ein serieller I/O Stream
In SAX ist kein Random Access möglich. Der Parser läuft linear durch das Dokument, zurückgehen auf eine
frühere Position ist nicht möglich.
SAX ist darum vor allem dann nützlich, wenn wir die Daten des XML Dokuments lesen oder gewisse
Elemente heraus filtern (aber das Dokument nicht verändern oder bearbeiten) wollen.
4.2 Wofür ist SAX geeignet?
Sax ist geeignet
•
für das schnelle, effiziente Lesen oder Validieren von XML Dokumenten.
•
für grosse Dokumente wenn wenig Speicher zur Verfügung steht. SAX benötigt wenig Speicher, da
die gelesenen Daten nicht intern abgespeichert, sondern direkt an die Applikation weitergeleitet
werden.
•
falls keine Änderungen in der XML Struktur nötig sind. Wenn die XML Struktur oder die XML Daten
verändert werden sollen oder die Daten nicht linear durchlaufen werden sollen, ist SAX nicht
geeignet. Für solche Anwendungen sind XSLT, StAX oder DOM geeigneter.
4.3 Wie funktioniert SAX?
Ganz zu Beginn beim Lesen wird ein startDocument Event erzeugt. Danach werden abhängig von der
Struktur des XML Dokuments die folgenden Events erzeugt.
<name>
<first_name>
Alan
</first_name>
<last_name>
Turing
</last_name>
</name>
-->
-->
-->
-->
-->
-->
-->
-->
startElement()
startElement()
characters()
endElement()
startElement()
characters()
endElement()
endElement()
Eine Start-Tag (<...>) triggert ein startElement Event, ein End-Tag (</...> ) triggert ein endElement Event.
Text Knoten triggern ein characters Event.
Als letztes wird ein endDocument Event erzeugt.
40
4.4 Übersicht über das SAX API
XMLParserFactory
Erzeugen eines SaxParsers
SAX Parser
Setzen der Parser Eigenschaften (validating, namespace-aware, ...)
Bietet verschiedene parse() Methoden an (aus File, InputStream, URI, ...).
Implementiert die verschiedenen Handler (Interfaces) leer.
Interface für die verschiedenen Event Handler Methoden
start / endDocument, start / endElement(), characters, ...
DefaultHandler
ContentHandler
ErrorHandler
Interface für die Fehlerbehandlung: error(), fatalError(), warning()
DTDHandler
Implementation der DTD Anweisungen (wird normalerweise nicht mehr gebraucht)
Funktionsweise des SAX Parsers
41
4.5 Implementation des Default Handlers
Um einen Sax-Parser zu schreiben, überschreibt man üblicherweise einfach die Klasse Default Handler. Da
dort bereits alle vom Interface geforderten Methoden leer implementiert sind, müssen wir nur noch die von
uns benötigten Methoden überschreiben.
startDocument / endDocument
Beim Parsen des XML Dokuments wird als erstes die Methode startDocument() aufgerufen. In dieser
können alle Initialisierungs-Schritte ausgeführt werden.
Ganz am Ende wird dann die Methode endDocument() aufgerufen, die zum Freigeben und Aufräumen aller
benutzten Ressourcen verwendet werden kann.
startElement
public void startElement(
String uri,
//
String lName,
//
String qName,
//
Attributes attrs)
//
throws SAXException
Namespace URI
lokaler Name
qualifizierter Name
Attribut-Liste
Die Methode startElement() wird immer dann aufgerufen, wenn der Parser ein Start-Tag liest.
Den Tag-Namen finden wir im Parameter qName (Tag-Name mit Namespace-Prefix, falls vorhanden), oder
als lName (lokaler Name) und uri (Namespace). uri und lName können leere Strings sein, falls der Parser
den Namespace ignoriert (durch Setzen der entsprechenden namespace-Property).
Im attrs-Argument befindet sich die Liste aller Attribute. Falls keine Attribute vorhanden sind, ist attrs eine
leere Attribut-Liste. In startElement können wir also die Attribute (name und value) des Elements lesen:
if (attrs != null) {
for(int i = 0; i < attrs.getLength(); i++) {
// Attribute name (local or qualified)
String aName = attrs.getLocalName(i);
if ("".equals(aName)) aName = attrs.getQName(i);
// Attribute value
String val = attrs.getValue(i);
}
}
Die Attribute haben entweder einen lokalen Namen
String getLocalName(int i)
oder einen qualifizierten Namen (mit Namespace)
String getQName(int i)
Den Wert des Attributes erhalten wir entweder über den Listen-Index
String getValue(int i)
oder über den Namen
String getValue(String aName).
42
characters
Der Parser ruft für jeden Textknoten (einmal oder mehrmals) die Methode characters auf.
StringBuffer textBuffer = new StringBuffer();
public void characters(
char chars[], // die Zeichen aus dem XML Dokument
int start,
// die Start-Position im Array
int length )
// die Anzahl Zeichen, welche gelesen werden können
throws SAXException {
// Auslesen der Zeichen aus dem Puffer chars und
// abspeichern in den Text-Puffer
textBuffer.append(chars, start, length);
}
Ein SAX Parser kann alle Zeichen des Dokuments auf einmal zurückgeben, oder sie in verschiedene Blöcke
zerteilen. Das Argument start gibt an, wo im Puffer chars die für diesen Textknoten relevante Information
anfängt. length gibt an, wie viele Zeichen des Puffers (ab Position start) zu diesem Aufruf gehören.
endElement
public void endElement(
String uri,
// Namespace URI
String lName,
// lokaler Name
String qName )
// qualifizierter Name
throws SAXException {
}
// verarbeite den Inhalt des Elements
// ev. aufräumen.
Die endElement Methode wird bei jedem XML End-Tag (oder am Ende eines leeren Elements) aufgerufen.
Da der Text–Inhalt eines Elements oft in mehreren Blöcken eingelesen wird, ist es sinnvoll, den Text-Puffer
aus der characters Methode erst in der endElement Methode zu verarbeiten.
ProcessingInstruction
Die Methode processingInstruction dient zur Behandlung von Verarbeitungs-Anweisungen.
Verarbeitungs-Anweisungen werden normalerweise vom Parser ignoriert. Die Methode processingInstruction kann zum Lesen der Verarbeitungsanweisungen benutzt werden.
startPrefixMapping / endPrefixMapping
Diese Methoden dienen zum Behandeln von Namespaces am Anfang, bzw. am Ende des Setzen eines
Namespace Prefix. start/endPrefixMapping wird immer am Anfang, bzw. am Ende des Gültigkeitsbereiches
einer Namespace Deklaration aufgerufen.
43
4.6 Fehlerbehandlung: ErrorHandler
Warnungen werden während der Verarbeitung des DTD oder des Schemas erzeugt: Unnötige (doppelte)
Deklarationen für Entities, Attribute oder Notations oder Fehler im Schema können zum Aufruf der
Methode warning() führen.
Ein Fehler (Aufruf von error()) entsteht, falls das XML-Dokument nicht dem Schema oder DTD entspricht,
also das XML-Dokument nicht gültig ist.
Die Methode fatalError() wird aufgerufen, falls das XML-Dokument nicht wohlgeformt ist. Bei einem
fatalError bricht der Parser normalerweise ab.
Um diese Fehler erkennen und bearbeiten zu können, ist es wichtig den ErrorHandler sinnvoll zu
implementieren und Fehlermeldungen auszugeben.
Die SAXParseException kennt die Zeile/Spalte, wo der Fehler im Dokument aufgetreten ist:
e.getLineNumber() --> Ausgabe der Zeilen Nummer
e.getColumnNumber() --> Ausgabe der Spalten Nummer
e.getLocalizedMessage() --> Ausgabe der Fehlermeldung
Ein SAX Beispiel
Ein vollständiges SAX Beispiel finden Sie auf der Übungsseite.
44
5 DOM: Das Document Object Model
Was ist DOM?
•
•
•
•
•
DOM definiert einen Standard zum Lesen und Bearbeiten von XML-Dokumenten.
DOM stellt XML-Dokumente als Baumstruktur dar.
DOM definiert eine Menge von Interfaces (Node, NodeList, Element, Attr, ...) und eine Menge von
Methoden darauf.
DOM ist Plattform- und Sprachunabhängig definiert.
DOM ist ein W3C Standard.
Die DOM Node Typen
Der W3C Standard definiert die folgenden Knoten-Typen:
Node
nodeName()
nodeValue()
attributes
NodeType()
Attr
name of attribute
value of attribute
null
2
CDATASection
#cdata-section
content of the
CDATA Section
null
4
Comment
#comment
content of the comment null
8
Document
#document
null
null
9
DocumentFragment
#document-fragment
null
null
11
DocumentType
document type name
null
null
10
Element
tag name
null
NamedNode
Map
1
Entity
entity name
null
null
6
EntityReference
name of entity
referenced
null
null
5
Notation
notation name
null
null
12
ProcessingInstruction target
entire content excluding null
the target
7
Text
content of the text node null
3
#text
45
5.1 Die org.w3c.dom Java Interfaces
Für jeden Knoten-Typ definiert Java ein entsprechendes Interface im org.w3c.dom Package.
•
Element
für Elementknoten
•
Attr
für Attribute
•
Text
für Text Knoten
•
Document
für das Document Element
•
Node
für beliebige Knoten
•
NodeList
für Listen von Knoten
•
ProcessingInstruction für Verarbeitungs-Anweisungen
•
...
Das Node Interface
Das Node Interface definiert die Methoden zum Lesen und Bearbeiten von DOM Knoten:
•
Node appendChild(Node newChild)
fügt einen neuen Knoten am Ende der Liste der Kind-Knoten ein.
•
Node cloneNode(boolean deep)
Kopiert diesen Knoten (deep=true --> mit allen Kind-Knoten)
•
NamedNodeMap getAttributes()
gibt eine NamedNodeMap zurück, welche die Attribute dieses Elements enthält oder null, falls
der Knoten kein Elementknoten ist.
•
NodeList getChildNodes()
gibt eine NodeList mit allen Kindknoten zurück.
•
Node getFirstChild() / getLastChild()
gibt den ersten/letzten Kind-Knoten dieses Knotens zurück.
•
String getLocalName()
gibt den lokalen Namen (ohne Namespace Prefix) zurück.
•
short getNodeType() / String getNodeValue()
der Node Type / Node Value (gemäss Tabelle in Abschnitt 8.2)
•
Node getParentNode()
gibt den Elternknoten dieses Knotens zurück (falls er existiert).
•
Node removeChild(Node oldChild)
entfernt oldChild aus der Liste der Kinder dieses Knotens.
•
...
Das NodeList Interface
Das NodeList Interface definiert Methoden zum Bearbeiten von (geordneten) Knotenmengen. Eine NodeList
erhalten wir zum Beispiel als Rückgabewert von getChildNodes.
Das NodeList Interface definiert die beiden Methoden
• int getLength()
gibt die die Länge der Liste zurück.
•
Node item(int n )
gibt das n-te Element der Liste (beginnend bei 0) zurück.
Das Document Interface
Die wichtigsten Methoden des Document Interfaces sind
46
•
NodeList getElementsByTagName(String tagname)
NodeList getElementsByTagNameNS(String namespace, String localName)
gibt eine NodeList mit allen Elementen mit dem Namen tagname zurück.
Die Reihenfolge der Liste ist die gleiche wie im XML-Dokument. Diese Methode ist im allgemeinen
einfacher zu benutzen als die Methode getChildNodes, da hier alle zurückgegebenen Knoten
Elementknoten sind.
•
void normalizeDocument()
hat den gleichen Effekt, wie wenn das Dokument gespeichert und neu geladen würde.
Das bedeutet, dass (beim validierenden DOM) erneut die Gültigkeit des Dokuments geprüft wird.
So kann geprüft werden, ob ein Dom-Baum im Memory immer noch der im Schema vorgegebenen
Struktur entspricht.
•
Element getElementById(String id)
gibt das eindeutige Element mit der ID id zurück (falls das Element existiert und die id als Id
deklariert ist). Mit Hilfe dieser Methoden können Referenzen aufgelöst werden.
Das Element Interface
Die wichtigsten Methoden des Element Interfaces sind
•
String getAttribute(String name)
String getAttributeNS(String namespace, String localName)
gibt den Inhalt des entsprechenden Attributs zurück (ohne / mit Namespace).
•
void removeAttribute(String name)
removeAttributeNS(String namespace, String localName)
Löscht im Element das Attribute name (ohne / mit Namespace)
•
void setAttribute(String name, String value) /
void setAttributeNS(String ns, String name, String value)
Fügt in das Element ein neues Attribut ein.
•
NodeList getElementsByTagName(String tagname)
NodeList getElementsByTagNameNS(String namespace, String localName)
gibt alle Nachfolger dieses Elements mit Namen tagname zurück (ohne/mit Namespace).
•
void setIdAttribute(String name, boolean isId)
void setIdAttributeNS(String ns, String localName, boolean idId)
Falls isId gleich true ist, wird das entsprechende name Attribute zu einem ID-Attribut (es gibt
keine Methode setIdElement). Diese Methode wird vorallem im Zusammenhang mit
getElementById() gebraucht.
47
5.2 Benutzen des DOM Parsers
public static final String fileName = "XML/catalog.xml";
private static final String schemaFile = "XML/catalog.xsd";
private static final String namespaces =
"http://xml.org/sax/features/namespaces";
static public void main(String[] argv) {
try {
// create validating document builder factory
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setFeature(namespaces, true);
// use validating parser
SchemaFactory schemaFactory =
SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema =
schemaFactory.newSchema(new StreamSource(new File(schemaFile)));
factory.setSchema(schema);
// parse XML tree into DOM document tree
DocumentBuilder builder = factory.newDocumentBuilder();
builder.setErrorHandler(new MyErrorHandler());
Document document = builder.parse(fileName);
. . .
} catch (Exceptions e) {
. . .
}
}
Navigieren durch den DOM Baum
Das Document Interface bietet Methoden zum Sammeln aller Elemente mit gleichem Tag Name.
DieseElemente können dann durch Iteration durch die NodeList gelesen werden:
NodeList nodeList = document.getElementsByTagName("tagName");
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
String value = node.getNodeValue();
// Wert des i-ten Elements
}
NamedNodeMap attrs = node.getAttributes(); // Wert des id Attributs
String idVal = attrs.getNamedItem("id").getNodeValue();
. . .
Ausserdem können wir das Element mit einer bestimmten ID suchen:
Element aNode = document.getElementById(idref);
getElementById() funktioniert aber nur , falls isId(id) zu true evaluiert. Dazu muss id entweder im Schema
oder programmatisch als ID definiert sein. Das kann zum Beispiel erreicht durch das explizite Setzen dieser
Eigenschaft: z. B. das Attribute mit Namen „id“ eines nodes wird durch node.setIdAttribute(“id“, true); zu
einer ID.
48
Falls ein Knoten kopiert werden soll, muss er zuerst durch clone() verdoppelt werden. Das boolesche
Argument (true/false) gibt an, ob der ganze Unterbaum neu angelegt werden soll.
Node clone = aNode.cloneNode(true);
Node parent = node.getParentNode();
parent.appendChild(clone);
// kopiere den Knoten aNode
// einfügen in parent von node
Löschen von Nodes
Da beim Löschen von Elementen aus einer NodeList gleichzeitig die Liste verändert wird, sollten die ListenElemente rückwärts (vom Ende zum Anfang der Liste) oder in einer while-Schleife gelöscht werden:
NodeList nodeList = document.getElementsByTagName("tagName");
for (int i = nodeList.getLength()-1; i >= 0; i--)
{
// Rückwärts!
Node node= nodeList.item(i);
Node parent = node.getParentNode();
parent.removeChild(node);
. . .
Ausgeben eines DOM Baums: LSSerializer
Seit dem DOM Level 3 gibt es mit Hilfe des LSSerializers eine komfortable Möglichkeit zum Schreiben von
DOM Dokumenten. Ein Beispiel dazu:
import com.sun.org.apache.xml.internal.serialize.*;
OutputFormat format = new OutputFormat(DOM_Document);
format.setLineWidth(lineWidth);
// define line width
format.setIndenting(true/false);
// define indentation
format.setIndent(indent);
// number of spaces
format.setOmitDocumentType(true/false);
// omit Document Type definition
FileOutputStream fos = new FileOutputStream(resultFile);
XMLSerializer serializer = new XMLSerializer(fos, format);
serializer.serialize(DOM_Document);
// print out document
Ein vollständiges DOM Beispiel finden Sie auf der Übungsseite.
49
6 StAX: Streaming API for XML
6.1 Was ist StAX?
StAX ist ein JAVA API, um XML Dateien zu verarbeiten. Die beiden vorherigen XML-APIs sind entweder
• baumbasiert – das gesamte Dokument wird als Baumstruktur in den Speicher gelesen und kann
dann dort bearbeitet werden (DOM), oder
• ereignisbasiert – die Anwendung bekommt ein Ereignis, wenn neue Knoten im Dokument entdeckt
werden (SAX).
Beide Varianten haben Vor- und Nachteile: die erste erlaubt wahlfreien Zugriff auf das Dokument, die
zweite benötigt weniger Speicher und ist daher üblicherweise viel schneller. Eine baumbasierte API erlaubt
einen lesenden und schreibenden Zugriff auf das Dokument, eine ereignisbasierte API ist ein einmaliger
lesender Durchlauf durch das Dokument.
StAX wurde als komfortablere Alternative für SAX entworfen. In StAX ist der programmatische Einstieg ein
Cursor, der eine Stelle im Dokument repräsentiert. Die StAX Anwendung bewegt den Cursor selber
vorwärts.
Die StAX API Dokumentation finden Sie unter javax.xml.stream. Wir beschränken uns hier auf die beiden
Interfaces XMLStreamReader und XMLStreamWriter.
XML-Dokumente lesen
Um mit Hilfe von StAX eine XML-Datei verarbeiten zu können, muss zuerst ein XMLStreamReader erzeugt
werden. Der XMLStreamReader dient dann als Parser zum Lesen des Dokuments.
InputStream inputStream = new FileInputStream(inFile);
XMLInputFactory factory = XMLInputFactory.newInstance();
XMLStreamReader reader = factory.createXMLStreamReader(inputStream);
Der Reader liefert beim Lesen des XML-Dokuments eine Reihe von Events. Die verschiedenen Event-Typen
sind als Konstanten in der Klasse XMLStreamConstants festgelegt:
•
•
•
•
•
START_DOCUMENT: END_DOCUMENT --> Beginn / Ende des XML-Dokuments.
START_ELEMENT: Start Tag des Elements --> Die Attribute können hier gelesen werden.
END_ELEMENT --> End Tag des Elements.
CHARACTERS --> gesamter Textknoten innerhalb eines Elements.
...
Ein Beispiel: Lesen eines XML-Dokuments mit StAX
while (reader.hasNext()) {
switch (reader.next()) {
case XMLStreamConstants.START_ELEMENT:
System.out.print(reader.getName());
if (reader .getAttributeCount() > 0)
System.out.print(" : " + reader.getAttributeValue(0));
break;
case XMLStreamConstants.END_ELEMENT:
System.out.print(reader.getName());
break;
case XMLStreamConstants.CHARACTERS:
System.out.print(reader.getText());
break;
}
50
Die Benutzung von StAX ist viel intuitiver als diejenige von SAX, so liest die Methode getText() den ganzen
Text-Knoten und nicht nur den nächsten Block.
XML-Dokumente schreiben
Im Gegensatz zu DOM-orientierten APIs, bei denen das gesamte Dokument im Speicher vorliegt und
verändert werden kann, ist es bei StAX nicht möglich, die vorhandene XML-Datei zu verändern. Mit Hilfe
von SAX ist es sehr mühsam, ein XML-Dokument zu schreiben. Hier bietet STaX hingegen gute
Möglichkeiten.
Mit Hilfe der XMLOutputFactory wird ein XMLStreamWriter erzeugt:
FileOutputStream fos = new FileOutputStream(outFile);
XMLOutputFactory factory = XMLOutputFactory.newInstance();
XMLStreamWriter outWriter =factory.createXMLStreamWriter(fos);
Der XMLStreamWriter bietet dann Methoden zum Schreiben der XML-Elemente und Attribute:
outWriter.writeStartDocument("1.0");
outWriter.writeStartElement(name);
outWriter.writeAttribute(attr, value)
outWriter.writeCharacters(string)
outWriter.writeComment(comment)
outWriter.writeEndElement();
-->
-->
-->
-->
-->
-->
<?xml version="1.0"?>
<name>
<... attr=“value“>
string
<!-- comment -->
</name>
(aus dem Kontext)
Es muss nicht angegeben werden, welches Element geschlossen werden muss. Dies erkennt StAX mit Hilfe
der Wohlgeformtheit jeweils von selber. Ein vollständiges StAX Beispiel finden Sie auf der Übungsseite.
51
52
JAXB
Java Architecture for XML Binding
jaxb.java.net
53
7 JAXB: Java Architecture for XML Binding
JAXB ist eine schnelle und einfache Methode, um ein XML Schema mit einer Java Repräsentation zu
verbinden. Damit ist es sehr einfach, XML Daten nach Java einzulesen, dort zu verarbeiten und wieder nach
XML abzuspeichern.
JAXB erzeugt aus dem Schema automatisch eine entsprechende Java Daten Hierarchie, liest die Daten aus
dem Dokument und stellt Zugriffs-Methoden für alle Elemente zur Verfügung.
JAXB kann als Ersatz für DOM oder SAX benutzt werden. Die Programmier-Details für das Lesen und
Schreiben der XML Daten bleiben verborgen. Wir müssen keine neuen Befehle kennen lernen. Der Zugriff
auf die Daten erfolgt nach den Namen, wie sie im XML Schema definiert sind.
7.1 Die JAXB Architektur
Eine JAXB Implementation besteht aus den folgenden Teilen:
•
Der Schema Compiler
Erzeugt aus einem Schema eine Menge von dazu passenden Java Klassen. Das Mapping erfolgt
gemäss der Namen im Schema, kann aber durch Schema-Annotations oder ein BindingsDeklarationsfile angepasst werden.
•
Der Schema Generator
Erzeugt aus existierenden Java Klassen ein passendes Schema. Das Mapping erfolgt gemäss den
Annotations in den Java Klassen.
•
Das Binding Runtime Framework
Bietet die Operationen unmarshalling (reading) und marshalling (writing) um von Java aus auf XML
Daten zuzugreifen, sie zu ändern oder zu validieren.
54
7.2 Das Binding
Der Binding Prozess besteht aus den folgenden Schritten:
1. Generate classes
Der xjc (xml to java compiler) Befehl generiert aus dem XML Schema die zugehörigen Java Klassen.
Der Befehl dazu lautet:
xjc.exe -p packageName schema.xsd -d outputDirectory
2. Compile classes
Die generierten Klassen müssen kompiliert werden:
javac outputDirectory/packageName/*.java
3. Unmarshal
Durch den unmarshal Befehl werden die Daten der XML Dokumente gelesen, die entprechenden
Java Objekte erzeugt und die gelesenen Daten darin abgespeichert. Das Unmarshalling funktioniert
nicht nur für Files sondern auch für DOM Knoten, SAX-Sourcen, String-Buffer, ... Der XML Baum wird
dabei gemäss der Definitionen im Schema in eine Java Objekt-Struktur abgefüllt.
4. Validate (optional)
Falls erwünscht kann während des unmashallings die eingelesene XML Source gegen das Schema
validiert werden.
5. Process content
Die Inhalte der Java Struktur können nun beliebig verändert werden.
6. Marshal
Die (geänderten) Java Objekte können dann wieder in ein XML Dokument (File, String, DOMKnoten, ...) zurückgeschrieben werden. Während des Schreibens der Daten (marshal) können diese
wiederum durch das Schema validiert werden.
55
7.3 Übersetzung verschiedener Basis-Datentypen
Die benutzten XML Schema Typen werden in (ziemlich) offensichtlicher Art in Java Typen übersetzt:
XML Schema Type
Java Data Type
xsd:string
xsd:integer
xsd:int
xsd.long
xsd:short
xsd:decimal
xsd:float
xsd:double
xsd:boolean
java.lang.String
java.math.BigInteger
int
long
short
java.math.BigDecimal
float
double
boolean
xsd:byte
byte
xsd:QName
javax.xml.namespace.QName
xsd:dateTime
javax.xml.datatype.XMLGregorianCalendar
xsd:base64Binary
byte[]
xsd:hexBinary
byte[]
xsd:unsignedInt
long
xsd:unsignedShort
int
xsd:unsignedByte
short
xsd:time
javax.xml.datatype.XMLGregorianCalendar
xsd:date
javax.xml.datatype.XMLGregorianCalendar
xsd:anySimpleType
java.lang.String
xsd:duration
javax.xml.datatype.Duration
xsd:NOTATION
javax.xml.namespace.QName
56
7.4 Erzeugen der Java Klassen
Die Java-Klassen und Member Variablen werden gemäss dem Schema erzeugt:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://sws.people.org"
elementFormDefault="qualified" xmlns="http://sws.people.org">
<xs:element name="people">
<xs:complexType>
<xs:sequence>
<xs:element name="person" type="personType"
maxOccurs="unbounded"/>
<xs:element name="address" type="addressType"
maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
Das obige (Teil-) Schema erzeugt eine Klasse People der Form
People
List<PersonType> person;
List<AddresType> address;
List<PersonType> getPerson();
List<AddressType> getAddress();
Die folgende Typendefinition
<xs:complexType name="personType">
<xs:sequence>
<xs:element name="name" type="nameType"/>
<xs:element name="born" type="bornType"/>
<xs:element name="died" type="diedType"/>
. . .
</xs:sequence>
</xs:complexType>
erzeugt eine Java Klasse der Form:
PersonType
NameType name;
BornType born;
...
NameType getName();
void setName(NameType name);
...
57
7.5 Einlesen der XML Daten
Die vom Framework gelieferte JAXBContext Klasse erstellt einen Zugriff zum JAXB API. Damit wird ein
Unmashaller erzeugt.
try{
JAXBContext jc = JAXBContext.newInstance(People.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
SchemaFactory schemaFactory = SchemaFactory
.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = schemaFactory.newSchema(new File("schema.xsd"));
unmarshaller.setSchema(schema);
Object obj =
unmarshaller.unmarshal( InputStream | File | DocNode | ... )
...
} catch(JAXBException e) { . . . }
Für unser People-Beispiel könnte das etwa so aussehen:
PeopleType people =
(People) unmarshaller.unmarshal( new File("People.xml") );
Durch die erzeugte Java Struktur kann dann mit den beim Binding erzeugten Zugriffsmethoden navigiert
werden:
for(PersonType b : people.getPerson()) {
String firstName = b.getName().getFirstName();
String lastName = b.getName().getLastName();
}
7.6 Schreiben der Daten in ein XML File
Zum (formatierten) Schreiben der Daten erzeugen wir mittels des JAXBContext ein Marshaller Objekt.
JAXBContext jc = JAXBContext.newInstance(People.class);
Marshaller ms = jc.createMarshaller();
ms.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE );
SchemaFactory sf =
SchemaFactory.newInstance( XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = sf.newSchema( new File("Schema.xsd"));
marshaller.setSchema(schema);
// Schreiben der Daten nach people.xml
ms.marshal( people, new FileOutputStream("people.xml"));
Dies generiert ein neues File „people.xml“ und scheibt die gesamte (oder Teile der) Java Objekt Struktur in
dieses File. Beim Schreiben der XML Daten wird hier die Struktur gegen das Schema validiert.
Die Java Objekte können nach Belieben in einen OutputStream, einen Document Node, einen
SaxContentHandler, .... geschrieben werden (vgl. JAXB Dokumentation).
58
7.7 Anpassen der generierten Java Klassen und Member Variablen
Durch Angabe einer appinfo-Annotation im Schema können die Namen für die generierten Klassen und
deren Member-Variablen verändert werden.
Die wichtigsten Annotations sind jxb:class und jxb:property. So kann zum Beispiel bestimmt werden, wie die
generierte Address-Klasse aussehen soll (vgl. Beispiel auf der Übungsseite)
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://sws.people.org"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb" jxb:version="2.0"
elementFormDefault="qualified" xmlns="http://sws.people.org">
<xs:complexType name="addressType">
<xs:annotation>
<xs:appinfo>
<jxb:class name="Address"/>
</xs:appinfo>
</xs:annotation>
<xs:sequence>
<xs:element name="country" type="xs:string"/>
<xs:element name="city" type="xs:string"/>
</xs:sequence>
<xs:attribute name="id" use="required" type="xs:string">
<xs:annotation>
<xs:appinfo>
<jxb:property name="addressId"/>
</xs:appinfo>
</xs:annotation>
</xs:attribute>
</xs:complexType>
. . .
erzeugt neu eine Klasse Address (statt AddressType) mit einer Member Variablen addressId (statt id).
59
7.8 Externe Binding-Deklaration
Statt die gewünschten Java-Typen als Annotations ins Schema File zu schreiben, kann man deren
Deklarationen auch in einem separaten File ablegen. Dieses Bindings-File muss dann als Parameter beim
Erzeugen der Java Klassen mit angegeben werden (vgl. www.sws.bfh.ch/~amrhein/XML/JAXB/People):
xjc -b peopleBindings.xjb -d . -p people people.xsd
Ein solches Bindings-File könnte etwa so aussehen:
<jxb:bindings version="1.0" xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xs="http://www.w3.org/2001/XMLSchema" schemaLocation="People.xsd">
<!-- die hobby-Elemente der Personen sollen in (der „PersonType“ Klasse in)
einer Member-Variablen „hobbyList“ abgelegt werden. -->
<jxb:bindings node="//xs:complexType[@name='personType']">
<jxb:bindings node=".//xs:element[@name='hobby']">
<jxb:property name="hobbyList"/>
</jxb:bindings>
</jxb:bindings>
<!-- die addressRef Attribute in born sollen in addrRef unbenannt werden -->
<jxb:bindings
node="//xs:complexType[@name='personType']/xs:sequence/xs:element[@name='born']">
<jxb:bindings node=".//xs:attribute[@name='addressRef']">
<jxb:property name="addrRef"/>
</jxb:bindings>
</jxb:bindings>
<!-- alle firstname elemente sollen nach givenName umbenannt werden -->
<jxb:bindings node="//xs:element[@name='firstName']">
<jxb:property name="givenName"/>
</jxb:bindings>
<!-- die name-Elemente der Personen sollen in einer Klasse
<jxb:bindings node="//xs:complexType[@name='nameType']">
<jxb:class name="Name"/>
</jxb:bindings>
„Name“ abgelegt werden. -->
</jxb:bindings>
Dies bewirkt, dass die Klasse PersonType neu wie folgt aussieht:
PersonType
Name name;
BornType born;
List<String> hobbyList;
...
NameType getName();
void setName(NameType name);
...
60
7.9 Erzeugen von Schematas
Aus einer Java Klassen-Hierarchie lässt sich umgekehrt mit Hilfe von Annotationen das dazu passende
Schema generieren
•
•
•
•
@XmlType
@XmlElement
@XmlAttribute
...
--> erzeugen eines Schema Types (mit angegebener Reihenfolge)
--> erzeugen eines Schema Elements
--> erzeugen eines Schema Attributs
Der Aufruf zum Erzeugen eines Schemas lautet
schemagen.exe package\*.java
Ein Beispiel:
Die People Klasse
import java.util.*;
import javax.xml.bind.annotation.*;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(propOrder = {
"person",
"address"
})
@XmlRootElement(name = "people")
public class People {
@XmlElement(required = true)
protected List<Person> person;
@XmlElement(required = true)
protected List<Address> address;
public List<Person> getPerson() {
if (person == null) {
person = new ArrayList<Person>();
}
return this.person;
}
public List<Address> getAddress() {
if (address == null) {
address = new ArrayList<Address>();
}
return this.address;
}
}
61
Die Address Klasse
import javax.xml.bind.annotation.*;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "addressType", propOrder = {
"country",
"city"
})
public class Address {
@XmlElement(required = true)
protected String country;
@XmlElement(required = true)
protected String city;
@XmlAttribute(name = "id", required = true)
protected String addressId;
public String getCountry() {
return country;
}
public void setCountry(String value) {
this.country = value;
}
. . .
Das daraus generierte Schema
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema elementFormDefault="qualified" version="1.0"
targetNamespace="http://sws.people.org" xmlns:tns="http://sws.people.org"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="people">
<xs:complexType>
<xs:sequence>
<xs:element name="person" type="personType" maxOccurs="unbounded"/>
<xs:element name="address" type="addressType" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="addressType">
<xs:sequence>
<xs:element name="country" type="xs:string"/>
<xs:element name="city" type="xs:string"/>
</xs:sequence>
<xs:attribute name="id" type="xs:string" use="required"/>
</xs:complexType>
. . .
</xs:schema>
62
7.10 Schreiben von XML Daten ohne ObjectFactory
Zum Schreiben von Java Daten in ein XML Dokument braucht es entweder die (beim Binding automatisch
generierte) ObjectFactory Klasse oder ein jaxb.index File, in welchem die Namen der annotierten Java
Klassen stehen.
Das jaxb.index File muss die Klassen Namen (lokale Namen ohne .java oder .class Endung) enthalten und
liegt im gleichen Package wie die annotierten Java-Klassen. Mit einem solchen jaxb.index File können wir
Java Daten nach XML schreiben, ohne vorher ein Java Binding ausführen zu müssen.
Unser Beispiel
63
64
XSLT / XPath / XSL-FO
Die Transformations- und
Adressierungs-Sprachen für XML
http://www.w3.org/TR/xslt20
http://www.w3.org/TR/xpath20
http://www.w3.org/TR/xslfo20
65
Die XSL Sprachen
Einleitung, Motivation
XSL ist ein vom World Wide Web Consortium empfohlener Standard
W3C Recommendation von XSLT2.0 und XPath2.0, sowie Xquery 1.0 vom 23 Januar 2007
XSLT:
www.w3.org/TR/xslt20
XPath: www.w3.org/TR/xpath-functions
W3C Recommendation des XSL- Formatting Objects Teil vom Dezember 2006
XSL-FO: www.w3.org/TR/xsl11
Vergleich: CSS und XSL
Die W3C hat mit dem XSL Standard angefangen, bevor derjenige von CSS (Cascading Stylesheet Language)
festgelegt war. Warum gibt es überhaupt zwei Stylesheet Sprachen ?
CSS
XSL
Verwendung mit HTML
ja
nein
Verwendung mit XML
ja
ja
Transformations-Sprache
nein
ja
Syntax
CSS
XML
CSS ist für das Layouting von HTML-Dokumenten geeignet.
XSL ist angepasst an die Bedürfnisse von XML. XSL ist viel mächtiger, differenzierter und ausgefeilter als CSS.
XSL kann XML- Dokumente beliebig transformieren (also auch in andere Sprachen wie TeX, Java,
HTML/CSS, ... umformen)
Beide Sprachen können als Stylesheet für XML- Dokumente verwendet werden.
CSS und XSL benutzen das gleiche Formatierungs-Modell und beide Sprachen bieten die gleichen
Formatierungs-Möglichkeiten.
CSS Stylesheet für HTML Files
HTML benutzt vordefinierte (und darum allgemein bekannte) Tags:
<h1> Titel-Element
<p>
neuer Abschnitt,
...
In CSS wird definiert, wie die verschiedenen HTML Elemente darzustellen sind (Fonts, Farben, ...)
h1 { font-family: sans-serif;
font-size: 48pt }
Die h1 Header sollen mit einer sans-serif Schrift der Grösse 48
ausgegeben werden.
p { font-size: 8pt;
color: blue }
Alle <p> - Elemente sollen in einer 8pt Schrift in blauer Farbe
ausgegeben werden.
Die Browser kennen diese HTML Tags und verwenden ein CSS (Default-) Stylesheet für deren Darstellung.
66
XSL - Stylesheet für XML
XML benutzt keine vordefinierten Tags: <table> kann eine HTML Tabelle oder auch ein Möbelstück sein.
Im XML-Dokument steht nicht, wie die Daten dargestellt werden sollen.
Es braucht einen Mechanismus, welcher beschreibt, wie die Daten eines XML-Dokumentes dargestellt
werden sollen. XSL bietet diesen Mechanismus
Das XML Dokument soll nur die reinen Daten enthalten und (im Gegensatz zu HTML) nichts über deren
Darstellung (ob als Liste, Tabelle, oder als Fliesstext in Abschnitte unterteilt, ...) aussagen.
Mit Hilfe eines XSL Stylesheet wird festgelegt, wie diese Daten dargestellt werden sollen.
CSS bietet keine Möglichkeit, Daten zu transformieren oder in Tabellen, Listen, usw. zu verpacken.
XSL ist eine Sprache, welche
•
•
•
•
•
XML nach (X)HTML (oder einer beliebigen Sprache) übersetzen kann,
XML Daten sortieren oder filtern kann,
Spezielle Teile von XML Dokumenten adressieren kann,
XML Daten zum Beispiel abhängig vom Wert verschieden formatieren kann (negative Zahlen rot,
positive Zahlen schwarz, ...)
XML Daten für verschiedene Devices formatieren kann (Bildschirm, Drucker, ...)
XSL kann aus den XML Daten nicht nur (neue) XML- Files oder XHTML- Files, sondern beliebige Formate
erzeugen. XSL wird oft auch verwendet, um die Daten des XML- Dokuments anders zu strukturieren (zum
Beispiel passend zu einem anderen Schema oder DTD).
Obwohl XSL eigentlich aus drei Teilen mit drei verschiedenen Namen zusammengesetzt ist, wird oft einfach
für alles der Name XSL benutzt.
Eine Transformationssprache --> XSLT (XSL Transformation)
Eine Adressierungssprache --> XPath (Adressieren und Selektieren)
Eine Formatierungssprache --> XSL-FO (XSL Formatting Objects)
67
8 Die Transformations-Sprache XSLT
•
XSLT ist der wichtigste Teil des XSL Standards. XSLT wird benutzt, um XML Dokumente in andere
XML-, HTML-, ... Dokumente umzuformen.
•
XSLT kann auch neue, nicht im XML-Dokument enthaltene Daten-Elemente in das AusgabeDokument einfügen (zum Beispiel Formatier-Befehle), Elemente umsortieren oder weglassen
•
XSLT kann die XML-Knoten (zum Beispiel auch abhängig com Wert des Elementes) unterschiedlich
behandeln.
8.1 Wie funktioniert XSLT?
•
Ein XSL File besteht aus Regeln (Templates), welche bestimmen, wie die einzelnen Knoten eines
XML- Dokuments umgeformt werden sollen.
•
XSLT benutzt im Transformations-Prozess die Sprache XPath, um die zu einer Regel (Template)
passenden Knoten des XML Dokuments heraus zu filtern.
•
Wenn im XML- Dokument ein passender Knoten (match) gefunden wird, formt XSLT diesen Knoten
mit Hilfe der angegebenen Regel um, und schreibt das Resultat ins Ausgabe-Dokument.
•
Alle Text-Knoten des XML- Dokumentes, welche nicht zu einer Regel passen, werden unmodifiziert
in das Ausgabe-Dokument kopiert (vgl. Default Template Rules).
68
Das Beispiel Dokument: People.xml
<?xml version="1.0"?>
<people>
<person>
<name>
<firstName>Alan</firstName>
<lastName>Turing</lastName>
</name>
<born date="1912" addressRef="gbl"/>
<died date="1954" addressRef="gbc"/>
<profession>computer scientist</profession>
<profession>mathematician</profession>
<profession>cryptographer</profession>
<hobby>philosophy</hobby>
<hobby>biology</hobby>
</person>
...
Das vollständige XML- Dokument finden Sie auf dem Zusatzblatt.
Verbinden mit einem Stylesheet
Im XML Dokument kann mit Hilfe der Prozess-Instruktion
<?xml-stylesheet ... ?>
das zu verwendende XSL-Stylesheet angegeben werden.
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="http://www.abc.ch/mystyle.xsl"?>
<people>
<person>
<name>
<firstName >Alan</firstName>
<lastName>Turing</lastName>
</name>
...
Falls das XML-Dokument nicht statisch zu einem Stylesheet verbunden werden soll, kann zum Beispiel auch
ein kleines Javaskript geschrieben werden, welche die beiden Teile verbindet.
Die URL des Stylesheets kann relativ sein, also z.Bsp. href="mystyle.xsl" (wie im obigen Beispiel) als absolute
Adresse.
69
8.2 Der Aufbau eines Stylesheets: Templates
XSL benutzt Templates (Regeln), um zu bestimmen, wie die XML-Knoten umgeformt werden sollen.
Ein "match"-Attribut wird benutzt, um ein Knoten einem Template zuzuordnen.
<xsl:template match= Knoten >
Action
</xsl:template>
Der Befehl xsl:template legt zuerst die Liste (sequence) aller Knoten des XML-Dokuments an, welche durch
match adressiert werden. Die Elemente der Liste werden dann der Reihe nach gemäss den Regeln in Action
transformiert.
Die Sprache XPath dient hier zur exakten Adressierung der Knoten (welche Knoten sollen umgeformt
werden). Das Resultat von Action (der Transformation) wird in das Ausgabe-Dokument geschrieben.
Ein erstes XSL Beispiel: hello world
Da das Stylesheet selber auch ein XML Dokument ist, fängt es mit einer xml-Deklaration an:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8"/>
<xsl:template match="people">
hello world
</xsl:template>
</xsl:stylesheet>
•
Der xsl:stylesheet Befehl in der zweiten Zeile ist der eigentliche Start des Stylesheets.
•
Der Namespace URI für xsl muss genau so angegeben werden.
•
Das <xsl:template> Element definiert den Start eines Templates.
•
Das Template Attribute match="people" adressiert das (alle) people-Element(e) des XMLDokumentes.
•
Zwischen dem Start- und dem End-Tag von xsl:template stehen die Anweisungen, welche für das
adressierte Element auszuführen sind.
•
Das Tag <xsl:output> definiert, wie das Output File aussehen soll. Hier ist die Ausgabe ein UTF-8
codiertes Text- File.
•
Die Ausgabe des Stylesheets ist „hello world“.
70
Fortsetzung: hello world
Wir ergänzen das obige Beispiel um eine weitere Regel:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8"/>
<xsl:template match="people">
hello world
</xsl:template>
<xsl:template match="person">
I am here
</xsl:template>
</xsl:stylesheet>
Trotz der zusätzlichen Regel für person lautet die Ausgabe wiederum bloss hello world.
Damit die zweite Regel ausgeführt wird, müsste sie im people-Template explizit aufgerufen werden.
Fortsetzung: hello world
Wir löschen die people Regel aus dem obigen Beispiel:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8"/>
<xsl:template match="person">
I am here
</xsl:template>
</xsl:stylesheet>
In diesem Stylesheet fehlt die people-Regel. Das bedeutet, dass die Default Regel zum Einsatz kommt,
welche alle (direkten) Nachfolger des Root-Knotens (people) sucht, im Stylesheet nach Regeln dafür sucht,
und diese ausführt.
Da das people Element mehrere person und address Kinder hat, werden person und address Regeln gesucht
und ausgeführt. Die "person"- Regel wird für jedes gefundene <person>- Element ausgeführt.
Es gibt im Stylesheet keine Regel für address-Elemente, also wird die Default Regel ausgeführt.
Diese kopiert alle Text-Kinder von <address> (vgl. Kapitel: Default Template Regeln)
Die Ausgabe ist darum:
I am here
I am here
I am here
I am here
Great Britain London Germany Ulm USA Queens, NY Switzerland Basel Great
Britain Cambridge USA Princeton
71
8.3 Die wichtigsten XSLT Befehle
Es kann hier nur eine Auswahl von XSL Befehlen und Konstrukten behandelt werden.
Die ganze Liste der Befehle mit Beispielen finden Sie zum Beispiel auch unter
http://www.saxonica.com/documentation
xsl:apply-templates, xsl:call-template, xsl:for-each
Welches Kind als nächstes behandelt werden soll, kann explizit durch ein select-Attribut ausgewählt werden
<xsl:apply-templates select="person"/>
Der Befehl xsl:apply-templates
•
sucht im XML den angegebenen Pfad,
•
eine Regel dazu und
•
führt diese aus.
Der Befehl
<xsl:apply-templates/>
sucht alle Kind (-Elemente) des aktuellen Knotens und führt deren Templates aus.
(Mit "Kind" sind jeweils nur die direkten Nachfolger gemeint).
Beispiele:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8"/>
<xsl:template match="people">
<xsl:apply-templates select="person"/>
</xsl:template>
<xsl:template match="person">
I am here
</xsl:template>
</xsl:stylesheet>
Die gleiche Ausgabe erhalten wir durch Aufruf der folgenden Templates:
<xsl:template match="people">
<xsl:call-template name="templ1"/>
</xsl:template>
<xsl:template name=" templ1">
<xsl:apply-templates select="person"/>
</xsl:template>
<xsl:template match="person">
I am here
</xsl:template>
Oder als dritte Möglichkeit:
<xsl:template match="people">
<xsl:for-each select="person">
I am here
</xsl:for-each>
</xsl:template>
72
xsl:value-of
Das XSL <xsl:value-of> Element kann benutzt werden, um den Wert bestimmter Knoten auszugeben.
Beispiele:
<xsl:value-of select="lastName"/>
<xsl:value-of select="firstName"/>
<xsl:value-of select="hobby" separator=", " />
value-of berechnet den Wert eines Ausdrucks oder XML Knotens nach den folgenden Regeln:
•
•
•
•
Element: der Text-Inhalt eines Elementes, nachdem alle Referenzen aufgelöst sind.
Text: der Text selber
Attribut: der Wert des Attributes
<xsl:value-of select=" . "/> gibt den Wert des aktuellen Knotens zurück.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xhtml" encoding="UTF-8"/>
<xsl:template match="people" >
<html>
<head>
<title>Famous Scientists</title>
</head>
<body>
<h4> Famous Scientists</h4>
<xsl:apply-templates select="person"/>
</body>
</html>
</xsl:template>
Die Ausgabe der Transformation:
<html>
<head><title> Famous
Scientists</title></head>
<body>
<h4> Famous Scientists</h4>
<p>Turing Alan</p>
<p>Feynman Richard</p>
<p>Einstein Albert</p>
<p>Euler Leonhard</p>
</body>
</html>
<xsl:template match="person">
<p><xsl:apply-templates select="name"/></p>
</xsl:template>
<xsl:template match="name">
<xsl:value-of select="lastName"/>
<xsl:text> </xsl:text>
<xsl:value-of select="firstName"/>
</xsl:template>
</xsl:stylesheet>
•
Das obige XSL-Stylesheet erzeugt ein HTML-Dokument. Die HTML-Tags gehören nicht zu XSL. Sie
werden darum einfach in die Ausgabe kopiert (literal result element).
•
Das people Template verpackt den Output in ein HTML-Dokument, mit head, title und body. Danach
wird das person Template aufgerufen.
•
Das person- Template fängt einen neuen Abschnitt an (<p>) und ruft das name- Template auf.
•
Im name Template wird durch das <xsl:text> Element sichergestellt, dass zwischen dem Namen und
dem Vornamen ein Abstand (Space) eingefügt wird. <xsl:text>mytext</xsl:text> kopiert den String
mytext (unverändert) in das Ausgabe-Dokument (inkl. Whitespace).
73
Adressieren von Attributen
Für das Adressieren von Attributen wird das Zeichen @ verwendet.
<xsl:value-of select=“born/@date“/> liefert den Wert des date Attributes im born Element.
<xsl:template match="person">
<b><xsl:apply-templates select="name"/></b>
<xsl:text> </xsl:text>
<small>
( <xsl:value-of select="born/@date"/> <xsl: value-of select="died/@date"/>)
</small>
<p/>
</xsl:template>
Template mit Modes
Es ist möglich, für denselben Knoten mehrere verschiedene Templates zu definieren, die dann
kontextabhängig angewendet werden.
Der Aufruf des Templates sowie das Template selber erhalten ein mode Attribute. Damit können zum
Beispiel Inhaltsverzeichnisse, Querverweise oder verschiedene Darstellungen der gleichen Datenelemente
erzeugt werden.
<xsl:stylesheet version="1.0 "
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="people">
<html>
<head> <title> Famous Scientists</title> </head>
<body>
<h3> Famous Scientists, Mode</h3>
<h4> Table of Contents </h4>
<ul>
<xsl:apply-templates select="person" mode ="toc"/>
</ul>
<xsl:apply-templates select="person"/>
</body>
</html>
</xsl:template>
Der erste Durchgang wird durch
<xsl:template match="person"
mode="toc">
gebildet, der zweite durch
<xsl:template match="person">
<xsl:template match="person" mode ="toc">
<xsl:apply-templates select="name" mode="toc"/>
</xsl:template>
<xsl:template match="person">
<p>
<xsl:apply-templates select="name"/>
<small> (<xsl:apply-templates select="born/@date"/> <xsl:apply-templates select="died/@date"/> ) </small>
</p>
</xsl:template>
<xsl:template match="name" mode ="toc">
<li> <xsl:value-of select="lastName"/> </li>
</xsl:template>
<xsl:template match="name">
...
--> vgl. Beispiel vorher
</xsl:template>
</xsl:stylesheet>
74
xsl:if
<xsl:if test="lastName = 'Euler'"> ... </xsl:if>
filtert nur die Elemente mit lastName gleich Euler.
<xsl:if test="born/@date > 1900" > ... </xsl:if>
behandelt nur die Personen, welche nach 1900 geboren sind.
Im Template:
<xsl:template match="person">
<xsl:if test="born/@date > 1900 ">
<xsl:apply-templates select="name"/>
</xsl:if>
</xsl:template>
Die Bedingungen können mit Hilfe von and oder or verbunden werden.
<xsl:template match="person">
<xsl:if test="born/@date > 1850 and name/firstName != 'Alan' ">
<xsl:apply-templates select="name"/>
</xsl:if>
</xsl:template>
Das Template gibt nur die Namen der Personen aus, welche später als 1900 geboren sind.
Komplizierte Bedingungen können mit runden Klammern gruppiert werden:
( ... and ... ) or ( ... or ...
<xsl:template match="person">
<xsl:if test="born/@date > 1900 or (name/firstName = 'Leonhard'
and name/lastName='Euler')" >
<xsl:apply-templates select="name"/>
</xsl:if >
</xsl:template>
75
xsl:choose
Es gibt in XSL kein if-else Konstrukt. Anstatt eines if-else gibt es ein xsl:choose.
Verzweigungen werden aus xsl:when und xsl:otherwise zusammengesetzt.
<xsl:choose>
<xsl:when test="...">
...
</xsl:when>
<xsl:otherwise>
...
</xsl:otherwise>
</xsl:choose>
xsl:choose ist vergleichbar mit einem Switch-Case-Statement in Java oder C++.
Nur der erste when-Ast, welcher zu true evaluiert, wird ausgeführt.
Falls keiner der when-Tests zu true evaluiert, wird otherwise ausgeführt.
Ein Beispiel
<xsl:template match="people">
. . .
vgl. Beispiel vorher
<xsl:apply-templates select="person"/>
. . .
</xsl:template>
<xsl:template match="person">
<xsl: choose >
<xsl: when test="profession='mathematician' ">
<font color="blue">
<xsl:apply-templates select="hobby"/>
</font>
</xsl: when >
<xsl: when test="profession='cryptographer' ">
<font color="red">
<xsl:apply-templates select="hobby"/>
</font>
</xsl: when >
<xsl: otherwise >
<xsl:apply-templates select="hobby"/>
</xsl: otherwise >
</xsl: choose >
</xsl:template>
blau für Mathematiker
rot für Kryptologen
sonst schwarz
<xsl:template match="hobby">
<li><xsl:value-of select="."/></li>
</xsl:template>
76
xsl:sort
Um eine Sequenz von Knoten während der Transformation (nach einem gewählten Schlüssel) zu sortieren,
gibt es das sort Element:
<xsl:sort select="name/lastName"/>
xsl:sort kann entweder innerhalb eines <xsl:apply-templates> oder eines <xsl:for-each> Elements
vorkommen.
Das select-Attribut gibt an, nach welchem Schlüssel sortiert werden soll.
Falls numerisch sortiert werden soll (der Sortier-Schlüssel eine Zahl ist) muss dies mit dem data-type
Attribut angegeben werden:
<xsl:sort select = "..." data-type="number" />
Beispiel: Sortieren mit xsl:apply-templates oder mit xsl:for-each
<xsl:template match="people">
<html>
<head> <title> Famous Scientists, xsl:sort</title> </head>
<body>
<h3>Famous Scientists</h3>
<xsl: apply-templates select="person">
Alle Personen sortiert aufzählen
<xsl:sort select="name/lastName" order="ascending"/>
</xsl:apply-templates>
<br/>
<b>Hobbies of the Famous</b>
<ul>
<xsl: for-each select="person/hobby">
Alle Hobbies sortiert aufzählen
<xsl:sort select="." order="descending"/>
<li><xsl:value-of select="."/></li>
</xsl:for-each>
</ul>
</body>
</html>
</xsl:template>
Der apply-templates Befehl sammelt alle Knoten unter dem XPath (hier person). Der Sort-Befehl bewirkt,
dass alle person-Elemente vor deren Verarbeitung nach ihrem Namen sortiert werden.
Der for-each Befehl sammelt hier alle Hobby Elemente aller Personen und sortiert sie vor deren Ausgabe.
77
xsl:variable
In XSL können auch Konstanten definiert werden:
<xsl:variable name="ntext">
value_of_variable
</xsl:variable>
Der Wert der Konstanten ntext kann mit $ntext gelesen werden:
<xsl:value-of select="$ntext"/>
Der Wert von ntext kann dann nicht mehr verändert werden!
Dies sind keine Variablen, wie man sie in C++ oder Java kennt, sondern eher von der Art der Variablen wie
man sie im funktionalen Programmieren kennt (benannte Konstanten). Trotzdem können diese Variablen
sehr nützlich sein.
Beispiel: Berechnen einer gewichteten Summe
Wir nehmen das Beispiel einer Bestellung.
<?xml version="1.0"?>
<order>
<book>
<title>XML</title>
<price>24.20</price>
<quantity>2</quantity>
</book>
<book>
<title>UML</title>
<price>43.20</price>
<quantity>1</quantity>
</book>
<book>
. . .
</book>
</order>
Von dieser Bestellung wollen wir den Gesamt-Preis berechnen.
<xsl:template match="totalBetrag">
<xsl:variable name="tmp">
<tmpPrice>
<xsl:for-each select="book">
<item>
<xsl:value-of select="price * quantity"/>
</item>
</xsl:for-each>
</tmpPrice>
</xsl:variable>
<xsl:value-of select="sum($tmp/tmpPrices/item)"/>
</xsl:template>
Der Inhalt der Variablen tmp ist dann:
Der sum Befehl zählt diese Werte
zusammen.
78
Auflösen von key / keyRef Paaren mit Hilfe von Variablen
<xsl:template match="born">
<xsl:value-of select="../name/lastName"/>,
<xsl:value-of select="name()"/>
<xsl:text> </xsl:text>
<xsl:value-of select="@date"/>
<xsl:text> in </xsl:text>
<xsl:variable name="myref" select="@addressRef"/>
<xsl:value-of select="//address[@id=$myref]/city"/>
</xsl:template>
Address-ID in der
Variable abspeichern
die gefundene Adresse
ausgeben
Dieses Vorgehen ist allerdings nicht effizient. Wir werden später ein besseres Verfahren kennen lernen.
xsl:param
Beim Aufruf von Templates können Parameter übergeben werden:
<xsl:apply-templates select="title">
<xsl:with-param name="p1">
<xsl:value-of select="irgendein Wert"/>
</xsl:with-param>
</xsl:apply-templates>
Verwendung im Template:
<xsl:template match="title">
<xsl:param name="p1"/>
... verwenden von $p1 ...
</xsl:template>
Es können auch mehrere Parameter übergeben werden:
<xsl:template match="people">
<xsl:apply-templates select="person">
<xsl: with-param name="a1">
<xsl:value-of select="address[1]/city"/>
</xsl:with-param>
<xsl: with-param name="a2">
<xsl:value-of select="address[2]/country"/>
</xsl:with-param>
</xsl:apply-templates>
</xsl:template>
Der Wert der Parameter kann im Template (analog zu den Variablen) mit $a1, bzw. $a2 gelesen werden.
Ausserdem kann ein Default-Wert angegeben werden, falls im Aufruf ein Parameter fehlt.
<xsl:template match="person">
<xsl:param name="a1"/>
beide Parameter einlesen
<xsl:param name="a2">
Germany
Default Wert für a2
</xsl:param>
<xsl:value-of select="name/lastName"/>
<xsl:value-of select="$a1"/>
<xsl:value-of select="$a2"/>
</xsl:template>
79
xsl:for-each-group
Das folgende Template gibt alle Adressen gruppiert nach Ländern aus.
Adressen aus dem selben Land werden durch ein Komma separiert.
<xsl:template match="people">
<xsl:for-each-group select="address"
group-by="country">
<xsl:value-of select="country"/>:
<xsl:value-of select="current-group()/city" separator=", "/>
<br/>
</xsl:for-each-group>
</xsl:template>
Die Ausgabe ist dann:
Great Britain:
London, Cambridge
Germany:
Ulm
USA:
Queens, NY, Princeton
Switzerland:
Basel
Importieren von Stylesheets
Die Befehle
<xsl:import href="URI">
und
<xsl:include href="URI">
fügen das unter der angegebenen Adresse gefundene Stylesheet ein.
Der Pfad kann dabei relativ
<xsl:include href="ss.xsl"/>
oder absolut sein:
<xsl:include href="http://www.sowieso.ch/ss.xsl"/>
Eingefügte Stylesheets können selber ebenfalls wieder mit xsl:include oder xsl:import andere Stylesheets
einlesen (Vorsicht: Zyklen!).
Beim Transformieren werden sowohl die Regeln des importierten als auch des importierenden Stylesheets
angewandt.
Durch <xsl:import> werden die Regeln beider Stylesheets benutzt. Falls sich Regeln widersprechen wird die
Regel des lokalen Stylesheets benutzt.
<xsl:include> kopiert den Inhalt des angegebenen Stylesheets in das einlesende Stylesheet. Falls sich Regeln
widersprechen (durch Templates mit gleichen Namen oder gleichen Pattern), tritt normalerweise ein Fehler
auf.
80
9 Grundlegendes zu XSLT
9.1 Default Template Regeln
Was geschieht mit den Knoten, wenn es im Stylesheet dafür kein Template gibt?
Auch wenn im Stylesheet keine explizite Regel für die Behandlung eines Knotens angegeben ist, gibt es
(abhängig vom Typ des Knotens) eine Regel für diesen Knoten.
Es gibt sieben Typen von Knoten in XML-Dokumenten
•
Root-Knoten
•
Element-Knoten
•
Attribut-Knoten
•
Text-Knoten
•
Kommentar-Knoten
•
Verarbeitungs-Anweisungen (Processing-Instructions)
•
Namespace-Knoten
Für jeden Knoten-Typ gibt es eine Default Template Regel, welche angibt, was mit einem solchen Knoten
passieren soll, falls im Stylesheet keine Regel dafür vorhanden ist.
Text- und Attribut-Knoten
Von Text- und Attribut-Knoten wird der Wert des Textes (des Attributes) in das Ausgabe-Dokument kopiert.
Als XSL-Template sieht dies wie folgt aus:
<xsl:template match= " text() | @* ">
<xsl:value-of select="."/>
</xsl:template>
Wir können uns vorstellen, dass in jedem Stylesheet diese Regel mit drin steht (auch wenn sie nicht explizit
vorhanden ist).
Die folgende Regel:
<xsl:template match="name">
<xsl:apply-templates select="firstName"/>
<xsl:text> </xsl:text>
<xsl:apply-templates select="lastName"/>
</xsl:template>
sagt zum Beispiel nichts darüber aus, was mit dem (Text-) Inhalt des firstName-, bzw. lastName-Knotens
(Alan, Euler, Turing, ...) geschehen soll (falls es kein entsprechendes Template gibt).
Falls es für firstName oder lastName keine Regel im Stylesheet gibt, wird automatisch die Default-Regel
angewandt, welche den Text (Alan, Euler, Turing, ...) unverändert in die Ausgabe kopiert.
81
Root- und Element-Knoten
Vom Root- und von allen Element-Knoten werden per Default die Template-Regeln aller Kindknoten
aufgerufen.
Als XSL-Template sieht dies wie folgt aus:
<xsl:template match= " / | * ">
<xsl:apply-templates/>
</xsl:template>
Falls es also im Stylesheet keine Regel für das Root-Element oder für "/" gibt, wird die Regel für dessen
Kind-Knoten gesucht und ausgeführt.
Falls es im Stylesheet für einen beliebiges Element keine Regel gibt, werden ebenfalls dessen Kind-Knoten
gesucht und deren Regeln ausgeführt.
Kommentare und Verarbeitungsanweisungen
Falls es keine explizite Regel dafür gibt, werden Kommentare und Processing Instructions nicht ausgegeben.
Als XSL-Template sieht dies wie folgt aus:
<xsl:template
match= "processing-instructions() | comment()" />
Es gibt keine Adressierung (keinen XPath Ausdruck) für Namespace-Knoten.
Kommentare, Namespaces und Verarbeitungsanweisungen machen im Ziel Dokument normalerweise
keinen Sinn mehr.
82
9.2 Template Driven vs. Data Driven Stylesheets
In allen Beispielen, welche wir bisher betrachtet haben, bestimmt das Template im Stylesheet, welche Regel
als nächstes benutzt werden soll. Diesen Programmierstil bezeichnet man als Template-Driven. Dies ist
immer dann sinnvoll, wenn die Source Dokumente stark struktuiert sind. Daten-bezogene XML- Dokumente
sind üblicherweise stark strukturiert.
Anders sieht es aus, wenn die XML Dokumente keinen strikten Aufbau haben. Dies findet man zum Beispiel
in Dokumenten, welche Texte, Briefe oder Webseiten Inhalte beschreiben.
Ein Beispiel XML Dokument, ohne strikten Aufbau
<?xml version='1.0'?>
<book-review>
<title>This Book</title> by <author>This Author</author>,
published by <publisher>The Publisher</publisher> on <date>date</date>,
is indeed a good book. However, the book titled <title>
Bad Book</title> by the same publisher is very bad. The reviewer
is left to wonder whether this is because <title>Bad Book</title>
was written by <author>Bad Author</author>, or because it was
published on <date>date</date>.
</book-review>
Für solche Dokumente ist es sehr schwierig, im Stylesheet die Reihenfolge der zu benutzenden Templates
festzulegen. Viel einfacher ist es, das Stylesheet Data-Driven zu implementieren: d.h. xsl:apply-templates
ohne select-Attribut. Im folgenden Stylesheet bestimmt allein das XML Dokument, in welcher Reihenfolge
die Regeln aufgerufen werden.
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html><body>
<xsl:apply-templates/>
</body></html>
</xsl:template>
<xsl:template match="book-review">
<p> <xsl:apply-templates/> </p>
</xsl:template>
<xsl:template match="title">
<span style="font-weight:bold">
<xsl:value-of select="."/>
</span>
</xsl:template>
Die Ausgabe
<xsl:template match="author">
<span style="font-style:italic">
<xsl:apply-templates/>
</span>
</xsl:template>
<xsl:template match="publisher">
<span style="color:blue">
<xsl:apply-templates/>
</span>
</xsl:template>
...
</xsl:stylesheet>
Die beiden Modelle (Template-Driven und Data-Driven) lassen sich in einem Stylesheet nach Bedarf
mischen.
83
10 XPath: Die XSL Adressierungssprache
Die Templates im Stylesheet können nur dann richtig (an der richtigen Stelle) angewandt werden, wenn die
Adressierung (match) korrekt ist.
XSL muss beliebige Knoten des XML-Dokumentes adressieren (identifizieren) können.
Dafür benutzt XSL die Sprache XPath.
Die W3C Spezifikation für XPath finden Sie unter www.w3.org/TR/xpath20/
Einige Beispiele
name
alle <name> Kinder des aktuellen Knotens
name/firstName
alle <firstName> Kinder aller
/
der Root Knoten des Dokumentes
.
der aktuelle Knoten
..
der Vorgänger (Parent) des aktuellen Knotens
//name
alle <name> Elemente des Dokumentes
.//name
alle <name> Nachfolger (direkte und indirekte) des aktuellen Knotens
<name> Kinder des aktuellen Knotens
//name/firstName alle <firstName> Elemente, welche Nachfolger von <name> sind.
//
ist die Abkürzung für „descendant-or-self“,
d.h. für alle direkten und indirekten Nachfolger, sowie den Knoten selber.
10.1 Die XPath Syntax
•
Die XPath-Syntax sieht ähnlich aus wie die übliche Filesystem-Adressierung.
•
Das Pattern matching ist abhängig vom Kontext: Ein XPath Ausdruck kann verschiedene Knoten
bezeichnen, abhängig von der Stelle im Dokument, in welchem er steht.
•
XPath findet alle passenden Knoten. Sollen nur gewisse Knoten aus dem Pfad selektiert werden,
kann der Pfad (durch Prädikate) eingeschränkt werden.
•
Ein XPath ist absolut, falls er mit einem Slash (" / ") anfängt, z.B. /person
•
Ein Pfad ist zusammengesetzt auf einer Reihe von Schritten, welche durch "/" getrennt sind:
people/person/born
•
Attribute werden durch "@" markiert.
born/@addressRef
•
Pfade können kombiniert werden durch "|" (Auswahl)
name/firstName | profession | hobby
84
Wildcards
Pfade können die Wildcards *, @* und node() enthalten.
*
@*
node()
•
•
•
selektiert alle Elemente
selektiert alle Attribute
selektiert alle Knoten
Attribute, Text-Knoten, Kommentare oder Verarbeitungsanweisungen (Processing-Instructions)
werden durch den Stern (*) nicht selektiert.
@* selektiert nur Attribute
node() selektiert alle Knoten: Elemente, Attribute, Text-Knoten, Kommentare,
Verarbeitungsanweisungen, …
Beispiele
//*
/*
str/*/title
//*/@id
//*/@*
findet alle Elemente im Dokument
alle Kinder von Root (also das Root-Element)
alle <title> Enkel von str
alle Attribute mit Namen id
alle Attribut Knoten im Dokument.
XPath Prädikate
XPath kann auch filtern. Dazu wird im select-Attribut zum Pfad ein Prädikat mit angegeben
<xsl:apply-templates
select="person[name/firstName != 'Alan']"/>
Mögliche Filter-Operatoren sind:
=
gleich
!=
ungleich
<
kleiner als
>
grösser als
XPath Filter können xsl:if Statements ersetzen und sind oft eleganter und effizienter.
Prädikate können in select Attributen, aber auch in match Attributen verwendet werden:
Die Regel
<xsl:template match=“person[@id]“>
gilt nur für person-Elemente, welche ein id-Attribut haben.
(Vorsicht: für die anderen person-Elemente benötigen Sie also eine separate Regel!)
XPath Prädikat Beispiele:
born[ @addressRef = 'gbc' ]
alle <born> Kinder, welche ein addressRef Attribut mit Wert "gbc" haben
died[ @addressRef ]
alle <died> Kinder, welche ein addressRef Attribut haben
person [born/@date > 1900 ]/name
alle Namen von Personen, welche später als 1900 geboren sind
name[last()]
das letzte <name> Kind des aktuellen Knotens
85
Zu beachten ist, dass die Adressierungen vom Kontext abhängig sind:
died[@addressRef] gibt nur dann ein Element zurück, wenn der aktuelle Knoten (Kontext) ein oder
mehrere died Kinder hat, welche ein addressRef Attribut haben.
Doppelte Einschränkungen (nacheinander ausgeführt)
name[last()][@addressRef] gibt das letzte name-Element zurück, falls dieses ein addressRefAttribut hat.
name[@addressRef][last()] gibt das letzte name-Element zurück, welches ein addressRef-Attribut
hat.
XPath Schritte
Jeder Schritt im Pfad ist ein Bezeichner, ein Wildcard oder ein Prädikat.
<xsl:template match="person">
<xsl:apply-templates select="*[@date]"/>
</xsl:template>
<xsl:template match="born | died">
<xsl:value-of select="../*/lastName"/>,
<xsl:value-of select="name(.)"/>: <xsl:value-of select="@date"/>
<xsl:variable name="var" select="@addressRef"/>
<xsl:apply-templates select="//*[@id=$var]/city"/>
<br/>
</xsl:template>
<xsl:template match="city">
in
<xsl:value-of select="."/>
</xsl:template>
Die verwendeten
Bezeichner
--> people, name, @date, ...
Wildcards
-->
*, @*, node()
Prädikate
•
Der Pfad *[@date] wählt alle Kind-Knoten von person aus, welche ein date Attribut haben.
•
Der Pfad // * [@id = $var] wählt alle Elemente Dokumentes aus, welche ein id-Attribut haben,
welches den gleichen Wert hat wie var (bzw. den gleichen Wert wie @addressRef). Gefunden
werden die address Elemente und es wird der Inhalt des <city>-Elements ausgegeben.
Weitere Beispiele von Pfaden mit Prädikaten:
//name/*
alle Kinder von name
//name/*[@*]
alle Kinder von name, die ein Attribut haben
//name/*[*]
alle Kinder von name, welche keine Blätter sind
//*[@*]
alle Elemente, die ein Attribut haben
//person[*/@id]/name
alle name Kinder von person Elementen, die ein Kind mit einem id Attribut haben
//*[@*]/*
alle Kinder von Elementen, die ein Attribut haben
86
87
10.2 Adressierungs-Achsen
preceding-sibling sind alle früheren, following-sibling alle im Dokument nachfolgenden Geschwister-Knoten
von self. Die Begriffe preceding und following beziehen sich auf die Reihenfolge im XML-Dokument.
following sind alle Knoten, welche im XML-Dokument hinter dem End-Tag des self-Knoten stehen.
preceding sind alle Knoten, die vor dem Start-Tag des self-Knoten stehen und keine ancestors sind.
Beispiele:
child::people
alle <people>-Kinder des aktuellen Knotens
following-sibling::profession alle <profession>- Geschwister des aktuellen Knotens, welche im XMLFile später auftreten.
descendent::*
alle (direkten und indirekten) Nachfolger des aktuellen Knotens
ancestor::*/child::person alle <person> Kinder aller Vorgänger Knoten des aktuellen Knotens
Für die wichtigsten Adressierungs-Achsen existieren (die bereits bekannten) Abkürzungen:
child
(leer)
parent
..
self
.
descendant-or-self
//
Die Bezeichnung "child::" kann immer weggelassen werden.
/child::people/child::person/child::profession
=
/people/child::person/profession
=
/people/person/child::profession
self wird vor allem im Zusammenhang mit value-of benutzt:
<xsl:value-of select=" self::* "/> ist gleichbedeutend mit <xsl:value-of select=" . "/>
descendant-or-self kann absolut oder relativ verwendet werden:
<xsl:apply-templates select= "//lastName”/>, d.h. alle lastName Elemente des Dokuments
<xsl:apply-templates select= "person//lastName”/>, d.h. nur die lastName Nachfolger von person.
Das Template <xsl:apply-templates select= "//lastName[string-length(text()) > 6]/.. "/>
findet zum Beispiel alle parent Knoten von allen lastName Elementen, deren Text-Inhalt mehr als 6
Buchstaben lang ist.
88
10.3 Die wichtigsten XPath Funktionen
Die W3C Recommendation zu XQuery 1.0 and XPath 2.0 Functions and Operators finden Sie unter
http://www.w3.org/TR/xquery-operators
Ausserdem finden Sie alle von saxon8 unterstützten XPath 2.0 Funktionen und Operatoren unter
http://www.saxonica.com/documentation
Einige Beispiele
boolean( obj ), number( obj ), string( obj )
konvertiert das object obj falls möglich zu einem boolean/number/string ...
boolean(0) ist falsch, boolean(5) ist wahr boolean(NaN) ist falsch, also auch
boolean(number('a')). (NaN steht für „not a Number“.)
boolean not (value)
gibt true zurück, falls value zu false evaluiert (und umgekehrt).
Funktionen auf Strings
String concat( String s1, String s2, String s3, ... )
setzt die Strings s1, s2, s3, ... zusammen
String substring(string s1, double start, double length)
gibt den Teil-String von s1 ab Position start mit Länge length zurück.
boolean contains( string s1, string s2 )
gibt true zurück, falls s2 ein Substring von s1 ist
number string-length( string )
gibt die Länge des Strings zurück
string translate( string s, string s1, string s2 )
ersetzt alle Vorkommnisse von s1 in s durch s2.
boolean matches(string, pattern)
gibt true zurück, falls der gegebene String das Pattern erfüllt.
String replace(string1, pattern, string2)
ersetzt in string1 alle Teile, welche das pattern erfüllen durch string2.
Numerische Funktionen
number abs(number), number avg(number), number max(items), number min(items)
Absolutwert, Durchschnitt, Maximum, Minimum
number round(number), number ceiling(number), number floor(number)
Runden, Aufrunden, Abrunden
atomicType sum(atomicType)
summiert die Werte aller Werte auf.
atomicType ist muss hier eine Zahl oder eine Zeitdauer (duration) sein.
Falls ein Argument-Knoten von sum keine Zahl oder Zeitdauer ist, ist der Rückgabe-Wert
"NaN" (Not a Number).
sum(//number) summiert alle Werte unter //number,
sum(//book/quantity) berechnet also zum Beispiel die Anzahl vorhandener Bücher.
String format-number(value, pictureString)
formatiert den value gemäss dem pictureString. format-number(500100, ' #.0 ')
Ausserdem existieren die normalen Grundoperationen +, -, *, mod und div.
89
Funktionen auf Sequenzen (Listen von Knoten)
number last()
berechnet die Anzahl Knoten im Kontext
//person[1] gibt die erste, //person[last()] gibt die letzte Person zurück.
number position()
gibt die Position des Kontext Knotens in der aktuell verarbeiteten Sequenz zurück.
Während dem Abarbeiten der Sequenzen wir die Position laufend aktualisiert.
Falls die Personen gefiltert oder sortiert werden, liefert position dennoch eine normale
aufsteigende Nummerierung.
number count( items)
zählt die Knoten in der Sequenz items.
z.B. count(//person) gibt 4, count(//address) gibt 6 zurück.
remove(...), insert-before(...), reverse(...), subsequence(...)
sind Funktionen auf Sequenzen zum Löschen, Einfügen, Umdrehen und Zerteilen der
Sequenzen.
boolean empty(items)
true, falls items eine leere Sequenz ist.
Datum und Zeit
date current-date(), dateTime currentTime()
gibt das aktuelle Datum, bzw. die aktuelle Zeit zurück.
Dieses kann nachher durch format-date(), bzw. format-dateTime() formatiert werden.
String format-date(date, pictureString)
formatiert das Datum date gemäss pictureString.
format-date(current-date(), ' [D]-[M]-[Y] ')
for Ausdrücke
Mit Hilfe von „for“ Ausdrücken ist es möglich, in einem XPath Aufruf über alle Elemente der ganzen Sequenz
zu iterieren. Die Syntax benutzt eine Iterator-Variable (hier z.B. x).
Aus einem
for $x in E return result
evaluiert result für jedes Element der Sequenz E
<xsl:value-of
select="sum(for $x in book
return $x/price * $x/quantity)"/>
summiert die price * quantity Werte aller book Elemente auf.
90
Einlesen von XML Dokumenten
Die Funktion
document($srcval )
lädt das an der Adresse (URI) srcval gefundene Dokument.
Durch Definition einer (globalen) Variable "input" kann folgendermassen auf die Elemente des Files
"Daten.xml" zugegriffen werden.
<xsl:variable name="input" select="document('Daten.xml')/person"/>
Diese Variable kann dann benutzt werden um die Namen der Personen im Daten File zu lesen:
<xsl:value-of select="$input/name"/>
xsl:key und key()-Funktion
Durch xsl:key kann eine Indexierung (Schlüssel) von Elementen angelegt werden.
Dies erzeugt eine Hash-Tabelle, über deren Schlüssel auf die Werte zugegriffen werden kann.
Die key-Funktion hat zwei Auswirkungen: Sie kann den xsl-Code vereinfachen und sie kann die Performance
positiv beeinflussen, indem der Parser eine Indexierung für alle key-Werte anlegt.
Alle ../born/@date-Attribute werden als Schlüssel für die name-Elemente abgelegt:
<xsl:key name="myKey1" match="name" use="../born/@date"/>
Alle hobby-Elemente werden unter ihrem Anfangsbuchstaben abgelegt:
<xsl:key name="myKey2" match="hobby" use="substring(.,1,1)"/>
Die XPath Funktion key() gibt dann die entsprechenden Elemente zurück.
<xsl:apply-templates select="key('myKey1','1912')"/>
gibt alle name-Knoten mit Geburtstjahr 1912 zurück.
<xsl:apply-templates select="key('myKey2','p')"/>
gibt alle hobby-Knoten mit Anfangsbuchstabe "p" zurück.
91
Ein Beispiel
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<-- indexieren aller Personennamen nach Datum -->
<xsl:key name="nameKey" match="name" use="../*/@date"/>
<-- indexieren aller Hobbys nach Anfangsbuchstaben -->
<xsl:key name="hobbyKey" match="hobby" use="substring(.,1,1)"/>
<-- indexieren aller Adressen nach ihrer id -->
<xsl:key name="addrKey" match="address" use="@id"/>
<xsl:template match="people">
<html>
<body>
<!-- Geburtsjahr und Ort, absteigend sortiert auflisten -->
<ul>
<xsl:for-each select="//*[@date]">
<xsl:sort select="@date" order="descending"/>
<li>
<xsl:value-of select="key('nameKey', @date)/firstName"/>
<xsl:text> </xsl:text>
<xsl:value-of select="key('nameKey', @date)/lastName"/>
<xsl:if test="key('addrKey', @address)">
<xsl:text>, </xsl:text>
<xsl:value-of select="name()"/> in
<!-- zum Datum die entsprechende Adresse ausgeben. -->
<xsl:value-of select="key('addrKey', @address)/country"/>
<xsl:text> </xsl:text>
<!-- und das Datum selber -->
<xsl:value-of select="@date"/>
</xsl:if>
</li>
</xsl:for-each>
</ul>
<!-- alle Hobbies die mit 'p' anfangen auflisten -->
<p>
<xsl:value-of select="key('hobbyKey','p')" separator=", "/>
</p>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
92
xsl:function
Beispiele von selber definierten XSL Funktionen
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"
xmlns:cs="http://www.isbe.ch/catalogFunctions"
xmlns:xs='http://www.w3.org/2001/XMLSchema'>
<xsl:function name="cs:substring">
<xsl:param name="str" as="xs:string"/>
<xsl:param name="n" as="xs:integer"/>
<xsl:sequence select= "if( string-length($str) >=$n )
then substring($str,1,$n) else error() "/>
</xsl:function>
<xsl:function name="cs:numberOfChildren">
<xsl:param name="node"/>
<xsl:sequence select="count($node/*)"/>
</xsl:function>
...
Solche selber definierten Funktionen können dann folgendermassen benutzt werden:
<xsl:value-of select="cs:numberOfChildren(/people)"/>
93
11 XSL-FO Einführung
XSL-FO
... bildet zusammen mit XSLT und XPath die XSL (eXtensible Stylesheet Language)
... ist eine XML Applikation
... definiert das visuelle Layout-Modell
... wird mit Hilfe von einem Transformations-Tool (FOP, XEP, ...) nach PDF, PostScript, ...
transformiert
Dabei werden normalerweise keine FO-Dokumente direkt geschrieben, sondern die XML Daten werden mit
Hilfe eines Stylesheets nach XSL-FO übersetzt, und dann mit Hilfe eines FO-Transformations-Tools nach
Postscript, PDF, ... transformiert.
11.1.1
Ein einfaches Beispiel
<?xml version="1.0"?>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="only"
page-width="5.5cm" margin-left="1cm">
<fo:region-body/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="only">
<fo:flow flow-name="xsl-region-body">
<fo:block font-size="18pt">
A small
<fo:external-graphic src="fo.jpg"/>
example
</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
11.2 Die wichtigsten FO Elemente
Es gibt 56 XSL-FO Elemente
fo:block, fo:block-container, fo:character, fo:external-graphic, fo:flow,
fo:footnote, fo:inline, fo:layout-master-set, fo:leader, fo:list-block,
fo:list-item, fo:list-item-body, fo:list-item-label, fo:page-number,
fo:page-sequence, fo:region-after, fo:region-before, fo:region-body,
fo:root, fo:simple-page-master, fo:table-and-caption, fo:table, fo:tablebody, fo:table-caption, fo:table-cell, fo:table-column, fo:table-footer,
fo:table-header, fo:table-row, . . .
Die Elemente von XSL-FO definieren die Struktur oder den Aufbau (Unterteilung in Abschnitte, Blöcke, TextFelder, Bilder, ...) des Ausgabe- Dokuments. Die Attribute definieren das (lokale) Aussehen.
Das Root Element
XSL-FO Dokumente sind XML Dokumente. Darum beginnen FO-Dokumente mit der XML-Deklaration:
<?xml version="1.0"?>
XSL-FO Dokumente haben als Root-Element einen fo:root Knoten, in welchem der fo Namespace deklariert
werden muss: xmlns:fo="http://www.w3.org/1999/XSL/Format"
95
Das Layout einer Seite
Eine Seite ist aufgeteilt in die fünf Bereiche region-before, region-after, region-start, region-end und regionbody. Diese sehen in der üblichen Lesart (von links nach rechts, von oben nach unten) wie folgt aus:
Normalerweise sind die Randbereiche (region-before, region-after, ...) reserviert für statische
(wiederkehrende) Ausgaben (Logos, Adresse, Seitenzahl, ...), während der eigentliche Inhalt der Seite im
Zentralbereich (body) ausgegeben wird.
Die einzelnen Bereiche können dann weiter aufgeteilt werden in Blöcke (zum Beispiel durch fo:block,
fo:table, fo:list-block, ...).
Das Layout Master Set
Das layout-master-set enthält alle Seiten-Vorlagen für die verschiedenen Seiten-Arten wie Titelseiten, linke
und rechte Seiten, ...
<fo:layout-master-set>
<fo:simple-page-master
master-name="first"
page-height="297mm" page-width="210mm"
margin-top="15mm" margin-bottom="15mm"
margin-left="20mm" margin-right ="15mm">
<fo:region-body margin-top="20mm"/>
<fo:region-before extent="15mm" region-name="fBefore"/>
</fo:simple-page-master>
<fo:simple-page-master
master-name="odd"
. . .
</...>
</fo:layout-master-set>
Die einzelnen Seiten-Vorlagen sind dann verpackt in verschiedene page-master Elemente.
Das layout-master-set Element hat keine Attribute, ist immer ein Kind-Knoten vom root-Knoten und hat als
(einzig mögliche) Kinder einen (oder mehrere) simple-page-master oder page-sequence-master Knoten.
Mit dem simple-page-master Knoten werden die Seitenränder (margin) und ev. die Papiergrösse festgelegt.
Weiter wird definiert, in wie viele Bereiche (regions) die Seite aufgeteilt werden soll (region-body, regionbefore, region-after, ...) . Die normalen A4 Seitengrösse ist page-height="29.7cm" und page-width="21cm"
Pro Seitentyp (Titelseite, Index-Seite, Inhaltsverzeichnis, ...) wird je eine separate Seiten-Vorlage definiert.
96
Die Platz-Verteilung für die Regionen
<fo:root xmlns:fo= "http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="simple" page-height="10cm"
page-width="9cm" margin-top="1.5cm" margin-bottom="1.5cm"
margin-left="1cm" margin-right="1cm">
<fo:region-body margin-top="2cm" margin-bottom="1.5cm"
background-color="#EEEEEE" />
<fo:region-before extent="1cm" background-color="yellow"/>
<fo:region-after extent="1cm" background-color="yellow"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="simple">
<fo:static-content flow-name="xsl-region-before">
<fo:block font-size="12pt">
Hier ist der Platz für das Region- Before
</fo:block>
</fo:static-content>
<fo:static-content flow-name="xsl-region-after" >
<fo:block font-size="12pt">
Region-After ist oberhalb vom unteren Rand
</fo:block>
</fo:static-content>
<fo:flow flow-name="xsl-region-body">
<fo:block font-size="20pt" padding="0.5cm">
Region Body Region Body Region Body ...
</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
97
Definieren und Benutzen von verschieden Seiten-Typen
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<!-- Definition der ersten Seite-->
<fo:simple-page-master master-name="erste" margin-left="5cm" margin-right="5cm“
margin-top="2cm" margin-bottom="3cm">
<fo:region-body margin-top="3cm" margin-bottom="2cm"/>
<fo:region-before extent="3cm" region-name="first-before"/>
<fo:region-after extent="1.5cm" region-name="first-after"/>
</fo:simple-page-master>
<!-- Definition der restlichen Seiten-->
<fo:simple-page-master margin-bottom="3cm" margin-left="5cm" margin-right="5cm“
margin-top="5cm" master-name="restliche">
<fo:region-body margin-top="2.5cm" margin-bottom="2cm"/>
<fo:region-before extent="2.5cm" region-name="rest-before"/>
<fo:region-after extent="1.5cm" region-name="rest-after"/>
</fo:simple-page-master>
<!-- Wann soll welche Definition benutzt werden -->
<fo:page-sequence-master master-name="global">
<fo:repeatable-page-master-alternatives>
<fo:conditional-page-master-reference master-reference="erste"
page-position="first"/>
<fo:conditional-page-master-reference master-reference="restliche"
page-position="rest"/>
<!-- default -->
<fo:conditional-page-master-reference master-reference="restliche"/>
</fo:repeatable-page-master-alternatives>
</fo:page-sequence-master>
</fo:layout-master-set>
<!-- Inhalt der verschiedenen Seiten -->
<fo:page-sequence initial-page-number="1" master-reference="global">
<fo:static-content flow-name="first-before">
<fo:block> Hier ist der Titel der ersten Seite </fo:block>
</fo:static-content>
<fo:static-content flow-name="rest-before">
<fo:block> Der Titel der restlichen Seiten </fo:block>
</fo:static-content>
<fo:static-content flow-name="first-after">
<fo:block> Hier ist die Fusszeile der ersten Seite </fo:block>
</fo:static-content>
<fo:static-content flow-name="rest-after">
<fo:block> Hier ist die Fusszeile der restlichen Seiten </fo:block>
</fo:static-content>
<fo:flow flow-name="xsl-region-body">
... hier kommt der Dokument Inhalt ...
</fo:flow>
</fo:page-sequence>
</fo:root>
98
Der Dokument Inhalt: fo:flow
fo:flow ist ein Kind-Knoten von fo:page-sequence und enthält eine beliebige Anzahl von Blöcken mit Text,
Tabellen, Listen und Bildern.
Mit Hilfe des flow Elementes wird der Dokument-Inhalt (der Fliesstext) definiert.
fo:flow hat als mögliche Kind-Elemente:
•
fo:block (neuer Abschnitt)
•
block-container (neuer Abschnitt an fixem Ort)
•
table, table-and-caption (Tabelle)
•
list-block (Listen)
Ein Beispiel
<fo:flow flow-name="xsl-region-body">
<fo:block font-size="16pt">
This is the document content. This is the
<fo:external-graphic src="cup.gif"/>
document content. This is the...
</fo:block>
</fo:flow>
Die statischen Bereiche: fo:static-content
In den Randbereichen befindet sich normalerweise wiederkehrende Information (Überschriften, Fussnoten,
Seitenzahlen, ...)
<fo:static-content flow-name="xsl-region-after">
<fo:block text-align="end" font-size="10pt">
Seite <fo:page-number/>
</fo:block>
</fo:static-content>
Abschnitte, Paragraphen, ... fo:block
fo:block erzeugt einen Bereich (ein oder mehrere Zeilen lang.
fo:block wird benutzt, um zusammengehörende Ausgabe-Elemente (ein Textabschnitt, eine Titelzeile, eine
Tabelle, ...) zu gruppieren.
<fo:block font-size="36pt">
Chapter 1: Introduction
</fo:block>
99
Fest positionierte Felder: fo:block-container
Ein fo:block-container Element kann an beliebiger Stelle auf des Seite positioniert werden
<fo:block-container border-color="black"
border-style="solid" border-width="1pt"
height="1cm" width="4cm" padding="5pt"
top="9.5cm" left="12cm" position="absolute" >
<fo:block text-align="start" line-height="10pt"
font-family="sans-serif" font-size="10pt">
Hier ist ein Text
</fo:block>
</fo:block-container>
Format Änderungen in Zeilen: fo:inline
Während mit fo:block ein neuer Abschnitt (eine neue Zeile) anfängt, kann fo:inline benutzt werden für
Format-Änderungen innerhalb eines Blockes (einer Zeile).
Typischerweise werden deshalb Blöcke entweder durch fo:block oder durch fo:inline Elemente unterteilt, je
nachdem ob ein neuer Absatz erwünscht wird oder nicht.
Einbinden von Bildern: fo:external-graphic
Mit Hilfe von fo:external-graphic wird ein Bild in ein Dokument eingebettet.
Mögliche Bildformate sind GIF und JPEG, ...
<fo:block>
Look at this!
<fo:external-graphic src="cup.jpg"/>
</fo:block>
100
Erstellen von Listen, Aufzählungen, ...
Jedes fo:list-item Element enthält ein fo:list-item-label und ein fo:list-item-body Element.
Ohne das start-indent Attribut im fo:list-item-body fängt der Inhalt der Auflistung am linken Rand an, und
überschreibt das eventuell vorhandene Aufzählungs-Zeichen.
<fo:list-block>
<fo:list-item>
<fo:list-item-label>
<fo:block>a)</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="body-start()">
<fo:block>Dies ist das erste ....</fo:block>
</fo:list-item-body>
</fo:list-item>
<fo:list-item>
<fo:list-item-label>
<fo:block>·</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="body-start()">
<fo:block>Dies ist das zweite ....</fo:block>
</fo:list-item-body>
</fo:list-item>
...
</fo:list-block>
101
11.2.1
Erzeugen von Tabellen
Zum Erzeugen von Tabellen gibt es die Elemente: fo:table, fo:table-body, fo:table-cell, fo:table-column,
fo:table-footer, fo:table-header, fo:table-row
fo:table enhält (optional) einen table-header und/oder table-footer sowie einen table-body.
Der table-body besteht dann aus table-row Elementen, welche wiederum aus table-cell Knoten zusammengesetzt sind.
Durch die table-column Elemente wird bestimmt, wie viele und wie breit die einzelnen Spalten werden
sollen.
Die Breite kann auch Proportional zur Gesamt-Breite des Dokuments definiert werden (zum Beispiel 25%):
column-width="proportional-column-width(25)"
table-header und table-body enthalten dann pro Zeile eine table-row, welche pro Spalte eine table-cell
enthält.
Falls die Tabelle einen Rahmen erhalten soll, kann dies entweder in fo:table (Rahmen um ganze Tabelle), in
table-column (Rahmen um eine Spalte), in table-row (Rahmen um eine Zeile) oder in fo:table-cell (Rahmen
um einzelne Zelle) angegeben werden.
Das Attribut padding gibt den Abstand vom Inhalt der Zelle (Text) und dem Rand der Zelle an.
102
Beispiel einer Tabelle
<fo:table background-color="#EEEEEE" padding="3pt">
<fo:table-column column-width="20mm"/>
<!--Definition der Spalten-Breiten -->
<fo:table-column
column-width="30mm"/>
<fo:table-header font-weight="bold" background-color="#CCCCCC>
<fo:table-row>
<fo:table-cell border="2pt solid black" padding="3pt">
<fo:block> HTML </fo:block>
</fo:table-cell>
<fo:table-cell border="2pt solid black" padding="3pt">
<fo:block> XML-FO </fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-header>
<fo:table-body>
<fo:table-row>
<fo:table-cell border="1pt solid black" padding="3pt">
<fo:block> THEAD </fo:block>
</fo:table-cell>
<fo:table-cell border="1pt solid black" padding="3pt">
. . . .
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
103
11.3 Die wichtigsten Attribute
11.3.1
Attribute sind Properties
Die Attribute der FO-Elemente sind Formatierungs-Anweisungen. Sie bestimmen das Aussehen des
Inhalts.
Es gibt mehr als 200 Format Properties (Attribute), welche oft in verschiedensten Elementen
angegeben werden können.
Properties werden von aussen nach innen abgearbeitet. Bei sich widersprechenden Angaben,
überschreibt die lokale Angabe die globale.
Eine Property, welche an verschiedenen Orten benutzt werden kann, hat immer dieselbe
Bedeutung.
•
•
•
•
11.3.2
Character Properties
Alle XSL-FO Elemente, welche Text enthalten können (fo:block, fo:inline, ...), erlauben Attribute für das
Setzen von Character Properties(color, font-size, font-family, text-decoration, ...).
<fo:block font-family="Helvetica" font-size="12pt">
Hier ist ein
<fo:inline text-decoration="underline">
wichtiger </fo:inline>
<fo:inline color="red" font-weight="900">
Text </fo:inline>
</fo:block>
11.3.3
Character Property: Farbe
Die color-Property setzt die Schriftfarbe:
<fo:inline color="green"> Text </fo:inline>
Wie in CSS gibt es 16 vordefinierte Farben:
Weitere Farben können als hexadezimale RGB-Trippel definiert werden: #RRGGBB.
104
11.3.4
Character Property: Font
Die Property font-family definiert den zu benutzenden Font:
<fo:inline font-family="Times Roman" >
Times Roman
</fo:inline>
Zur Verfügung stehen unter anderem die Schriften Serif, Sans Serif, Times Roman, Courier und Symbol.
Es können als fall-back auch mehrere font-family Werte angegeben werden.
font-family=”Arial, Helvetica, sans-serif”
Ausserdem können mit FOP alle Systemfonts eingebettet werden.
11.3.5
Character Property: Schriftgrösse
Die Property font-size definiert die zu benutzende Schriftgrösse:
<fo:inline font-family="Helvetica"
ein Text in 24 Punkt Schrift
</fo:inline>
11.3.6
font-size="24pt">
Character Property: Schrift Style
Der Style des Fonts wird definiert durch die Property font-style
<fo:block font-family="Times Roman"
Times Roman italic
</fo:block>
font-style="italic">
Es gibt die Styles italic, normal, oblique, reverse-normal und reverse-oblique.
11.3.7
Character Property: Schrift-Dicke
Die Dicke der Schrift wird definiert durch die Property font-weight:
<fo:block font-family="Times Roman" font-weight="bold">
Hier ist ein bold Text
</fo:block>
<fo:block font-family="Times Roman" font-weight="normal">
Hier ist ein normaler Text
</fo:block>
105
11.3.8
Character Property: Schrift-Dekorationen
Unabhängig vom gewählten Font (Style, Farbe,...) können verschiedene Text Properties gesetzt werden.
Die Property text-transform definiert, ob der ganze Text in Grossbuchstaben (uppercase), Kleinbuchstaben
(lowercase) oder bloss die Anfangsbuchstaben in gross gesetzt werden sollen (capitalize). Die Property texttransform ist in FOP (noch) nicht implementiert.
Die Property score-spaces definiert, ob im unter- (über/durch)-gestrichenen Text auch die Spaces unter
(über/durch)-strichen sein sollen oder nicht.
text-decoration="underline" --> unterstrichen
text-decoration="overline"
--> überstrichen
text-decoration="line-through" --> durchgestrichen
text-shadow="gray"
--> Schattenschrift
text-transform="capitalize" --> Alle Ersten Buchstaben Gross
text-transform="uppercase" --> GROSSSCHRIFT
text-transform="lowercase" --> kleinschrift
Ein Beispiel:
<fo:block text-align="start" line-height="12pt" font-family="sans-serif"
font-size="10pt" text-decoration="underline" color="blue">
Ein blauer, unterstrichener sans-serif Text in 10pt Schrift.
</fo:block>
11.3.9
Sentence Properties
Sentence Properties bestimmen den Platz zwischen den
einzelnen Buchstaben (letter-spacing), zwischen einzelnen
Wörtern im Text (word-spacing) und zwischen den einzelnen
Linien im Text (line-height, text-depth, text-altitude, ...), die
Ausrichtung des Texts (text-align), ...
<fo:block font-family="Helvetica" font-size="10pt" text-align="center"
line-height="11pt">
Hier ist ein zentrierter Text. Hier ist ein zentrierter Text. Hier ist ein zentrierter Text.
<fo:leader leader-pattern="rule" leader-length="6cm"/> <!- - Linie - ->
</fo:block>
<fo:block font-family="Helvetica" font-size="10pt" text-align="justify"
letter-spacing="1pt">
Hier ist ein gesperrter . . . Hier ist ein Text. Hier ist noch ein Text.
<fo:leader leader-pattern="rule" leader-length="6cm"/> <!- - Linie - ->
</fo:block>
106
107
11.3.10
Sentence Property: Zeilenabstand
Der Zeilenabstand im Text kann kontrolliert werden durch die Properties line-height, text-depth und textaltitude.
<fo:block font-size="10pt" line-height="16pt" ...>
Hier ist ein Text, ...
</fo:block>
Die Sentence Property line-height-shift-adjustment legt fest, ob subscripts und superscripts den LinienAbstand vergrössern sollen oder nicht.
Durch text-depth (text-altitude) wird zusätzlicher Abstand nach (vor) jeder Zeile eingefügt.
<fo:block font-family="Helvetica" font-size="10pt" text-align="left"
text-depth="3pt" text-altitude="3pt" line-height="16pt">
Hier ist ein Text. Hier ist ein Text. Hier ist ein Text.
</fo:block>
11.3.11
Sentence Property: Text Ausrichtung
Ob der Text linksbündig, rechtsbündig, zentriert oder im
Blocksatz gesetzt werden soll, wird durch die Property textalign gesetzt.
Diese kann die folgenden Werte annehmen:
start oder left --> linksbündig
center --> zentriert
end oder right --> rechtsbündig
justify --> Blocksatz
<fo:flow flow-name="xsl-region-body" >
<fo:block font-size="12pt" text-align="start">
Hier ist ein linksbündiger Text, der . . .
</fo:block>
<fo:block> <fo:leader leader-length="7cm" leader-pattern="rule"/> </fo:block>
<fo:block font-size="12pt" text-align="center" line-height="20pt">
Hier ist ein zentrierter Text mit grossem . . .
</fo:block>
<fo:block> <fo:leader leader-length="7cm" leader-pattern="rule"/> </fo:block>
<fo:block font-size="12pt" text-align="end">
Hier ist ein rechtsbündiger Text . . .
</fo:block>
<fo:block> <fo:leader leader-length="7cm" leader-pattern="rule"/> </fo:block>
<fo:block font-size="12pt" text-align="justify">
Hier ist ein Blocksatz Text, der . . .
</fo:block>
</fo:flow>
108
109
11.3.12
Attribut Listen
Zum Erlangen eines konsistenten Layouts sollten für die verschiedenen Text-Bereiche (Fliesstext, Header,
Footer, Tabellen, Listen) jeweils entsprechende Styles definiert werden. Hier zum Beispiel die Definition des
text-style für den Fliesstext (pageMaster.xsl):
<xsl:attribute-set name="text-style">
<xsl:attribute name="font-family">Arial, Helvetica, sans-serif</xsl:attribute>
<xsl:attribute name="font-size">12pt</xsl:attribute>
<xsl:attribute name="font-weight">normal</xsl:attribute>
<xsl:attribute name="line-height">15pt</xsl:attribute>
<xsl:attribute name="text-align">left</xsl:attribute>
</xsl:attribute-set>
Dieser wird dann wie folgt im Stylesheet benutzt (makeFO.xsl):
<fo:flow flow-name="xsl-region-body">
<fo:block xsl:use-attribute-sets="text-style">
<xsl:apply-templates select="doc"/>
</fo:block>
</fo:flow>
Analog sollte für Tabellen, Listen, ... vorgegangen werden.
11.3.13
Für die Übung: Einstellungen in oXygen für XSL-FO
Beim Ankreuzen von „FO Transformation ausführen“ wird das xml-Dokument mit Hilfe des Stylesheets nach
XSL-FO transformiert und das erzeugte fo-File danach mit FOP nach pdf umgewandelt.
110
Zugehörige Unterlagen
Herunterladen