Supporto per librerie XML in Java

1. Introduzione

In questo articolo confronteremo le librerie XML e le API Java.

Questo è il secondo articolo della serie sul supporto Java per XML, se vuoi approfondire il supporto XPath in Java dai un'occhiata all'articolo precedente.

2. Panoramica

Ora approfondiremo il supporto del mondo XML e per questo inizieremo spiegando il più semplice possibile tutte le iniziali relative al soggetto.

Nel supporto Java XML possiamo trovare poche definizioni API, ognuna ha i suoi pro e contro.

SAX : è un'API di parsing basata su eventi, fornisce un accesso di basso livello, è efficiente in termini di memoria e più veloce del DOM poiché non carica l'intero albero del documento in memoria ma non fornisce supporto per la navigazione come quello fornito da XPath, sebbene sia più efficiente è anche più difficile da usare.

DOM : come parser basato su modello che carica un documento con struttura ad albero in memoria, quindi abbiamo l'ordine degli elementi originale, possiamo navigare nel nostro documento in entrambe le direzioni, fornisce un'API per la lettura e la scrittura, offre la manipolazione XML ed è molto facile da usare anche se il prezzo è un alto carico sulle risorse di memoria.

StAX : Offre la facilità di DOM e l'efficienza di SAX ma manca di alcune funzionalità fornite da DOM come la manipolazione XML e ci permette solo di navigare nel documento in avanti.

JAXB : ci permette di navigare nel documento in entrambe le direzioni, è più efficiente del DOM, consente la conversione da XML a tipi java e supporta la manipolazione XML ma può solo analizzare un documento XML valido.

Potresti ancora trovare alcuni riferimenti a JAXP ma l'ultima versione di questo progetto è di marzo 2013 ed è praticamente morto.

Tabella API XML

3. L'XML

In questa sezione vedremo le implementazioni più popolari, in modo da poter testare campioni funzionanti reali e controllare le differenze tra loro.

Nei seguenti esempi lavoreremo con un semplice file XML con una struttura come questa:

  Guava Introduction to Guava 04/04/2016 GuavaAuthor  ... 

4. DOM4J

Inizieremo dando un'occhiata a cosa possiamo fare con DOM4J e per questo esempio dobbiamo aggiungere l'ultima versione di questa dipendenza.

Questa è una delle librerie più popolari per lavorare con file XML , poiché ci consente di eseguire letture bidirezionali, creare nuovi documenti e aggiornare quelli esistenti.

DOM4J può funzionare con DOM , SAX , XPath e XLST . SAX è supportato tramite JAXP .

Diamo un'occhiata qui per esempio, come possiamo selezionare un elemento filtrante per un dato id.

SAXReader reader = new SAXReader(); Document document = reader.read(file); List elements = document.selectNodes("//*[@tutId='" + id + "']"); return elements.get(0);

La classe SAXReader è responsabile della creazione di un albero DOM4J dagli eventi di analisi SAX . Una volta che abbiamo un org.dom4j.Document, dobbiamo solo chiamare il metodo necessario e passarvi l' espressione XPath come String.

Possiamo caricare un documento esistente, apportare modifiche al suo contenuto e quindi aggiornare il file originale.

for (Node node : nodes) { Element element = (Element)node; Iterator iterator = element.elementIterator("title"); while (iterator.hasNext()) { Element title =(Element)iterator.next(); title.setText(title.getText() + " updated"); } } XMLWriter writer = new XMLWriter( new FileWriter(new File("src/test/resources/example_updated.xml"))); writer.write(document); writer.close();

Nell'esempio sopra, stiamo cambiando il contenuto di ogni titolo e creiamo un nuovo file.

Si noti qui quanto sia semplice ottenere il nodo di ogni titolo in una lista chiamando elementIterator e passando il nome del nodo.

Una volta modificato il contenuto, utilizzeremo XMLWriter che accetta un albero DOM4J e lo formatta in un flusso come XML .

Creare un nuovo documento da zero è semplice come vediamo di seguito.

Document document = DocumentHelper.createDocument(); Element root = document.addElement("XMLTutorials"); Element tutorialElement = root.addElement("tutorial").addAttribute("tutId", "01"); tutorialElement.addAttribute("type", "xml"); tutorialElement.addElement("title").addText("XML with Dom4J"); ... OutputFormat format = OutputFormat.createPrettyPrint(); XMLWriter writer = new XMLWriter( new FileWriter(new File("src/test/resources/example_new.xml")), format); writer.write(document); writer.close(); 

DocumentHelper ci fornisce una raccolta di metodi da utilizzare da DOM4J , come createDocument che crea un documento vuoto per iniziare a lavorarci.

Possiamo creare tutti gli attributi o gli elementi di cui abbiamo bisogno con i metodi forniti da DOM4J e, una volta completato il nostro documento, lo scriviamo semplicemente su un file come abbiamo fatto prima con il caso di aggiornamento.

5. JDOM

Per lavorare con JDOM, dobbiamo aggiungere questa dipendenza al nostro pom.

Lo stile di lavoro di JDOM è abbastanza simile a quello di DOM4J , quindi daremo un'occhiata solo ad un paio di esempi:

