Java Language
XML-parsing met behulp van de JAXP API's
Zoeken…
Opmerkingen
XML Parsing is de interpretatie van XML-documenten om hun inhoud te manipuleren met behulp van verstandige constructies, of het nu "knooppunten", "attributen", "documenten", "naamruimten" of gebeurtenissen zijn die verband houden met deze constructen.
Java heeft een native API voor XML-documentverwerking, JAXP genoemd, of Java API voor XML-verwerking . JAXP en een referentie-implementatie zijn gebundeld met elke Java-release sinds Java 1.4 (JAXP v1.1) en zijn sindsdien geëvolueerd. Java 8 wordt geleverd met JAXP versie 1.6.
De API biedt verschillende manieren om te communiceren met XML-documenten, die zijn:
- De DOM-interface (Document Object Model)
- De SAX-interface (Simple API voor XML)
- De StAX-interface (Streaming API voor XML)
Principes van de DOM-interface
De DOM-interface is bedoeld om een W3C DOM- compatibele manier te bieden om XML te interpreteren. Verschillende versies van JAXP hebben verschillende DOM-specificatieniveaus ondersteund (tot niveau 3).
Onder de interface Document-objectmodel wordt een XML-document weergegeven als een boom, beginnend met het "Document-element". Het basistype van de API wordt de Node
-type, is het mogelijk om te navigeren van een Node
aan haar moedermaatschappij, haar kinderen, of zijn broers en zus (hoewel niet alle Node
s kunnen kinderen hebben, bijvoorbeeld Text
nodes zijn definitief in de boom, en heb nooit childre). XML-tags worden weergegeven als Element
s, die met name de Node
uitbreiden met aan attributen gerelateerde methoden.
De DOM-interface is erg handig omdat het een "one-line" parsen van XML-documenten als bomen mogelijk maakt, en eenvoudige aanpassing van de geconstrueerde boom mogelijk maakt (toevoeging van knooppunten, onderdrukking, kopiëren, ...), en ten slotte de serialisatie ervan (terug naar schijf) ) wijzigingen aanbrengen. Dit heeft echter een prijs: de boom bevindt zich in het geheugen, daarom zijn DOM-bomen niet altijd praktisch voor grote XML-documenten. Bovendien is de constructie van de boomstructuur niet altijd de snelste manier om met XML-inhoud om te gaan, vooral als men niet in alle delen van het XML-document geïnteresseerd is.
Principes van de SAX-interface
De SAX API is een gebeurtenisgerichte API voor het verwerken van XML-documenten. In dit model worden de componenten van XML-documenten geïnterpreteerd als gebeurtenissen (bijv. "Een tag is geopend", "een tag is gesloten", "een tekstknooppunt is aangetroffen", "een opmerking is aangetroffen"). ..
De SAX API maakt gebruik van een "push-parsing" -benadering, waarbij een SAX Parser
verantwoordelijk is voor het interpreteren van het XML-document en methoden oproept bij een gemachtigde (een ContentHandler
) om elke gebeurtenis in het XML-document aan te pakken. Gewoonlijk schrijft men nooit een parser, maar men verschaft een handler om alle benodigde informatie uit het XML-document te verzamelen.
De SAX-interface overwint de beperkingen van de DOM-interface door alleen de minimaal noodzakelijke gegevens op parserniveau te houden (bijv. Naamruimtencontexten, validatiestatus), daarom zijn alleen informatie die wordt bewaard door ContentHandler
- waarvoor u, de ontwikkelaar, verantwoordelijk bent - in het geheugen gehouden. Het nadeel is dat er geen manier is om "terug te gaan in de tijd / het XML-document" met een dergelijke benadering: hoewel DOM een Node
toestaat terug te keren naar zijn ouder, is er geen dergelijke mogelijkheid in SAX.
Principes van de StAX-interface
De StAX API heeft een vergelijkbare aanpak voor het verwerken van XML als de SAX API (dat wil zeggen gebeurtenisgestuurd), het enige zeer belangrijke verschil is dat StAX een pull-parser is (waarbij SAX een push-parser was). In SAX heeft de Parser
controle en gebruikt callbacks op de ContentHandler
. In Stax roept u de parser aan en bepaalt u wanneer / of u de volgende XML-"event" wilt verkrijgen.
De API begint met XMLStreamReader (of XMLEventReader ), de gateways waardoor de ontwikkelaar nextEvent()
op een iteratorachtige manier kan vragen.
Een document parseren en navigeren met behulp van de DOM API
Overweegt het volgende document:
<?xml version='1.0' encoding='UTF-8' ?>
<library>
<book id='1'>Effective Java</book>
<book id='2'>Java Concurrency In Practice</book>
</library>
Men kan de volgende code gebruiken om een DOM-boom te bouwen uit een 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");
}
}
De code levert het volgende op:
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
Een document parseren met de StAX API
Overweegt het volgende document:
<?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>
Men kan de volgende code gebruiken om het te ontleden en een kaart van boektitels op boek-ID samenstellen.
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);
}
Dit geeft uit:
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 dit voorbeeld moet men op een paar dingen letten:
Het gebruik van
xmlStreamReader.getAttributeValue
werkt omdat we eerst hebben gecontroleerd dat de parser zich in deSTART_ELEMENT
status bevindt. In elke andere staat (behalveATTRIBUTES
), is de parser verplichtIllegalStateException
te gooien, omdat attributen alleen aan het begin van elementen kunnen verschijnen.hetzelfde geldt voor
xmlStreamReader.getTextContent()
, het werkt omdat we opSTART_ELEMENT
en in dit document weten dat het element<book>
geen niet-tekst onderliggende knooppunten heeft.
Voor complexere parsing van documenten (diepere, geneste elementen, ...), is het een goede gewoonte om de parser te "delegeren" aan BookParser
of andere objets, bijv. Een BookParser
klasse of -methode te hebben en deze met elk element te laten omgaan van START_ELEMENT tot END_ELEMENT van de XML-tag van het boek.
Men kan ook een Stack
object gebruiken om belangrijke gegevens op en neer in de boom te houden.