Programmieren II Martin Schultheiß Hochschule Darmstadt Sommersemester 2012 1 / 34 Annotationen XML JAXB JAXP SAX DOM 2 / 34 Annotationen (1/3) Annoataionen sind Sprachelemente, durch welche Metadaten (das sind Informationen über andere Daten) in den Quelltext eingefügt werden können. Diese Daten können (je nach Definition) sowohl zur Compileals auch zur Laufzeit des Programms ausgewertet werden. Dabei sind Annotationen spezielle Schnittstellen, welche durch ein @ vor dem Schlüsselwort interface gekennzeichnet werden 3 / 34 Handout S. 1
Annotationen (2/3) Annotationen können dabei je nach Typ auf Klassen/Schnittstellen, Methoden oder auf andere Annotationen angewendet werden. Bereits bekanntes Beispiel ist die -Annotation, durch die eine überschriebene Methode gekennzeichnet werden kann. Annotationen können zusätzlich Parameter beinhalten. Diese werden in der Schnittstellen-Definition als parameterlose Funktionen definiert, die einen Wert vom entsprechenden Datentyp zurückliefern. 4 / 34 Annotationen (3/3) Beispiel: @ i n t e r f a c e Person { S t r i n g vorname ( ) ; S t r i n g name ( ) ; i n t a l t e r ( ) ; @Person (name = " Martin S c h u l t h e i s s ", a l t e r = 30) Account admin = new Account ( ) ; 5 / 34 Einführung in XML XML ist eine Auszeichnungssprache zur strukturellen Beschreibung von Dokumenten. Refenzdefinition ist die XML Recommendation vom W3C (World Wide Web Consortium), erste Fassung von 1998. XML sieht zwar aus wie HTML (spitze Klammern), im eigentlich Sinne hat XML nicht direkt mit HTML zu tun. Korrekte Analogie: SGML XML HTML XHTML 6 / 34 Handout S. 2
Grundlegende Definitionen Ein XML-Dokument heißt wohlgeformt wenn es syntaktisch korrekt ist: Nur ein Wurzelelement. Jeder geöffnete Tag geht wieder zu. Kein Überlappen über Tag-Grenzen hinweg. Kein Element mit doppeltem Attribut mit gleichem Namen. gültig wenn es gegen eine semantische Beschreibung validiert, d. h. einer inhaltlichen Beschreibung entspricht, welche Elemente ein XML-Dokument für einen bestimmten Zweck wann und wie enthalten darf. 7 / 34 Schemasprachen Eine Schemasprache beschreibt für einen bestimmten Zweck, wie ein gültiges XML-Dokument auszusehen hat. Hier sind weit verbreitet: DTD (Document Type Definion) alter Standard, in SGML, wenig Features (keine Wertebereiche, keine Key-Constraints) XML Schema (XSD) neuerer Standard, in XML, erlaubt z. B. Angabe von Wertebereichen, Constraints für Schlüssel etc. 8 / 34 Beispiel-Schema kontakt.xsd <?xml v e r s i o n=" 1. 0 " encoding="utf-8 "?> <xsd:schema xmlns:xsd=" h t t p : //www. w3. org /2001/XMLSchema"> <xsd: element name=" kontakte " type=" roottype "></ xsd: element> <xsd:complextype name=" roottype "> <xsd: sequence> <xsd: element name=" person " type=" persontype " maxoccurs=" unbounded" minoccurs="0"> </ xsd: element> </ xsd: sequence> </ xsd:complextype> <xsd:complextype name=" persontype "> <xsd: sequence> <xsd:element name="vorname" type=" x s d : s t r i n g " maxoccurs="5" minoccurs="1"/> <xsd:element name="nachname" type=" x s d : s t r i n g "/> <xsd:element name=" firma " type=" x s d : s t r i n g " maxoccurs="1" minoccurs="0"/> </ xsd: sequence> <x s d : a t t r i b u t e name=" vip " type=" xsd:boolean " use=" o p t i o n a l " d e f a u l t=" f a l s e "/> </ xsd:complextype> </ xsd:schema> 9 / 34 Handout S. 3
Beispiel-Daten personen.xml <?xml v e r s i o n=" 1. 0 " encoding="utf-8 "?> <kontakte x m l n s : x s i=" h t t p : //www. w3. org /2001/XMLSchema- i n s t a n c e " xsi:nonamespaceschemalocation=" kontakt. xsd "> <person vip=" true "> <vorname>klaus</vorname> <nachname>hoeppner</nachname> <firma>gsi</ firma> </ person> <person> <vorname>karl</ vorname> <nachname>schmidt</nachname> </ person> <person> <vorname>maria</ vorname> <nachname>mustermann</nachname> <firma>merck</ firma> </ person> </ kontakte> 10 / 34 JAXB JAXB ist die Java API for XML Binding. Diese Programmschnittstelle erlaubt, Daten aus einer XML-Schema-Instanz heraus automatisch an Java-Klassen zu binden, und diese Java-Klassen aus einem XML-Schema heraus zu generieren. JAXB ermöglicht auch den umgekehrten Weg, d. h. das Erstellen eines Schemas aus Java-Klassen (mit speziellen Annotationen). 11 / 34 Workflow Zunächst wird ein XML-Schema für die Daten erstellt (hier: kontakt.xsd) Dann wird mit dem Compiler xjc die entsprechende Klassenhierarchie erzeugt, z. B. xjc -d src -p kontakt kontakt.xsd erzeugt Java-Klassen zum Schema innerhalb des Paketes kontakt, das sich im Verzeichnis src befindet. Dort entstehen die Klassen RootType und PersonType mit entsprechenden Attributen, Gettern und Settern, die die komplexten Typen im Schema abbilden. Weiterhin wird eine Klasse ObjectFactory erzeugt, mit der neue Instanzen erzeugt werden können, die dann in XML abgebildet werden. 12 / 34 Handout S. 4
Schaubild 13 / 34 Beispiel import java. i o. * ; import javax. xml. bind. JAXBContext ; import javax. xml. bind. JAXBException ; import javax. xml. bind. JAXBElement ; import javax. xml. bind. Unmarshaller ; import kontakt. * ; p u b l i c c l a s s JAXBParser { p u b l i c s t a t i c void main ( S t r i n g [ ] args ) { JAXBContext j c = JAXBContext. newinstance ( " kontakt " ) ; Unmarshaller u = j c. createunmarshaller ( ) ; JAXBElement<?> kelement = ( JAXBElement<?>) u. unmarshal ( new FileInputStream ( " personen. xml" ) ) ; RootType kontakte = ( RootType ) kelement. getvalue ( ) ; 14 / 34 Beispiel (Forts.) f o r ( PersonType person : kontakte. getperson ( ) ) { System. out. p r i n t l n ( person. getnachname ( ) ) ; System. out. p r i n t l n ( person. getfirma ( ) ) ; System. out. p r i n t l n ( person. isvip ( ) ) ; catch ( JAXBException e ) { catch ( FileNotFoundException e ) { 15 / 34 Handout S. 5
Verarbeitung von XML Um XML ohne die im Vorherigen Kapitel vorgestellte Bindung an Klassen zu verarbeiten, steht in Java JAXP (Java API for XML Processing) zur Verfügung. Diese bietet zwei Modelle zum Parsen und Verarbeiten von XML-Dateien: SAX und DOM Zusätzlich erlaubt JAXP Transformationen von XML-Dokumenten mit XSLT und die Validierung von Dokumenten anhand eines gegebenen XML Schemas. 16 / 34 SAX vs. DOM SAX als ereignisorientierte Methode, bei der Aktionen (hooks) beim Start und Ende eines Tags ausgelöst werden. Dies ist eine schnelle und schlanke Methode, da nicht das gesamte Dokument im Speicher gehalten werden muss. DOM als Aufbau ein DOM-Tree (DOM = Document Object Model), wobei das gesamte Dokument analysiert wird und so wahlfreien Zugriff auf alle Knoten des Baums erlaubt. Aufwändiger, aber mächtiger als SAX. 17 / 34 SAX SAX (Simple API for XML) ist eine ereignisorientierte Methode zum Parsen von XML-Dateien. Dies bedeutet, das beim Parsen definierte Callbacks ausgeführt werden, wenn das Dokument beginnt oder endet, Elemente beginnen oder enden, Text-Inhalt gelesen wird. Die Reihenfolge des Aufrufens der Callbacks ist fest durch die Reihenfolge der Elemente im Dokument vorgegeben. SAX ist daher unflexibel, aber spart Ressourcen, da nicht das komplette XML-Dokument im Speicher gehalten werden muss. 18 / 34 Handout S. 6
Das Interface ContentHandler Beim Parsen mit SAX wird dem Parser ein ContentHandler übergeben. Im Interface ContentHandler sind dabei die Methoden abstrakt definiert, die beim Auftreten der entsprechenden Ereignisse aufgerufen werden sollen: startdocument beim Beginn des XML-Dokumentes, enddocument beim Ende des XML-Dokumentes, startelement beim öffnenden Tag eines Elementes, hierbei werden der Name und die Attribute des Elements übergeben, endelement beim schließenden Tag eines Elemtes, characters für normalen Text. 19 / 34 Die Klasse DefaultHandler Wie bereits an anderen Stellen in Java existiert eine Klasse, die das Interface implementiert, indem die fraglichen Methoden leer definiert werden. In diesem Fall implementiert die Klasse DefaultHandler das Interface ContentHandler. Hiervon erben selbst definierte Klassen für Handler, in denen dann die Methoden nach Wunsch überladen werden können. 20 / 34 UML-Diagramm «interface» ContentHandler characters(ch: char[], start: int, length: int) : void startdocument() : void enddocument() : void startelement(uri : String, localname: String, qname: String, atts: Attributes) : void endelement() : void DefaultHandler characters(ch: char[], start: int, length: int) : void startdocument() : void enddocument() : void startelement(uri : String, localname: String, qname: String, atts: Attributes) : void endelement() : void 21 / 34 Handout S. 7
Grundlegendes Beispiel import java. i o. IOException ; import javax. xml. p a r s e r s. * ; import org. xml. sax. * ; import org. xml. sax. h e l p e r s. DefaultHandler ; p u b l i c c l a s s MyXMLParser1 extends DefaultHandler { p u b l i c s t a t i c void main ( S t r i n g [ ] args ) { SAXParserFactory f a c t o r y = SAXParserFactory. newinstance ( ) ; SAXParser p a r s e r = f a c t o r y. newsaxparser ( ) ; p a r s e r. parse ( " personen. xml", new MyXMLParser1 ( ) ) ; catch ( ParserConfigurationException e ) { catch ( SAXException e ) { catch ( IOException e ) { 22 / 34 Grundlegendes Beispiel (Forts.) p u b l i c void enddocument ( ) throws SAXException { System. out. p r i n t l n ( "Ende des Dokumentes" ) ; p u b l i c void endelement ( S t r i n g uri, S t r i n g localname, S t r i n g qname) { System. out. format ( "Ende von Element %s \n", qname ) ; p u b l i c void startdocument ( ) throws SAXException { System. out. p r i n t l n ( " S t a r t des Dokumentes" ) ; 23 / 34 Grundlegendes Beispiel (Forts.) p u b l i c void startelement ( S t r i n g uri, S t r i n g localname, S t r i n g qname, A t t r i b u t e s a t t s ) throws SAXException { System. out. format ( " S t a r t von Element %s \n",qname ) ; f o r ( i n t i =0; i<a t t s. getlength ( ) ; i++) { System. out. format ( " Attr : %s=%s \n", a t t s. getqname( i ), a t t s. getvalue ( i ) ) ; p u b l i c void c h a r a c t e r s ( char [ ] ch, i n t s t a r t, i n t length ) throws SAXException { System. out. p r i n t l n ( S t r i n g. copyvalueof ( ch, s t a r t, length ) ) ; 24 / 34 Handout S. 8
SAX-Beispiel: HTML-Tabelle Im Folgenden soll ein SAX-Contenthandler geschrieben werden, der aus einer XML-Datei mit Kontakten eine HTML-Datei mit tabellarischer Darstellung der Personen erzeugt. Dieser Contenthandler muss folgende Eigenschaften haben: Beim Start oder Ende eines XML-Elementes muss das passende öffnende bzw. schließende HTML-Tag geschrieben werden. Text-Inhalt darf nur geschrieben werden, wenn er sich innerhalb einer der Elemente vorname, nachname oder rma befindet, während z. B. der Leerraum zwischen diesen Elementen ignoriert werden soll. 25 / 34 Implementierung Im Contenthandler existieren ein Writer, in den der HTML-Code ausgegeben wird, sowie ein Flag, anhand dessen entschieden wird, ob Textinhalt geschrieben wird. p u b l i c c l a s s HTMLWriter extends DefaultHandler { p r i v a t e S t r i n g fname ; p r i v a t e Writer out = n u l l ; p r i v a t e boolean w r i t e c h a r s = f a l s e ; p u b l i c HTMLWriter( S t r i n g fname ) { t h i s. fname = fname ; //... 26 / 34 Implementierung (Forts.) p u b l i c void startdocument ( ) throws SAXException { out = new F i l e W r i t e r ( fname ) ; out. w r i t e ( "<html><body>\n" ) ; catch ( IOException e ) { p u b l i c void enddocument ( ) throws SAXException { out. w r i t e ( "</body></html>\n" ) ; out. c l o s e ( ) ; catch ( IOException e ) { 27 / 34 Handout S. 9
Implementierung (Forts.) p u b l i c void startelement ( S t r i n g uri, S t r i n g localname, S t r i n g name, A t t r i b u t e s a t t r i b u t e s ) throws SAXException { i f (name. equals ( " kontakte " ) ) { out. w r i t e ( "<t a b l e border =\"1\">\n" ) ; catch ( IOException e ) { e l s e i f (name. e quals ( " person " ) ) { out. w r i t e ( "<tr >\n" ) ; catch ( IOException e ) { e l s e i f (name. e quals ( "vorname" ) name. e quals ( "nachname" ) name. e quals ( " firma " ) ) { out. w r i t e ( "<td>" ) ; catch ( IOException e ) { w r i t e c h a r s = true ; 28 / 34 Implementierung (Forts.) p u b l i c void endelement ( S t r i n g uri, S t r i n g localname, S t r i n g name) throws SAXException { i f (name. equals ( " kontakte " ) ) { out. w r i t e ( "</table >\n" ) ; catch ( IOException e ) { e l s e i f (name. e quals ( " person " ) ) { out. w r i t e ( "</tr >\n" ) ; catch ( IOException e ) { e l s e i f (name. e quals ( "vorname" ) name. e quals ( "nachname" ) name. e quals ( " firma " ) ) { out. w r i t e ( "</td>" ) ; catch ( IOException e ) { w r i t e c h a r s = f a l s e ; 29 / 34 Implementierung (Forts.) p u b l i c void c h a r a c t e r s ( char [ ] ch, i n t s t a r t, i n t length ) throws SAXException { i f ( w r i t e c h a r s ) { out. w r i t e ( ch, s t a r t, length ) ; catch ( IOException e ) { 30 / 34 Handout S. 10
DOM Bei DOM, dem Document Object Model, wird das XML komplett gelesen und liegt als Baum im Speicher vor. Daher werden mehr Ressourcen benötigt, aber da die Verarbeitung nicht an die Reihenfolge im Dokument gebunden ist, ist dieser Weg mächtiger als SAX. Der DOM-Baum besteht aus Knoten (Interface Node), die eine NodeList von Kindknoten enthalten können. Jeder Knoten hat dabei einen Typ, und je nach Typ eventuell Name, Wert bzw. Textinhalt. Die Methode getnodetype() gibt den Knotentyp zurück, wobei für jeden Typ ein Subinterface existiert. 31 / 34 Nodes und Nodetypen Interface Node.XXX_NODE Art Attr ATTRIBUTE_NODE Attribute Comment COMMENT_NODE Kommentar Document DOCUMENT_NODE Das eigentliche Dokument Element ELEMENT_NODE Element Text TEXT_NODE Text Node.XXX_NODE ist hierbei eine statische Konstante vom Typ short, mit der das Ergebnis von getnodetype() verglichen werden kann. 32 / 34 Beispiel import java. i o. IOException ; import javax. xml. * ; import javax. xml. p a r s e r s. * ; import org. w3c. dom. * ; import org. xml. sax. SAXException ; p u b l i c c l a s s MyDOMParser { p u b l i c s t a t i c void main ( S t r i n g [ ] args ) { DocumentBuilderFactory f a c t o r y = DocumentBuilderFactory. newinstance ( ) ; DocumentBuilder b u i l d e r = f a c t o r y. newdocumentbuilder ( ) ; Document doc = b u i l d e r. parse ( " personen. xml" ) ; Element root = doc. getdocumentelement ( ) ; 33 / 34 Handout S. 11
Beispiel (Forts.) NodeList personen = root. getelementsbytagname ( " person " ) ; f o r ( i n t i =0; i<personen. getlength ( ) ; i++) { Element elem = ( Element ) personen. item ( i ) ; Node nachname = elem. getelementsbytagname ( "nachname" ). item ( 0 ) ; System. out. p r i n t l n ( nachname. gettextcontent ( ) ) ; i f ( elem. g e t A t t r i b u t e ( " vip " ). equals ( " true " ) ) { System. out. p r i n t l n ( "VIP" ) ; catch ( ParserConfigurationException e ) { catch ( SAXException e ) { catch ( IOException e ) { 34 / 34 Handout S. 12