SAXBuilder builder = new SAXBuilder(); Document doc = builder.build(this.getFile()); Element tutorials = doc.getRootElement(); List titles = tutorials.getChildren("tutorial"); 

Nell'esempio sopra, stiamo recuperando tutti gli elementi dall'elemento radice in un modo molto semplice come possiamo fare con DOM4J:

SAXBuilder builder = new SAXBuilder(); Document document = (Document) builder.build(file); String filter = "//*[@tutId='" + id + "']"; XPathFactory xFactory = XPathFactory.instance(); XPathExpression expr = xFactory.compile(filter, Filters.element()); List node = expr.evaluate(document);

Di nuovo, qui nel codice sopra, abbiamo un SAXBuilder che crea un'istanza di documento da un dato file. Stiamo recuperando un elemento dal suo attributo tutId passando un'espressione XPath a XPathFactory fornito da JDOM2.

6. StAX

Ora, vedremo come recuperare tutti gli elementi dal nostro elemento radice utilizzando l' API Stax . Stax è incluso nel JDK a partire da Java 6, quindi non è necessario aggiungere alcuna dipendenza.

Innanzitutto, dobbiamo creare una classe Tutorial :

public class Tutorial { private String tutId; private String type; private String title; private String description; private String date; private String author; // standard getters and setters }

e poi siamo pronti a seguire:

List tutorials = new ArrayList(); XMLInputFactory factory = XMLInputFactory.newInstance(); XMLEventReader eventReader = factory.createXMLEventReader(new FileReader(this.getFile())); Tutorial current; while (eventReader.hasNext()) { XMLEvent event = eventReader.nextEvent(); switch (event.getEventType()) { case XMLStreamConstants.START_ELEMENT: StartElement startElement = event.asStartElement(); String qName = startElement.getName().getLocalPart(); ... break; case XMLStreamConstants.CHARACTERS: Characters characters = event.asCharacters(); ... break; case XMLStreamConstants.END_ELEMENT: EndElement endElement = event.asEndElement(); // check if we found the closing element // close resources that need to be explicitly closed break; } }

Nell'esempio sopra, per aiutarci a recuperare le informazioni, dovevamo creare una classe in cui archiviare i dati recuperati.

Per leggere il documento, abbiamo dichiarato quelli che vengono chiamati gestori di eventi e li abbiamo usati per navigare nel nostro documento. Ricorda che le implementazioni SAX non forniscono la navigazione bidirezionale. Come puoi vedere qui, è necessario fare molto lavoro solo per recuperare un semplice elenco di elementi.

7. JAXB

JAXB è incluso con JDK , così come Xerces, quindi non è necessaria alcuna dipendenza aggiuntiva per questo.

È molto semplice caricare, creare e manipolare le informazioni da un file XML utilizzando JAXB .

Abbiamo solo bisogno di creare le entità java corrette per associare l' XML e il gioco è fatto.

JAXBContext jaxbContext = JAXBContext.newInstance(Tutorials.class); Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller(); Tutorials tutorials = (Tutorials) jaxbUnmarshaller.unmarshal(this.getFile());

Nell'esempio sopra, carichiamo il nostro file XML nel nostro oggetto e da lì possiamo gestire tutto come una normale struttura Java;

Per creare un nuovo documento, è semplice come leggerlo ma in modo inverso, come nel codice seguente.

Firstly, we are going to modify our Tutorial class to add JAXB annotations to getters and setters:

public class Tutorial { ... public String getTutId() { return tutId; } @XmlAttribute public void setTutId(String tutId) { this.tutId = tutId; } ... @XmlElement public void setTitle(String title) { this.title = title; } ... } @XmlRootElement public class Tutorials { private List tutorial; // standard getters and setters with @XmlElement annotation }

With @XmlRootElement we define what object is going to represent the root node of our document and then we use @XmlAttribute or @XmlElement to define whether that attribute represents an attribute of a node or an element of the document.

Then we can follow with:

Tutorials tutorials = new Tutorials(); tutorials.setTutorial(new ArrayList()); Tutorial tut = new Tutorial(); tut.setTutId("01"); ... tutorials.getTutorial().add(tut); JAXBContext jaxbContext = JAXBContext.newInstance(Tutorials.class); Marshaller jaxbMarshaller = jaxbContext.createMarshaller(); jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); jaxbMarshaller.marshal(tutorials, file);

As you can see, binding XML file to Java objects is the easiest way to work this kind of files.

8. XPath Expression Support

To create complex XPath expressions, we can use Jaxen. This is an open source XPath library adaptable to many different object models, including DOM, XOM, DOM4J, and JDOM.

We can create XPath expressions and compile them against many supported documents.

String expression = "/tutorials/tutorial"; XPath path = new DOMXPath(expression); List result = path.selectNodes(xmlDocument);

To make it work we'll need to add this dependency to our project.

9. Conclusion

As you can see there are many options for working with XML, depending on the requirements of your application, you could work with any of them or you may have to choose between efficiency and simplicity.

You can find the full working samples for this article in our git repository here.