Recherche…


Remarques

XML Parsing est l'interprétation des documents XML afin de manipuler leur contenu à l'aide de constructions sensibles, qu'il s'agisse de "nœuds", "attributs", "documents", "espaces de noms" ou d'événements liés à ces constructions.

Java possède une API native pour la gestion des documents XML, appelée JAXP ou API Java pour le traitement XML . JAXP et une implémentation de référence ont été regroupés avec chaque version de Java depuis Java 1.4 (JAXP v1.1) et ont évolué depuis. Java 8 fourni avec JAXP version 1.6.

L'API propose différentes manières d'interagir avec les documents XML, à savoir:

  • L'interface DOM (Document Object Model)
  • L'interface SAX (API simple pour XML)
  • L'interface StAX (API de streaming pour XML)

Principes de l'interface DOM

L'interface DOM a pour but de fournir une manière conforme à l'interprétation du XML du W3C DOM . Diverses versions de JAXP ont pris en charge divers niveaux de spécification DOM (jusqu'au niveau 3).

Dans l'interface du modèle d'objet de document, un document XML est représenté sous la forme d'une arborescence, en commençant par "l'élément de document". Le type de base de l'API est le type Node , il permet de naviguer d'un Node vers son parent, ses enfants ou ses frères (bien que tous les Node ne puissent pas avoir d'enfants, par exemple, les nœuds de Text sont définitifs dans l'arborescence). et ne jamais avoir childre). Les balises XML sont représentées sous forme d' Element s, qui étendent notamment le Node avec des méthodes liées aux attributs.

L’interface DOM est très utile car elle permet d’analyser des documents XML en tant qu’arbres, et de modifier facilement l’arbre construit (ajout de nœud, suppression, copie, etc.) et enfin sa sérialisation (retour au disque). ) publier des modifications. Cela a cependant un prix: l'arbre réside dans la mémoire, par conséquent, les arbres DOM ne sont pas toujours pratiques pour les documents XML volumineux. De plus, la construction de l'arborescence n'est pas toujours le moyen le plus rapide de gérer le contenu XML, surtout si toutes les parties du document XML ne l'intéressent pas.

Principes de l'interface SAX

L'API SAX est une API orientée événement pour traiter les documents XML. Dans ce modèle, les composants d'un document XML sont interprétés comme des événements (par exemple, "un tag a été ouvert", "un tag a été fermé", "un noeud de texte a été rencontré", "un commentaire a été rencontré"). ..

L'API SAX utilise une approche "d'analyse par poussée", dans laquelle un Parser SAX est chargé d'interpréter le document XML et appelle des méthodes sur un délégué (un ContentHandler ) pour traiter tout événement trouvé dans le document XML. Généralement, on n'écrit jamais un analyseur, mais on fournit un gestionnaire pour rassembler toutes les informations nécessaires à partir du document XML.

L’interface SAX surmonte les limitations de l’interface DOM en ne conservant que le minimum de données nécessaires au niveau de l’analyseur (ex: contextes des espaces de noms, état de validation), seules les informations conservées par le ContentHandler - dont vous êtes responsable tenu en mémoire. Le compromis est qu'il n'y a aucun moyen de "remonter le temps / le document XML" avec une telle approche: alors que DOM permet à un Node de revenir à son parent, il n'y a pas de possibilité dans SAX.

Principes de l'interface StAX

