SERVEI DE XML







Introducció

Propòsit

El Servei XML té 2 propòsits principals:

  1. Serialització i deserialització d'objectes en documents XML
  2. Manipulació i lectura de fitxers XML

Es tracten de dues característiques diferenciades, però amb el propòsit comú d'oferir la possibilitat de tractament de fitxers XML.

Context i Escenaris d'Ús

El Servei XML es troba ubicat dins els Serveis de Presentació de Canigó. L'explicació del per què s'ubica en aquesta capa és degut al seu objectiu d'integració amb clients. De la mateixa forma, la manipulació de fitxers XML i serialització/deserialització es considera un tractament necessari per transformar dades d'entrada en objectes de la lògica de negoci i viceversa.

Versions i Dependències

Les dependències descrites a la següent url són requerides per tal de compilar i fer funcionar el projecte:
Dependències Servei de XML

A qui va dirigit

Aquest document va dirigit als següents perfils:

  1. Programador. Per conéixer l'ús del servei
  2. Arquitecte. Per conéixer quins són els components i la configuració del servei
  3. Administrador. Per conéixer com configurar el servei en cadascun dels entorns en cas de necessitat

Documents i Fonts de Referència

XStream http://xstream.codehaus.org/
Dom4j http://www.dom4j.org
Referències generals (benchmarking,...)
http://www.rpbourret.com/xml/XMLDataBinding.htm
    The Server side. Opinion: What tool for xml binding? http://www.theserverside.com/common/printthread.tss?thread_id=30658
Xstream: http://weblogs.java.net/blog/scottschram/archive/2005/09/the_xstream_lib.html
Performances: http://www.sosnoski.com/opensrc/xmlbench/results.html
Java document model usage:http://www-128.ibm.com/developerworks/xml/library/x-injava2/index.html

Descripció Detallada

Arquitectura i Components

La comunitat opensource proposa una desena d'implementacions diferents per a la serialització de XML. Actualment, i a causa del seu grau de facilitat i de performance canigo es basa en la llibreria XStream. A diferència de totes les altres, aquesta llibreria no necessita cap configuració específica.

En quant a manipulació dels documents XML, usarem la llibreria dom4j, amb un rendiment millor que jdom i amb més documentació.

El servei permet la manipulació de documents XML per mitjà de l'ús de tres interfícies:

  • XMLSerializationService, per a la serialització / deserialització de documents XML
  • XMLSerializationConfiguration, per a configurar el mapeig entre classes Java i XML
  • XMLDomHelper, per a manipular el fitxer XML (org.w3c.Document) i usar fulls d'estil XSLT

Per a més informació sobre les llibreries XML, una comparació de les APIs i un benchmark de les performances, veure la secció 'Documents i Fonts de Referència'

Els components podem classificar-los en:

  1. Interfícies i Components Genérics. Interfícies del servei i components d'ús general amb independència de la implementació escollida.
  2. Implementació de la serialització basada en XStream
  3. Implementació del parseig basada en DOM4J
    Es pot trobar tota la documentació JavaDoc i el codi font referent aquests components a les següents urls:

+JavaDoc: http://canigo.ctti.gencat.net/confluence/canigodocs/site/canigo2_0/canigo-services-xml/apidocs/index.html
+Codi Font:  http://canigo.ctti.gencat.net/confluence/canigodocs/site/canigo2_0/canigo-services-xml/xref/index.html

Instal.lació

La instal.lació del servei requereix de la utilització de la llibreria 'canigo-services-xml' i les dependències indicades a l'apartat 'Introducció-Versions i Dependències'.

Configuració

La configuració del Servei XML implica 3 pasos:

  1. Definir els servei de serialització i el mapeig dels objectes
  2. Definir el servei de parseig

Definició del servei de serialització

Fitxer de configuració: canigo-services-xml.xml

Ubicació proposada: <PROJECT_ROOT>/src/main/resources/spring

En aquesta configuració es defineix quina implementació específica s'usarà per la serialització. En l'actualitat es permet l'ús de:

  1. net.gencat.ctti.canigo.services.xml.xstream.XMLSerializationServiceXStreamImpl

Per aquesta implementació podem definir de forma addicional quin serà el mapeig entre les classes i atributs i els tags XML del fitxer.

