Java XML i JSON: Przetwarzanie dokumentów dla Java SE, część 1: SAXON i Jackson

Poprzednia 1 2 Strona 2 Strona 2 z 2

Transformacja

Teraz spróbujmy transformacji. Wykonaj następujące polecenie:

java XSLTDemo books.xml books.xsl

Niestety ta transformacja kończy się niepowodzeniem: należy obserwować dane wyjściowe identyfikujące Apache Xalan jako fabrykę transformatorów oraz komunikat o błędzie informujący, że xsl:for-each-groupnie jest obsługiwany.

Spróbujmy ponownie. Zakładając, że saxon9he.jari XSLTDemo.classznajdują się w bieżącym katalogu, wykonaj następujące polecenie:

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

Tym razem należy zwrócić uwagę na następujące posortowane i odpowiednio pogrupowane dane wyjściowe:

Dodatek do rozdziału 11: Przetwarzanie JSON z Jacksonem

Konwersja XML do JSON z Jacksonem

Java XML i JSON, rozdział 11, przedstawia Jacksona, który udostępnia interfejsy API do analizowania i tworzenia obiektów JSON. Możliwe jest również użycie Jacksona do konwersji dokumentów XML na dokumenty JSON.

W tej sekcji pokażę dwa sposoby konwertowania XML na JSON, najpierw z wiązaniem danych, a następnie z przechodzeniem po drzewie. Zakładam, że przeczytałeś rozdział 11 i znasz Jacksona. Aby śledzić te demonstracje, powinieneś pobrać następujące pliki JAR z repozytorium Maven:

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

Będziesz także potrzebować kilku dodatkowych plików JAR; większość jest wspólna dla obu technik konwersji. Wkrótce przedstawię informacje na temat uzyskiwania tych plików JAR.

Konwertuj XML na JSON z wiązaniem danych

Powiązanie danych umożliwia mapowanie zserializowanych danych na obiekt Java. Na przykład załóżmy, że masz mały dokument XML opisujący pojedynczą planetę. Listing 4 przedstawia ten dokument.

Listing 4. planet.xml

  Earth 3 9 

Listing 5 przedstawia równoważną Planetklasę Javy, której obiekty są odwzorowywane na planet.xmlzawartość.

Listing 5. Planet.java

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

Proces konwersji wymaga, aby najpierw przeanalizować XML na Planetobiekt. Możesz wykonać to zadanie, pracując z com.fasterxml.jackson.dataformat.xml.XmlMapperklasą w następujący sposób:

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

XmlMapperto dostosowany, com.fasterxml.jackson.databind.ObjectMapperktóry czyta i zapisuje XML. Udostępnia kilka readValue()metod odczytu pojedynczej wartości XML ze źródła wejściowego specyficznego dla XML; na przykład:

 T readValue(XMLStreamReader r, Class valueType)

Każda readValue()metoda wymaga javax.xml.stream.XMLStreamReaderobiektu jako pierwszego argumentu. Ten obiekt jest zasadniczo parserem opartym na strumieniu StAX do wydajnego analizowania tekstu w przód.

Drugi argument to java.lang.Classobiekt typu docelowego, którego instancja jest tworzona, zapełniana danymi XML i którego instancja jest następnie zwracana z metody.

Najważniejsze w tym fragmencie kodu jest to, że zawartość listy 4 jest wczytywana do Planetobiektu, który readValue()powraca do obiektu wywołującego.

Po utworzeniu obiektu łatwo jest zapisać go jako JSON, pracując z ObjectMapperi jego String writeValueAsString(Object value)metodą:

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

Wyciągnąłem te fragmenty kodu z XML2JSONaplikacji, której pełny kod źródłowy znajduje się na listingu 6.

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

Zanim skompilujesz zestawienia 5 i 6, musisz pobrać Jackson Dataformat XML, który implementuje XMLMapper. Pobrałem wersję 2.9.7, która jest zgodna z wersjami pozostałych trzech pakietów Jacksona.

Zakładając, że pomyślnie pobrałeś jackson-dataformat-xml-2.9.7.jar, wykonaj następujące polecenie (rozłożone na dwa wiersze dla czytelności), aby skompilować kod źródłowy:

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

Zanim będziesz mógł uruchomić wynikową aplikację, musisz pobrać moduł Jackson: JAXB Annotations, a także pobrać StAX 2 API. Ściągnąłem JAXB Annotations w wersji 2.9.7 i StAX 2 API w wersji 3.1.3.

Zakładając, że pomyślnie pobrałeś jackson-module-jaxb-annotations-2.9.7.jari stax2-api-3.1.3.jarwykonaj następujące polecenie (rozłożone na trzy linie dla czytelności), aby uruchomić aplikację:

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

Jeśli wszystko pójdzie dobrze, powinieneś zwrócić uwagę na następujący wynik:

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

Konwertuj XML na JSON z przechodzeniem po drzewie

Innym sposobem konwersji z formatu XML na JSON jest najpierw przeanalizowanie XML do postaci drzewa węzłów JSON, a następnie zapisanie tego drzewa w dokumencie JSON. Możesz wykonać pierwsze zadanie, wywołując jedną z XMLMapperdziedziczonych readTree()metod:

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

ObjectMapper„s JsonNode readTree(byte[] content)metoda deserializes zawartości JSON w drzewie jackson.databind.JsonNodeobiektów i powraca do głównego JsonNodeprzedmiotu tego drzewa. W XmlMapperkontekście ta metoda deserializuje zawartość XML do drzewa. W obu przypadkach zawartość JSON lub XML jest przekazywana do tej metody jako tablica bajtów.

Drugie zadanie - konwersja drzewa obiektów do JSON - wykonuje się w podobny sposób, jak wcześniej pokazałem. Tym razem jest to JsonNodeobiekt główny przekazywany do 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

Materiał przedstawiony w tym artykule należy traktować jako dodatek do rozdziałów 6 i 11 w drugiej edycji języka Java XML i JSON . Natomiast mój następny artykuł będzie związany z książką, ale całkowicie nowym materiałem. Miej oko na mój nadchodzący artykuł o wiązaniu obiektów Java z dokumentami JSON za pomocą JSON-B.

Ta historia „Java XML i JSON: przetwarzanie dokumentów dla Java SE, część 1: SAXON i Jackson” została pierwotnie opublikowana przez JavaWorld.