L'API StAX adopte une approche similaire au traitement de XML en tant qu'API SAX (c'est-à-dire pilotée par des événements), la seule différence très significative étant que StAX est un analyseur d'extraction (où SAX était un analyseur poussé). Dans SAX, l' Parser est en contrôle et utilise des rappels sur le ContentHandler . Dans Stax, vous appelez l'analyseur et contrôlez quand / si vous souhaitez obtenir le prochain "événement" XML.

L'API commence par XMLStreamReader (ou XMLEventReader ), qui sont les passerelles par lesquelles le développeur peut demander à nextEvent() , de manière itérative.

Analyse et navigation d'un document à l'aide de l'API DOM

Considérant le document suivant:

<?xml version='1.0' encoding='UTF-8' ?>
<library>
   <book id='1'>Effective Java</book>
   <book id='2'>Java Concurrency In Practice</book>
</library>

On peut utiliser le code suivant pour construire un arbre DOM à partir d'une String :

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.StringReader;

public class DOMDemo {

public static void main(String[] args) throws Exception {
    String xmlDocument = "<?xml version='1.0' encoding='UTF-8' ?>"
            + "<library>"
            + "<book id='1'>Effective Java</book>"
            + "<book id='2'>Java Concurrency In Practice</book>"
            + "</library>";

    DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
    // This is useless here, because the XML does not have namespaces, but this option is usefull to know in cas
    documentBuilderFactory.setNamespaceAware(true);
    DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
    // There are various options here, to read from an InputStream, from a file, ...
    Document document = documentBuilder.parse(new InputSource(new StringReader(xmlDocument)));

    // Root of the document
    System.out.println("Root of the XML Document: " + document.getDocumentElement().getLocalName());

    // Iterate the contents
    NodeList firstLevelChildren = document.getDocumentElement().getChildNodes();
    for (int i = 0; i < firstLevelChildren.getLength(); i++) {
        Node item = firstLevelChildren.item(i);
        System.out.println("First level child found, XML tag name is: " + item.getLocalName());
        System.out.println("\tid attribute of this tag is : " + item.getAttributes().getNamedItem("id").getTextContent());
    }

    // Another way would have been
    NodeList allBooks = document.getDocumentElement().getElementsByTagName("book");
}
}

Le code donne les informations suivantes:

Root of the XML Document: library
First level child found, XML tag name is: book
id attribute of this tag is : 1
First level child found, XML tag name is: book
id attribute of this tag is : 2

Analyse d'un document à l'aide de l'API StAX

Considérant le document suivant:

<?xml version='1.0' encoding='UTF-8' ?>
<library>
   <book id='1'>Effective Java</book>
   <book id='2'>Java Concurrency In Practice</book>
   <notABook id='3'>This is not a book element</notABook>
</library>

On peut utiliser le code suivant pour l'analyser et créer une carte des titres de livres par identifiant de livre.

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamReader;
import java.io.StringReader;
import java.util.HashMap;
import java.util.Map;

public class StaxDemo {

public static void main(String[] args) throws Exception {
    String xmlDocument = "<?xml version='1.0' encoding='UTF-8' ?>"
            + "<library>"
                + "<book id='1'>Effective Java</book>"
                + "<book id='2'>Java Concurrency In Practice</book>"
                + "<notABook id='3'>This is not a book element </notABook>"
            + "</library>";

    XMLInputFactory xmlInputFactory = XMLInputFactory.newFactory();
    // Various flavors are possible, e.g. from an InputStream, a Source, ...
    XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(new StringReader(xmlDocument));

    Map<Integer, String> bookTitlesById = new HashMap<>();

    // We go through each event using a loop
    while (xmlStreamReader.hasNext()) {
        switch (xmlStreamReader.getEventType()) {
            case XMLStreamConstants.START_ELEMENT:
                System.out.println("Found start of element: " + xmlStreamReader.getLocalName());
                // Check if we are at the start of a <book> element
                if ("book".equals(xmlStreamReader.getLocalName())) {
                    int bookId = Integer.parseInt(xmlStreamReader.getAttributeValue("", "id"));
                    String bookTitle = xmlStreamReader.getElementText();
                    bookTitlesById.put(bookId, bookTitle);
                }
                break;
            // A bunch of other things are possible : comments, processing instructions, Whitespace...
            default:
                break;
        }
        xmlStreamReader.next();
    }

    System.out.println(bookTitlesById);
}

Cela produit:

Found start of element: library
Found start of element: book
Found start of element: book
Found start of element: notABook
{1=Effective Java, 2=Java Concurrency In Practice}

Dans cet exemple, il faut faire attention à quelques choses:

  1. L'utilisation de xmlStreamReader.getAttributeValue fonctionne car nous avons vérifié en premier que l'analyseur est dans l'état START_ELEMENT . Dans d' autres Etats Evey (sauf ATTRIBUTES ), l'analyseur est chargé de lancer IllegalStateException , car les attributs ne peuvent apparaître au début des éléments.

  2. Il en va de même pour xmlStreamReader.getTextContent() , cela fonctionne car nous sommes à un START_ELEMENT et nous savons dans ce document que l'élément <book> n'a pas de nœud enfant non textuel.

Pour l'analyse de documents plus complexes (éléments plus profonds, imbriqués, ...), il est BookParser de "déléguer" l'analyseur à des sous-méthodes ou à d'autres objets, par exemple, avoir une classe ou une méthode BookParser et traiter tous les éléments. de START_ELEMENT à END_ELEMENT de la balise XML du livre.

On peut également utiliser un objet Stack pour conserver des données importantes dans l’arbre.



Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow