Java XML y JSON: procesamiento de documentos para Java SE, Parte 1: SAXON y Jackson

Anterior 1 2 Página 2 Página 2 de 2

Transformación

Ahora intentemos la transformación. Ejecute el siguiente comando:

java XSLTDemo books.xml books.xsl

Desafortunadamente, esta transformación falla: debe observar la salida que identifica a Apache Xalan como la fábrica de transformadores y un mensaje de error que indica que xsl:for-each-groupno es compatible.

Intentemoslo de nuevo. Suponiendo que saxon9he.jary XSLTDemo.classestán ubicados en el directorio actual, ejecute el siguiente comando:

java -cp saxon9he.jar;. XSLTDemo books.xml books.xsl

Esta vez, debe observar la siguiente salida ordenada y agrupada correctamente:

Anexo al Capítulo 11: Procesamiento de JSON con Jackson

Conversión de XML a JSON con Jackson

Java XML y JSON, Capítulo 11, presenta Jackson, que proporciona API para analizar y crear objetos JSON. También es posible utilizar Jackson para convertir documentos XML en documentos JSON.

En esta sección, le mostraré dos formas de convertir XML a JSON, primero con enlace de datos y luego con cruce de árbol. Asumiré que ha leído el capítulo 11 y está familiarizado con Jackson. Para seguir estas demostraciones, debería haber descargado los siguientes archivos JAR del repositorio de Maven:

  • jackson-annotations-2.9.7.jar
  • jackson-core-2.9.7.jar
  • jackson-databind-2.9.7.jar

También necesitará algunos archivos JAR adicionales; la mayoría son comunes a ambas técnicas de conversión. Proporcionaré información sobre cómo obtener estos archivos JAR en breve.

Convierta XML a JSON con enlace de datos

El enlace de datos le permite asignar datos serializados a un objeto Java. Por ejemplo, suponga que tiene un pequeño documento XML que describe un solo planeta. El Listado 4 presenta este documento.

Listado 4. planet.xml

  Earth 3 9 

El Listado 5 presenta una Planetclase Java equivalente cuyos objetos se asignan al planet.xmlcontenido de.

Listado 5. Planet.java

public class Planet { public String name; public Integer planet_from_sun; public Integer moons; }

El proceso de conversión requiere que primero analice el XML en un Planetobjeto. Puede realizar esta tarea trabajando con la com.fasterxml.jackson.dataformat.xml.XmlMapperclase, de la siguiente manera:

XmlMapper xmlMapper = new XmlMapper(); XMLInputFactory xmlif = XMLInputFactory.newFactory(); FileReader fr = new FileReader("planet.xml"); XMLStreamReader xmlsr = xmlif.createXMLStreamReader(fr); Planet planet = xmlMapper.readValue(xmlsr, Planet.class);

XmlMapperes un com.fasterxml.jackson.databind.ObjectMapperarchivo XML personalizado que lee y escribe. Proporciona varios readValue()métodos para leer un único valor XML de una fuente de entrada específica de XML; por ejemplo:

 T readValue(XMLStreamReader r, Class valueType)

Cada readValue()método requiere un javax.xml.stream.XMLStreamReaderobjeto como primer argumento. Este objeto es esencialmente un analizador basado en flujo basado en StAX para analizar texto de manera eficiente de manera directa.

El segundo argumento es un java.lang.Classobjeto para el tipo de destino que se está instanciando, llenado con datos XML y cuya instancia se devuelve posteriormente desde el método.

La conclusión de este fragmento de código es que el contenido del Listado 4 se lee en un Planetobjeto que readValue()regresa a su llamador.

Una vez que se ha creado el objeto, es fácil escribirlo como JSON trabajando con ObjectMappery su String writeValueAsString(Object value)método:

ObjectMapper jsonMapper = new ObjectMapper(); String json = jsonMapper.writeValueAsString(planet);

Extraje estos fragmentos de código de una XML2JSONaplicación cuyo código fuente completo aparece en el Listado 6.

Listado 6. XML2JSON.java (Versión 1)

import java.io.FileReader; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamReader; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.dataformat.xml.XmlMapper; import static java.lang.System.*; public class XML2JSON { public static void main(String[] args) throws Exception { XmlMapper xmlMapper = new XmlMapper(); XMLInputFactory xmlif = XMLInputFactory.newFactory(); FileReader fr = new FileReader("planet.xml"); XMLStreamReader xmlsr = xmlif.createXMLStreamReader(fr); Planet planet = xmlMapper.readValue(xmlsr, Planet.class); ObjectMapper jsonMapper = new ObjectMapper(); String json = jsonMapper.writeValueAsString(planet); out.println(json); } }

Antes de que pueda compilar los listados 5 y 6, deberá descargar Jackson Dataformat XML, que implementa XMLMapper. Descargué la versión 2.9.7, que coincide con las versiones de los otros tres paquetes de Jackson.

