JAXB Java Architecture for XML Binding http://jaxb.java.net Warum JAXB? JAXB ist eine schnelle und einfache Methode, um ein XML Schema mit einer Java Repräsentation zu verbinden. Damit ist es sehr einfach, XML Daten nach Java einzulesen, dort zu verarbeiten und wieder nach XML abzuspeichern. JAXB kann als Ersatz für DOM oder SAX benutzt werden. Die Programmierdetails für das Lesen und Schreiben der XML Daten bleiben verborgen. Wir müssen keine neuen Befehle kennen lernen. Der Zugriff auf die Daten erfolgt nach den Relationen, wie sie im XML Schema definiert sind. Die Architektur von JAXB 2.0 Binding Erzeugen der Java Klassen xjc.exe -p pge schema.xsd –d out Kompilieren der Java Klassen javac out/pge/*.java Unmarshalling der XML Dokumente, Benutzen der generierten Objekte, Marshalling der Java Daten, Validierung, … Übersetzung verschiedener Basis-Datentypen XML-Datentyp xsd:string xsd:integer xsd:int xsd:long xsd:short xsd:decimal xsd:float xsd:double xsd:boolean xsd:byte xsd:dateTime xsd:time xsd:date xsd:anySimpleType Java-Datentyp java.lang.String java.math.BigInteger int long short java.math.BigDecimal float double boolean byte XMLGregorianCalendar XMLGregorianCalendar XMLGregorianCalendar java.lang.String Das Beispiel Schema <?xml version="1.0"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="people"> <xs:complexType> <xs:sequence> <xs:element name="person" type="personType" maxOccurs="unbounded"/> <xs:element name="address" type="addressType" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> </xs:element> ... Die erzeugten Java Klassen: People People List<PersonType> person; List<AddressType> address; List <PersonType> getPerson() List <AddressType> getAddress() Die erzeugten Klassen-Attribute mit Zugriffsfunktionen Die erzeugten Java Klassen: PersonType PersonType NameType name BornType born … NameType getName() void setName(NameType) BornType getBorn() void setBorn(BornType) String getProfession() ... <xs:complexType name="personType"> <xs:sequence> <xs:element name="name" type="nameType"/> <xs:element name="born" type="bornType"/> <xs:element name="died" type="diedType"/> … </xs:sequence> </xs:complexType> Marshalling / Unmarshalling Java XML / XML Java Der Unmarshaller Das JAXBContext-Objekt erstellt einen Zugriff zum JAXB API. Damit wird ein Unmashaller erzeugt. try{ JAXBContext jc = JAXBContext.newInstance( ClassName ); Unmarshaller u = jc.createUnmarshaller(); Object obj = u.unmarshal( InputStream | File | DocNode | ... ) ... } catch(JAXBException e) { . . . } Validierung Vor dem Lesen der XML Daten kann mit dem Unmarshaller ein Schema verknüpft werden. SchemaFactory schemaFactory = SchemaFactory .newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); Schema schema = schemaFactory.newSchema(new File("People.xsd")); unmarshaller.setSchema(schema); Lesen der XML Daten Der Unmarshaller liefert dann ein Objekt des Typs PeopleType (gemäss dem Root-Element der XML Struktur). Object obj = u.unmarshal( ... )); PeopleType people = (PeopleType) obj; Navigation durch die Daten Die generierten get-Methoden liefern die weiteren Elemente for(PersonType b : people.getPerson()) { String firstName = b.getName().getFirstName(); String lastName = b.getName().getLastName(); } Der Marshaller Zum Schreiben der Daten nach XML erzeugen wir ein JAXBContext und damit ein Marshaller Objekt. JAXBContext jc = JAXBContext.newInstance(ClassName); Marshaller ms = jc.createMarshaller(); ms.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT, true ); // Formatiertes Schreiben der Daten ms.marshal( people, new FileOutputStream( FileName )); Validierung Auch der Marshaller kann durch Setzen eines Schemas validierend gemacht werden. SchemaFactory sf = SchemaFactory.newInstance( XMLConstants.W3C_XML_SCHEMA_NS_URI); Schema schema = sf.newSchema( SchemaFile ); marshaller.setSchema(schema); Customizing Anpassen der Java Klassen Namen Definieren der generierten Klassen Im Schema können die gewünschten (Ziel-) Klassen Namen definiert werden: <xs:complexType name="addressType"> <xs:annotation> <xs:appinfo> <jxb:class name="Address"/> </xs:appinfo> </xs:annotation> ... </complexType> Definieren der Membervariablen Ebenso die gewünschten (Ziel-) Membervariablen <xs:attribute name="id" type="xs:string"> <xs:annotation> <xs:appinfo> <jxb:property name="addressId"/> </xs:appinfo> </xs:annotation> ... </xs:attribute> Externes Binding Konfigurations-File Die hobby-Elemente der Personen sollen in einer Member-Variablen „hobbyList“ abgelegt werden: <jxb:bindings node="//xs:complexType[@name='personType']"> <jxb:bindings node=".//xs:element[@name='hobby']"> <jxb:property name="hobbyList"/> </jxb:bindings> </jxb:bindings> Bindings File Die name-Elemente der Personen sollen in einer Klasse „Name“ abgelegt werden <jxb:bindings node="//xs:complexType[@name='nameType']"> <jxb:class name="Name"/> </jxb:bindings> Erzeugen eines XML Schemas Schemagen.exe Aus den Java Klassen lässt sich mit Hilfe von Annotations (@XmlType, @XmlElement, … ) das dazu passende Schema generieren. Der Aufruf zum Erzeugen des Schemas lautet schemagen.exe package\*.java Ein Beispiel: Die Klasse People // serialize all member variables @XmlAccessorType(XmlAccessType.FIELD) // in the following order @XmlType( propOrder = { "person", "address" }) // people is the root element @XmlRootElement(name = "people") public class People { @XmlElement(required=true) protected List<PersonType> person; @XmlElement(required=true) protected List<AddressType> address; public List<PersonType> getPerson() { . . . } public List<AddressType> getAddress() { . . . } } Das erzeugte Schema <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="people"> <xs:complexType> <xs:sequence> <xs:element name="person" type="personType" maxOccurs="unbounded"/> <xs:element name="address" type="addressType" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> </xs:element> . . . Die Klasse Address @XmlType( name = "addressType", propOrder = { "country", "city“ }) public class Address { @XmlAttribute(required=true) private String id @XmlElement(name="country", required=true) private String country @XmlElement(required=true) private String city; public String getId() { . . . } public void setId(String value) { . . . } public String getCountry() { . . . } public void setCountry(String value) { . . . } . . . } Das erzeugte Schema <xs:complexType name="peopleType"> <xs:sequence> <xs:element name="person" type="personType" maxOccurs="unbounded"/> <xs:element name="address" type="addressType" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> <xs:complexType name="addressType"> <xs:sequence> <xs:element name="country" type="xs:string"/> <xs:element name="city" type="xs:string"/> </xs:sequence> <xs:attribute name="id" type="xs:string" use="required"/> </xs:complexType> . . . Marshalling ohne Object Factory