Desenredando XmlBeans II

De nuevo he tenido que liarme en un desarrollo relacionado con XmlBeans, y de nuevo he encontrado esos pequeños problemas que no explican en ningún manual, pero que te encuentras a menudo. Así que como en el anterior artículo voy a seguir comentando estos problemas que seguro que os pueden ayudar en el desarrollo de proyectos con XmlBeans.

1. Como manejar tags xs:any en XmlBeans

Cuando compilamos un XSD con XmlBeans, este nos genera una serie de clases con funciones de acceso a los diferentes nodos (gets y sets) definidos en el esquema. Pero, qué pasa si compilamos un esquema que incluye la particula xs:any ? Como podréis comprobar xmlBeans no nos genera una funcion getAny o setAny.

Para acceder y manejar estos nodos la API de XmlBeans incluye las siguientes alternativas:

  • El uso de instancias tipo XmlCursor.
  • Usar el método selectPath para obtener la información del XML via XPath
  • Usar el método selectChildren para obtener los nodos por nombre.
  • Utilizar la API DOM para recorrer el árbol de nodos.

A continuación os dejo una dirección donde explica detalladamente el uso de estos métodos con ejemplos:
Handling xs:any with the XMLBeans API

2. Problema con el uso de XPath con XmlBeans

Como consecuencia del anterior punto, he tenido un pequeño problema de librerias que sucede cuando utilizamos XPath en Xmlbeans. El mensaje de error era el siguiente:

java.lang.RuntimeException:  Trying XBeans path engine... Trying XQRL... Trying Saxon... FAILED

Primero vamos a repasar lo que señala el manual de instalación de XmlBeans:

For full XQuery and XPath support, be sure to download the Saxon XQuery processor as follows:

  • For XmlBeans 2.0.0 and XMLBeans 2.1.0 you need Saxon 8.1.1 ONLY.
  • For XmlBeans 2.2.0 you need Saxon 8.6.1 (may work with later revisions, but not tested

Es decir, si queremos utilizar XPath y XQuery necesitamos las librerías de Saxon. Además también debemos añadir la librería xbean_xpath.jar que se encuentra en las librerías de XmlBeans.

3. Problemas con fragmentos de documentos XML

Este fue posiblemente el problema que mas me ha traído de cabeza, y es que para mi resulta difícil entender porqué es tan complicado tratar con "pedazos" de documentos XML en XmlBeans. Os voy a poner unos cuantos ejemplos para situaros en contexto.

Tenemos el siguiente XSD compilado con xmlBeans que nos servirá de ejemplo:





























3.1. Queremos crear el siguiente xml:



New Street Address


Para ello utilizamos las siguientes funciones que nos proporciona las clases creadas por xmlBeans:

AddressType addressType = AddressType.Factory.newInstance();addressType.setStreet("New Street Address");addressType.toString();

El resultado de este codigo seria el siguiente:



New Street Address


La razón de todo ello es que Address implementa la interficie XmlObject que representa el contenido y no el nodo en si mismo. Hay tres tipos de XmlObject diferentes:

  1. Contenido de un elemento. ej. atributos, elementos internos y texto interno sin el nombre del elemento.
  2. Contenido simple de un tipo. ej. texto que contiene un nodo.
  3. Contenido de un documento. La correspondiente clase generada por xmlBeans lleva el sufijo "Document" en el nombre.

En el caso de ejecutar XmlObject.toString() en el caso 3 nos va a devolver el documento entero, pero no así para los casos 1 y 2, porque representan partes internas de un documento. En nuestro ejemplo la clase AddressType se trata de un XmlObject de tipo 1, por eso mismo cuando hacemos un toString() este va mostrar el contenido del nodo dentro de un elemento .

Para solucionar este problema lo que vamos a hacer es crear un tipo superior (en este caso "Addresses") y le añadiremos el tipo que queremos sacar por pantalla (en este caso "Address"), de tal manera que al hacer un toString del nodo superior tendremos su contenido.

AddressesType addressesType = AddressesType.Factory.newInstance();
addressesType.setAddressArray(new AddressType[]){addressType});
return addressesType.toString();

Esto nos dará como resultado:





New Street Address




Finalmente modificaremos la función toString para que no nos imprima los tags "xml-fragment":

FileOutputStream fos = new FileOutputStream(new File("outFile.xml"));
addressesType.save(fos);

3.2. Por otro lado si nos dan un trozo de un documento xml como este:



New Street Address


y intentamos parsearlo con xmlBeans:

Address address = Address.Factory.parse(xmlToParse);

podremos comprobar que esta funcion no ha echo nada y la clase "Adress" sigue vacía. En este caso la solución mas rápida y segura que encontré fue emular una "cascara" del xml desde el elemento root donde añadiremos el xml que nos han pasado. Por ejemplo:

String xmlDoc = ""+xmlToParse+"";

Entonces podemos parsear el xml resultante desde el elemento document (root, en este caso "addresses") y obtener la clase que necesitamos navegando por las APIs generadas por XmlBeans:

AddressesDocument theDoc = AddressesDocument.Factory.parse(xmlDoc);
Addresses theAddresses = theDoc.getAddresses();
Lis
listAddress = theAddresses.getAddressList();

En el caso de que la creación de un "contenedor" xml vacío sea difícil, otra solución seria substituir el elemento

por , así podríamos parserlo sin problemas.

Enlaces relacionados

Finalmente os voy añadir las direcciones donde he encontrado la solución para estos problemas, que ha sido principalmente en foros y listas de correo:Atenea tech blog › Edit — WordPress

Contacto

¿Te interesan nuestros servicios?

Contáctanos