Java XML e JSON: elaborazione dei documenti per Java SE, parte 1: SAXON e Jackson

Precedente 1 2 Pagina 2 Pagina 2 di 2

Trasformazione

Ora proviamo la trasformazione. Esegui il seguente comando:

java XSLTDemo books.xml books.xsl

Sfortunatamente, questa trasformazione fallisce: dovresti osservare l'output che identifica Apache Xalan come la fabbrica del trasformatore e un messaggio di errore che indica che xsl:for-each-groupnon è supportato.

Proviamo di nuovo. Supponendo che saxon9he.jare si XSLTDemo.classtrovino nella directory corrente, eseguire il seguente comando:

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

Questa volta, dovresti osservare il seguente output ordinato e correttamente raggruppato:

Addendum al Capitolo 11: Elaborazione di JSON con Jackson

Conversione da XML a JSON con Jackson

Java XML e JSON, il capitolo 11, introduce Jackson, che fornisce API per l'analisi e la creazione di oggetti JSON. È anche possibile utilizzare Jackson per convertire documenti XML in documenti JSON.

In questa sezione, ti mostrerò due modi per convertire XML in JSON, prima con il data binding e poi con il tree traversal. Presumo che tu abbia letto il capitolo 11 e abbia familiarità con Jackson. Per seguire queste demo, dovresti aver scaricato i seguenti file JAR dal repository Maven:

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

Avrai anche bisogno di alcuni file JAR aggiuntivi; la maggior parte sono comuni a entrambe le tecniche di conversione. Fornirò a breve informazioni su come ottenere questi file JAR.

Converti XML in JSON con data binding

Il data binding consente di mappare i dati serializzati su un oggetto Java. Ad esempio, supponi di avere un piccolo documento XML che descrive un singolo pianeta. Il Listato 4 presenta questo documento.

Listato 4. planet.xml

  Earth 3 9 

Il Listato 5 presenta una Planetclasse Java equivalente i cui oggetti sono mappati al planet.xmlcontenuto di.

Listato 5. Planet.java

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

Il processo di conversione richiede prima di analizzare l'XML in un Planetoggetto. È possibile eseguire questa attività lavorando con la com.fasterxml.jackson.dataformat.xml.XmlMapperclasse, come segue:

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);

XmlMapperè un personalizzato com.fasterxml.jackson.databind.ObjectMapperche legge e scrive XML. Fornisce diversi readValue()metodi per leggere un singolo valore XML da una sorgente di input specifica per XML; per esempio:

 T readValue(XMLStreamReader r, Class valueType)

Ogni readValue()metodo richiede un javax.xml.stream.XMLStreamReaderoggetto come primo argomento. Questo oggetto è essenzialmente un parser basato su stream basato su StAX per analizzare in modo efficiente il testo in modo diretto.

Il secondo argomento è un java.lang.Classoggetto per il tipo di destinazione che viene istanziato, popolato con dati XML e la cui istanza viene successivamente restituita dal metodo.

La linea di fondo di questo frammento di codice è che il contenuto del listato 4 viene letto in un Planetoggetto che readValue()ritorna al suo chiamante.

Una volta che l'oggetto è stato creato, è facile scriverlo come JSON lavorando con ObjectMappere il suo String writeValueAsString(Object value)metodo:

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

Ho estratto questi frammenti di codice da XML2JSONun'applicazione il cui codice sorgente completo appare nel Listato 6.

Listato 6. XML2JSON.java (Versione 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); } }

Prima di poter compilare gli elenchi 5 e 6, è necessario scaricare Jackson Dataformat XML, che implementa XMLMapper. Ho scaricato la versione 2.9.7, che corrisponde alle versioni degli altri tre pacchetti Jackson.

Supponendo che tu abbia scaricato correttamente jackson-dataformat-xml-2.9.7.jar, esegui il seguente comando (distribuito su due righe per leggibilità) per compilare il codice sorgente:

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

Prima di poter eseguire l'applicazione risultante, è necessario scaricare Jackson Module: JAXB Annotations e scaricare anche StAX 2 API. Ho scaricato JAXB Annotations versione 2.9.7 e StAX 2 API versione 3.1.3.

Supponendo che tu abbia scaricato con successo jackson-module-jaxb-annotations-2.9.7.jare stax2-api-3.1.3.jar, esegui il seguente comando (distribuito su tre righe per leggibilità) per eseguire l'applicazione:

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

Se tutto va bene, dovresti osservare il seguente output:

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

Converti XML in JSON con attraversamento dell'albero

Un altro modo per convertire da XML a JSON è analizzare prima l'XML in un albero di nodi JSON e quindi scrivere questo albero in un documento JSON. È possibile eseguire la prima attività chiamando uno dei metodi XMLMapperereditati di readTree():

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

ObjectMapperIl JsonNode readTree(byte[] content)metodo di deserializza il contenuto JSON in un albero di jackson.databind.JsonNodeoggetti e restituisce l' JsonNodeoggetto radice di questo albero. In un XmlMappercontesto, questo metodo deserializza il contenuto XML nell'albero. In entrambi i casi, il contenuto JSON o XML viene passato a questo metodo come matrice di byte.

La seconda operazione, la conversione dell'albero degli oggetti in JSON, viene eseguita in modo simile a quanto mostrato in precedenza. Questa volta, è l' JsonNodeoggetto radice che viene passato 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

Il materiale presentato in questo articolo deve essere considerato come addendum ai capitoli 6 e 11 nella seconda edizione di Java XML e JSON . Al contrario, il mio prossimo articolo sarà relativo al libro ma materiale completamente nuovo. Tieni gli occhi aperti per il mio prossimo articolo sull'associazione di oggetti Java a documenti JSON con JSON-B.

Questa storia, "Java XML e JSON: elaborazione dei documenti per Java SE, parte 1: SAXON e Jackson" è stata originariamente pubblicata da JavaWorld.