Prise en charge des bibliothèques XML en Java

1. Introduction

Dans cet article, nous comparerons les bibliothèques Java XML et les API.

Ceci est le deuxième article de la série sur la prise en charge de Java pour XML, si vous souhaitez approfondir la prise en charge de XPath en Java, consultez l'article précédent.

2. Aperçu

Maintenant, nous allons approfondir le support du monde XML et pour cela nous allons commencer par expliquer aussi simplement que possible toutes les initiales liées au sujet.

Dans le support Java XML, nous pouvons trouver quelques définitions d'API, chacune ayant ses avantages et ses inconvénients.

SAX : Il s'agit d'une API d'analyse basée sur les événements, elle fournit un accès de bas niveau, est efficace en mémoire et plus rapide que DOM car elle ne charge pas toute l'arborescence du document en mémoire mais elle ne prend pas en charge la navigation comme celle fournie par XPath, bien qu'il soit plus efficace, il est également plus difficile à utiliser.

DOM : Il s'agit d'un analyseur basé sur un modèle qui charge un document d'arborescence en mémoire, nous avons donc l'ordre des éléments d'origine, nous pouvons naviguer dans notre document dans les deux sens, il fournit une API pour la lecture et l'écriture, il offre une manipulation XML et c'est très facile à utiliser même si le prix est élevé sur les ressources mémoire.

StAX : Il offre la facilité du DOM et l'efficacité de SAX mais il manque de certaines fonctionnalités fournies par DOM comme la manipulation XML et il nous permet seulement de faire avancer le document.

JAXB : Il nous permet de naviguer dans le document dans les deux sens, il est plus efficace que DOM, il permet la conversion du XML vers les types java et il supporte la manipulation XML mais il ne peut analyser qu'un document XML valide.

Vous pourriez encore trouver des références à JAXP mais la dernière version de ce projet date de mars 2013 et il est pratiquement mort.

Tableau des API XML

3. Le XML

Dans cette section, nous allons voir les implémentations les plus populaires, afin de pouvoir tester de vrais échantillons de travail et vérifier les différences entre eux.

Dans les exemples suivants, nous travaillerons avec un simple fichier XML avec une structure comme celle-ci:

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

4. DOM4J

Nous allons commencer par jeter un œil à ce que nous pouvons faire avec DOM4J et pour cet exemple, nous devons ajouter la dernière version de cette dépendance.

C'est l'une des bibliothèques les plus populaires pour travailler avec des fichiers XML , car elle nous permet d'effectuer une lecture bidirectionnelle, de créer de nouveaux documents et de mettre à jour ceux existants.

DOM4J peut fonctionner avec DOM , SAX , XPath et XLST . SAX est pris en charge via JAXP .

Jetons un coup d'œil ici par exemple, comment pouvons-nous sélectionner un élément filtrant par un identifiant donné.

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

La classe SAXReader est responsable de la création d'une arborescence DOM4J à partir des événements d'analyse SAX . Une fois que nous avons un org.dom4j.Document, il suffit d'appeler la méthode nécessaire et de lui transmettre l' expression XPath sous forme de chaîne.

Nous pouvons charger un document existant, apporter des modifications à son contenu puis mettre à jour le fichier d'origine.

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

Dans l'exemple ci-dessus, nous modifions le contenu de chaque titre et créons un nouveau fichier.

Notez ici à quel point il est simple d'obtenir le nœud de chaque titre dans une liste en appelant elementIterator et en passant le nom du nœud.

Une fois notre contenu modifié, nous utiliserons le XMLWriter qui prend un arbre DOM4J et le formate en flux au format XML .

Créer un nouveau document à partir de zéro est aussi simple que nous le voyons ci-dessous.

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 nous donne une collection de méthodes à utiliser par DOM4J , comme createDocument qui crée un document vide pour commencer à travailler avec lui.

Nous pouvons créer autant d'attributs ou d'éléments que nécessaire avec les méthodes fournies par DOM4J , et une fois notre document terminé, nous l'écrivons simplement dans un fichier comme nous l'avons fait avec le cas de mise à jour précédent.

5. JDOM

Afin de travailler avec JDOM, nous devons ajouter cette dépendance à notre pom.

Le style de travail de JDOM est assez similaire à celui de DOM4J , nous allons donc jeter un coup d'œil à quelques exemples:

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

Dans l'exemple ci-dessus, nous récupérons tous les éléments de l'élément racine d'une manière très simple comme nous pouvons le faire avec 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);

Encore une fois, ici dans le code ci-dessus, nous avons un SAXBuilder créant une instance de Document à partir d'un fichier donné. Nous récupérons un élément par son attribut tutId en passant une expression XPath à la XPathFactory fournie par JDOM2.

6. StAX

Now, we are going to see how we could retrieve all elements from our root element using the Stax API. Stax is included in the JDK since Java 6 so you don't need to add any dependencies.

Firstly, we need to create a Tutorial class:

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 }

and then we are ready to follow with:

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

In the example above, in order to help us retrieve the information, we needed to create a class to store the retrieved data in.

To read the document, we declared what is called event handlers and we used them to navigate our document ahead. Remember that the SAX implementations don't provide bi-directional navigation. As you can see here, a lot of work needs to be done just to retrieve a simple list of elements.

7. JAXB

JAXB is included with the JDK, as well as Xerces, se don't need any extra dependency for this one.

It's very simple to load, create and manipulate information from an XML file using JAXB.

We just need to create the correct java entities to bind the XML and that's it.

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

In the example above, we load our XML file into our object and from there we can handle everything as a normal Java structure;

To create a new document, it is as simple as reading it but doing the reverse way, like done in the below code.

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.