Per a més referència consultar la web de 'XStream'. En l'apartat d'exemples es mostra un cas pràctic de configuració d'aquest fitxer de mapeig.

Definició del servei de parseig

Fitxer de configuració: canigo-services-xml.xml

Ubicació proposada: <PROJECT_ROOT>/src/main/resources/spring

En aquesta configuració es defineix quina implementació específica s'usarà per a la manipulació de fitxers XML. En l'actualitat es permet l'ús de:

  • net.gencat.ctti.canigo.services.xml.dom4j.XMLDomHelperDom4jImpl

Utilització del Servei

La utilització del Servei es basa en l´ús de les interfícies definides a l'apartat 'Arquitectura i Components'. Consultar l'apartat 'Exemples' per veure alguns exemples del tractament de fitxers XML amb l'API proporcionada.

A mode de resum podem resumir que:
1. La interfície XMLSerializationService proporciona principalment els mètodes següents:

  • toXML, serialització d'un objecte (JavaBean o no) cap a un document XML
  • fromXML, deserialització d'un document XML cap a un objecte Java
  • getXMLBindingConfiguration, getter de la configuració del mapeig XML

2. La interfície XMLSerializationConfiguration conté els mètodes següents:

  • aliasClass, per a fer el mapeig del nom d'una classe
  • aliasField, per a fer el mapeig d'un camp

3. La interfície XMLDomHelper conté els mètodes següents per a manipular documents DOM de la interfície org.w3c.Document:

  • parse, per a construir un document XML a partir d'un String
  • writeToFile, per a escriure el contingut d'un document XML en un fitxer
  • transform, per a realitzar transformacions XSLT amb jaxp interfícies

Exemples

Exemple de Serialització basada en XStream

Per a serialitzar un objecte seguirem el següent procediment:

  • Crear les classes que volem serialitzar en XML
    public class Person {
        private String firstname;
        private String lastname;
        private PhoneNumber phone;
        private PhoneNumber fax;
        // ... constructors and methods
    }
    
    public class PhoneNumber {
        private int code;
        private String number;
        // ... constructors and methods
    }
    
    ..
    
    Person objectToSerialize = new Person("Joe", "Walnes");
    objectToSerialize.setPhone(new PhoneNumber(123, "1234-456"));
    objectToSerialize.setFax(new PhoneNumber(123, "9999-999"));



  • Configuració del mapeig

Per defecte, Xstream usa el nom complet de la classe de l'objecte que serialitza. Per exemple, la classe com.mycompany.business.model.Person genera el XML següent:

<?xml version="1.0"  encoding="ISO-8859-1"?>

<com.mycompany.business.model.person>

...



Si volem un nom més fàcil d'ús, podem afegir el mapeig següent:

  • Mapeig de la classe Person
    xmlSerializationService.getXMLBindingConfiguration().aliasClass("person", Person.class);

1. Serialització d'un objecte a XML

String xml = xmlSerializationService.toXML(this.objectToSerialize)


El resultat de la serialització és el document XML següent:

<?xml version="1.0"  encoding="ISO-8859-1"?>

<person>

<firstname>Joe</firstname>

<lastname>Walnes</lastname>

<phone>

<id>123</id>

<number>1234-456</number>

</phone>

<fax>

<id>123</id>

<number>9999-999</number>

</fax>

</person>

A partir de la versió 2.3.9 del Framework Canigó, la serialització de l'objecte es pot fer indicant atributs. A continuació es mostra un exemple de com fer-ho:

Blog blog = new Blog("CSCanigó");

ArrayList llista = new ArrayList();
llista.add(new Entrada("CAN-1054", "Consulta", "Consulta que deriva en el canvi CAN-1055"));
llista.add(new Entrada("CAN-1055", "Peticio de Canvi", "Afegir atributs en la serialització d'objectes"));
blog.setLlista(llista);

serializationService.alias(Blog.class, "blog");
serializationService.alias(Entrada.class, "entrada");

serializationService.addImplicitCollection(Blog.class, "llista");
serializationService.useAttributeFor("autor", String.class);
serializationService.useAttributeFor("codi", String.class);

serializationService.registerConverter(new AutorConverter());

