XML-Technologien und Programmierung Master

Werbung
Softwaretechnologien
Teil: XML-Technologien und Programmierung
Master-Studiengang IKT
Herbst 2010
Matthias K. Krause, Hochschule für Telekommunikation, Leipzig
7. Oktober 2010
Dieses Skript ist hier
http://www.hft-leipzig.de/~krause/lehre/m_ikt_swt_2010/SWT_MasterIKT10.pdf
. . . und ergänzendes Material zur Veranstaltung liegt hier
http://www.hft-leipzig.de/~krause/lehre/m_ikt_swt_2010/
1
Inhaltsverzeichnis
1 Themen
3
2 Ein kurzer Exkurs zu ant
4
3 Extended Markup Language (XML)
3.1 XML . . . . . . . . . . . . . . . . . . . . . . . .
3.1.1 Document Type Description (DTD) . .
3.1.2 XML Schema . . . . . . . . . . . . . . .
3.2 XSL/XSLT . . . . . . . . . . . . . . . . . . . .
3.2.1 XSL in der XML-Sprachfamilie . . . . .
3.2.2 Einfache Transformationen mit Schleifen
3.2.3 Bedingungen . . . . . . . . . . . . . . .
3.2.4 Gruppierungen . . . . . . . . . . . . . .
3.2.5 Templates . . . . . . . . . . . . . . . . .
3.2.6 Fremdschlüssel . . . . . . . . . . . . . .
3.2.7 ”Durchschleifen” von XML-Tags . . . .
3.3 Ein komplettes Beispiel . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
7
7
9
11
15
15
16
17
17
18
20
21
21
4 XML-API-Programmierung
4.1 Java API for XML Processing (JAXP) .
4.1.1 Simple API for XML (SAX) . . .
4.1.2 Document Object Model (DOM)
4.1.3 XSLT . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
26
26
26
31
35
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
5 Grundlegende Probleme
39
5.1 Konfigurationsdaten und Internationalisierung (I18n) . . . . . . . . . . . . . . 39
5.2 Datenbank-Programmierung mit JDBC . . . . . . . . . . . . . . . . . . . . . 42
2
1
Themen
Der Vorlesungsteil beschäftigt sich schwerpunktmäßig mit XML-Technologien:
• Einführend wird ein Softwaretool namens ant vorgestellt, dessen Steuerdateien im
XML-Format dargestellt werden. ant dient der Automatisierung von Abläufen, anhand
der Steuerdateien wird ersichtlich, wie XML prinzipiell aufgebaut ist und wie der
Rahmen XML, der an sich ohne jegliche inhaltliche Bedeutung ist, als Behälter für
etwas wie eine Ablaufprogrammierung dienen kann.
• Der nächste Teil beschreibt XML (Extended Markup Language) mit ihren Eigenschaften und Bestandteilen, im weiteren wird gezeigt, wie mit der XML-Sprache XSLT
(Extended Stylesheet Language Transformations) Transformationen zwischen verschiedenen XML-Formaten durchgeführt werden können.
• Weiterhin geht es um dem Umgang mit XML-Dokumenten aus Programmiersprachen heraus, hier insbesondere am Beispiel von Java.
Ergänzend werden einige grundlegende Themen wie
• Ablage von Konfigurationsdaten durch Programme,
• Internationalisierung
• und Datenbankprogrammierung
innerhalb von Java angerissen.
3
2
Ein kurzer Exkurs zu ant
ant ist ein Produkt der Apache Software Foundation. Es ist ein Tool, welches, ähnlich wie
make, in einem automatisierten Ablauf eine Reihe von Handlungen abarbeiten kann und
dabei Schritte bedingt ausführen kann. So kann man mit ant z.B. Compilieren und/oder
Linken, wenn beim Linken festgestellt wird, daß der Quellcode neuer als der Objektcode ist,
wird vorher noch compiliert.
ant bedient sich einer Konfigurationsdatei, die in XML geschrieben ist, was in diesem Kurs
als Einstieg in XML verwendet werden soll. Andererseit ist die Leistung von ant an sich
interessant und an vielen Stellen für die Automatisierung von Abläufen verwendbar. Von
Vorteil ist die Tatsache, daß das Tool betriebssystemunabhängig ist, Voraussetzungen sind
nur die im Folgenden genannten Software-Voraussetzungen:
• ant (die Software und Informationen dazu befinden sich im jwsdp, in der Java Enterprise Edition oder kann bei der Apache Software Foundation bezogen werden)
• Java-Standard-Edition
Ein Blick ins ant-Manual [1] bringt uns Infos zum Aufruf (das “Makefile“ heißt build.xml)
ant [options] [target [target2 [target3] ...]]
Options:
-help, -h
print this message
-version
print the version information and exit
-quiet, -q
be extra quiet
-verbose, -v
be extra verbose
-debug, -d
print debugging information
-lib <path>
specifies a path to search for jars and classes
-buildfile <file>
use given buildfile (default: build.xml)
-file
<file>
’’
-f
<file>
’’
-D<property>=<value>
use value for given property
-propertyfile <name>
load all properties from file with -D
properties taking precedence
...
und im Teil “Using ant“ einen Überblick zu seinen wesentlichen Bestandteilen:
• project, das Rootelement, welches alle Informationen zum Build-Vorgang enthält. Das
Default-Target (default-Attribut) wird bei Aufruf ohne Targetangabe verwendet:
1
2
3
4
<project name="MyProject" default="dist" basedir=".">
<description>
simple example build file
</description>
5
6
... HIER STEHEN ALLE ANDEREN ELEMENTE DER STEUERDATEI
7
8
</project>
• properties sind Eigenschaften, die an zentraler Stelle gesetzt und dann an verschiedenen Stellen im Skript genutzt werden können
(Vorsicht: properties sind NICHT änderbar, ist der Wert gesetzt, bleibt er so, auch
wenn er scheinbar im Text überschrieben wurde!!!)
4
1
2
3
4
5
6
...
<property
<property
<property
<property
...
name="src" location="src"/>
name="build" location="build"/>
name="dist" location="dist"/>
name="who" value="Peter"/>
• targets sind Container für Tasks, die beim Ruf angegeben und ausgeführt werden
können. Über ein depends-Attribut können andere Targets angegeben werden, die,
falls ihr Produkt nicht aktuell ist, vorher ausgeführt werden.
1
2
3
4
<target name="copyshop" depends="init" ...>
<mkdir ... />
<copy ... />
</target>
Hier enthält das Target zwei Tasks mit den Namen mkdir und copy. Ist das Target init
nicht aktuell (das bedeutet, das der Zustand der Ergebnisse der Abarbeitung von init
nicht aktuell ist) wird init aufgerufen. Danach werden die beiden eingeschlossenen
Tasks abgearbeitet.
• tasks sind Aufgaben, die ausgeführt werden können, hier beschreibt der Elementname
schon den Charakter der Task, Beispiele sind:
Compilieren von Javacode: javac,
Kopieren von Files: copy,
Verpacken mit dem Zip-Mechanismus: zip,
Durchführen einer XSL Transformation: Xslt/Style
Folgendes Listing bringt einen Einblick in die Möglichkeiten, die sich mit ant eröffnen:
Listing 1: einfaches Makefile build.xml
1
2
3
4
5
6
7
8
<project name="MyProject" default="dist" basedir=".">
<description>
simple example build file
</description>
<!-- set global properties for this build -->
<property name="src" location="src"/>
<property name="build" location="build"/>
<property name="dist" location="dist"/>
9
10
11
12
13
14
15
<target name="init">
<!-- Create the time stamp -->
<tstamp/>
<!-- Create the build directory structure used by compile -->
<mkdir dir="${build}"/>
</target>
16
17
18
19
20
21
<target name="compile" depends="init"
description="compile the source " >
<!-- Compile the java code from ${src} into ${build} -->
<javac srcdir="${src}" destdir="${build}"/>
</target>
22
5
23
24
25
26
27
28
29
30
<target name="doc" depends="compile"
description="generate the javadoc docu" >
<!-- Create the doc directory -->
<mkdir dir="${dist}/doc"/>
<javadoc destdir="${dist}/doc">
<fileset dir="${src}" />
</javadoc>
</target>
31
32
33
34
35
<target name="dist" depends="compile,doc"
description="generate the distribution" >
<!-- Create the distribution directory -->
<mkdir dir="${dist}/lib"/>
36
37
38
39
<!-- Put everything in ${build} into the MyProject-${DSTAMP}.jar file -->
<jar jarfile="${dist}/lib/MyProject-${DSTAMP}.jar" basedir="${build}"/>
</target>
40
41
42
43
44
45
46
<target name="clean" description="clean up" >
<!-- Delete the ${build} and ${dist} directory trees -->
<delete dir="${build}"/>
<delete dir="${dist}"/>
</target>
</project>
Das File ist nahezu selbsterklärend, hingewiesen werden soll lediglich auf die Erzeugung
eines Zeitstempels (Timestamp - Zeile 12) und die Nutzung des zugehörigen Datumsstempels
(Zeile 35).
Übung 1 Schreiben Sie ein build-File für ant, durch das eine Verzeichnisstruktur (Angabe
in einer property) in ein Zip-File verpackt wird, dessen Name das Datum in der Form
...yyyymmdd... enthält!
Im weiteren Verlauf werden wir ant auch verwenden, um Aufgaben im Bereich XML/XSLT
zu realisieren:
• XmlValidate (optional task, validiert eine XML-Datei, im Beispiel ist die DTD in der
XML-Datei angegeben)
<xmlvalidate file="data.xml"/>
• XSLT (core task, macht eine XSL-Transformation ohne Validierung)
<xslt in="data.xml" style="style.xsl" out="data.html"/>
• SchemaValidate (optional task, validiert eine XML-Datei, speziell zur Validierung gegen ein XMLSchema)
<schemavalidate noNamespaceFile="schema.xsd" file="data.xml" />
Das File data.xml selbst enthält selbst keine Schemadeklaration bzw. Namespaces
6
3
Extended Markup Language (XML)
Folgenden Stoff wollen wir behandeln:
• Aufbau und Gestaltung von XML-Files
• inhaltliche Restriktionen mit DTD und XMLSchema
• textuelle Transformationen mit XSLT
3.1
XML
• Unter http://www.w3.org/TR/REC-xml finden Sie die Empfehlung des W3C zur Extensible Markup Language (XML) 1.0 (Second Edition), DIE Quelle zur Spezifikation
von XML. Es gibt dort auch eine deutsche Übersetzung, die allerdings, da nicht sämtliche Links im Dokument vorhanden sind, nicht so gut navigierbar ist wie das Original.
• Unter http://www.edition-w3c.de (12.3.2003) ist eine navigierbare deutsche Übersetzung zu finden.
• Kurz und handlich ist XML kurz & gut“ [2]
”
• Im Java Enterprise Tutorial“ [3, Kap. Introduction To XML] finden Sie eine kur”
ze Einführung in XML, Publikationen wie Java ist auch eine Insel“[10] und das
”
HTML-Kompendium Selfhtml [9] von Stefan Münz enthalten mittlerweile auch gute Einführungen bzw. Zusammenfassungen.
Zu XML etc. gibt es eine umfangreiche Sammlung von Tutorials, die genutzt werden
können, z.B. http://www.aboutwebdesign.de/awd/content/1024415102.shtml
Sie sollten ein XML-File verstehen, aber auch selbst aus einem Datensatz entwickeln können.
Folgende Teile sollten Ihnen geläufig sein:
• der Prolog mit seinen Teilen und Attributen
• eine einfache DTD
• Kommentare
• Elemente und Attribute
• Processing Instructions
Struktur eines Dokuments:
• Prolog:
– XMLDeclaration (optional, immer 1.Zeile):
<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>
– DocumentTypeDeclaration(optional):
<!DOCTYPE Buchladen SYSTEM "_bsp.dtd">
• Wurzel-Element: ein Dokument enthält genau ein (Wurzel-)Element, welches wiederum Elemente und/oder Charakterdaten enthält.
Ein Element besteht aus einem Starttag (ggf. mit Parametern), Inhalt (Elemente,
Charakterdaten) und einem Endetag
7
<elementname parm1="wert1" ...> Inhalt </elementname>
oder aber ist leer und besteht aus einem Anfangs- und Endetag mit Parametern (oder
ohne)
<elementname parm1="wert1" ... />
Ein typisches Beispiel für ein leeres Element ohne Parameter ist <br/>, der Linebreak
im XHTML, der entsprechend dem XML-Standard nicht als einzelnes öffnendes Tag
<br>, wie oft im HTML genutzt, erscheinen darf.
• Verschiedenes (Miscellaneous) (an beliebigen Stellen von Prolog oder Element,
aber nicht in Tags):
– Kommentare:
<!-- This is a comment -->
– Processing Instructions:
<?target instructions?>
oft im Prolog eines XML-Datensheets mit Hinweis auf das entsprechende Stylesheet
Mögliche oder notwendige Eigenschaften eines XML-Dokuments:
• Wohlgeformtheit (Well Formedness):
Das Dokument entspricht in der Struktur der W3C-Empfehlung (allen Well Formedness Constraints der Empfehlung), jedes XML-Dokument muss dieser Eigenschaft
genügen
• Gültigkeit (Validity):
Die Element- und Attribut-Zusammensetzung entspricht einer Document Type Description (DTD) (siehe 3.1.1) oder einem XML Schema (siehe 3.1.2) (allen Validity
Constraints der Empfehlung), ein Dokument kann diese Eigenschaft haben.
Namespaces (Namensräume)
• Die Vereinbarung von Namespaces erfolgt die Angabe eines Attributes
xmlns:nsname="http://my.com" innerhalb eines Elementes, wobei nsname der zu vergebende Namespacename ist
• Die Nutzung durch die Angabe des Namespacenamens als Präfix nsname:elementname
Beispiel: der XSL-Namespace im XSL Stylesheet
Beispiele für XML-Dateien
Listing 2: zunächst ein einfaches File mit (optionaler) xml-Deklaration
1
<?xml version=’1.0’ encoding=’ISO-8859-1’ standalone=’yes’?>
2
3
4
5
6
7
<Buchladen
Ort="Leipzig"
Strasse="Heldenplatz"
>
<!-- ein Kommentar -->
8
8
9
10
11
12
13
<Buch Genre="Prosa">
<Autor> Peter Traurig </Autor>
<Titel> Großes Drama </Titel>
<Verlag> Weinheim Heuler </Verlag>
</Buch>
14
15
16
17
18
19
20
<Buch Genre="Sachbuch">
<Einband Quelle="c2736251627.gif"/>
<Autor> Hans Hansen </Autor>
<Titel> Neue Sichten </Titel>
<Verlag> Taschen </Verlag>
</Buch>
21
22
</Buchladen>
3.1.1
Document Type Description (DTD)
Ein XML-Dokument kann durch die Angabe einer Document Type Description inhaltlichen Zwängen der Elementzusammensetzung und -struktur unterworfen werden. Eine DTD
enthält im Wesentlichen
• ELEMENT-Beschreibungen
<!ELEMENT elementname typangabe>
wobei es für die Typangabe verschiedene Möglichkeiten gibt:
– ANY (bedeutet beliebiger Inhalt)
– die Typangabe kann in Klammern gesetzt werden, z.B. (#PCDATA) (von Parsed
Character Data)
– eine Komma-Liste von Elementen, dann ist die Reihenfolge zwingend, oder eine
Auswahl (mit Trenner |), dazu optional die RegExpr-Wiederholungszeichen (*,+,?
für 0 bis beliebig oft, 1 bis beliebig oft, optional)
• Beschreibungen von Attributlisten von Elementen
<!ATTLIST elementname attributliste>
wobei attributliste eine spaceseparierte Liste aus Attributbeschreibungen mit
– Attributname,
– Typ (CDATA | Auswahl | ID..eindeutiger Schlüssel im Dokument | IDREF |
spaceseparierte IDREFS | ...),
– Defaultdeklaration (#REQUIRED | #IMPLIED | (#FIXED)? Defaultwert)
ist.
• Entity-Definitionen
<!ENTITY entityname "ersetzungszeichen">
9
Nutzung im Text mit &entityname;
Es gibt eine ganze Reihe vordefinierte Entities: & < > " ' für
& < > " ’
. . . und die XML-Datei von oben mit einem Link auf eine externe DTD ( die DTD bzw. ein
XML Schema ist zwingend, wenn es sich um gültiges XML handeln soll)
Listing 3: XML-File mit Link auf externe DTD
1
<?xml version=’1.0’ encoding=’ISO-8859-1’?>
2
3
<!DOCTYPE Buchladen SYSTEM "_bsp.dtd">
4
5
6
7
8
<Buchladen
Ort="Leipzig"
Strasse="Heldenplatz"
>
9
10
11
...
...
12
13
</Buchladen>
... mit der dazugehörigen Document Type Definition (_bsp.dtd) ...
Listing 4: externe DTD
1
<?xml version=’1.0’ encoding=’ISO-8859-1’?>
2
3
4
5
<!-DTD fuer einen Buchladen
-->
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<!ELEMENT Buchladen (Buch*)>
<!ATTLIST Buchladen
Ort
CDATA
#REQUIRED
Strasse
CDATA
#REQUIRED
Besitzer CDATA
#IMPLIED
>
<!ELEMENT Buch (Einband?, Autor, Titel, Verlag)>
<!ATTLIST Buch
Genre (Prosa | Lyrik | Sachbuch) #IMPLIED
>
<!ELEMENT Einband EMPTY>
<!ATTLIST Einband
Alternative CDATA #IMPLIED
Quelle
CDATA
#REQUIRED
Typ
CDATA
"image/gif"
>
<!ELEMENT Autor (#PCDATA)>
<!ELEMENT Titel (#PCDATA)>
<!ELEMENT Verlag (#PCDATA)>
<!ENTITY copyright "&#xA9">
10
Die DTD kann auch, quasi inline, im XML-File liegen, hier Auszüge aus einer solchen
Version:
Listing 5: XML-File mit inline DTD
1
<?xml version=’1.0’ encoding=’ISO-8859-1’?>
2
3
4
5
6
7
8
9
<!DOCTYPE Buchladen [
<!ELEMENT Buchladen (Buch*)>
...
...
<!ELEMENT Titel (#PCDATA)>
<!ELEMENT Verlag (#PCDATA)>
]>
10
11
12
13
14
15
<Buchladen
Ort="Leipzig"
Strasse="Heldenplatz"
>
<!-- ein Kommentar -->
16
17
...
18
19
</Buchladen>
Übung 2 In einem XML-File soll eine Semestergemeinschaft gespeichert werden. Die Semestergemeinschaft hat einen Namen und enthält Studenten, die eine Matrikelnummer,
einen Namen, einen Vornamen und ein Geburtsdatum haben. Geben Sie ein entsprechendes
XML-File mit min. einem Studenten und einer dazu passenden inline-DTD an.
3.1.2
XML Schema
Im Gegensatz zur DTD bietet XML Schema umfangreiche Möglichkeiten der Festlegung von
Datentypen und Restriktionen. Folgende Dokumente beinhalten die Definition von XML
Schema:
• XML Schema Part 0: Primer Second Edition
http://www.w3.org/TR/xmlschema-0/
ein Tutorial mit Beispielen und Einführungen
• XML Schema Part 1: Structures Second Edition
http://www.w3.org/TR/xmlschema-1/
• XML Schema Part 2: Datatypes Second Edition
http://www.w3.org/TR/xmlschema-2/
Es ist selbst in XML formuliert, was die Möglichkeit der Behandlung mittels XML-Tools
bietet.
Jede XML Schema definition besteht aus einem Wurzelelement schema, der Name des Namespaces ist nicht vorgeschrieben:
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
...
</xsd:schema>
Auf diese Schemadefinition wird, bei Arbeit ohne Namespaces im XML-File, folgendermaßen
verwiesen:
11
<documentRoot
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation=’Buchladen.xsd’
>
...
</documentRoot>
Wesentliche Bestandteile einer XML Schema Definition:
• element
Attribute: name ref type
Inhalt: anstelle des Attributes type kann auch ein Typ-Element (simpleType, complexType) oder Struktur-Element (sequence, . . . ) eingebettet sein
• simpleType
Standardtypen (sind bereits definiert): string, int, integer, positiveInteger, nonPositiveInteger, date, . . .
. . . oder mit dem XML-Element simpleType eigene Typen definieren!
• restriction
Constraints on Simple Type Definition Schema Components (siehe Part 2) können mit
Facetten (facets) realisiert werden: pattern, minLength, minExclusive, minInclusive,
max. . . , . . . (alles XML-Elemente)
• complexType charakterisiert eine (komplexe) Datenstruktur, nicht nur einen Einzelwert
• sequence stellt eine geordnete Reihenfolge von Elementen dar, die im Defaultfall jedes
genau einmal vorkommen
• choice, genau ein Element erscheint
Listing 6: XML Schema für den Buchladen
1
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
2
3
4
5
6
7
<xsd:annotation>
<xsd:documentation xml:lang="de">
XML Schema fuer Buchladen
</xsd:documentation>
</xsd:annotation>
8
9
<xsd:element name="Buchladen" type="BuchladenTyp"/>
10
11
12
13
14
15
16
17
18
19
<xsd:complexType name="BuchladenTyp">
<xsd:sequence>
<xsd:element name="Buch" type="BuchTyp"
minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="Ort"
type="xsd:string" use="required"/>
<xsd:attribute name="Strasse" type="xsd:string" use="required"/>
<xsd:attribute name="Besitzer" type="xsd:string"/>
</xsd:complexType>
12
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<xsd:complexType name="BuchTyp">
<xsd:sequence>
<xsd:element name="Einband" type="xsd:string" minOccurs="0">
<xsd:attribute name="Alternative"/>
<xsd:attribute name="Quelle" use="required"/>
<xsd:attribute name="Typ"
default="image/gif"/>
</xsd:element>
<xsd:element name="Autor" type="xsd:string"/>
<xsd:element name="Titel" type="xsd:string"/>
<xsd:element name="Verlag" type="xsd:string"/>
</xsd:sequence>
<xsd:attribute name="Genre" type="xsd:GenresTyp"/>
</xsd:complexType>
34
35
36
37
38
39
40
41
<xsd:simpleType name="GenresTyp">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="Prosa"/>
<xsd:enumeration value="Lyrik"/>
<xsd:enumeration value="Sachbuch"/>
</xsd:restriction>
</xsd:simpleType>
42
43
</xsd:schema>
Der folgende Schemaausschnitt verdeutlicht am Beispiel der Definition eines einfachen Datentyps für numerische IP-Adressen, wie mit regulären Ausdrücken das Aussehen von Strings
gewissen Regeln unterworfen werden kann. Der Name des Datentypes, auf den dann in
Element- oder Attributdefinitionen Bezug genommen werden kann, ist IP4Num. Er beruht
auf dem Datentyp string und ist einer durch ein pattern-Element formulierten Bedingung
unterworfen.
Listing 7: Datentyp für numerische IP-Adresse
1
2
3
4
5
<xsd:simpleType name="IP4Num">
<xsd:restriction base="xsd:string">
<xsd:pattern value="\d{1,3}(\.\d{1,3}){3}"/>
</xsd:restriction>
</xsd:simpleType>
Und das folgende XML Schema aus dem XML Schema Part 0: Primer Second Edition soll
ergänzend einige Bestandteile von XML Schema zeigen:
Listing 8: XSD aus Part 0 Primer
1
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
2
3
4
5
6
7
8
<xsd:annotation>
<xsd:documentation xml:lang="en">
Purchase order schema for Example.com.
Copyright 2000 Example.com. All rights reserved.
</xsd:documentation>
</xsd:annotation>
9
13
10
<xsd:element name="purchaseOrder" type="PurchaseOrderType"/>
11
12
<xsd:element name="comment" type="xsd:string"/>
13
14
15
16
17
18
19
20
21
22
<xsd:complexType name="PurchaseOrderType">
<xsd:sequence>
<xsd:element name="shipTo" type="USAddress"/>
<xsd:element name="billTo" type="USAddress"/>
<xsd:element ref="comment" minOccurs="0"/>
<xsd:element name="items" type="Items"/>
</xsd:sequence>
<xsd:attribute name="orderDate" type="xsd:date"/>
</xsd:complexType>
23
24
25
26
27
28
29
30
31
32
33
34
<xsd:complexType name="USAddress">
<xsd:sequence>
<xsd:element name="name" type="xsd:string"/>
<xsd:element name="street" type="xsd:string"/>
<xsd:element name="city" type="xsd:string"/>
<xsd:element name="state" type="xsd:string"/>
<xsd:element name="zip" type="xsd:decimal"/>
</xsd:sequence>
<xsd:attribute name="country" type="xsd:NMTOKEN"
fixed="US"/>
</xsd:complexType>
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<xsd:complexType name="Items">
<xsd:sequence>
<xsd:element name="item" minOccurs="0" maxOccurs="unbounded">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="productName" type="xsd:string"/>
<xsd:element name="quantity">
<xsd:simpleType>
<xsd:restriction base="xsd:positiveInteger">
<xsd:maxExclusive value="100"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="USPrice" type="xsd:decimal"/>
<xsd:element ref="comment" minOccurs="0"/>
<xsd:element name="shipDate" type="xsd:date" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="partNum" type="SKU" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
58
59
60
61
62
63
<!-- Stock Keeping Unit, a code for identifying products -->
<xsd:simpleType name="SKU">
<xsd:restriction base="xsd:string">
<xsd:pattern value="\d{3}-[A-Z]{2}"/>
</xsd:restriction>
14
64
</xsd:simpleType>
65
66
</xsd:schema>
3.2
XSL/XSLT
Software-Voraussetzung:
• ein XSLT-fähiger Browser (Internetexplorer, Mozilla, Firefox, . . . )
• . . . oder ein XSLT-Prozessor (der ab Java 1.4 bereits in der Standardbibliothek enthalten ist)
3.2.1
XSL in der XML-Sprachfamilie
Während XML ganz allgemein eine Markup-Sprache zur Speicherung beliebiger Daten/Informationen ist, wurden zur Trennung von Daten und Formatierung weitere Empfehlungen
für ebenfalls auf XML beruhenden Sprachen und damit verbundene Spezifikationen wie XSL,
XSLT, XPath und viele andere durch das W3C entwickelt:
• XML (Extensible Markup Language (XML) 1.0 (Second Edition))
http://www.w3.org/TR/REC-xml
die Empfehlung zum Aufbau jedes XML-Dokumentes
• Extensible Stylesheet Language (XSL) Version 1.0
http://www.w3.org/TR/xsl/
beschreibt die Möglichkeit, xml-Daten mittels Stylesheet (auch XML) in beliebige Zielformate formatieren zu können
• XSL Transformations (XSLT) Version 1.0
http://www.w3.org/TR/xsl/
beschreibt die Möglichkeit, xml-Daten mittels Stylesheet (auch XML) rein textuell
transformieren zu können
• XML Path Language (XPath) Version 1.0
http://www.w3.org/TR/xpath
Ausdruckssprache (expression language) für den Zugriff auf XML-Elemente, die in
XSLT genutzt wird, sie enthält XPath-Funktionen (The default prefix for the function
namespace is fn, and the URI is http://www.w3.org/2005/02/xpath-functions)
Für eine Transformation werden also im Allgemeinen Daten und eine Transformationsanweisung benötigt.
Einige XSLT-Tutorials:
• http://www.heise.de/ix/artikel/2001/01/167/
XSLT-Tutorial I: Grundlagen und erste Beispielanwendung
• http://www.topxml.com/xsl/tutorials/intro/default.asp
XSLT & XPath Tutorial
• http://www.w3schools.com/xsl/
XSLT Tutorial
15
3.2.2
Einfache Transformationen mit Schleifen
Listing 9: Einfaches Beispiel eines Datenfiles gw.xml
1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="ISO-8859-1" standalone="no" ?>
<?xml-stylesheet href="gw.xsl" type="text/xsl" ?>
<x>
<xy a="1"> <b>1</b> <xyz> A </xyz> </xy>
<xy a="1"> <b>1</b> <xyz> B </xyz> </xy>
<xy a="2"> <b>2</b> <xyz> D </xyz> <opt> 12 </opt> </xy>
<xy a="3"> <b>3</b> <xyz> E </xyz> </xy>
<xy a="3"> <b>3</b> <xyz> F </xyz> <opt> 17 </opt> </xy>
<xy a="4"> <b>4</b> <xyz> G </xyz> </xy>
<xy a="1"> <b>1</b> <xyz> C </xyz> </xy>
</x>
welches über eine Transformation mittels gw.xsl, wie die Instruktionsanweisung in der 2.
Zeile des Datenfiles besagt, transformiert werden soll. Die Einbettung des Namens des Transformationssheets in das xml-File ist nicht unbedingt nötig, sie wird vor allem dort verwendet,
wo eine feste Zuordnung gewünscht bzw. notwendig ist, wenn z.B. das xml-File direkt durch
den Browser angefordert wird.
Durch die folgende Transformation wird ein Teil der Daten (das Attribut a und der Inhalt
von b) aller Datensätze ausgegeben:
Listing 10: Das XSLT-File gw.xsl zum Datenfiles gw.xml
1
<?xml version="1.0" encoding="ISO-8859-1"?>
2
3
4
5
<!-- <xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl">
... working draft (fuer IE 5.x zu verwenden)
-->
6
7
8
9
10
11
12
13
14
15
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="/">
Attr_a | b
<xsl:for-each select="x/xy">
Datensatz <xsl:value-of select="@a" /> | <xsl:value-of select="b" />
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Das durch die Transformation erzeugte Produkt sieht folgendermaßen aus:
Attr_a | b
Datensatz
Datensatz
Datensatz
Datensatz
Datensatz
Datensatz
Datensatz
1
1
2
3
3
4
1
|
|
|
|
|
|
|
1
1
2
3
3
4
1
16
An diesem Beispiel wird ersichtlich, daß die Transformationsanweisungen des xsl-Files innerhalb des template-Tags beliebigen Text enthalten kann, wodurch dann auch ein beliebiges
Output-Format (z.B. html, oder auch NICHT-XML) entstehen kann.
3.2.3
Bedingungen
Soll es zur Abarbeitung von Teilen des Transformationsskriptes unter bestimmten Bedingungen kommen, kann man den Befehl
<xsl:if test="..."> ... </xsl:if>
verwenden. Wollen wir beispielsweise aus der xml-Datei des letzten Abschnittes (siehe 3.2.2,
S.16) für jedes <xy>-Element den Inhalt von <xyz> und, falls vorhanden, von <opt> drucken,
machen wir das mittels folgender XSLT-Befehle:
1
2
3
4
5
6
7
8
9
10
11
...
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="/">
<xsl:for-each select="x/xy">
<xsl:value-of select="xyz"/> <xsl:if test="opt">
<xsl:value-of select="opt"/>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
3.2.4
Gruppierungen
An dieser Stelle erscheint es nun interessant, nach übereinstimmenden Werten von Attributen oder Elementen zu gruppieren. Das kann für das Attribut a folgendermaßen geschehen:
Listing 11: Realisierung einer Gruppierung
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="/">
ANFANG
<xsl:for-each select="x/xy[not(@a=preceding-sibling::xy/@a)]">
Attr_a = <xsl:value-of select="@a" />
b xyz
<xsl:for-each select="/x/xy[@a=current()/@a]">
Datensatz <xsl:value-of select="b" />
<xsl:value-of select="xyz" />
</xsl:for-each>
</xsl:for-each>
ENDE
</xsl:template>
</xsl:stylesheet>
Das Stylesheet enthält zwei geschachtelte for-each-Schleifen. Die äußere macht die Trennung
der Gruppen, dazu wird eine Bedingung genutzt, daß das Element nur selektiert wird, wenn
sein Attribut a (Attribute werden mit dem at-Zeichen @ gekennzeichnet) keinem schon gefundenen a eines vorangegangenen Geschwisterelementes (siehe XPath: preceeding-sibling,
das ist eine Achse) gleicht. Die innere for-each-Schleife läuft nun innerhalb dieser Gruppe
über alle Elemente mit gleichem a.
17
Es ergibt sich folgendes Produkt:
ANFANG
Attr_a = 1
b xyz
Datensatz 1 A
Datensatz 1 B
Datensatz 1 C
Attr_a = 2
b xyz
Datensatz 2 D
Attr_a = 3
b xyz
Datensatz 3 E
Datensatz 3 F
Attr_a = 4
b xyz
Datensatz 4 G
ENDE
3.2.5
Templates
Bisher haben wir das xsl-Element template nur zum Greifen“des Wurzelelements verwen”
det, die Bearbeitung wurde mit xsl:for-each realisiert, was wir für Konstrukte wie Gruppierungen auch weiterhin verwenden werden! Die gebräuchliche Art, Transformationen zu
realisieren, sind aber Templates (für jedes zu transformierende Element wird ein Template
angelegt) und der Befehl <xsl:apply-templates ... />.
xsl:template
Der Parameter match (entsprechend XPath) kennzeichnet die Elemente, für die das Template gilt.
xsl:apply-templates
Der optionale Parameter select (entsprechend XPath) kennzeichnet die Elemente, die getroffen werden sollen. Fehlt er, werden alle Kindelemente des aktuellen Elements rekursiv
verarbeitet. Wird für ein Element ein Template gefunden, wird es verarbeitet, ansonsten
werden die Inhalte der Elemente ausgegeben (Testen!).
Listing 12: XML-Datenfile eines CD- und Buchverzeichnisses
1
<?xml version="1.0" encoding="ISO-8859-1" standalone="no" ?>
2
3
<?xml-stylesheet href="shop.xsl" type="text/xsl" ?>
4
5
6
7
8
9
10
11
<Shop>
<CD>
<Title>Cruel</Title>
<Artist>The Singer</Artist>
<Track Nr="1" Length="24"> Part One </Track>
<Track Nr="2" Length="29"> Part Two </Track>
</CD>
18
12
13
...
14
15
16
17
<book> Dies ist ein Buch! </book>
<book> Dies ist noch ein Buch! <autor> Hillu Hilbert </autor> </book>
</Shop>
Listing 13: Das entsprechende Transformationsfile
1
<?xml version="1.0" encoding="ISO-8859-1"?>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.w3.org/TR/REC-html40">
<xsl:output method="html" />
<xsl:template match="/">
<html>
<head><title>Shop</title></head>
<body>
<xsl:apply-templates />
<!-- <xsl:apply-templates select="Shop/book" /> -->
</body>
</html>
</xsl:template>
16
17
18
19
20
<xsl:template match="book">
<br/> Buch: Autor
<xsl:value-of select="autor" />
</xsl:template>
21
22
23
24
25
26
27
<xsl:template match="CD">
<br/> CD : <xsl:value-of select="Artist" /> :
<xsl:value-of select="Title" />
Länge: <xsl:value-of select="sum(Track/@Length)" />
</xsl:template>
</xsl:stylesheet>
Die Länge der CDs werden durch die Aggregatfunktion sum(...) berechnet, die in XPath
beschrieben ist.
Listing 14: Transformationsprodukt HTML
1
2
3
4
5
6
7
8
9
10
11
12
13
<html xmlns="http://www.w3.org/TR/REC-html40">
<head>
<title>Shop</title>
</head>
<body>
<br/> CD : The Singer :
Cruel
Länge: 53
<br/> CD : The Singer :
Awesome
Länge: 42.57
<br/> CD : Tim Tom :
Lieder
19
14
15
16
17
18
19
Länge: 7.8
<br/> Buch: Autor
<br/> Buch: Autor
Hillu Hilbert
</body>
</html>
Die html-igen Umlautcodierungen entstehen durch das method-Attribut mit dem Wert html
im output-Tag
3.2.6
Fremdschlüssel
Wie in relationalen Datenbanken kann man im XML Attribute als Fremdschlüssel (IDREF(S))
auf Attribute, die Schlüssel (ID) darstellen, zeigen lassen, wie die Definition der Fremdschlüssel und Sclüsselkandidaten in den RDBMS ist hier die Verwendung der Attributtypen
ID und IDREF nicht notwendig für die Referenzen, sondern nur hilfreich für das Gewährleisten der referenziellen Integrität, deren Verletzung im XML zu einem ungültigen Dokument
führt.
Folgendes Beispiel ist eine Modifikation des obigen Shop-Beispiels, wobei die Artist-Elemente
aus den CD-Elementen ausgelagert und durch Referenzen ersetzt wurden:
Listing 15: Anlegen von Fremdschlüsseln
1
<?xml version="1.0" encoding="ISO-8859-1" standalone="no" ?>
2
3
4
5
6
7
8
9
10
<?xml-stylesheet href="shop_fk_html.xsl" type="text/xsl" ?>
<Shop>
<CD ArtistID="a01"> <Title>Cruel</Title> </CD>
<CD ArtistID="a01"> <Title>Awesome</Title> </CD>
<CD ArtistID="a02"> <Title>Lieder</Title> </CD>
<Artist ArtistID="a01">The Singer</Artist>
<Artist ArtistID="a02">Tim Tom</Artist>
</Shop>
Im dazugehörigen Stylesheet werden nur die CD-Templates berücksichtigt, die benötigten
Artist-Daten jedoch über die Referenz ArtistID geholt:
Listing 16: Nutzung der Fremdschlüssel in der Transformation
1
2
3
...
<xsl:apply-templates select="Shop/CD" />
...
4
5
6
7
8
9
10
<xsl:template match="CD">
<br/>
<xsl:value-of select="/Shop/Artist[@ArtistID=current()/@ArtistID]" /> :
<xsl:value-of select="Title" />
</xsl:template>
</xsl:stylesheet>
Übung 3 Transformieren Sie mittels XSLT das XML-File von Übung 2 (S.11) in ein
XHTML-File, welches die Daten (Matrikelnummer, Name, Vorname, Geburtsdatum) der
Studenten in einer Tabelle ausgibt. Erweitern Sie das XML-File um einige Studenten.
20
3.2.7
”Durchschleifen” von XML-Tags
Enthält ein Element eines XML-Files XML-Tags, die 1:1 weitergegeben werden sollen (z.B.,
wenn man HTML-Tags wie <br/>, <ul>, <li> ... zur Formatierung benutzen will,) arbeitet man mit Templates.
Das Element, welches die Tags enthält, wird mittels <xsl:apply-templates ... /> aufgerufen, die entsprechenden Tags müssen ihrerseits über Templates verfügen:
Listing 17: Die XML-Daten
1
2
3
4
5
6
7
8
9
10
11
...
<Beschreibung>
Folgende Teile sind zu berücksichtigen:
<ul>
<li>der linke Teil</li>
<li>der rechte Teil
<br/> unter besonderer Beachtung des rechten oberen Teils ;-)
</li>
</ul>
</Beschreibung>
...
Listing 18: Die XSLT-Transformation
1
2
3
4
5
6
...
<xsl:apply-templates select="Beschreibung" />
...
<xsl:tempate match="Beschreibung"> <!-- kann auch wegfallen -->
<xsl:apply-templates />
</xsl:template>
7
8
9
10
<xsl:tempate match="br">
<br/>
</xsl:template>
11
12
13
14
15
16
<xsl:tempate match="ul">
<ul>
<xsl:apply-templates />
</ul>
</xsl:template>
17
18
19
<xsl:tempate match="li">
...
3.3
Ein komplettes Beispiel
Das vorliegende Beispiel soll zeigen, wie ein XML-Datensatz (Listings 19 bzw. 21) mit DTD
(Listing 20) bzw. XMLSchema (Listing 22) validiert werden kann. Eine Transformation des
Datensatzes in HTML erfolgt durch das in Listing 23 dargestellt Stylesheet.
Die Validierungen und Transformationen können mit Targets des in Listing 24 ant-buildFiles realisiert werden.
Listing 19: Ein XML-Datenfile shop4.xml mit Bezug auf DTD (Listing 20)
1
<?xml version="1.0" encoding="ISO-8859-1" standalone="no" ?>
21
2
3
<!DOCTYPE Shop SYSTEM "shop4.dtd">
4
5
6
7
8
9
10
11
<Shop>
<CD ArtistID="a01">
<Title>Cult</Title>
<Track Nr="01" Length="3.1">Path</Track>
<Track Nr="02" Length="3.43">Struggle</Track>
<Track Nr="03" Length="3.45">Romance</Track>
</CD>
12
13
14
...
<!-- as much CDs you ever want -->
15
16
17
18
<Artist ArtistID="a01">Apocalyptica</Artist>
<Artist ArtistID="a02">Manu Chao</Artist>
</Shop>
Listing 20: Die zugehörige DTD shop4.dtd
1
<?xml version=’1.0’ encoding=’ISO-8859-1’?>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!ELEMENT Shop (CD*,Artist*)>
<!ELEMENT CD (Title,Track+)>
<!ATTLIST CD
ArtistID IDREF #REQUIRED
CDNr
CDATA #IMPLIED
>
<!ELEMENT Title (#PCDATA)>
<!ELEMENT Artist (#PCDATA)>
<!ATTLIST Artist
ArtistID ID
#REQUIRED
>
<!ELEMENT Track (#PCDATA)>
<!ATTLIST Track
Nr
CDATA
#REQUIRED
Length CDATA
#REQUIRED
>
19
20
<!ENTITY copyright "©">
Listing 21: XML-Datenfile shop4xsd.xml (Auszug) mit Bezug auf Schema (Listing 22)
1
<?xml version="1.0" encoding="ISO-8859-1" standalone="no" ?>
2
3
4
5
6
<Shop
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="shop4xsd.xsd"
>
7
8
...
9
10
</Shop>
22
Listing 22: Das zugehörige XMLSchema shop4xsd.xsd
1
<?xml version=’1.0’ encoding=’ISO-8859-1’?>
2
3
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
4
5
6
7
8
9
<xsd:annotation>
<xsd:documentation xml:lang="de">
XML Schema fuer einen Shop
</xsd:documentation>
</xsd:annotation>
10
11
<xsd:element name="Shop" type="ShopTyp"/>
12
13
14
15
16
17
18
19
20
<xsd:complexType name="ShopTyp">
<xsd:sequence>
<xsd:element name="CD" type="CDTyp"
minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="Artist" type="ArtistTyp"
minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<xsd:complexType name="CDTyp" >
<xsd:sequence>
<xsd:element name="Title" type="xsd:string"/>
<xsd:element name="Track" minOccurs="1" maxOccurs="unbounded">
<xsd:complexType>
<xsd:simpleContent>
<xsd:extension base="xsd:string">
<xsd:attribute name="Nr"
type="xsd:string" use="required"/>
<xsd:attribute name="Length" type="xsd:decimal"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
<xsd:attribute name="ArtistID" type="xsd:IDREF" use="required"/>
<xsd:attribute name="CDNr"
type="xsd:string"/>
</xsd:complexType>
39
40
41
42
43
44
45
46
<xsd:complexType name="ArtistTyp" >
<xsd:simpleContent>
<xsd:extension base="xsd:string">
<xsd:attribute name="ArtistID" type="xsd:ID" use="required"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
47
48
49
</xsd:schema>
Listing 23: Das XSL-Transformationsfile shop4.xsl mit HTML-Output
1
<?xml version="1.0" encoding="ISO-8859-1"?>
23
2
3
4
5
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.w3.org/TR/REC-html40">
6
7
<xsl:output method="html" />
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<xsl:template match="/">
<html>
<head><title>Shop</title></head>
<body>
<xsl:for-each select="Shop/CD
[not(@ArtistID=preceding-sibling::CD/@ArtistID)]">
<font color="red" size="+1">
<xsl:value-of select="/Shop/Artist
[@ArtistID=current()/@ArtistID]" />
</font> <br/>
<xsl:apply-templates select="/Shop/CD
[@ArtistID=current()/@ArtistID]" />
</xsl:for-each>
</body>
</html>
</xsl:template>
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<xsl:template match="CD">
Album: <strong><xsl:value-of select="Title" /></strong>
(<xsl:value-of
select="0.01*round(100.*sum(Track/@Length))" /> min.)
<ol>
<xsl:for-each select="Track">
<li><xsl:value-of select="." />
(<xsl:value-of select="./@Length" /> min.)
</li>
</xsl:for-each>
</ol>
</xsl:template>
</xsl:stylesheet>
Listing 24: ant-build-File für Validierung und Transformation mit den Files aus Listings 19
bis 23
1
2
3
<project name="XsltTrans" basedir=".">
<property name="src" location="."/>
<property name="dest" location="./out"/>
4
5
6
7
<target name="v">
<xmlvalidate file="${src}/shop4.xml"/>
</target>
8
9
10
11
<target name="vs">
<schemavalidate file="shop4xsd.xml" />
</target>
12
13
<target name="t" depends="v">
24
14
15
16
<xslt in="${src}/shop4.xml" style="${src}/shop4.xsl"
out="${dest}/shop4.html"/>
</target>
17
18
19
20
21
<target name="ts" depends="vs">
<xslt basedir="${src}" includes="shop4xsd.xml" destdir="${dest}"
extension=".html" style="${src}/shop4.xsl"/>
</target>
22
23
</project>
25
4
XML-API-Programmierung
Es existieren eine Reihe von APIs für XML (Java, Perl, . . . ). Prinzipiell kann man all diese
für XML-Handling verwenden, wir wollen uns hier konkret den Java-APIs zuwenden.
2 grundlegende Kategorien:
• dokumenten-orientiert
– Java API for XML Processing (JAXP)
enthält alles, was benötigt wird, um XML-Files zu parsen (SAX),
in einen Objektbaum (DOM) zu wandeln
und entsprechend XSLT-Transformationsinstruktionen zu transformieren
• prozedur-orientiert
– Java API for XML-based RPC (JAX-RPC)
die Java-API zur Entwicklung und Nutzung von Web-Services
(sends SOAP method calls to remote parties over the Internet and receives the
results)
– Java API for XML Messaging (JAXM)
sends SOAP messages over the Internet in a standard way
– Java API for XML Registries (JAXR)
provides a standard way to access business registries and share information
Das Java Enterprise Tutorial liefert eine gute Einführung in XML, als Software ist die Java
Standard Edition hinreichend. (Eine recht umfangreiche Einführung in die Probleme um
Java und XML wird auch in [8] gegeben.)
Folgenden Stoff wollen wir behandeln:
• Sequentielles Parsen und Verarbeiten von XML-Files mit der Simple API for XML
(SAX)
• das Document Object Model (DOM) als baumartige Objektstruktur zur Haltung und
Bearbeitung von XML-Datei-Inhalten
• XML Stylesheet Language for Transformations (XSLT)
Zur XML-XSL-XSLT-Problemetik gibt es auch dasXALAN-Projekt
(http://xml.apache.org/xalan-j/), das auch die hier von uns benötigte Java-APIs
enthält
4.1
Java API for XML Processing (JAXP)
Software-Voraussetzung:
• Java-Standard-Edition
Beispiele zu den unterschiedlichen Teilen der JAXP finden Sie unter anderem im examplesVerzeichnis des Java Web Services Tutorial [5].
Ab JDK1.4.xx sind die JAXP-Klassen bereits in der Standard-rt.jar enthalten.
4.1.1
Simple API for XML (SAX)
Informationen zum SAX-Projekt (auch zu Features and Properties) findet man unter
http://www.saxproject.org/.
SAX realisiert ein sequentielles Parsen einer XML-Quelle und die Möglichkeit, auf ParserEreignisse zu reagieren. Dabei wird ein eventorientiertes, mit dem AWT-Eventhandling vergleichbares System verwendet. Trifft der SAXParser im geparsten XML auf eine bestimmte
26
inhaltliche Struktur (ein Element, ein Kommentar, Text, . . . ), ruft er eine dieser Struktur
entsprechende Methode des bei ihm (als Parameter im Ruf der parse(. . . )-Methode) gemeldeten Handlers auf. Trifft der Parser z.B. auf das öffnende Tag eines Elementes, ruft er die
Methode startElement(...).
Abb. aus [5]
Der Handler kann z.B. von der Klasse org.xml.sax.helpers.DefaultHandler (vergleichbar mit so etwas wie MouseAdapter, in der Abb.(aus [5]) ist der Handler aus unerfindlichen
Gründen als SAXReader bezeichnet), abgeleitet werden.
org.xml.sax.helpers.DefaultHandler implementiert die Interfaces
• ContentHandler,
• ErrorHandler,
• DTDHandler,
• und EntityResolver
mit leeren Methodenkörpern. Soll eine Reaktion erfolgen, müssen die entsprechenden Methoden überschrieben werden. Hier sind die Köpfe der Handlermethoden des folgenden Beispiels
(Listing 25) zusammengefaßt:
- public void startDocument() ...
- public void endDocument() ...
- public void startElement(String namespaceURI,
String sName, // simple name
String qName, // qualified name
Attributes attrs
) ...
- public void endElement(String namespaceURI,
String sName, // simple name
String qName // qualified name
) ...
27
- public void characters(char buf[], int offset, int len) ...
Die Namen sind sprechend, so daß der Quelltext eigentlich selbsterklärend ist. Für die Behandlung des Elementnamens, der Attribute etc. werden den entsprechenden Methoden
Parameter übergeben.
Ein Beispiel aus dem Java Web Services Tutorial [5] ist Echo01.java, ein nicht validierender Parser (kann aber umgestellt werden, ein validierender, erweiterter Parser ist
Echo10.java) ist im folgenden Listing dargestellt.
Die Klasse Echo01 beinhaltet sowohl die main()-Methode, die den Ablauf durch das hier
oft verwendete Entwurfsmuster mit Einsatz einer Factory realisiert, als auch die benötigten
Handler-Methoden (durch Ableitung von der Klasse DefaultHandler und Überschreiben
der relevanten Methoden).
Im main(...) wird ein Exemplar der Klasse (Zeile 21) zur Verwendung beim Parsen (Zeile 31) instantiiert. Die SAXParserFactory (Zeile 24) schafft einen SAXParser (Zeile 30),
welcher mit seiner Methode parse(File f, DefaultHandler h) ein File f parst und dem
DefaultHandler h immer dann eine Nachricht sendet (d.h. die entsprechende Handlermethode ruft), wenn im XML-File eine entsprechende XML-Struktur gefunden wurde.
In den Zeilen 41 - 100 sind die Handlermethoden definiert, die etwas konkretes tun sollen.
Listing 25: Auszug aus Echo01 [5]
1
import java.io.*;
2
3
4
import org.xml.sax.*;
import org.xml.sax.helpers.DefaultHandler;
5
6
7
8
import javax.xml.parsers.SAXParserFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
9
10
11
public class Echo01 extends DefaultHandler
{
12
13
14
15
16
17
18
public static void main(String argv[])
{
if (argv.length != 1) {
System.err.println("Usage: cmd filename");
System.exit(1);
}
19
20
21
// Use an instance of ourselves as the SAX event handler
DefaultHandler handler = new Echo01();
22
23
24
25
26
27
// Use the default (non-validating) parser
SAXParserFactory factory = SAXParserFactory.newInstance();
try {
// Set up output stream
out = new OutputStreamWriter(System.out, "UTF8");
28
29
30
31
// Parse the input
SAXParser saxParser = factory.newSAXParser();
saxParser.parse( new File(argv[0]), handler);
32
28
} catch (Throwable t) {
t.printStackTrace();
}
System.exit(0);
33
34
35
36
37
}
38
39
static private Writer out;
40
41
42
43
//===========================================================
// SAX DocumentHandler methods
//===========================================================
44
45
46
47
48
49
50
public void startDocument()
throws SAXException
{
emit("<?xml version=’1.0’ encoding=’UTF-8’?>");
nl();
}
51
52
53
54
55
56
57
58
59
60
61
public void endDocument()
throws SAXException
{
try {
nl();
out.flush();
} catch (IOException e) {
throw new SAXException("I/O error", e);
}
}
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
public void startElement(String namespaceURI,
String sName, // simple name
String qName, // qualified name
Attributes attrs)
throws SAXException
{
String eName = sName; // element name
if ("".equals(eName)) eName = qName; // not namespaceAware
emit("<"+eName);
if (attrs != null) {
for (int i = 0; i < attrs.getLength(); i++) {
String aName = attrs.getLocalName(i); // Attr name
if ("".equals(aName)) aName = attrs.getQName(i);
emit(" ");
emit(aName+"=\""+attrs.getValue(i)+"\"");
}
}
emit(">");
}
82
83
84
85
86
public void endElement(String namespaceURI,
String sName, // simple name
String qName // qualified name
)
29
throws SAXException
{
String eName = sName; // element name
if ("".equals(eName)) eName = qName; // not namespaceAware
emit("</"+eName+">");
}
87
88
89
90
91
92
93
public void characters(char buf[], int offset, int len)
throws SAXException
{
String s = new String(buf, offset, len);
emit(s);
}
94
95
96
97
98
99
100
//===========================================================
// Utility Methods ...
//===========================================================
101
102
103
104
// Wrap I/O exceptions in SAX exceptions, to
// suit handler signature requirements
private void emit(String s)
throws SAXException
{
try {
out.write(s);
out.flush();
} catch (IOException e) {
throw new SAXException("I/O error", e);
}
}
105
106
107
108
109
110
111
112
113
114
115
116
117
// Start a new line
private void nl()
throws SAXException
{
String lineEnd = System.getProperty("line.separator");
try {
out.write(lineEnd);
} catch (IOException e) {
throw new SAXException("I/O error", e);
}
}
118
119
120
121
122
123
124
125
126
127
128
129
}
Das Befähigen des Parsers, mit Namespaces umzugehen, erfolgt durch Umstellen der
SAXParserFactory mittels Ruf von setNamespaceAware(true).
Übung 4 Parsen Sie ein XML-File mit SAX, geben Sie es als XML wieder aus (Echo01
des JWSDP), lassen Sie validierend parsen! Nutzen Sie das Programm als Ausgangspunkte,
um eine Applikation zu programmieren, die ein XML-File (XHTML) parst und alle hrefAttribute von a-Elementen
(<a href=XXXXXX> ... </a>) erfasst und ausgibt!
30
4.1.2
Document Object Model (DOM)
Die DOM-Spezifikationen liegen beim W3C (http://www.w3.org/TR/DOM-Level-2-Core/).
Das Interface beschreibt, wie ein Dokument, welches einen XML-Baum abbildet, als Objektbaum aufgebaut werden kann und mit welchen Methoden es manipulierbar sein soll. Dabei
spielt die mögliche Implementierung keine Rolle.
Abb. aus [5]
Das folgende Beispiel (aus dem Java Web Services Tutorial [5]) dokumentiert den Aufbau
eines DOM an einem einfachen Beispiel. Es wird entsprechend des allgemeinen Entwurfsmusters zunächst eine DomBuilderFactory instantiiert (Zeile 26), diese produziert durch einen
entsprechenden Methodenruf einen neuen DomBuilder (Zeile 31), welcher nun (siehe APIDoc) ein DOM (Klasse Document) durch Parsen eines XML-Files generieren kann (Zeile 32).
Es kann aber auch durchaus ein leeres DOM (siehe weiter unten) hergestellt werden, dem
dann im weiteren Verlauf Elemente hinzugefügt werden. In Zeile 28 und 29 wird gezeigt,
wie die Factory in die Lage versetzt wird, einen validierenden und mit Namespaces umgehen
könnenden DomBuilder zu bauen.
Listing 26: DomEcho01.java [5]
1
2
3
4
import
import
import
import
javax.xml.parsers.DocumentBuilder;
javax.xml.parsers.DocumentBuilderFactory;
javax.xml.parsers.FactoryConfigurationError;
javax.xml.parsers.ParserConfigurationException;
5
6
7
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
8
9
10
import java.io.File;
import java.io.IOException;
11
12
13
import org.w3c.dom.Document;
import org.w3c.dom.DOMException;
14
15
16
17
public class DomEcho01{
// Global value so it can be ref’d by the tree-adapter
static Document document;
18
19
public static void main(String argv[])
31
{
20
if (argv.length != 1) {
System.err.println("Usage: java DomEcho filename");
System.exit(1);
}
21
22
23
24
25
DocumentBuilderFactory factory =
DocumentBuilderFactory.newInstance();
//factory.setValidating(true);
//factory.setNamespaceAware(true);
try {
DocumentBuilder builder = factory.newDocumentBuilder();
document = builder.parse( new File(argv[0]) );
26
27
28
29
30
31
32
33
} catch (SAXParseException spe) {
// Error generated by the parser
System.out.println("\n** Parsing error"
+ ", line " + spe.getLineNumber()
+ ", uri " + spe.getSystemId());
System.out.println(" " + spe.getMessage() );
34
35
36
37
38
39
40
// Use the contained exception, if any
Exception x = spe;
if (spe.getException() != null)
x = spe.getException();
x.printStackTrace();
41
42
43
44
45
46
} catch (SAXException sxe) {
// Error generated during parsing)
Exception x = sxe;
if (sxe.getException() != null)
x = sxe.getException();
x.printStackTrace();
47
48
49
50
51
52
53
} catch (ParserConfigurationException pce) {
// Parser with specified options can’t be built
pce.printStackTrace();
54
55
56
57
} catch (IOException ioe) {
// I/O error
ioe.printStackTrace();
}
} // main
58
59
60
61
62
63
}
Der folgende Auszug aus der DOM-Spezifikation soll anhand von zwei Interfaces (node, element)
zeigen, wie die Spezifikation Konstanten zur Charakterisierung von Zuständen und Signaturen von Methoden zur Bearbeitung eines Documents vorschreibt. Durch diese Spezifikation
wird gewährleistet, das für das Handling mit DOM-Implementationen in verschiedenen Programmiersprachen de facto keine Unterschiede bestehen.
Listing 27: Auszug aus der DOM-Spezifikation (interface Node)
1
interface Node {
32
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// NodeType
const unsigned
const unsigned
const unsigned
const unsigned
const unsigned
const unsigned
const unsigned
const unsigned
const unsigned
const unsigned
const unsigned
const unsigned
short
short
short
short
short
short
short
short
short
short
short
short
ELEMENT_NODE
ATTRIBUTE_NODE
TEXT_NODE
CDATA_SECTION_NODE
ENTITY_REFERENCE_NODE
ENTITY_NODE
PROCESSING_INSTRUCTION_NODE
COMMENT_NODE
DOCUMENT_NODE
DOCUMENT_TYPE_NODE
DOCUMENT_FRAGMENT_NODE
NOTATION_NODE
=
=
=
=
=
=
=
=
=
=
=
=
1;
2;
3;
4;
5;
6;
7;
8;
9;
10;
11;
12;
16
17
18
19
20
readonly attribute DOMString
attribute DOMString
...
...
nodeName;
nodeValue;
21
22
Node
insertBefore(in Node newChild,
in Node refChild)
raises(DOMException);
Node
replaceChild(in Node newChild,
in Node oldChild)
raises(DOMException);
Node
removeChild(in Node oldChild)
raises(DOMException);
Node
appendChild(in Node newChild)
raises(DOMException);
23
24
25
26
27
28
29
30
31
32
33
34
35
36
boolean hasChildNodes();
37
38
39
...
};
Auf node-Ebene werden hier Methoden zum Einfügen, Ersetzen, Löschen von Nodes etc.
festgelegt, die dann genau so auch von der speziellen Node-Klasse Element ohne eine Neudefinition genutzt werden können. Methoden zur Manipulation von Attributen finden wir
dann in der Beschreibung von Element, welches von Node abgeleitet ist.
Listing 28: Auszug aus der DOM-Spezifikation (interface Element)
41
interface Element : Node {
42
43
...
44
45
46
47
void setAttribute(in DOMString name,
in DOMString value)
raises(DOMException);
48
33
49
50
void removeAttribute(in DOMString name)
raises(DOMException);
51
52
Attr getAttributeNode(in DOMString name);
53
54
55
Attr setAttributeNode(in Attr newAttr)
raises(DOMException);
56
57
58
Attr removeAttributeNode(in Attr oldAttr)
raises(DOMException);
59
60
NodeList getElementsByTagName(in DOMString name);
61
62
63
...
};
Im folgenden Listing wird wieder ein DOM aufgebaut, hier allerdings ein leeres (Zeile 7).
Dieses noch leere Dokument wird benutzt, um ein neues XML-Element mit dem Namen
rootElement zu kreieren, welches noch keinen strukturellen Bezug zum Dokument hat.
Erst in Zeile 11 wird dieses Element dem Dokument hinzugefügt, es wird zum Rootelement
des Dokumentes, da dieses vorher leer war. Ihm wird in Zeile 12 ein Attribut hinzugefügt.
An das Rootelement mit Namen rootElement werden TextNodes angehängt (Zeilen 13 bis
15). Es ist zu beachten, daß die Java-Variablennamen (z.B. root auf Zeile 9) NICHTS mit
den Namen der XML-Elemente zu tun haben!
Listing 29: Aufbau eines Documents
1
2
3
4
5
6
7
public static void buildDom()
{
DocumentBuilderFactory factory =
DocumentBuilderFactory.newInstance();
try {
DocumentBuilder builder = factory.newDocumentBuilder();
document = builder.newDocument(); // Create from whole cloth
8
9
10
11
12
13
14
15
Element root =
(Element) document.createElement("rootElement");
document.appendChild(root);
root.setAttribute("attr","wert");
root.appendChild( document.createTextNode("Some") );
root.appendChild( document.createTextNode(" ") );
root.appendChild( document.createTextNode("text") );
16
17
// document.normalize();
18
19
20
21
22
} catch (ParserConfigurationException pce) {
// Parser with specified options can’t be built
pce.printStackTrace();
23
24
25
}
} // buildDom
34
Übung 5 Bauen Sie einen Datenbank - XML bzw. DOM - Adapter. Dazu schreiben Sie in
Anlehnung an Übung 15 eine Methode
public Document getTable(String tabname, Connection c),
die alle Datensätze einer Datenbank-Tabelle in einem DOM zurückgibt. Das Root-Element
soll den Namen der Tabelle (z.B. Kunden) tragen, bei jedem Datensatz soll der Elementname
aus ’ds’ und dem Tabellennamen zusammengesetzt sein (z.B. dsKunden), jeder Datensatz
soll wieder Elemente mit den Spaltennamen haben, deren Inhalt mit getString(...) erhaltene
PCDATA sind.
Alternativ geben Sie die Daten als XML-String zurück!
Übung 6 Lesen Sie das XML-File von Übung 2 (S.11), nachdem Sie es um einige Studenten
erweitert haben, in ein DOM ein.
Übung 7 Lesen Sie eine Datenbanktabelle und bauen Sie die Daten in ein Dokument (DOM)
ein, stellen Sie dazu eine Konvention für die Namen von Tabelle und einzelnem Datensatz
im DOM auf !
4.1.3
XSLT
Empfehlungen des W3C:
• Extensible Stylesheet Language (XSL) Version 1.0 (http://www.w3.org/TR/xsl)
• XSL Transformations (XSLT) (http://www.w3.org/TR/xslt)
Abb. aus [5]
Für Transformationen gibt es z.B.
• den XSLT-Transformer-Prozeß des XALAN-Projektes:
java org.apache.xalan.xslt.Process -IN data.xml -XSL view.xsl
[-OUT personen.html]
(Java 1.4, in 1.5 ist die Klasse verschoben, und main() heißt _main()),
• den Prozessor saxon (gibt es auch in Perl)
• oder man benutzt einfach ant mit der Task Xslt.
35
Im folgenden Quelltext wird eine XSL-Transformation durchgeführt, die Importanweisungen
sollen einen Eindruck über die Anzahl der benutzten Pakete geben. Bis Zeile 50 gibt es
im Beispiel nichts Neues, es wird ein DOM gebaut (mittels Parsen einer XML-Datei) und
modifiziert (durch Anhängen eines neuen Elementes, dabei werden die bekannten Fabriken
und “Arbeits-Klassen“ verwendet.
Ab Zeile 52 wird die XSL-Transformation realisiert, eine TransformerFactory baut einen
Transformer (Zeile 55 oder 56), wobei die Methode newTransformer()
• ohne Parameter eine 1:1-Transformation des DOMs in ein XML realisiert, das ist die
Standardart, mit der ein DOM wieder in XML transportiert wird,
• wird ihr allerdings ein in eine StremSource gewandeltes XSLT-Stylesheet-File übergeben (Zeile 55), so führt der Transformer beim Ruf von
transform(DOMSource s, StreamResult r) (Zeile 60)
die Stylesheet- Transformationsanweisungen aus.
Listing 30: Transformer-Programm .../examples/jaxp/xslt/samples/Stylizer.java [5]
1
2
3
4
import
import
import
import
javax.xml.parsers.DocumentBuilder;
javax.xml.parsers.DocumentBuilderFactory;
javax.xml.parsers.FactoryConfigurationError;
javax.xml.parsers.ParserConfigurationException;
import
import
import
import
org.xml.sax.SAXException;
org.xml.sax.SAXParseException;
org.w3c.dom.Document;
org.w3c.dom.DOMException;
// For
import
import
import
import
import
import
import
write operation
javax.xml.transform.Transformer;
javax.xml.transform.TransformerException;
javax.xml.transform.TransformerFactory;
javax.xml.transform.TransformerConfigurationException;
javax.xml.transform.dom.DOMSource;
javax.xml.transform.stream.StreamSource;
javax.xml.transform.stream.StreamResult;
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import java.io.*;
21
22
23
24
25
public class Stylizer
{
// Global value so it can be ref’d by the tree-adapter
static Document document;
26
27
28
29
30
31
32
public static void main (String argv [])
{
if (argv.length != 2) {
System.err.println ("Usage: java Stylizer stylesheet xmlfile");
System.exit (1);
}
33
34
35
36
37
DocumentBuilderFactory factory =
DocumentBuilderFactory.newInstance();
//factory.setNamespaceAware(true);
//factory.setValidating(true);
38
36
try {
File stylesheet = new File(argv[0]);
File datafile = new File(argv[1]);
39
40
41
42
DocumentBuilder builder = factory.newDocumentBuilder();
document = builder.parse(datafile);
43
44
45
46
org.w3c.dom.Element e = document.createElement("Person");
document.getDocumentElement().appendChild(e);
47
48
49
50
51
52
53
54
55
56
//
// Use a Transformer for output
TransformerFactory tFactory =
TransformerFactory.newInstance();
StreamSource stylesource = new StreamSource(stylesheet);
Transformer transformer = tFactory.newTransformer(stylesource);
Transformer transformer = tFactory.newTransformer();
57
58
59
60
DOMSource source = new DOMSource(document);
StreamResult result = new StreamResult(System.out);
transformer.transform(source, result);
Bis hier ist de facto alles wichtige im Quelltext passiert, ab hier erscheint nur noch ein
bißchen Exceptionhandling.
62
63
64
65
66
67
68
} catch (TransformerConfigurationException tce) {
// Error generated by the parser
System.out.println ("\n** Transformer Factory error");
System.out.println(" " + tce.getMessage() );
69
70
71
72
73
74
// Use the contained exception, if any
Throwable x = tce;
if (tce.getException() != null)
x = tce.getException();
x.printStackTrace();
75
76
77
78
79
} catch (TransformerException te) {
// Error generated by the parser
System.out.println ("\n** Transformation error");
System.out.println(" " + te.getMessage() );
80
81
82
83
84
85
// Use the contained exception, if any
Throwable x = te;
if (te.getException() != null)
x = te.getException();
x.printStackTrace();
86
87
88
89
} catch (SAXException sxe) {
// Error generated by this application
// (or a parser-initialization error)
37
Exception x = sxe;
if (sxe.getException() != null)
x = sxe.getException();
x.printStackTrace();
90
91
92
93
94
} catch (ParserConfigurationException pce) {
// Parser with specified options can’t be built
pce.printStackTrace();
95
96
97
98
} catch (IOException ioe) {
// I/O error
ioe.printStackTrace();
}
99
100
101
102
103
} // main
104
105
106
}
Übung 8 Geben Sie das Dokument aus Übung 7 oder Übung 6 (S.35) über einen Transformer eins zu eins als XML aus!
Übung 9 Lesen Sie das XML-File von Übung 2 (S.11), nachdem Sie es um einige Studenten
erweitert haben, in ein DOM ein. Transformieren Sie dieses DOM in XML unter einer
Transformation entsprechend Übung 3 (S.20)
38
5
Grundlegende Probleme
5.1
Konfigurationsdaten und Internationalisierung (I18n)
Software-Voraussetzung:
• Java-Standard-Edition
Inhalt dieses Abschnittes:
• die Klasse Properties zur Haltung von Konfigurationsinformationen
• die Klasse Locale zur Einstellung von Land und Sprache
• die Klasse RessourceBundle (zur String-Ersetzung, mehrsprachige Varianten)
• die Klasse Collator für Stringsortierung
• Formatierung von Datum und Uhrzeit (java.text.DateFormat)
• Formatierung von Zahlen (java.text.NumberFormat)
Zunächst wollen wir uns kurz der Parametrisierung von Programmen widmen:
Zum Halten von Parametern eines Programms wie Datenbankname, Nutzer, Passwort u.s.w.,
die in extra Konfigurationsfiles und nicht in den Quelltexten gehalten werden sollen, gibt es
die Klasse Properties. Ein Objekt dieser Klasse kann über einen InputStream (z.B. aus
einer Datei) befüllt werden.
Listing 31: Die Klasse Properties
1
2
Properties prop = new Properties();
InputStream in = null;
3
4
5
6
7
8
9
10
11
12
try{
in = new FileInputStream(new File("p.properties"));
prop.load(in);
}
catch(Exception e){ }
finally {
try { if (in!=null) in.close();}
catch(Exception e){ }
}
13
14
15
String DRIVER = prop.getProperty("driver");
System.out.print("Driver : " + DRIVER);
Das zugehörige File p.properties:
driver = mySQL-Treiber
user = root
password = myPass
Die Methode setProperty(key,value) der Klasse Properties erlaubt das Setzen von SchlüsselWert-Paaren per Programm!
Übung 10 Schreiben Sie eine Klasse (Konsolenanwendung), die alle Schlüssel-Wert-Paare
eines Properties-Objektes ausgibt!
39
Begriffe (aus dem Linux German-HOWTO):
• Locale
Ist die formale Beschreibung eines Teils der kulturellen Eigenheiten für ein Land oder
einen Spracheraum und die vom jeweiligen Programm benötigten übersetzten Texte.
• Internationalization
Veränderung eines Programms zur Unterstützung mehrerer Sprachen.
• i18n
Abkürzung für internationalization. Da viele Leute zu faul waren dieses lange Wort
immer wieder auszuschreiben, wurden einfach der erste und letzte Buchstabe belassen
und der Zwischenraum durch die Anzahl fehlender Buchstaben ersetzt.
• Localisation (Abk.: l10n)
Mit localisation wird der Prozeß bezeichnt, einem bereits internationalisierten Programm alle benötigten Informationen zur Verfügung zu stellen, um den nationalen
Besonderheiten, bezüglich der Sprache und kulturellen Umfeld zu entsprechen. Kurz
gesagt, i18n (sollte wohl l10n heißen, A.d.A.) ist der eigentliche Übersetzungsprozeß.
Mit Internationalisierung beschäftigen sich sowohl
• der Trail Internationalization im Java-Tutorial [4]
• als auch Absatz 17.4 in GoTo Java 2“ [6][7]
”
Ein Prinzip-Beispiel für Internationalisierung von Texten ...
Listing 32: Die Klasse ResourceBundle
1
import java.util.*;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class ResBundleTest {
public static void main(String [] a) {
String s=null;
try{
// ResourceBundle rb = ResourceBundle.getBundle("Texte",
//
new Locale("en","UK"));
ResourceBundle rb = ResourceBundle.getBundle("Texte",Locale.getDefault());
}
catch(Exception e){ System.out.print(e);}
...
s = rb.getString("hello");
System.out.println(s);
}
16
17
}
Listing 33: Die Resourcendateien
Texte_de_DE.properties:
hello=Guten Tag!
goodbye=Auf Wiedersehen!
Texte_en_UK.properties:
hello=Hello!
goodbye=Good bye!
40
RessourceBundle ist eine abstrakte Klasse, geliefert wird ein Objekt von Typ PropertyRessourceBundle. (Wie läßt sich das ermitteln?)
Beachten Sie, daß ResourceBundle.getBundle("BundleName") zunächst nach einer Klasse
BundleName, und dann nach einem File BundleName.properties sucht (siehe API-Dokumentation),
bei Spezifikation einer speziellen Locale ergibt sich folgende Suchreihenfolge:
<baseclass>+<specific language>+<specific country>+<specific variant>
<baseclass>+<specific language>+<specific country>
<baseclass>+<specific language>
<baseclass>+<default language>+<default country>+<default variant>
<baseclass>+<default language>+<default country>
<baseclass>+<default language>
<baseclass>
Hierbei gilt dann bei Suche eines speziellen Schlüssel: Wird er in der spezifizierten und gefundenen Version nicht gefunden, aber weiter unten in dieser Reihe, wird der weiter unten
gefundene Wert genommen.
ListRessourceBundle (abstrakt) dient zum Handling zweidimensionaler Objekt-Array-Strukturen
für Eigenschaften, die anderen besprochenen Klassen speichern nur Strings.
Übung 11 Schreiben Sie eine Testapplikation, die ermittelt, welches RessourceBundle bei
Angabe einer bestimmten Locale verwendet wird, wenn das genau passende RessourceBundle
nicht vorhanden ist!
Die Listen der Sprach- bzw. Ländercodes können mit den Methoden Locale.getISOLanguages
und Locale.getISOCountries erhalten werden. Die entsprechenden Standards gibt es gegen
Cash bei der ISO:
• ISO 639-1:2002
Codes for the representation of names of languages – Part 1: Alpha-2 code
• ISO 3166-1:1997
Codes for the representation of names of countries and their subdivisions – Part 1:
Country codes
Im Zusammenhang mit der Lokalisierung von Texten muß die alphabetische Sortierung
von Strings entsprechend der Locale realisiert werden, die im Deutschen die Einsortierung
z.B. der Umlaute zu den entsprechenden Vokalen realisiert, was bei einer Stringsortierung
nach Zeichentabelle, wie es im Englischen durchgeführt werden kann, zu einer Platzierung
der Umlaute nach dem z führen würde.
Listing 34: Sortierung
1
2
import java.util.*;
import java.text.*;
3
4
public class CollatorDemo {
5
Collator collator = Collator.getInstance(new Locale("fr","FR"));
...
// collator.compare(word1, word2 ) < 0 , wenn word1 vor word2 liegt
...
// Klasse java.util.Collections:
// static void sort(List l, Comparator c)
6
7
8
9
10
11
12
}
41
Collator (Zeile 6) ist ein Klasse für locale-sensitive Stringvergleiche. Sie wird für Suchund Sortierroutinen verwendet. Collator implementiert das Interface Comparator mit den
Methoden equals und compare und entscheidet somit, welcher von zwei Strings bei einer
alphabetischen Sortierung kleiner und welcher größer ist. Er kann als Comparator-Parameter
der sort-Routine der Klasse java.util.Collections (Zeile 11) dienen, als zu sortierender
List-Parameter kann z.B. ein Vector übergeben werden.
Übung 12 Füllen Sie einen Vector mit Strings (deutschen Wörtern), wobei Sie Umlaute
und “ß“ mit den entsprechenden Vokalen und “s“ in Vergleich treten lassen! Sortieren Sie
diesen Vector unter Verwendung einer englischen und einer deutschen Locale!
In Ergänzung können Sie die Ausgabe von Übung 10 nach Schlüsseln sortieren! Finden Sie
dazu einen Weg, das Properties-Objekt implementiert das List-Interface nicht und ist so
mit der o.g. sort-Funktion nicht sortierbar!
Eine weitere Problematik ist die locale-sensitive Formatierung von Zahlen und Datumswerten, welche im folgenden Quelltextschnipsel grob angedeutet werden soll:
Listing 35: . . . und Formatierung
1
import java.text.*;
2
3
4
5
6
7
8
9
10
11
12
public class Formatierung
{
public static void main(String[] args)
{
GregorianCalendar cal = new GregorianCalendar();
Locale lf = new Locale("fr","FR");
DateFormat df = DateFormat.getDateInstance(DateFormat.FULL,lf);
System.out.println ( df.format (cal.getTime()) );
df = DateFormat.getTimeInstance(DateFormat.FULL,lf);
System.out.println ( df.format (cal.getTime()) );
13
DecimalFormat decf = new DecimalFormat("###,###,###,##0.000");
// Formatierung entsprechend DefaultLocale
System.out.println(decf.format(Double.parseDouble(args[0])));
14
15
16
}
17
18
}
5.2
Datenbank-Programmierung mit JDBC
Software-Voraussetzung:
• Java-Standard-Edition
• eine Datenbank (MySQL, . . . ), zugehöriger Java-Treiber bzw. ein ODBC-Treiber
Verschaffen Sie sich
• anhand des Trails JDBC Database Access im Java-Tutorial [4]
• oder über das Kapitel Datenbankzugriffe mit JDBC in GoTo java 2“ [6]
”
einen Überblick über Datenbankzugriffe mit Java.
Java Database Connectivity (JDBC) ist ein Call-Level-Interface (CLI) zur Datenbank. Eine
Alternative dazu wäre Embedded SQL, das sich in Java nicht durchgesetzt hat.
4 Typen von JDBC-Treibern
42
1. die JDBC-ODBC-Bridge
2. ein JDBC-Treiber, der (clientseitig) auf die proprietären Datenbanktreiber zugreift
3. ein JDBC-Treiber, der über eine entsprechende Middleware (z.B. auch Java-Netzwerkkommunikation
mit Gegenstück auf dem Server) serverseitig auf die proprietären Datenbanktreiber zugreift
4. ein JDBC-Treiber, der direkt mit der Datenbank in derem Protokoll spricht
Im Folgenden einige Auszüge dazu aus dem Java-Tutorial [4]
Type 1 JDBC drivers are the bridge drivers such as the jdbc-odbc bridge. These drivers rely
on an intermediary such as ODBC to transfer the SQL calls to the database. Bridge drivers
often rely on native code, although the jdbc-odbc library native code is part of the Java1 2
virtual machine.
Type 2 Drivers use the existing database API to communicate with the database on the
client. Although Type 2 drivers are faster than Type 1 drivers, Type 2 drivers use native
code and require additional permissions to work in an applet. A Type 2 driver might need
client-side database code to connect over the network.
Type 3 Drivers call the database API on the server. JDBC requests from the client are first
proxied to the JDBC Driver on the server to run. Type 3 and 4 drivers can be used by thin
clients as they need no native code.
Type 4 Drivers: The highest level of driver reimplements the database network API in the
Java language. Type 4 drivers can also be used on thin clients as they also have no native
code.
Wichtige Klassen bzw. Schnittstellen im Paket java.sql.* :
• DriverManager
• Driver (ein Interface, das ein DB-Treiber implementieren muß)
• Connection
• Statement
• PreparedStatement
• ResultSet
• DatabaseMetaData
• ResultSetMetaData
• ...
Ein simples Beispiel zur Illustration:
Listing 36: Laden eines Datenbanktreibers
1
2
3
4
5
6
import java.sql.*;
...
...
try {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
// Class.forName("org.gjt.mm.mysql.Driver");
43
7
8
9
} catch(java.lang.ClassNotFoundException e) {
System.err.println(e.getMessage());
}
Listing 37: Arbeit auf einer Datenbank
11
12
13
for (Enumeration e = DriverManager.getDrivers() ; e.hasMoreElements() ;) {
System.out.println("driver: " + e.nextElement());
} // Ausgabe der Namen ALLER geladenen Treiber
14
15
16
17
18
19
try {
Connection con;
Statement stmt;
String url = "jdbc:odbc:sample-MySQL";
// String url = "jdbc:mysql://localhost/mysql" ;
20
21
22
23
24
//
//
//
//
jdbc:<subprotocol>:<subname>
<subprotokol> = odbc | mysql | ...
<subname> ist abhaengig vom subprotokoll
siehe dazu den JDBC-Teil in der Doku zum jdk
25
26
27
28
29
30
31
con = DriverManager.getConnection(url, username, password);
System.out.println ("Ok, connection to the DB worked.");
stmt = con.createStatement();
//
//
stmt = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
//
ResultSet.CONCUR_READ_ONLY);
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
ResultSet rs = stmt.executeQuery(" SELECT * FROM user;");
while (rs.next()) {
String s1 = rs.getString(1);
...
}
stmt.close();
} catch(SQLException ex) {
System.err.println("==> SQLException: ");
// unter Umstaenden kann hier wohl mehr als eine Exception
// angeflogen kommen:
while (ex != null) {
System.out.println("Message: " + ex.getMessage ());
System.out.println("SQLState: " + ex.getSQLState ());
System.out.println("ErrorCode: " + ex.getErrorCode ());
ex = ex.getNextException();
System.out.println("");
}
}
...
Mit con.createStatement() (Zeile 18) wird ein Statement instantiiert, der ResultSets
liefert, die, wie üblicherweise ein Cursor in einer Datenbank, einmal von vorn bis hinten
durchlaufen werden können. Die nächsten, auskommentierten Zeilen liefern bidirektional
iterierbare ResultSets, d.h. Methoden wie last(), first(), . . . sind hier anwendbar.
Dem executeQuery(...) eines Statement-Objektes kann ein (variabler) String übergeben
werden, somit kann das Statement-Objekt beliebig oft genutzt werden. Nachteil dieser Vor44
gehensweise ist, daß der SQL-Code jedes mal neu auf Fehlerfreiheit überprüft werden muß.
Deshalb werden aus Performancegründen für die wiederholte Abarbeitung gleicher Befehle
mit unterschiedlichen Parametern (z.B. das Einfügen vieler neuer Artikel in eine Artikeltabelle) variable PreparedStatements mit Platzhaltern ("?") für die Parameter generiert:
Listing 38: Nutzung eines PreparedStatement für wiederkehrende Aufgaben
1
2
3
4
5
PreparedStatement pstmt = con.prepareStatement("UPDATE EMPLOYEES
SET SALARY = ? WHERE ID = ?");
pstmt.setBigDecimal(1, 153833.00);
pstmt.setInt(2, 110592);
pstmt.execute();
Je nachdem, ob man ein INSERT, UPDATE, DELETE oder aber eine Query absetzen will,
nutzt man:
boolean execute() oder
ResultSet executeQuery()
auf dem Statement oder PreparedStatement
Metadaten werden mittels getMetaData() gewonnen
• auf einem ResultSet- oder PreparedStatement-Objekt
auf dem letzteren im mysql-connector-java-3.0.9-stable-bin.jar nicht implementiert,
aber in der JDBC-ODBC-Bridge
→ ResultSetMetaData
• auf einem Connection-Objekt
→ DataBaseMetaData
siehe API-Dokumentation
Übung 13 Schaffen Sie sich die Möglichkeit eines Datenbankzugriffs auf Ihrem PC! Als einfache Variante bietet sich die Kombination aus JDBC-ODBC-Bridge, ODBC-Treiber und
Access- oder MySQL-Datenbank an. Legen Sie in dieser Datenbank eine einfache Tabelle
(z.B. 2 Spalten: Name, Telefonnummer) an, geben Sie einige Datensätze ein und programmieren Sie dazu eine einfache Konsolenanwendung (Java-Programm), mit der Sie alle Datensätze dieser Tabelle ausgeben!
Übung 14 Befragen Sie die Datenbank nach den existierenden Tabellen und dann nach
den Spalten dieser Tabellen (Name, Typ), finden Sie für die Spaltenabfrage 2 verschiedene
Lösungen, und geben Sie die Informationen einfach formatiert aus (einfaches Konsolenprogramm)!
Übung 15 Schreiben Sie eine Methode
public String [][] getTable(String tabname, Connection c),
die alle Datensätze einer Datenbank-Tabelle als zweidimensionales String-Array zurückgibt.
Optional kann Zeile 0 die Spaltennamen enhalten!
45
Literatur
[1] Apache ant manual. http://ant.apache.org.
[2] R. Eckstein, XML kurz & gut, O’Reilly, 2000.
[3] The j2ee tutorial - a practical, example-based guide to the j2ee platform. http://java.
sun.com.
[4] The Java Tutorial. http://java.sun.com.
[5] Java web services tutorial. http://java.sun.com.
[6] G. Krüger, Go To Java2, Addison Wesley, 2000.
[7] G. Krüger, Handbuch der Java-Programmierung, Addison Wesley, 2002.
[8] B. McLaughlin, Java und XML, O’Reilly, 2001.
[9] S. Münz, Selfhtml v.8.1.2. http://www.selfhtml.org, 2007.
[10] C. Ullenboom, Java ist auch eine Insel, Galileo Computing, 2006.
46
Glossar und Abkürzungsverzeichnis
ant
API
AWT
(engl. Ameise) hier ein Tool der Apache Foundation zur Automatisierung von
Abläufen im Rahmen des Software-Engineering
Application Programmers Interface
Abstract Windowing Toolkit . . . ein Framework zur Entwicklung von Graphical
User Interfaces (GUI) in der Programmiersprache Java
CLI
Call Level Interface . . . eine Schnittstelle zur Kontaktaufnahme mit Datenbanken
DOM
DTD
Document Object Model
Document Type Description
GUI
Graphical User Interface (graphische Nutzerschnittstelle)
I18N
Internationalization . . . (ein I, dann 18 Buhstaben, dann ein N) bezeichnet
die Gestaltung von Programmen so, daß sie in verschiedenen Sprachen (Kulturräumen) laufen können
JAXP
Java API for XML Processing . . . ein API zum Bearbeiten von XMLDokumenten incl. XSL Transformationen
Java DataBase Connectivity
JDBC
L10N
Localization . . . die Einrichtung eines internationalisierten Programmes (siehe
I18N) für eine bestimmte Sprache
SAX
Simple API for XML
W3C
WWW
World Wide Web Consortium
World Wide Web
XML
XSL
XSLT
Extended Markup Language
Extensible Stylesheet Language
XSL Transformations
47
Index
ant, 4
project, 4
property, 4
target, 5
task, 5
Apache, 4
AWT, 26
Call-Level-Interface, siehe CLI
CLI, 42
DOM, 31
DTD, 9
extern, 10
inline, 11
Gültigkeit, 8
I18N, 39, 40
Internationalisierung, siehe I18N
JDBC, 42
Connection, 43
DatabaseMetaData, 43
DriverManager, 43
PreparedStatement, 43
ResultSet, 43
ResultSetMetaData, 43
Statement, 43
L10N, 40
Lokalisierung, siehe L10N
SAX, 26
Validity, siehe Gültigkeit
Well Formedness, siehe Wohlgeformtheit
Wohlgeformtheit, 8
XML, 7
entity, 9
Fremdschlüssel, 20
Prolog, 7
Struktur, 7
XML Schema, 11
XSLT, 15, 35
template, 18
48
Herunterladen