Suponiendo que ha descargado correctamente jackson-dataformat-xml-2.9.7.jar, ejecute el siguiente comando (distribuido en dos líneas para facilitar la lectura) para compilar el código fuente:

javac -cp jackson-core-2.9.7.jar;jackson-databind-2.9.7.jar;jackson-dataformat-xml-2.9.7.jar;. XML2JSON.java

Antes de que pueda ejecutar la aplicación resultante, deberá descargar Jackson Module: JAXB Annotations y también descargar StAX 2 API. Descargué JAXB Annotations versión 2.9.7 y StAX 2 API versión 3.1.3.

Suponiendo que haya descargado correctamente jackson-module-jaxb-annotations-2.9.7.jary stax2-api-3.1.3.jar, ejecute el siguiente comando (distribuido en tres líneas para facilitar la lectura) para ejecutar la aplicación:

java -cp jackson-annotations-2.9.7.jar;jackson-core-2.9.7.jar;jackson-databind-2.9.7.jar; jackson-dataformat-xml-2.9.7.jar;jackson-module-jaxb-annotations-2.9.7.jar; stax2-api-3.1.3.jar;. XML2JSON

Si todo va bien, debe observar el siguiente resultado:

{"name":"Earth","planet_from_sun":3,"moons":9}

Convierta XML a JSON con cruce de árboles

Otra forma de convertir de XML a JSON es analizar primero el XML en un árbol de nodos JSON y luego escribir este árbol en un documento JSON. Puede realizar la primera tarea llamando a uno de XMLMapperlos readTree()métodos heredados :

XmlMapper xmlMapper = new XmlMapper(); JsonNode node = xmlMapper.readTree(xml.getBytes());

ObjectMapperEl JsonNode readTree(byte[] content)método de deserializa el contenido JSON en un árbol de jackson.databind.JsonNodeobjetos y devuelve el JsonNodeobjeto raíz de este árbol. En un XmlMappercontexto, este método deserializa el contenido XML en el árbol. En cualquier caso, el contenido JSON o XML se pasa a este método como una matriz de bytes.

La segunda tarea, convertir el árbol de objetos a JSON, se realiza de manera similar a lo que mostré anteriormente. Esta vez, es el JsonNodeobjeto raíz que se pasa a writeValueAsString():

ObjectMapper jsonMapper = new ObjectMapper(); String json = jsonMapper.writeValueAsString(node);

I excerpted these code fragments from an XML2JSON application whose complete source code appears in Listing 7.

Listing 7. XML2JSON.java (version 2)

import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.dataformat.xml.XmlMapper; import static java.lang.System.*; public class XML2JSON { public static void main(String[] args) throws Exception { String xml = "\n"+ "\n" + " Earth\n" + " 3\n" + " 1\n" + "\n"; XmlMapper xmlMapper = new XmlMapper(); JsonNode node = xmlMapper.readTree(xml.getBytes()); ObjectMapper jsonMapper = new ObjectMapper(); String json = jsonMapper.writeValueAsString(node); out.println(json); } }

Execute the following command (spread over two lines for readability) to compile Listing 7:

javac -cp jackson-core-2.9.7.jar;jackson-databind-2.9.7.jar;jackson-dataformat-xml-2.9.7.jar XML2JSON.java

Before you can run the resulting application, you'll need to download Woodstox, which is a high-performance XML processor that implements StAX, SAX2, and StAX2. I downloaded Woodstox 5.2.0. Then execute the following command (spread across three lines for readability) to run the application:

java -cp jackson-annotations-2.9.7.jar;jackson-core-2.9.7.jar;jackson-databind-2.9.7.jar; jackson-dataformat-xml-2.9.7.jar;stax2-api-3.1.3.jar;woodstox-core-5.2.0.jar;. XML2JSON

If all goes well, you should observe the following output:

{"name":"Earth","planet_from_sun":"3","moons":"1"}

Notice that the numbers assigned to the planet_from_sun and moons XML elements are serialized to JSON strings instead of numbers. The readTree() method doesn't infer the data type in the absence of an explicit type definition.

Jackson's support for XML tree traversal has additional limitations:

  • Jackson is unable to differentiate between objects and arrays. Because XML provides no means to differentiate an object from a list (array) of objects, Jackson collates repeated elements into a single value.
  • Jackson doesn't support mixed content (textual content and elements as children of an element). Instead, it maps each XML element to a JsonNode object. Any text is lost.

Given these limitations, it's not surprising that the official Jackson documentation recommends against parsing XML into JsonNode-based trees. You're better off using the data binding conversion technique.

Conclusion

El material presentado en este artículo debe considerarse como un anexo a los capítulos 6 y 11 de la segunda edición de Java XML y JSON . En contraste, mi próximo artículo estará relacionado con el libro pero con material completamente nuevo. Esté atento a mi próximo artículo sobre el enlace de objetos Java a documentos JSON con JSON-B.

Esta historia, "Java XML y JSON: procesamiento de documentos para Java SE, Parte 1: SAXON y Jackson" fue publicada originalmente por JavaWorld.