serializationService.toXML(blog);

L'XML resultant serà:

<blog autor="CSCanigó">
  <entrada codi="CAN-1054">
    <tipus>Consulta</tipus>
    <descripcio>Consulta que deriva en el canvi CAN-1055</descripcio>
  </entrada>
  <entrada codi="CAN-1055">
    <tipus>Peticio de Canvi</tipus>
    <descripcio>Afegir atributs en la serialització d&apos;objectes</descripcio>
  </entrada>
</blog>


2. Deserialització de l'objecte des de XML

Person person2 = xmlSerializationService.fromXML(xml)


Exemple de Manipulació de Fitxers XML

Presentarem a través d'exemples concrets les APIs bàsiques de dom4j per realitzar amb poc codi les operacions següents:

1) Parsing XML
2) Ús d'Iterators
3) Navegació amb XPath
4) Manipulació de gran documents
5) Creació de document XML
6) Escriure en un fitxer
7) Conversió en un String
8) Realitzar transformacions XSLT

Per a més informació sobre dom4j, veure la pàgina http://www.dom4j.org/cookbook.html

En els exemples següents, "domHelper" referencia el bean del servei XML.

Parseig XML

Per a construir un document XML, amb la interfície org.w3c.Document:

String xml = "<?xml version="1.0" encoding="ISO-8859-1"?><person>  ...</person>";

org.w3c.Document = domHelper.parse(xml);

amb la interfície org.dom4j.Document:
String xml = "<?xml version="1.0" encoding="ISO-8859-1"?><person>  ...</person>";

SAXReader reader = new SAXReader(new  StringReader(xm));

org.dom4j.Document document = reader.read();


Ús d'Iteradors


public void bar(org.dom4j.Document document) throws DocumentException
{
    Element root = document.getRootElement();

    // Iteración de los elementos de la rais del Documento
    for ( Iterator i = root.elementIterator(); i.hasNext(); ) {
    Element element = (Element) i.next();
        ...
    }

    // Iteración de los elementos de la raizdel Documento cuyo nombre es "foo"
    for ( Iterator i = root.elementIterator( "foo" ); i.hasNext(); ) {
    Element foo = (Element) i.next();
        // do something
    }

}


Navegació amb XPath

Podem avaluar amb XPath expressions per qualsevol element de l'arbre representat al document XML (Attribute, Element):

public void bar(org.dom4j.Document document) {
    List list = document.selectNodes( "//foo/bar" );

    Node node = document.selectSingleNode( "//foo/bar/author" );

    String name = node.valueOf( "@name" );
}

Per a més informació sobre XPath, veure el tutorial 'http://www.zvon.org/xxl/XPathTutorial/General/examples.html

Manipulació de grans documents

Els grans documents no es poden manipular amb iterators perquè aquells necessiten massa memòria. En en el seu lloc usarem mètodes recursius:

org.dom4j.Element root = document.getRootElement();
treeWalk(root);

public void treeWalk(org.dom4j.Element element) {
    for ( int i = 0, size = element.nodeCount(); i < size; i++ ) {
        Node node = element.node;
        if ( node instanceof Element ) {
            treeWalk( (Element) node );
        }
        else {
            // do something....
        }
    }
}


Creació de documents XML


org.dom4j.Document document = DocumentHelper.createDocument();

Element  root = document.addElement( "root" );

Element author1 = root.addElement( "escritor" )

.addAttribute( "name",  "Jaume" )

.addAttribute( "location", "Barcelona" )

.addText( "Jaume  Primero" );


Escriure en un fitxer

Amb la interfície org.w3c.Document:

org.w3c.Document document = ...
domHelper.writeToFile(document, "foo.xml");

Amb la interfície org.dom4j.Document:

org.dom4j.Document document = ...
FileWriter out = new FileWriter( "foo.xml" );
document.write( out );

Conversió del fitxer XML en un String


org.dom4j.Document document = ...;

String text = document.asXML();


Realitzar transformacions XSLT


// Get the XML source and XSLT

DOMSource xml = new DOMSource(new  File("afile.xml"));

DOMSource xslt = new DOMSource(new  File("astyle.xslt"));

DOMResult result = domHelper.transform(xml, xslt);