Ricerca…


Osservazioni

L'analisi XML è l'interpretazione dei documenti XML al fine di manipolare il loro contenuto utilizzando costrutti sensibili, siano essi "nodi", "attributi", "documenti", "spazi dei nomi" o eventi correlati a questi costrutti.

Java ha un'API nativa per la gestione dei documenti XML, denominata JAXP o API Java per l'elaborazione XML . JAXP e un'implementazione di riferimento sono stati forniti in bundle con ogni versione Java da Java 1.4 (JAXP v1.1) e si sono evoluti da allora. Java 8 fornito con JAXP versione 1.6.

L'API offre diversi modi di interagire con i documenti XML, che sono:

  • L'interfaccia DOM (Document Object Model)
  • L'interfaccia SAX (Simple API for XML)
  • L'interfaccia StAX (Streaming API for XML)

Principi dell'interfaccia DOM

L'interfaccia DOM mira a fornire un modo W3C DOM di interpretare XML. Varie versioni di JAXP hanno supportato vari Livelli DOM di specifica (fino al livello 3).

Sotto l'interfaccia Modello oggetto documento, un documento XML viene rappresentato come un albero, a partire da "Elemento documento". Il tipo di base dell'API è il tipo di Node , consente di navigare da un Node al relativo genitore, ai suoi figli o ai suoi fratelli (sebbene, non tutti i Node possano avere figli, ad esempio, i nodi di Text sono finali nell'albero, e non avere mai bambini). I tag XML sono rappresentati come Element s, che estendono notevolmente il Node con metodi relativi agli attributi.

L'interfaccia DOM è molto utile poiché consente l'analisi "a una riga" di documenti XML come alberi e consente di modificare facilmente l'albero costruito (aggiunta del nodo, soppressione, copia, ...) e infine la sua serializzazione (torna al disco ) post modifiche. Questo ha un prezzo, però: l'albero risiede nella memoria, quindi gli alberi DOM non sono sempre pratici per enormi documenti XML. Inoltre, la costruzione dell'albero non è sempre il modo più rapido per gestire il contenuto XML, specialmente se non si è interessati a tutte le parti del documento XML.

Principi dell'interfaccia SAX

L'API SAX è un'API event-oriented per gestire documenti XML. Sotto questo modello, i componenti di un documento XML vengono interpretati come eventi (ad es. "Un tag è stato aperto", "un tag è stato chiuso", "è stato rilevato un nodo di testo", "è stato riscontrato un commento"). ..

L'API SAX utilizza un approccio "push parsing", in cui un Parser SAX è responsabile dell'interpretazione del documento XML e richiama i metodi su un delegato (un ContentHandler ) per gestire qualsiasi evento venga trovato nel documento XML. Di solito, non si scrive mai un parser, ma si fornisce un gestore per raccogliere tutte le informazioni necessarie dal documento XML.

L'interfaccia SAX supera le limitazioni dell'interfaccia DOM mantenendo solo i dati minimi necessari a livello di parser (ad es. Contesti namespace, stato di validazione), quindi, solo le informazioni che sono tenute da ContentHandler - di cui tu, lo sviluppatore, è responsabile - sono tenuto in memoria. Il compromesso è che non c'è modo di "tornare indietro nel tempo / il documento XML" con un simile approccio: mentre il DOM consente a un Node di tornare ai suoi genitori, non esiste tale possibilità in SAX.

Principi dell'interfaccia StAX

L'API StAX adotta un approccio simile all'elaborazione di XML come API SAX (ovvero, basata su eventi), l'unica differenza molto significativa è che StAX è un parser di pull (dove SAX era un parser di push). In SAX, il Parser controllo e utilizza i callback su ContentHandler . In Stax, chiami il parser e controlli quando / se vuoi ottenere il successivo "evento" XML.

L'API inizia con XMLStreamReader (o XMLEventReader ), che sono i gateway attraverso i quali lo sviluppatore può chiedere nextEvent() , in modo iteratore.

Analisi e navigazione di un documento utilizzando l'API DOM

Considerando il seguente documento:

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

Si può usare il seguente codice per costruire un albero DOM fuori da una 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");
}
}

Il codice produce quanto segue:

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

Analisi di un documento utilizzando l'API StAX

Considerando il seguente documento:

<?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>

Si può usare il seguente codice per analizzarlo e costruire una mappa di titoli di libri per id libro.

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

Questo produce:

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}

In questo esempio, si deve essere carente di alcune cose:

  1. L'uso di xmlStreamReader.getAttributeValue funziona perché abbiamo verificato prima che il parser si trovi nello stato START_ELEMENT . In tutti gli altri stati (eccetto gli ATTRIBUTES ), il parser è obbligato a lanciare IllegalStateException , perché gli attributi possono apparire solo all'inizio degli elementi.

  2. lo stesso vale per xmlStreamReader.getTextContent() , funziona perché siamo a un START_ELEMENT e sappiamo in questo documento che l'elemento <book> non ha nodi figlio non di testo.

Per l'analisi di documenti più complessi (elementi più profondi, nidificati, ...), è buona norma "delegare" il parser a sottoprogrammi o altri oggetti, ad esempio avere una classe o un metodo BookParser e farlo trattare con ogni elemento da START_ELEMENT a END_ELEMENT del tag XML del libro.

Si può anche usare un oggetto Stack per mantenere intorno a dati importanti su e giù dall'albero.



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow