XML
Schema et Marshalling
Marshalling en XML
Pour pouvoir utiliser
le XML comme format d'échange entre les serveurs, il faut
un mécanisme de transformation entre les types de données
de langages d'applications (C, Java, Python, PHP, Perl, ....)
et XML :
- Marshalling et unmarshalling
- agrégation en XML et l'inverse
- en Java : basé sur API JAXB (java
XML Binding)
- La description des données en XML
se fait grace à Schéma :
- XSD un langage XML de descrition de données
XML
- grammaire plus puissante que la DTD
- Source de Chien.java
package chien;
public class Chien {
public String nom;
public Personne maitre;
public int nombrePuces;
public Chien() { }
public Chien(String n, Personne p, int i) {
nom = n; maitre = p; nombrePuces = i ;
}
}
|
Source de Personne.java
package chien;
public class Personne {
public String nom;
public String adresse;
public Personne() { }
public Personne(String n, String a) {
nom = n; adresse = a ;
}
}
|
- Marshall et unmarshall :
- A l'objet instance
de Chien :
- de nom milou,
- de maitre la personne
:
- de nom tnitin
- et d'adresse chateau
de moulinsart
- et de nombre de
puces 3
- correspond le document
xml :
<tns:chien xmlns=tns:"urn:MeuteService">
<tns:nom>milou</tns:nom>
<tns:maitre>
<tns:nom>Tintin</tns:nom>
<tns:adresse>chateau de Moulinsart</tns:adresse>
</tns:maitre>
<tns:nombrePuces>3</tns:nombrePuces>
</tns:chien>
|
- son schéma est :
<schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns=tns:"urn:MeuteService"
targetNamespace="urn:MeuteService">
<complexType name="Personne">
<sequence>
<element name="nom" nillable="true" type="xsd:string"/>
<element name="adresse" nillable="true" type="xsd:string"/>
</sequence>
</complexType>
<element name="Chien">
<complexType">
<sequence>
<element name="nom" nillable="true" type="xsd:string"/>
<element name="maitre" nillable="true" type="tns:Personne"/>
<element name="nombrePuces" type="xsd:int"/>
</sequence>
</complexType>
<element>
</schema>
|
XML Schema
- langage de definition de document XML
plus puissant que la DTD :
- définit des éléments
lexicaux, des structures syntaxiques et des types.
- permet d'exprimer la "grammaire"
:
- des langages à structures XML (balises,
emboitement, ID, IDRef, ..)
- des données des langages de programmation
(type complexes, types dérivés, héritage,
...)
- des données de tables de bases
de données
- Pour conformer un document XML à
un schema :
<racine
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://.../monSchema.xsd">
........... le document XML ..............
</racine>
- Comparaison aux DTDs :
- une DTD peut s'exprimer en schema mais
l'inverse est plus rare
- Schema est écrit en XML et non
en EBNF comme la DTD
- Schéma contient :
- des nombreux types simples
- un mécanisme de type complexe :
sequence, choice, ...
- un mécanisme d'extension de type
- une forme de spécialisation
- norme : http://www.w3.org/XML/Schema
- un exemple de schema : celui de SOAP
Les constructions
de Schema
MonSchema.xsd :
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://.../monSchema.xsd">
.... déclarations ....
</xsd:schema>
- spécification du Namespace
<xsd:annotation>
<xsd:documentation>
.......... commentaire de documentation .............
</xsd:documentation>
</xsd:annotation>
<xsd:element name="livre">
... description de l'élément .....
</xsd:element>
<xsd:element name="livre" type="TypeLivre"/>
- déclaration à partir d'un
type simple ou dérivé.
- le type est içi nommé
- permet de définir un nouveau type
<xsd:complexType name=TypeLivre">
<xsd:sequence>
<xsd:element name="titre" type="xsd:string"/>
<xsd:element name="auteur" type="xsd:string"/>
</xsd:sequence>
<xsd:attribute name="isbn" type="IsbnType"/>
<xsd:complexType/>
- plusieures variantes : sequence choice
all (peuvent apparaitre ou non et dans n'importe quel ordre)
- remarquons la déclaration d'un
attribut dans l'exemple précédent
<xsd:complexType name=TypeLivre">
<xsd:sequence>
<xsd:element name="titre" type="xsd:string"/>
<xsd:element name="auteur" type="xsd:string"
minOccurs="1" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
- un certain nombre d'attributs précise
les définitions : default, fixed, minOccurs, ....
- içi, le nombre d'occurrence de
l'élément
- il est possible de grouper des definitions
- Ci-dessous, un groupe nommé d'attributs
<xsd:attributeGroup name="AttributsLivre">
<xsd:attribute name="isbn" type="IsbnType"/>
<xsd:attribute name="prix" type="xsd:float"/>
</xsd:attributeGroup>
<xsd:complexType name=TypeLivre">
<xsd:sequence>
<xsd:element name="titre" type="xsd:string"/>
<xsd:element name="auteur" type="xsd:string"/>
</xsd:sequence>
<xsd:attributeGroup ref="AttributsLivre"/>
</xsd:complexType>
- boolean,
- string,
- base64Binary, ....,
- integer, int, positiveInteger, ... , long,
unsignedInt, ....
- decimal, float, double,
- time,date, duration, ...
- ID, IDREF, ENTITY, NOTATION, ....
- Dérivation de type par restriction
<xsd:simpleType name="centPremierEntier">
<xsd:restriction base="xsd:integer">
<xsd:minInclusive value="0"/>
<xsd:maxInclusive value="99"/>
</xsd:restriction>
</xsd:simpleType>
- est obtenue grace à 2 facettes
: minInclusive et maxInclusive
- Ceci est une définition de type
simple
- la restriction est possible sur une définition
de type complex
<xsd:simpleType name="TypeNumeroVoiture">
<xsd:restriction base="xsd:string">
<xsd:pattern value="\d{4} [A-Z]{2} \d{2}"/>
</xsd:restriction>
</xsd:simpleType>
- obtenu grace à la facette
pattern.
- Dérivation de type par extension
:
<xsd:complexType name="TypeELivre">
<xsd:complexContent>
<xsd:extension base="TypeLivre"/>
<xsd:sequence>
<xsd:element name="url" type="xsd:anyURI"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
- il aurait été possible d'empêcher
la dérivation précédente ainsi :
<xsd:complexType name=TypeLivre" final="extension">
..........
<xsd:complexType/>
- a l'inverse, il est possible de déclarer
un type abstract
<xsd:complexType name="TypeDocument" abstract="true"/>
<xsd:complexType name="TypeLivre">
<xsd:complexContent>
<xsd:extension base="target:TypeDocument"/>
</xsd:complexContent>
...
- Importer/Inclure d'autres schemas :
<xsd:include schemaLocation="http://.../autre_schema.xsd"/>
- Facettes :
- chaque type de donnée est caractérisée
par :
- son espace de valeurs
- son espace lexical
- ses facettes
- les représentations lexicales 6.5
et 6.50 peuvent correspondre à la même valeur d'un
xsd:float
et 6.5 est aussi une valeur de xsd:string
- les facettes sont des propriétés
:
- comme égalité, ordre, borne,
...
qui s'appliquent à tous les types
- mais aussi : length, minLength, ..., pattern,
enumeration, minExclusive, ...,
precision, scale, encoding, duration, period, whitespace, ....
qui s'appliquent à certains types
- et le reste :
- unicité, key, ...
- list, enumeration, union,....
- namespace, ...
- any, ...
- substitutiongroup, ..
JAXB
- Java XML Binding
- récupérer l'API JAXB sur
le site java.sun.com
- Décompactez-le :
$ java -jar JAXB2_20070122.jar
- Préparer les variables PATH et
CLASSPATH :
JAVA_HOME=/usr/lib/jvm/java-1.5.0-sun/jre ; export
JAVA_HOME
JAXB_HOME=$HOME/repertoire/jaxb-ri-20070122; export JAXB_HOME
PATH=$JAXB_HOME/bin:$PATH ; export PATH
CLASSPATH=.:$JAXB_HOME/lib/activation.jar:
$JAXB_HOME/lib/jaxb-impl.jar:
$JAXB_HOME/lib/jaxb1-impl.jar:
$JAXB_HOME/lib/jaxb-xjc.jar:
$JAXB_HOME/lib/jaxb-api.jar:
$JAXB_HOME/lib/jsr173_1.0_api.jar; export CLASSPATH
recuperez setpathxsd<:font>
- le rendre executable et l'executer sans "fork" :
$ chmod u+x setpathxsd
$ . setpathxsd
- Rendre exécutable les outils de
transformations Java2Schema et Schema2Java :
$ chmod u+x $JAXB_HOME/bin/*.sh
- Transformation
Schema2Java :
- soit le fichier de schema chien.xsd :
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="chien">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="nom" type="xsd:string"/>
<xsd:element name="maitre" type="personne"/>
<xsd:element name="puces" type="xsd:int"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:complexType name="personne">
<xsd:sequence>
<xsd:element name="nom" type="xsd:string"/>
<xsd:element name="adresse" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
|
- compiler le schema :
$ xjc.sh chien.xsd -p chienp
parsing a schema...
compiling a schema...
chienp/Chien.java
chienp/ObjectFactory.java
chienp/Personne.java
- pour obtenir un package de classes JAVA
nommé chienp
- la classe Chien
- et la factory
- générer la documentation
de ce package:
$ javadoc -package chienp -sourcepath . -d doc_chienp/api -windowtitle
"Interface pour chien.xsd"
- le "binding" JAVA XSD
est approxivement le suivant :
- xsd:int
int
- xsd.long
long
- xsd:float
float
- xsd:double
double
- xsd:boolean
boolean
- xsd:hexBinary
byte[]
- xsd:string
java.lang.String
- xsd:dateTime
java.util.Calendar
- xsd:time
java.util.Calendar
- xsd:date
java.util.Calendar
- xsd:complexType :
- complex type
Classe
voire Interface
- attribute
property
(getNomDeAttribut et setNomDeAttribut)
- element
property
(getNomDElement et setNomDElement)
- element à plusieurs occurences
List
- XML Namespace
package
- Unmarshalling :
- transformer un document XML en objet(s)
Java
- il s'agit de tranformer un document XML
conforme au schema chien.xsd en des objets instance des classes
du package chienp
- unmarshall, c'est désagréger
- le fichier xml à tranformer est
milou.xml
<?xml version="1.0"?>
<chien>
<nom>milou</nom>
<maitre>
<nom>tintin</nom>
<adresse>chateau de moulinsart</adresse>
</maitre>
<puces>5</puces>
</chien>
|
- Source de Transform.java
import java.io.FileInputStream;
import java.io.IOException;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import chienp.*;
public class Transform {
public static void main(String[] args) {
try {
JAXBContext jc = JAXBContext.newInstance("chienp");
Unmarshaller u = jc.createUnmarshaller();
Chien mimi =
(Chien)u.unmarshal(new FileInputStream("milou.xml"));
System.out.println("nom du chien :" +mimi.getNom());
Personne mait = mimi.getMaitre();
System.out.println("nom du maitre :" +mait.getNom() );
System.out.println("adresse du maitre : " +mait.getAdresse());
System.out.println("nombre de puces = " +mimi.getPuces());
} catch( Exception e ) {
e.printStackTrace();
}
}
}
|
Les méthodes
getMaitre, getNom, .... sont celles du package chienp
- COMPILATION et EXECUTION :
$ javac chienp/*.java
$ javac Transform.java
$ java Transform
nom du chien :milou
nom du maitre :tintin
adresse du maitre : chateau de moulinsart
nombre de puces = 5
L'objet obtenu contient bien les informations
du document xml "milou.xml"
- Transformationb>
Java2Schema :
- soit le package chienp :
$ schemagen.sh chienp/*.java
Note: Writing schema1.xsd
- pour obtenir un 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="chien">
<xs:complexType>
<xs:sequence>
<xs:element name="nom" type="xs:string"/>
<xs:element name="maitre" type="personne"/>
<xs:element name="puces" type="xs:int"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="personne">
<xs:sequence>
<xs:element name="nom" type="xs:string"/>
<xs:element name="adresse" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
|
- Marshalling
:
- il s'agit de transformer un objet en document
XML
- içi, un objet Chien en document
XML
- marshall, c'est agréger
- Source de Creer.java
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import chienp.*;
public class Creer {
public static void main( String[] args ) {
try {
JAXBContext jc = JAXBContext.newInstance( "chienp" );
ObjectFactory factory = new ObjectFactory();
Chien medor = factory.createChien();
medor.setNom("medor");
Personne memere = factory.createPersonne();
memere.setNom("Michu");
memere.setAdresse("impasse du puit");
medor.setMaitre(memere);
medor.setPuces(76);
Marshaller m = jc.createMarshaller();
m.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
m.marshal(medor, System.out);
} catch( Exception e ) {
e.printStackTrace();
}
}
}
|
Les méthodes
createChien, setNom, .... sont celles du package chienp
- COMPILATION et EXECUTION :
$ javac Creer.java
$ java Creer
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<chien>
<nom>medor</nom>
<maitre>
<nom>Michu</nom>
<adresse>impasse du puit</adresse>
</maitre>
<puces>76</puces>
</chien>
L'objet construit est bien transformé
en document xml
exercice
- Voici le célèbre Chat
des BDs de Johann SFAR :
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"nom",
"rabin",
"aFaitSaBarMitsva",
"albums"
})
@XmlRootElement(name = "ChatDuRabin")
public class ChatDuRabin {
public String nom = "";
public String rabin = null;
public boolean aFaitSaBarMitsva = false;
public String[] albums = null;
public ChatDuRabin()
{ }
public ChatDuRabin(String n, String r, boolean m, String[]a)
{ nom=n; rabin=r; aFaitSaBarMitsva=m ; albums=a; }
}
|
- générer un schema équivalent
- puis, à partir de ce shéma,
obtenir un package nommé "sfar" de classes JAVA
- enfon supprimez la classe initiale .java et .class pour eviter des Pbs de compilation
- A l'aide de Creer.java,
créez un objet chat du rabin et "marshall"-lez
le en document xml
- nom : "chat"
- rabin : "Abraham Sfar"
- et non, il n'est pas juif !
- les albums sont "La Bar-Mitsva",
"Le Malka des Lions", "L'Exode"
- Enfin "unmarshaller" le document
xml en un objet
Correction