Java XML i JSON: Obrada dokumenata za Java SE, 1. dio: SAXON i Jackson

Prethodna 1 2 Stranica 2 Stranica 2 od 2

Transformacija

Pokušajmo sada preobrazbu. Izvršite sljedeću naredbu:

java XSLTDemo books.xml books.xsl

Nažalost, ova transformacija ne uspije: trebali biste promatrati izlaz koji identificira Apache Xalan kao tvornicu transformatora i poruku o pogrešci koja navodi da xsl:for-each-groupnije podržana.

Pokušajmo ponovo. Pod pretpostavkom da su saxon9he.jari XSLTDemo.classnalaze se u trenutnom direktorijumu, izvršite sljedeću naredbu:

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

Ovaj put, trebali biste promatrati sljedeći sortirani i pravilno grupirani izlaz:

Dodatak poglavlju 11: Obrada JSON-a s Jacksonom

Pretvaranje XML-a u JSON s Jacksonom

Java XML i JSON, poglavlje 11, predstavljaju Jackson, koji nudi API-je za raščlanjivanje i stvaranje JSON objekata. Također je moguće koristiti Jackson za pretvaranje XML dokumenata u JSON dokumente.

U ovom odjeljku pokazat ću vam dva načina za pretvorbu XML-a u JSON, prvo povezivanjem podataka, a zatim obilaženjem stabla. Pretpostavit ću da ste pročitali 11. poglavlje i da ste upoznati s Jacksonom. Da biste pratili ove demonstracije, trebali ste preuzeti sljedeće JAR datoteke iz spremišta Maven:

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

Trebat će vam i nekoliko dodatnih JAR datoteka; većina je zajednička objema tehnikama pretvorbe. Uskoro ću pružiti informacije o dobivanju ovih JAR datoteka.

Pretvorite XML u JSON uz vezanje podataka

Vezanje podataka omogućuje vam mapiranje serializiranih podataka na Java objekt. Na primjer, pretpostavimo da imate mali XML dokument koji opisuje jedan planet. Popis 4 predstavlja ovaj dokument.

Popis 4. planet.xml

  Earth 3 9 

Popis 5 predstavlja ekvivalentnu Java Planetklasu čiji se objekti preslikavaju na planet.xmlsadržaj.

Popis 5. Planet.java

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

Proces pretvorbe zahtijeva da prvo raščlanite XML u Planetobjekt. Ovaj zadatak možete postići radeći s com.fasterxml.jackson.dataformat.xml.XmlMapperrazredom, kako slijedi:

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

XmlMapperje prilagođen za com.fasterxml.jackson.databind.ObjectMapperčitanje i pisanje XML-a. Pruža nekoliko readValue()metoda za čitanje jedne XML vrijednosti iz XML specifičnog ulaznog izvora; na primjer:

 T readValue(XMLStreamReader r, Class valueType)

Svaka readValue()metoda zahtijeva javax.xml.stream.XMLStreamReaderobjekt kao prvi argument. Ovaj je objekt u osnovi StAX-ov parser zasnovan na streamu za učinkovito raščlanjivanje teksta naprijed.

Drugi je argument java.lang.Classobjekt ciljne vrste koji se instancira, popunjava XML podacima i čija se instanca naknadno vraća iz metode.

Dno ovog fragmenta koda je da se sadržaj popisa 4 čita u Planetobjekt koji se readValue()vraća pozivatelju.

Jednom kada je objekt stvoren, lako ga je zapisati kao JSON radeći s ObjectMapperi njegovom String writeValueAsString(Object value)metodom:

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

Ove fragmente koda izlučio sam iz XML2JSONaplikacije čiji se cjeloviti izvorni kod nalazi na popisu 6.

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

Da biste mogli sastaviti popise 5 i 6, morat ćete preuzeti Jackson Dataformat XML, koji implementira XMLMapper. Preuzeo sam verziju 2.9.7 koja se podudara s inačicama ostala tri Jackson paketa.

Pod pretpostavkom da ste uspješno preuzeli jackson-dataformat-xml-2.9.7.jar, izvršite sljedeću naredbu (raširite se u dva retka radi čitljivosti) za sastavljanje izvornog koda:

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

Da biste mogli pokrenuti rezultirajuću aplikaciju, morat ćete preuzeti Jackson Module: JAXB Annotations, a također i StAX 2 API. Preuzeo sam JAXB Annotations verzije 2.9.7 i StAX 2 API verzije 3.1.3.

Pod pretpostavkom da ste uspješno preuzeli jackson-module-jaxb-annotations-2.9.7.jari stax2-api-3.1.3.jar, pokrenite sljedeću naredbu (raširenu u tri retka radi čitljivosti) da biste pokrenuli aplikaciju:

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

Ako sve bude u redu, trebali biste promatrati sljedeći rezultat:

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

Pretvori XML u JSON pomoću zaokretanja stabla

Drugi način pretvorbe iz XML-a u JSON je prvo analizirati XML u stablo JSON čvorova, a zatim to stablo zapisati u JSON dokument. Prvi zadatak možete ostvariti pozivanjem jedne od XMLMappernaslijeđenih readTree()metoda:

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

ObjectMapper's JsonNode readTree(byte[] content)metodom deserializira JSON sadržaj u stablo jackson.databind.JsonNodeobjekata i vraća korijenski JsonNodeobjekt ovog stabla. U XmlMapperkontekstu, ova metoda deserijalizira XML sadržaj u stablu. U oba slučaja, JSON ili XML sadržaj prosljeđuje se ovoj metodi kao niz bajtova.

Drugi zadatak - pretvaranje stabla objekata u JSON - postiže se na sličan način kao što sam prethodno pokazao. Ovoga puta to je JsonNodekorijenski objekt kojem se prosljeđuje 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

Materijal predstavljen u ovom članku treba smatrati dodatkom poglavljima 6 i 11 u drugom izdanju Java XML i JSON . Suprotno tome, moj sljedeći članak bit će povezan s knjigom, ali s potpuno novim materijalom. Pripazite na moj nadolazeći članak o vezivanju Java objekata s JSON dokumentima pomoću JSON-B.

Ovu priču, "Java XML i JSON: Obrada dokumenata za Java SE, 1. dio: SAXON i Jackson" izvorno je objavio JavaWorld.