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: &amp; &lt; &gt; &quot; &apos; 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&auml;nge: 53 <br/> CD : The Singer : Awesome L&auml;nge: 42.57 <br/> CD : Tim Tom : Lieder 19 14 15 16 17 18 19 L&auml;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 "&#xA9;"> 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