Verarbeitung von XMLDokumenten © Klaus Schild, XML Clearinghouse 2003 1 Lernziele Was unterscheidet Pull- von Push-Parser? Was unterscheidet Einschritt- von Mehrschritt-Parser? Wie ordnen sich SAX und DOM bezüglich dieser Kategorien ein? Warum sollte immer die Anwendungslogik vom Datenzugriff getrennt werden? Was sind Schema-Übersetzer? © Klaus Schild, XML Clearinghouse 2003 2 Grundlegende Architektur Zeichenkette XMLDokument Anwendung Serialisierer Parser standardisierte APIs Möglichst immer standardisierte APIs verwenden! Parser: Analysiert XML-Dokument und erstellt Parse-Baum mit Tags, Text-Inhalten und Attribut-Wert-Paaren als Knoten. Serialisierer: Generiert aus Datenstruktur einer Anwendung ein XML-Dokument. © Klaus Schild, XML Clearinghouse 2003 3 Kategorien von Parser Parser können bezüglich folgender Kriterien eingeordnet werden: Pull- vs. Push-Parser: Wer hat die Kontrolle über das Parsen, die Anwendung oder der Parser selbst? Einschritt- vs. Mehrschritt-Parser (engl. one-step vs. multistep parsing): Wird das XML-Dokument in einem Schritt vollständig geparst oder werden die einzelnen syntaktischen Einheiten Schritt für Schritt analysiert? Beachte: Die Kategorien sind unabhängig voneinander, sie können beliebig kombiniert werden. © Klaus Schild, XML Clearinghouse 2003 4 Pull-Parser nächste Einheit? Pull-Parser übersetzte Einheit Anwendung Die Anwendung hat die Kontrolle über das Parsen. Die Analyse der nächsten syntaktischen Einheit muss von der Anwendung aktiv angefordert werden. © Klaus Schild, XML Clearinghouse 2003 5 Push-Parser Push-Parser übersetzte Einheit Anwendung Der Parser selbst hat die Kontrolle über das Parsen. Sobald der Parser eine syntaktische Einheit analysiert hat, benachrichtigt er die Anwendung und übergibt die entsprechende Analyse. © Klaus Schild, XML Clearinghouse 2003 6 XML-Parser One-step Pull Multi-step JAXP DOM Push SAX DOM: Document Object Model SAX: Simple API for XML JAXP: Java API for XML Processing © Klaus Schild, XML Clearinghouse 2003 7 Simple API for XML (SAX) standardisiertes API für Push-Mehrschritt-Parsen von XML-Dokumenten ursprünglich nur Java-API, inzwischen werden aber auch andere Sprachen unterstützt kein W3C-Standard, sondern de facto Standard © Klaus Schild, XML Clearinghouse 2003 8 Ereignisbasiertes Parsen SAX-Parser Information Parse Event Handler Anwendung © Klaus Schild, XML Clearinghouse 2003 9 Ereignisbasiertes Parsen <priceList> [Parser ruft startElement auf] <priceList> <coffee> <coffee> [Parser ruft startElement auf] <name> <name> [Parser ruft startElement auf] MochaJava Java [Parser ruft characters auf] Mocha </name> </name> [Parser ruft endElement auf] <price> <price> [Parser ruft startElement auf] 11.95 11.95 [Parser ruft characters auf] </price> </price> [Parser ruft endElement auf] </coffee> </coffee> [Parser ruft endElement auf] </priceList> [Parser ruft endElement auf] </priceList> Sobald eine syntaktische Einheit geparst wurde, wird die Anwendung benachrichtigt: z.B. mit startElement(…,priceList,…) Beachte: Es wird kein Parse-Baum aufgebaut! © Klaus Schild, XML Clearinghouse 2003 10 Callback-Methoden startElement, endElement und characters werden Call-BackMethoden genannt, weil sie vom Parser aufgerufen werden. Für jede syntaktische Struktur in XML gibt es eine eigene Callback-Methode. Die Standard-Implementierung der Call-Back-Methoden (DefaultHandler) machen gar nichts. Jede Callback-Methode kann aber entsprechend den Erfordernissen überschrieben werden. © Klaus Schild, XML Clearinghouse 2003 11 Ein SAX-Parser SAXParserFactoryfactory factory==SAXParserFactory.newInstance(); SAXParserFactory.newInstance(); SAXParserFactory SAXParsersaxParser saxParser==factory.newSAXParser(); factory.newSAXParser(); SAXParser saxParser.parse("priceList.xml",handler); handler); saxParser.parse("priceList.xml", SAXParserFactory.newInstance() liefert eine SAXParserFactory. Die Methode newSAXParser() liefert einen SAXParser mit einer Methode parse(). priceList.xml: die zu parsende Datei (kann auch eine URL oder ein Stream sein). handler: Instanz von DefaultHandler, implementiert die Callback-Funktionen. © Klaus Schild, XML Clearinghouse 2003 12 Exkurs: Factory Method Design Pattern aus „Design Patterns“ von Gamma, Helm, Johnson, Vlissides (1995). liefert ein Objekt Objekt ist Instanz einer abstrakten Klasse oder einem Interface. wird von mehreren Klassen implementiert Beispiel: Iterator i = list.iterator(); © Klaus Schild, XML Clearinghouse 2003 13 Beispiel <priceList> <priceList> <coffee> <coffee> <name> <name> MochaJava Java Mocha </name> </name> <price> <price> 11.95 11.95 </price> </price> </coffee> </coffee> </priceList> </priceList> © Klaus Schild, XML Clearinghouse 2003 Gib des Preis des Kaffees Mocha Java aus! 14 Die Callback-Methoden publicvoid voidstartElement(..., startElement(...,String StringelementName, elementName,...){ ...){ public (elementName.equals("name")){ inName inName==true; true; }} ifif(elementName.equals("name")){ elseifif(elementName.equals("price") (elementName.equals("price")&& &&inMochaJava inMochaJava){ ){ else inPrice==true; true; inPrice <name>MochaJava</name> Java</name> <name>Mocha inName==false; false; }}}} inName <price>11.95</price> <price>11.95</price> publicvoid voidcharacters(char characters(char[][]buf, buf,int intoffset, offset,int intlen) len){{ public Stringss==new newString(buf, String(buf,offset, offset,len); len); String (inName&& &&s.equals("Mocha s.equals("MochaJava")) Java")){{ ifif(inName inMochaJava==true; true; inMochaJava inName==false; false; }} inName elseifif(inPrice) (inPrice){{ else System.out.println("Theprice priceof ofMocha MochaJava Javais: is:""++s); s); System.out.println("The inMochaJava==false; false; inMochaJava inPrice==false; false; }} }} inPrice © Klaus Schild, XML Clearinghouse 2003 15 Die Callback-Methoden publicvoid voidstartElement(..., startElement(...,String StringelementName, elementName,...){ ...){ public (elementName.equals("name")){ inName inName==true; true; }} ifif(elementName.equals("name")){ elseifif(elementName.equals("price") (elementName.equals("price")&& &&inMochaJava inMochaJava){ ){ else inPrice==true; true; inPrice <name>MochaJava</name> Java</name> <name>Mocha inName==false; false; }}}} inName <price>11.95</price> <price>11.95</price> publicvoid voidcharacters(char characters(char[][]buf, buf,int intoffset, offset,int intlen) len){{ public Stringss==new newString(buf, String(buf,offset, offset,len); len); String (inName&& &&s.equals("Mocha s.equals("MochaJava")) Java")){{ ifif(inName inMochaJava==true; true; inMochaJava inName==false; false; }} inName elseifif(inPrice) (inPrice){{ else System.out.println("Theprice priceof ofMocha MochaJava Javais: is:""++s); s); System.out.println("The inMochaJava==false; false; inMochaJava inPrice==false; false; }} }} inPrice © Klaus Schild, XML Clearinghouse 2003 16 Die Callback-Methoden publicvoid voidstartElement(..., startElement(...,String StringelementName, elementName,...){ ...){ public (elementName.equals("name")){ inName inName==true; true; }} ifif(elementName.equals("name")){ elseifif(elementName.equals("price") (elementName.equals("price")&& &&inMochaJava inMochaJava){){ else inPrice==true; true; inPrice <name>MochaJava</name> Java</name> <name>Mocha inName==false; false; }}}} inName <price>11.95</price> <price>11.95</price> publicvoid voidcharacters(char characters(char[][]buf, buf,int intoffset, offset,int intlen) len){{ public Stringss==new newString(buf, String(buf,offset, offset,len); len); String (inName&& &&s.equals("Mocha s.equals("MochaJava")) Java")){{ ifif(inName inMochaJava==true; true; inMochaJava inName==false; false; }} inName elseifif(inPrice) (inPrice){{ else System.out.println("Theprice priceof ofMocha MochaJava Javais: is:""++s); s); System.out.println("The inMochaJava==false; false; inMochaJava inPrice==false; false; }} }} inPrice © Klaus Schild, XML Clearinghouse 2003 17 Die Callback-Methoden publicvoid voidstartElement(..., startElement(...,String StringelementName, elementName,...){ ...){ public (elementName.equals("name")){ inName inName==true; true; }} ifif(elementName.equals("name")){ elseifif(elementName.equals("price") (elementName.equals("price")&& &&inMochaJava inMochaJava){ ){ else inPrice==true; true; inPrice <name>MochaJava</name> Java</name> <name>Mocha inName==false; false; }}}} inName <price>11.95</price> <price>11.95</price> publicvoid voidcharacters(char characters(char[][]buf, buf,int intoffset, offset,int intlen) len){{ public Stringss==new newString(buf, String(buf,offset, offset,len); len); String (inName&& &&s.equals("Mocha s.equals("MochaJava")) Java")){{ ifif(inName inMochaJava==true; true; inMochaJava inName==false; false; }} inName elseifif(inPrice) (inPrice){{ else System.out.println("Theprice priceof ofMocha MochaJava Javais: is:""++s); s); System.out.println("The inMochaJava==false; false; inMochaJava inPrice==false; false; }} }} inPrice © Klaus Schild, XML Clearinghouse 2003 18 Vor- und Nachteile von SAX + sehr effizient, auch bei großen XML-Dateien – Kontext (Parse-Baum) muss von der Anwendung selbst verwaltet werden. – Abstrahiert nicht von der spezifischen XML-Syntax. – nur Parsen von XML-Dokumenten möglich, keine Modifikation oder Erstellung von Dokumenten © Klaus Schild, XML Clearinghouse 2003 19 Weitere Informationen zu SAX Î http://www.saxproject.org/ © Klaus Schild, XML Clearinghouse 2003 20 Zusätzliche Schicht zum Datenzugriff Anwendung SAX SAX startElement characters Datenzugriff Datenzugriff Anwendungslogik getPriceList() Immer Anwendungslogik durch spezielle Schicht von dem Datenzugriff trennen (nicht nur bei SAX). Z.B. könnte getPriceList() eine Liste von Ware-PreisPaaren liefern. Sollte nicht nur von SAX-APIs, sondern auch von der XML-Syntax abstrahieren. © Klaus Schild, XML Clearinghouse 2003 21 Document Object Model (DOM) XMLParser DOM Anwendung W3C-Standard zum Zugreifen, Modifizieren und Erstellen von Parse-Bäumen nicht nur für XML-, sondern auch für HTML-Dokumente abstrakte Schnittstelle, unabhängig von Programmiersprachen im Ergebnis ein Einschritt-Pull-Parser © Klaus Schild, XML Clearinghouse 2003 22 Parse-Bäume in DOM <?xmlversion="1.0" version="1.0"?> ?> <?xml <priceList> <priceList> <coffee> <coffee> <name>MochaJava</name> Java</name> <name>Mocha <price>11.95</price> <price>11.95</price> </coffee> </coffee> </priceList> </priceList> Document Node NodeList Element Node: PriceList NodeList Element Node: coffee Beachte: In DOM ist priceList nicht die Dokument-Wurzel. DOM führt virtuelle Dokument-Wurzel ein, um auch syntaktische Einheiten außerhalb von priceList repräsentieren zu können. © Klaus Schild, XML Clearinghouse 2003 23 Parse-Bäume in DOM <?xmlversion="1.0" version="1.0"?> ?> <?xml Beachte: Text-Inhalte <priceList> <priceList> werden als eigene Knoten <coffee> <coffee> dargestellt. <name>Mocha Java</name> <name>Mocha Java</name> <price>11.95</price> <price>11.95</price> </coffee> </coffee> Element Node: coffee </priceList> </priceList> NodeList Element Node: name Element Node: price NodeList NodeList Text Node: Mocha Java Text Node: 11.95 © Klaus Schild, XML Clearinghouse 2003 24 Navigationsmodell parentNode previousSibling Node nextSibling childNodes firstChild © Klaus Schild, XML Clearinghouse 2003 lastChild 25 Ein DOM-Parser DocumentBuilderFactoryfactory factory== DocumentBuilderFactory.newInstance(); DocumentBuilderFactory.newInstance(); DocumentBuilderFactory DocumentBuilderbuilder builder==factory.newDocumentBuilder(); factory.newDocumentBuilder(); DocumentBuilder Documentdocument document==builder.parse("priceList.xml"); builder.parse("priceList.xml"); Document DocumentBuilderFactory.newInstance() liefert eine DocumentBuilderFactory. Die Methode newDocumentBuilder() von DocumentBuilderFactory liefert einen DOM-Parser. Der DOM-Parser hat eine Methode parse(). © Klaus Schild, XML Clearinghouse 2003 26 Beispiel <priceList> <priceList> <coffee> <coffee> <name> <name> MochaJava Java Mocha </name> </name> <price> <price> 11.95 11.95 </price> </price> </coffee> </coffee> </priceList> </priceList> © Klaus Schild, XML Clearinghouse 2003 Gib des Preis des Kaffees Mocha Java aus! 27 DOM-Methoden NodeListcoffeeNodes coffeeNodes==document.getElementsByTagName("coffee"); document.getElementsByTagName("coffee"); NodeList Direkter Zugriff auf bestimmte Elemente mit getElementsByTagName möglich. Resultat ist eine NodeList. © Klaus Schild, XML Clearinghouse 2003 <?xmlversion="1.0" version="1.0"?> ?> <?xml <priceList> <priceList> <coffee> <coffee> <name>MochaJava</name> Java</name> <name>Mocha <price>11.95</price> <price>11.95</price> </coffee> </coffee> </priceList> </priceList> 28 DOM-Methoden NodeListcoffeeNodes coffeeNodes==document.getElementsByTagName("coffee"); document.getElementsByTagName("coffee"); NodeList for(int (inti=0; i=0;ii<<coffeeNodes.getLength(); coffeeNodes.getLength();i++) i++){{ for thisCoffeeNode==coffeeNodes.item(i); coffeeNodes.item(i); thisCoffeeNode … … }} coffeeNodes.item(0) © Klaus Schild, XML Clearinghouse 2003 <?xmlversion="1.0" version="1.0"?> ?> <?xml <priceList> <priceList> <coffee> <coffee> <name>MochaJava</name> Java</name> <name>Mocha <price>11.95</price> <price>11.95</price> </coffee> </coffee> </priceList> </priceList> 29 DOM-Methoden NodeListcoffeeNodes coffeeNodes==document.getElementsByTagName("coffee"); document.getElementsByTagName("coffee"); NodeList for(int (inti=0; i=0;ii<<coffeeNodes.getLength(); coffeeNodes.getLength();i++) i++){{ for thisCoffeeNode==coffeeNodes.item(i); coffeeNodes.item(i); thisCoffeeNode NodethisNameNode thisNameNode==thisCoffeeNode.getFirstChild(); thisCoffeeNode.getFirstChild(); Node Stringdata data==thisNameNode.getFirstChild().getNodeValue(); thisNameNode.getFirstChild().getNodeValue(); String (data.equals("MochaJava")) Java")){{ ifif(data.equals("Mocha NodethisPriceNode thisPriceNode==thisCoffeeNode.getNextSibling(); thisCoffeeNode.getNextSibling(); Node <?xmlversion="1.0" version="1.0"?> ?> <?xml Stringprice price== thisPriceNode.getFirstChild().getNodeValue(); thisPriceNode.getFirstChild().getNodeValue(); String <priceList> <priceList> break;}}}} break; <coffee> <coffee> <name>MochaJava</name> Java</name> <name>Mocha firstChild <price>11.95</price> <price>11.95</price> </coffee> </coffee> </priceList> </priceList> © Klaus Schild, XML Clearinghouse 2003 30 DOM-Methoden NodeListcoffeeNodes coffeeNodes==document.getElementsByTagName("coffee"); document.getElementsByTagName("coffee"); NodeList for(int (inti=0; i=0;ii<<coffeeNodes.getLength(); coffeeNodes.getLength();i++) i++){{ for thisCoffeeNode==coffeeNodes.item(i); coffeeNodes.item(i); thisCoffeeNode NodethisNameNode thisNameNode==thisCoffeeNode.getFirstChild(); thisCoffeeNode.getFirstChild(); Node Stringdata data==thisNameNode.getFirstChild().getNodeValue(); thisNameNode.getFirstChild().getNodeValue(); String (data.equals("MochaJava")) Java")){{ ifif(data.equals("Mocha NodethisPriceNode thisPriceNode==thisCoffeeNode.getNextSibling(); thisCoffeeNode.getNextSibling(); Node <?xmlversion="1.0" version="1.0"?> ?> <?xml String price = thisPriceNode.getFirstChild().getNodeValue(); String price = thisPriceNode.getFirstChild().getNodeValue(); <priceList> <priceList> firstChild break;}}}} break; <coffee> <coffee> <name>MochaJava</name> Java</name> <name>Mocha Beachte: getFirstChild() liefert <price>11.95</price> <price>11.95</price> </coffee> den Text-Knoten, nicht dessen </coffee> </priceList> Inhalt „Mocha Java“! </priceList> © Klaus Schild, XML Clearinghouse 2003 31 DOM-Methoden NodeListcoffeeNodes coffeeNodes==document.getElementsByTagName("coffee"); document.getElementsByTagName("coffee"); NodeList for(int (inti=0; i=0;ii<<coffeeNodes.getLength(); coffeeNodes.getLength();i++) i++){{ for thisCoffeeNode==coffeeNodes.item(i); coffeeNodes.item(i); thisCoffeeNode NodethisNameNode thisNameNode==thisCoffeeNode.getFirstChild(); thisCoffeeNode.getFirstChild(); Node Stringdata data==thisNameNode.getFirstChild().getNodeValue(); thisNameNode.getFirstChild().getNodeValue(); String (data.equals("MochaJava")) Java")){{ ifif(data.equals("Mocha NodethisPriceNode thisPriceNode==thisNameNode.getNextSibling(); thisNameNode.getNextSibling(); Node Stringprice price== thisPriceNode.getFirstChild().getNodeValue(); thisPriceNode.getFirstChild().getNodeValue(); <?xmlversion="1.0" version="1.0"?> ?> <?xml String <priceList> break;}}}} <priceList> break; <coffee> <coffee> <name>MochaJava</name> Java</name> <name>Mocha nextSibling <price>11.95</price> <price>11.95</price> </coffee> </coffee> </priceList> </priceList> © Klaus Schild, XML Clearinghouse 2003 32 DOM-Methoden <?xmlversion="1.0" version="1.0"?> ?> <?xml NodeList coffeeNodes = document.getElementsByTagName("coffee"); NodeList coffeeNodes = document.getElementsByTagName("coffee"); <priceList> <priceList> for(int (inti=0; i=0;ii<<coffeeNodes.getLength(); coffeeNodes.getLength();i++) i++){{ for <coffee> <coffee> thisCoffeeNode==coffeeNodes.item(i); coffeeNodes.item(i); thisCoffeeNode <name>MochaJava</name> Java</name> <name>Mocha NodethisNameNode thisNameNode==thisCoffeeNode.getFirstChild(); thisCoffeeNode.getFirstChild(); <price>11.95</price> Node <price>11.95</price> </coffee> Stringdata data==thisNameNode.getFirstChild().getNodeValue(); thisNameNode.getFirstChild().getNodeValue(); </coffee> String firstChild </priceList> </priceList> (data.equals("MochaJava")) Java")){{ ifif(data.equals("Mocha NodethisPriceNode thisPriceNode==thisNameNode.getNextSibling(); thisNameNode.getNextSibling(); Node Stringprice price== thisPriceNode.getFirstChild().getNodeValue(); thisPriceNode.getFirstChild().getNodeValue(); String break;}}}} break; © Klaus Schild, XML Clearinghouse 2003 33 Vor- und Nachteile von DOM + Kontext (Parse-Baum) muss nicht von der Anwendung verwaltet werden. + Auch direkter Zugriff auf Elemente und Attribute über ihre Namen (unabhängig von deren Position) möglich. + Nicht nur Parsen von XML-Dokumenten möglich, sondern auch Modifikation oder Erstellung von Dokumenten. – speicherintensiv, insbesondere bei großen XML-Dateien – Abstrahiert nur unzureichend von der spezifischen XMLSyntax. © Klaus Schild, XML Clearinghouse 2003 34 SAX oder DOM? SAX ist geeignet, um gezielt bestimmte Teile von XMLDokumenten herauszufiltern, ohne dass zu einem späteren Zeitpunkt andere Teile des Dokumentes benötigt werden. DOM ist geeignet, um auf unterschiedliche Teile eines XML-Dokumentes zu verschiedenen Zeitpunkten zuzugreifen. DOM ist zum Erstellen und Modifizieren von Dokumenten geeignet. © Klaus Schild, XML Clearinghouse 2003 35 Schema-Übersetzer Datenabstraktion XMLSchema übersetzen va Instanz XMLDokument lid ie re n JavaKlassen Instanzen deserialisieren serialisieren JavaObjekte Î Java Architecture for XML Binding (JAXB) © Klaus Schild, XML Clearinghouse 2003 36 Marshalling/Unmarshalling marshal XMLDokument serialisieren JavaObjekte deserialisieren unmarshal Deserialisieren/Unmarshalling erstellt keinen Parse-Baum, sondern Java-Objekte mit Methoden zum Zugreifen und Modifizieren der Daten. Marshalling = führen, geleiten © Klaus Schild, XML Clearinghouse 2003 37 Beispiel <priceList> <priceList> <coffee> <coffee> <name>MochaJava</name> Java</name> <name>Mocha <price>11.95</price> <price>11.95</price> </coffee> </coffee> </priceList> </priceList> PriceList-Schema JAXB publicinterface interfacePriceList PriceList{{ public java.util.ListgetCoffee(int getCoffee(intindex); index); java.util.List publicinterface interfaceCoffeeType CoffeeType{{ public StringgetName(); getName(); String voidsetName(String setName(Stringvalue) value) void java.math.BigDecimalgetPrice(); getPrice(); java.math.BigDecimal voidsetPrice(java.math.BigDecimal setPrice(java.math.BigDecimalvalue) value)}}}} void © Klaus Schild, XML Clearinghouse 2003 38 Weiterführende Informationen zu JAXB Î http://java.sun.com/xml/jaxb/ © Klaus Schild, XML Clearinghouse 2003 39 Zusammenfassung Ein Parser analysiert XML-Dokumente und erstellt ParseBäume mit Tags, Text-Inhalten und Attribut-Wert-Paaren als Knoten. Ein Serialisierer generiert aus interner Datenstruktur einer Anwendung ein XML-Dokument. Bei einem Pull-Parser hat die Anwendung die Kontrolle über das Parsen, bei einem Push-Parser übernimmt der Parser selbst die Kontrolle. Einschritt-Parser analysieren das vollständige Dokument in einem einzigen Schritt, Mehrschritt-Parser analysieren die einzelnen syntaktischen Einheiten Schritt für Schritt. © Klaus Schild, XML Clearinghouse 2003 40 Zusammenfassung SAX (Simple API for XML) ist ein API für das Push- Mehrschritt-Parsen von XML-Dokumenten. Ereignisbasiertes Parsen von SAX wird mit Call-BackMethoden realisiert. DOM (Document Object Model) ist eine abstrakte Schnittstelle zum Zugreifen, Modifizieren und Erstellen von XML-Parse-Bäumen. Im Ergebnis ist DOM ein Einschritt-Pull-Parser. DOM ist ein W3C-Standard, SAX ein de facto Standard. © Klaus Schild, XML Clearinghouse 2003 41 Zusammenfassung SAX ist geeignet, um gezielt bestimmte Teile von XMLDokumenten herauszufiltern, ohne dass zu einem späteren Zeitpunkt andere Teile des Dokumentes benötigt werden. DOM ist geeignet, um auf unterschiedliche Teile eines XML-Dokumentes zu verschiedenen Zeitpunkten zuzugreifen. DOM ist zum Erstellen und Modifizieren von Dokumenten geeignet. © Klaus Schild, XML Clearinghouse 2003 42 Zusammenfassung Immer Anwendungslogik durch spezielle Schicht von dem Datenzugriff trennen (sowohl bei SAX, als auch bei DOM). Schema-Übersetzer wie JAXB (Java Architecture for XML Binding) generieren eine solche Datenzugriffsschicht automatisch. © Klaus Schild, XML Clearinghouse 2003 43