Abteilung Verteilte Systeme Projektgruppe AspectIX Universität Ulm Fakultät für Informatik AVID-Übung 1 XML Schema, XML-Verarbeitung mit Java 6. Mai 2004 Andreas I. Schmied (schmied@inf...)
Aufgabenstellung Gegeben: XML-Dokument: XHTML mit eingebetteten Daten. 1. XML-Schema für Daten-Fragment <avid:data> geben 2. Java-Programm entwerfen Einlesen der Daten mit JAXP-DOM Implementieren der Steuerelemente Ausgabe auf STDOUT Validieren des Dokuments (?) Achtung: Die Quelltexte und XML-Fragmente sind ggf. gekürzt und so nicht direkt verwendbar. Copyright 2004 Andreas I. Schmied (schmied@inf...), Abteilung Verteilte Systeme, Universität Ulm 2/29
XML-Dokument <?xml version="1.0" encoding="iso-8859-1"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/tr/xhtml1/dtd/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"... xmlns:avid="de.uni-ulm/infvs/avid"> <head> <title>avid-uebung 1</title> </head> <body>... </body> <avid:data xmlns="de.uni-ulm/infvs/avid">... </avid:data> </html> Was ist fehlerhaft? Copyright 2004 Andreas I. Schmied (schmied@inf...), Abteilung Verteilte Systeme, Universität Ulm 3/29
XML-Dokument <?xml version="1.0" encoding="iso-8859-1"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/tr/xhtml1/dtd/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"... xmlns:avid="de.uni-ulm/infvs/avid"> <head> <title>avid-uebung 1</title> </head> <body>... </body> <avid:data xmlns="de.uni-ulm/infvs/avid">... </avid:data> </html> Was ist fehlerhaft? de.uni-ulm/infvs/avid ist keine URI! Lösung: schemaprefix:de.uni-ulm/infvs/avid (z.b. http:) Copyright 2004 Andreas I. Schmied (schmied@inf...), Abteilung Verteilte Systeme, Universität Ulm 4/29
XML-Dokument: Datenbereich <avid:data xmlns="de.uni-ulm/infvs/avid">... <lect nick="gdi1" title="grundlagen der Informatik 1"> <prof ref-id="yves"/> <prof ref-id="loth"/> <stud ref-id="s-13"/> <stud ref-id="s-1"/> <stud ref-id="s-6"/> <stud ref-id="s-7"/> <stud ref-id="s-8"/> </lect>... <prof id="loth"> <name>prof. Dr. Loth Jordan</name> <dept>theoretische Informatik</dept> </prof>... <stud id="s-1" mnr="47114712-1"> <name>anna Berta</name> <branch>medien-informatik</branch> </stud>... </avid:data> Copyright 2004 Andreas I. Schmied (schmied@inf...), Abteilung Verteilte Systeme, Universität Ulm 5/29
Teilaufgabe 1: XML-Schema Struktur: 4 Typen: Person, Student, Professor, Lecture Person ist Basistyp für Student und Professor Gemeinsamkeit: Attribut id/ref-id und Subelement name Assoziationen: Student geht in keine oder beliebig viele Lectures Lecture hat mindestens einen Student Professor hält mindestens eine Lecture Lecture wird von 0..2 Professoren gehalten Copyright 2004 Andreas I. Schmied (schmied@inf...), Abteilung Verteilte Systeme, Universität Ulm 6/29
XML-Schema: "Rahmen" <?xml version="1.0" encoding="iso-8859-1"?> <xs:schema xmlns:xs="http://www.w3.org/2001/xmlschema" xmlns:xsi="http://www.w3.org/2001/xmlschema-instance" xsi:schemalocation="http://www.w3.org/2001/xmlschema http://www.w3.org/2001/xmlschema.xsd" xmlns:avid="avid-ulm:de.uni-ulm/infvs/avid" targetnamespace="avid-ulm:de.uni-ulm/infvs/avid" elementformdefault="qualified"> <xs:element name="data">... <xs:complextype name="lecttype">... <xs:complextype name="reftype">... <xs:complextype name="persontype">... <xs:complextype name="studtype">... <xs:complextype name="proftype">... </xs:schema> Copyright 2004 Andreas I. Schmied (schmied@inf...), Abteilung Verteilte Systeme, Universität Ulm 7/29
XML-Schema: das Haupt-Element <xs:element name="data"> <xs:complextype> <xs:sequence minoccurs="0" maxoccurs="unbounded"> <xs:element name="lect" type="avid:lecttype" minoccurs="0"/> <xs:element name="prof" type="avid:proftype" minoccurs="0"/> <xs:element name="stud" type="avid:studtype" minoccurs="0"/> </xs:sequence> </xs:complextype> <xs:key name="key_of_prof"> <xs:selector xpath="./prof"/> <xs:field xpath="@id"/> </xs:key> <xs:keyref name="ref_to_prof" refer="avid:key_of_prof"> <xs:selector xpath="./lect/prof"/> <xs:field xpath="@ref-id"/> </xs:keyref>... ebenso für stud </xs:element> Copyright 2004 Andreas I. Schmied (schmied@inf...), Abteilung Verteilte Systeme, Universität Ulm 8/29
XML-Schema: freie Typen <xs:complextype name="lecttype"> <xs:sequence> <xs:element name="prof" type="avid:reftype" minoccurs="0" maxoccurs="2"/> <xs:element name="stud" type="avid:reftype" maxoccurs="unbounded"/> </xs:sequence> <xs:attribute name="nick" type="xs:string" use="required"/> <xs:attribute name="title" type="xs:string" use="required"/> </xs:complextype> <xs:complextype name="reftype"> <xs:attribute name="ref-id" type="xs:idref" use="required"/> </xs:complextype> Copyright 2004 Andreas I. Schmied (schmied@inf...), Abteilung Verteilte Systeme, Universität Ulm 9/29
XML-Schema: "Vererbung" bzw. Erweiterung <xs:complextype name="persontype"> <xs:sequence> <xs:element name="name" type="xs:string"/> </xs:sequence> <xs:attribute name="id" type="xs:id" use="required"/> </xs:complextype> AVID-Übung 1 <xs:complextype name="studtype"> <xs:complexcontent> <xs:extension base="avid:persontype"> <xs:sequence> <xs:element name="branch" type="xs:string"/> </xs:sequence> <xs:attribute name="mnr" type="xs:string" use="required"/> </xs:extension> </xs:complexcontent> </xs:complextype> Copyright 2004 Andreas I. Schmied (schmied@inf...), Abteilung Verteilte Systeme, Universität Ulm 10/29
Teilaufgabe 2: Einlesen mit JAXP-DOM JAXP: Java API for XML Processing Parsing SAX: Ereignisorientierter Parser Simple API for XML DOM: Objektmodell-Parser Document Object Model Baum aus Elementen mit Attributen,... Transformation mit XSLT Weitere Technologiepakete: JAXB (Binding), JAXR (Registries), JAX-RPC Copyright 2004 Andreas I. Schmied (schmied@inf...), Abteilung Verteilte Systeme, Universität Ulm 11/29
Erzeugen eines Builder und Parsen Beliebigen Parser erzeugen (CLASSPATH!) DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setnamespaceaware(true); DocumentBuilder builder = factory.newdocumentbuilder(); builder.seterrorhandler(new org.xml.sax.errorhandler() {... } ); Document doc = builder.parse(file); Element root = doc.getdocumentelement(); Copyright 2004 Andreas I. Schmied (schmied@inf...), Abteilung Verteilte Systeme, Universität Ulm 12/29
Arbeiten mit dem DOM Struktur (vereinfacht): Document Element (NodeList) Attribute (NamedNodeList) Element (NodeList) andere Node-Objekte (parent link) andere Node-Objekte Auch Texte sind Node-Objekte: <div myattr="bla"> ein Text </div> Element div NamedNodeList [0] #text: " ein Text " Copyright 2004 Andreas I. Schmied (schmied@inf...), Abteilung Verteilte Systeme, Universität Ulm 13/29
Einlesen des Datenbereichs (1) Titel zwischenspeichern (für avid:generate="page-title") Element head = (Element) root.getelementsbytagname("head").item(0); Element headtitle = (Element) head.getelementsbytagname("title").item(0); title = headtitle.getfirstchild().getnodevalue(); Achtung: Element.getElementsByTagName findet alle Descendants, also Kinder und Kindeskinder des aktuellen Knoten Datenbereich avid:data einlesen und aus Baum entfernen: Element data = (Element) root.getelementsbytagname("avid:data").item(0);... s.u.... data.getparentnode().removechild(data); Copyright 2004 Andreas I. Schmied (schmied@inf...), Abteilung Verteilte Systeme, Universität Ulm 14/29
Einlesen des Datenbereichs (2) Datenbereich avid:data einlesen (innerer Teil) Node child = data.getfirstchild(); while(child!=null) { } if (child.getnodetype() == Node.ELEMENT_NODE) { Element e = (Element) child; String name = e.getnodename(); if (name.equals("lect")) lects.add(new Lect(e)); else if (name.equals("prof")) profs.put(e.getattribute("id"), new Prof(e)); else if (name.equals("stud")) studs.put(e.getattribute("id"), new Stud(e)); } child = child.getnextsibling(); In Lect-Objekten die Verknüpfungen herstellen: ref-id -> id über prof.., stud[@ref-id] iterieren auf eben erzeugte Prof/Stud-Objekte verweisen (via HashMap über Attribut id) Copyright 2004 Andreas I. Schmied (schmied@inf...), Abteilung Verteilte Systeme, Universität Ulm 15/29
Teilaufgabe 2: Steuerelemente Erzeugen aus Daten dynamisch HTML-Text 1: <div avid:generate="page-title"/> wird gefüllt mit Text aus //head/title 2: avid:for-lectures iteriert über alle Veranstaltungen 3: avid:get-lecture Titel der aktuellen Veranstaltung 4: avid:for-students iteriert über alle avid:stud 5: avid:get-student Name des aktuellen Student 6: avid:get-professors Namensliste der Professoren 7: avid:sum-branches Verteilung auf Studienfächer Copyright 2004 Andreas I. Schmied (schmied@inf...), Abteilung Verteilte Systeme, Universität Ulm 16/29
Steuerelemente: Anwendung Elemente (3-7) sind kontextabhängig von (2), (5) auch von (4) <avid:for-lectures> <h2> <avid:get-lecture/> </h2> <p> <avid:get-professors/> </p> <ul> <avid:for-students> <li> <avid:get-student/> </li> </avid:for-students> </ul> <p>anteil an Studienrichtung: <avid:sum-branches/> </avid:for-lectures> </p> Copyright 2004 Andreas I. Schmied (schmied@inf...), Abteilung Verteilte Systeme, Universität Ulm 17/29
Steuerelemente: Ausgabe... <h2>grundlagen der Informatik 1 (GDI1)</h2> <p>dozenten: Prof. Dr. Yves Martin, Prof. Dr. Loth Jordan</p> <ul> <li>anna Berta</li> <li>karen Linus</li> <li>moni Nathan</li> <li>otto Patrick</li> <li>yvette Zausel</li> </ul> <p>anteil an Studienrichtung: 2 Medien-Informatik, 2 Diplom-Informatik, 1 Master-Informatik</p>... Copyright 2004 Andreas I. Schmied (schmied@inf...), Abteilung Verteilte Systeme, Universität Ulm 18/29
Implementierung der Steuerelemente Zustandsvariablen für die Iteratoren avid:for-xxx: Lect statelect; Stud statestud; sichern Kontext innerhalb Iteratoren (non-reentrant!) Rekursive Methode startet am Node-Objekt für /html/body: }... process(body, null) public Node process(node node, Element parent) { String name = node.getnodename(); String prefix = node.getprefix();... s.u.... } Copyright 2004 Andreas I. Schmied (schmied@inf...), Abteilung Verteilte Systeme, Universität Ulm 19/29
Implementierung: Auswahl avid:* und Rekursion Sonderbehandlung für avid:...-elemente Rekursion über Attribute und Subelemente if (prefix!=null && prefix.equals("avid")) {... s.u.... } else if (node.getnodetype() == Node.ELEMENT_NODE){ NamedNodeMap atts = node.getattributes(); for (int i=0; atts!=null && i<atts.getlength(); i++) process(atts.item(i), (Element) node); AVID-Übung 1 } NodeList children = node.getchildnodes(); for (int i=0; i<children.getlength(); i++) process(children.item(i), (Element) node); return node; Copyright 2004 Andreas I. Schmied (schmied@inf...), Abteilung Verteilte Systeme, Universität Ulm 20/29
Implementierung: Sonderbehandlung (1) Attribut avid:generate="..." gefunden switch(node.getnodetype()) { case Node.ATTRIBUTE_NODE: { Attr attr = (Attr) node; if (name.equals("avid:generate")...) { 1. Text gentext = doc.createtextnode(...); 2. parent.appendchild(gentext); 3. parent.setattribute("style","font-size:18pt;..."); 4. parent.removeattributenode(attr); } } break;... 1. Text-Knoten erzeugen (am Document-Objekt) 2. an <div>-element anfügen 3. Attribut <div style="..."> setzen 4. Attribut avid:generate="..." entfernen Copyright 2004 Andreas I. Schmied (schmied@inf...), Abteilung Verteilte Systeme, Universität Ulm 21/29
Implementierung: Sonderbehandlung (2) Element avid:... gefunden case Node.ELEMENT_NODE: { Element elem = (Element) node; 1. if (name.equals("avid:for-lectures")) { for (Iterator ilect = lects.iterator(); ilect.hasnext();){ 2. statelect = (Lect) ilect.next(); 3. NodeList children = elem.getchildnodes(); for (int i=0; i<children.getlength(); i++) { 4. Node clone = children.item(i).clonenode(true); 5. parent.insertbefore(process(clone,null),elem); } } 6. parent.removechild(elem); }... 1. Varianten unterscheiden (s.u.) 2. ggf. Zustandsvariable setzen 3. für sämtliche Unterelemente (des Steuerelements)... 4.... Klon anlegen (Deep-Copy) 5.... Rekursion und vor Steuerelement einhängen 6. Steuerelement entfernen Copyright 2004 Andreas I. Schmied (schmied@inf...), Abteilung Verteilte Systeme, Universität Ulm 22/29
Implementierung: Sonderbehandlung (3) kontextabhängig aktuellen Student bzw. Professoren anzeigen elem ist entweder <avid:get-student/> oder <avid:get-professors/>... else if (name.equals("avid:get-student")) { Text gen = doc.createtextnode(statestud.name+...); parent.insertbefore(gen,elem); parent.removechild(elem); } else if (name.equals("avid:get-professors")) { String profs="dozenten: "; for (Iterator i=statelect.profs.iterator(); i.hasnext();) profs += ((Prof) i.next()).name + (i.hasnext()?", ":""); } Text gen = doc.createtextnode(profs); parent.insertbefore(gen,elem); parent.removechild(elem); Copyright 2004 Andreas I. Schmied (schmied@inf...), Abteilung Verteilte Systeme, Universität Ulm 23/29
Ausgabe auf STDOUT via XSLT-Packages: import javax.xml.transform.transformer; import javax.xml.transform.transformerfactory; try { TransformerFactory tfactory = TransformerFactory.newInstance(); Transformer transformer = tfactory.newtransformer(); DOMSource source = new DOMSource(doc); StreamResult result = new StreamResult(System.out); transformer.transform(source, result); } catch(transformerconfigurationexception e) {... } catch(transformerexception e) {... } Alternativen: Ausgabe als HTML, text/plain,... statt XHTML weitere verkettete XSL-Transformationsschritte Copyright 2004 Andreas I. Schmied (schmied@inf...), Abteilung Verteilte Systeme, Universität Ulm 24/29
Experiment: Validierung JAXP soll Xerces-Parser von Apache.org verwenden: CLASSPATH! 1. Versuch: Nur Daten-Fragment in eigener Datei validieren Validierender Parser (hier mit XERCES-Optionen): DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setvalidating(true);... factory.setattribute( "http://apache.org/xml/features/validation/schema", new Boolean(true)); factory.setattribute( "http://apache.org/xml/features/validation/schema-full-checking", new Boolean(true)); 2. Versuch: Compound-Dokument XHTML-Schema defekt? Copyright 2004 Andreas I. Schmied (schmied@inf...), Abteilung Verteilte Systeme, Universität Ulm 25/29
Alternativen zur Transformation (1) Transformation mit XSLT (XML Stylesheet Language Transformations) Mustersuche auf dem DOM-Baum mittels XPath <?xml version='1.0' encoding='iso-8859-1'?> <xsl:stylesheet xmlns:xsl='http://www.w3.org/1999/xsl/transform' version='1.0' xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://www.w3.org/1999/xhtml" xmlns:avid="avid-ulm:de.uni-ulm/infvs/avid" exclude-result-prefixes="h" > <xsl:output method='xml' indent='yes' encoding='iso-8859-1' /> <xsl:template match="...">... s.u.... </xsl:template> </xsl:stylesheet> Copyright 2004 Andreas I. Schmied (schmied@inf...), Abteilung Verteilte Systeme, Universität Ulm 26/29
Alternativen zur Transformation (2) <xsl:template match="avid:for-lectures"> <xsl:for-each select="//avid:data/avid:lect"> <h2><xsl:value-of select="@title"/></h2> <p>dozenten:...</p> <ul> <xsl:for-each select="avid:stud">... <li> <xsl:variable name="refid"> <xsl:value-of select="@ref-id"/> </xsl:variable> <xsl:value-of select = "//avid:data/avid:stud[@id=$refid]/avid:name"/> </li> </xsl:for-each> </ul> <p>anteil an Studienrichtung: <xsl:call-template name="aggr"/> </p> </xsl:for-each> </xsl:template> Copyright 2004 Andreas I. Schmied (schmied@inf...), Abteilung Verteilte Systeme, Universität Ulm 27/29
Alternativen zur Transformation (3) <xsl:template match="h:div[@avid:generate='page-title']"> <div style="font-size:18pt;..."> <xsl:value-of select="//h:head/h:title/text()"/> </div> </xsl:template> Copyright 2004 Andreas I. Schmied (schmied@inf...), Abteilung Verteilte Systeme, Universität Ulm 28/29
Ausblick Alternative Traversierung/Modifikation SAX JDOM XPATH-API XSLT-API v.a. XSLTC - XSLT Compiler Einbettung von Java/Python-Code, ECMA-Script in XSLT-Skripte alternative Parser,... Alternative Schemasprachen RelaxNG Schematron Pollo-Schema... Copyright 2004 Andreas I. Schmied (schmied@inf...), Abteilung Verteilte Systeme, Universität Ulm 29/29