Ich werde eine allgemeine Q & A-orientierte Antwort auf diese Frage geben:
Antwort auf Fragen
Warum brauchen wir XML-Parser?
Wir brauchen XML-Parser, weil wir nicht alles in unserer Anwendung von Grund auf neu machen wollen, und wir brauchen einige "Hilfsprogramme" oder Bibliotheken, um etwas sehr Niedriges, aber für uns sehr Notwendiges zu tun. Zu diesen einfachen, aber notwendigen Dingen gehören das Überprüfen der Form, das Überprüfen des Dokuments anhand seiner DTD oder seines Schemas (nur zum Überprüfen von Parsern), das Auflösen von Zeichenreferenzen, das Verstehen von CDATA-Abschnitten usw. XML-Parser sind solche "Hilfsprogramme" und erledigen all diese Aufgaben. Mit dem XML-Parser sind wir vor vielen dieser Komplexitäten geschützt und können uns darauf konzentrieren, durch die von den Parsern implementierten APIs nur auf hoher Ebene zu programmieren und so die Programmiereffizienz zu steigern.
Welches ist besser, SAX oder DOM?
Sowohl der SAX- als auch der DOM-Parser haben ihre Vor- und Nachteile. Welches besser ist, sollte von den Eigenschaften Ihrer Anwendung abhängen (siehe einige Fragen unten).
Welcher Parser kann bessere Geschwindigkeits-, DOM- oder SAX-Parser erhalten?
SAX-Parser kann eine bessere Geschwindigkeit erreichen.
Was ist der Unterschied zwischen einer baumbasierten API und einer ereignisbasierten API?
Eine baumbasierte API ist um eine Baumstruktur zentriert und bietet daher Schnittstellen zu Komponenten eines Baums (bei denen es sich um ein DOM-Dokument handelt) wie Dokumentschnittstelle, Knotenschnittstelle, NodeList-Schnittstelle, Elementschnittstelle, Attr-Schnittstelle usw. Im Gegensatz dazu bietet eine ereignisbasierte API jedoch Schnittstellen für Handler. Es gibt vier Handler-Schnittstellen, die ContentHandler-Schnittstelle, die DTDHandler-Schnittstelle, die EntityResolver-Schnittstelle und die ErrorHandler-Schnittstelle.
Was ist der Unterschied zwischen einem DOM-Parser und einem SAX-Parser?
DOM-Parser und SAX-Parser funktionieren auf unterschiedliche Weise:
Ein DOM-Parser erstellt aus dem Eingabedokument eine Baumstruktur im Speicher und wartet dann auf Anforderungen vom Client. Ein SAX-Parser erstellt jedoch keine interne Struktur. Stattdessen werden die Vorkommen von Komponenten eines Eingabedokuments als Ereignisse verwendet und dem Client mitgeteilt, was beim Lesen des Eingabedokuments gelesen wird. EIN
Der DOM-Parser bedient die Clientanwendung immer mit dem gesamten Dokument, unabhängig davon, wie viel der Client tatsächlich benötigt. Ein SAX-Parser bedient die Client-Anwendung jedoch immer nur mit Teilen des Dokuments zu einem bestimmten Zeitpunkt.
- Beim DOM-Parser müssen Methodenaufrufe in der Clientanwendung explizit sein und eine Art Kette bilden. Bei SAX werden jedoch einige bestimmte Methoden (normalerweise vom Cient überschrieben) automatisch (implizit) auf eine Weise aufgerufen, die als "Rückruf" bezeichnet wird, wenn bestimmte Ereignisse auftreten. Diese Methoden müssen vom Client nicht explizit aufgerufen werden, obwohl wir sie explizit aufrufen könnten.
Wie entscheiden wir, welcher Parser gut ist?
Idealerweise sollte ein guter Parser schnell (zeiteffizient), platzsparend, funktionsreich und einfach zu bedienen sein. In Wirklichkeit verfügt jedoch keiner der Hauptparser über alle diese Funktionen gleichzeitig. Ein DOM-Parser ist beispielsweise reich an Funktionen (da er einen DOM-Baum im Speicher erstellt und es Ihnen ermöglicht, wiederholt auf einen beliebigen Teil des Dokuments zuzugreifen und den DOM-Baum zu ändern), ist jedoch platzsparend, wenn das Dokument sehr groß ist und es dauert ein bisschen lange, um zu lernen, wie man damit arbeitet. Ein SAX-Parser ist jedoch bei großen Eingabedokumenten viel platzsparender (da er keine interne Struktur erstellt). Darüber hinaus läuft es schneller und ist leichter zu erlernen als DOM Parser, da seine API sehr einfach ist. Aber aus Sicht der Funktionalität, Es bietet weniger Funktionen, was bedeutet, dass sich die Benutzer selbst um mehr kümmern müssen, z. B. um die Erstellung eigener Datenstrukturen. Was ist übrigens ein guter Parser? Ich denke, die Antwort hängt wirklich von den Eigenschaften Ihrer Bewerbung ab.
In welchen realen Anwendungen ist die Verwendung des SAX-Parsers vorteilhafter als die Verwendung des DOM-Parsers und umgekehrt? Was ist die übliche Anwendung für einen DOM-Parser und für einen SAX-Parser?
In den folgenden Fällen ist die Verwendung des SAX-Parsers vorteilhafter als die Verwendung des DOM-Parsers.
- Das Eingabedokument ist zu groß für den verfügbaren Speicher (in diesem Fall ist SAX Ihre einzige Wahl).
- Sie können das Dokument in kleinen zusammenhängenden Eingabestücken verarbeiten. Sie benötigen nicht das gesamte Dokument, bevor Sie nützliche Arbeit leisten können
- Sie möchten nur den Parser verwenden, um die gewünschten Informationen zu extrahieren, und Ihre gesamte Berechnung basiert vollständig auf den von Ihnen selbst erstellten Datenstrukturen. Tatsächlich erstellen wir in den meisten unserer Anwendungen eigene Datenstrukturen, die normalerweise nicht so kompliziert sind wie der DOM-Baum. In diesem Sinne ist die Wahrscheinlichkeit, einen DOM-Parser zu verwenden, geringer als die eines SAX-Parsers.
In den folgenden Fällen ist die Verwendung des DOM-Parsers vorteilhafter als die Verwendung des SAX-Parsers.
- Ihre Anwendung muss gleichzeitig auf weitgehend separate Teile des Dokuments zugreifen können.
- Ihre Anwendung verwendet möglicherweise eine interne Datenstruktur, die fast so kompliziert ist wie das Dokument selbst.
- Ihre Anwendung muss das Dokument wiederholt ändern.
- Ihre Anwendung muss das Dokument über viele Methodenaufrufe für einen erheblichen Zeitraum speichern.
Beispiel (Verwenden Sie einen DOM-Parser oder einen SAX-Parser?):
Angenommen, ein Ausbilder verfügt über ein XML-Dokument, das alle persönlichen Informationen der Schüler sowie die Punkte enthält, die seine Schüler in seiner Klasse gemacht haben, und weist den Schülern jetzt mithilfe einer Anwendung die Abschlussnoten zu. Was er produzieren will, ist eine Liste mit der SSN und den Noten. Wir gehen auch davon aus, dass der Ausbilder in seiner Bewerbung keine Datenstruktur wie Arrays verwendet, um die persönlichen Informationen des Schülers und die Punkte zu speichern. Wenn der Ausbilder beschließt, denjenigen, die den Klassendurchschnitt oder höher erreicht haben, A zu geben und den anderen B zu geben, sollte er in seiner Anwendung einen DOM-Parser verwenden. Der Grund ist, dass er nicht wissen kann, wie hoch der Klassendurchschnitt ist, bevor das gesamte Dokument verarbeitet wird. Was er wahrscheinlich in seiner Bewerbung tun muss, ist zuerst alle Studenten durchzusehen Punkte und berechnen Sie den Durchschnitt. Sehen Sie sich dann das Dokument erneut an und weisen Sie jedem Schüler die Abschlussnote zu, indem Sie die Punkte, die er verdient hat, mit dem Klassendurchschnitt vergleichen. Wenn der Ausbilder jedoch eine solche Bewertungsrichtlinie anwendet, dass den Schülern, die 90 Punkte oder mehr erhalten haben, A und den anderen B zugewiesen werden, sollte er wahrscheinlich einen SAX-Parser verwenden. Der Grund dafür ist, dass jeder Schüler, um eine Abschlussnote zu erhalten, nicht auf die Verarbeitung des gesamten Dokuments warten muss. Er könnte einem Schüler sofort eine Note zuweisen, sobald der SAX-Parser die Note dieses Schülers liest. In der obigen Analyse haben wir angenommen, dass der Ausbilder keine eigene Datenstruktur erstellt hat. Was ist, wenn er seine eigene Datenstruktur erstellt, z. B. ein Array von Zeichenfolgen zum Speichern der SSN und ein Array von Ganzzahlen zum Speichern der Punkte? In diesem Fall, Ich denke, SAX ist eine bessere Wahl, bevor dies sowohl Speicher als auch Zeit sparen und dennoch die Arbeit erledigen kann. Nun, noch eine Überlegung zu diesem Beispiel. Was ist, wenn der Ausbilder nicht eine Liste drucken möchte, sondern das Originaldokument mit der aktualisierten Note jedes Schülers zurückspeichert? In diesem Fall sollte ein DOM-Parser eine bessere Wahl sein, unabhängig davon, welche Bewertungsrichtlinie er anwendet. Er muss keine eigene Datenstruktur erstellen. Was er tun muss, ist, zuerst den DOM-Baum zu ändern (dh den Wert auf den Knoten 'grade' zu setzen) und dann den gesamten geänderten Baum zu speichern. Wenn er einen SAX-Parser anstelle eines DOM-Parsers verwendet, muss er in diesem Fall eine Datenstruktur erstellen, die fast so kompliziert ist wie ein DOM-Baum, bevor er die Aufgabe erledigen kann. noch erledigen Sie die Arbeit. Nun, noch eine Überlegung zu diesem Beispiel. Was ist, wenn der Ausbilder nicht eine Liste drucken möchte, sondern das Originaldokument mit der aktualisierten Note jedes Schülers zurückspeichert? In diesem Fall sollte ein DOM-Parser eine bessere Wahl sein, unabhängig davon, welche Bewertungsrichtlinie er anwendet. Er muss keine eigene Datenstruktur erstellen. Was er tun muss, ist, zuerst den DOM-Baum zu ändern (dh den Wert auf den Knoten 'grade' zu setzen) und dann den gesamten geänderten Baum zu speichern. Wenn er einen SAX-Parser anstelle eines DOM-Parsers verwendet, muss er in diesem Fall eine Datenstruktur erstellen, die fast so kompliziert ist wie ein DOM-Baum, bevor er die Aufgabe erledigen kann. noch erledigen Sie die Arbeit. Nun, noch eine Überlegung zu diesem Beispiel. Was ist, wenn der Ausbilder nicht eine Liste drucken möchte, sondern das Originaldokument mit der aktualisierten Note jedes Schülers zurückspeichert? In diesem Fall sollte ein DOM-Parser eine bessere Wahl sein, unabhängig davon, welche Bewertungsrichtlinie er anwendet. Er muss keine eigene Datenstruktur erstellen. Was er tun muss, ist, zuerst den DOM-Baum zu ändern (dh den Wert auf den Knoten 'grade' zu setzen) und dann den gesamten geänderten Baum zu speichern. Wenn er einen SAX-Parser anstelle eines DOM-Parsers verwendet, muss er in diesem Fall eine Datenstruktur erstellen, die fast so kompliziert ist wie ein DOM-Baum, bevor er die Aufgabe erledigen kann. Aber um das Originaldokument mit der aktualisierten Note jedes Schülers wieder zu speichern? In diesem Fall sollte ein DOM-Parser eine bessere Wahl sein, unabhängig davon, welche Bewertungsrichtlinie er anwendet. Er muss keine eigene Datenstruktur erstellen. Was er tun muss, ist, zuerst den DOM-Baum zu ändern (dh den Wert auf den Knoten 'grade' zu setzen) und dann den gesamten geänderten Baum zu speichern. Wenn er einen SAX-Parser anstelle eines DOM-Parsers verwendet, muss er in diesem Fall eine Datenstruktur erstellen, die fast so kompliziert ist wie ein DOM-Baum, bevor er die Aufgabe erledigen kann. Aber um das Originaldokument mit der aktualisierten Note jedes Schülers wieder zu speichern? In diesem Fall sollte ein DOM-Parser eine bessere Wahl sein, unabhängig davon, welche Bewertungsrichtlinie er anwendet. Er muss keine eigene Datenstruktur erstellen. Was er tun muss, ist, zuerst den DOM-Baum zu ändern (dh den Wert auf den Knoten 'grade' zu setzen) und dann den gesamten geänderten Baum zu speichern. Wenn er einen SAX-Parser anstelle eines DOM-Parsers verwendet, muss er in diesem Fall eine Datenstruktur erstellen, die fast so kompliziert ist wie ein DOM-Baum, bevor er die Aufgabe erledigen kann. Knoten) und speichern Sie dann den gesamten geänderten Baum. Wenn er einen SAX-Parser anstelle eines DOM-Parsers verwendet, muss er in diesem Fall eine Datenstruktur erstellen, die fast so kompliziert ist wie ein DOM-Baum, bevor er die Aufgabe erledigen kann. Knoten) und speichern Sie dann den gesamten geänderten Baum. Wenn er einen SAX-Parser anstelle eines DOM-Parsers verwendet, muss er in diesem Fall eine Datenstruktur erstellen, die fast so kompliziert ist wie ein DOM-Baum, bevor er die Aufgabe erledigen kann.
Ein Beispiel
Problemstellung : Schreiben Sie ein Java-Programm, um alle Informationen zu Kreisen zu extrahieren, die Elemente in einem bestimmten XML-Dokument sind. Wir nehmen an, dass jedes Kreiselement drei untergeordnete Elemente (dh x, y und Radius) sowie ein Farbattribut hat. Ein Beispieldokument ist unten angegeben:
<?xml version="1.0"?>
<!DOCTYPE shapes [
<!ELEMENT shapes (circle)*>
<!ELEMENT circle (x,y,radius)>
<!ELEMENT x (#PCDATA)>
<!ELEMENT y (#PCDATA)>
<!ELEMENT radius (#PCDATA)>
<!ATTLIST circle color CDATA #IMPLIED>
]>
<shapes>
<circle color="BLUE">
<x>20</x>
<y>20</y>
<radius>20</radius>
</circle>
<circle color="RED" >
<x>40</x>
<y>40</y>
<radius>20</radius>
</circle>
</shapes>
Programmieren Sie mit DOMparser
import java.io.*;
import org.w3c.dom.*;
import org.apache.xerces.parsers.DOMParser;
public class shapes_DOM {
static int numberOfCircles = 0; // total number of circles seen
static int x[] = new int[1000]; // X-coordinates of the centers
static int y[] = new int[1000]; // Y-coordinates of the centers
static int r[] = new int[1000]; // radius of the circle
static String color[] = new String[1000]; // colors of the circles
public static void main(String[] args) {
try{
// create a DOMParser
DOMParser parser=new DOMParser();
parser.parse(args[0]);
// get the DOM Document object
Document doc=parser.getDocument();
// get all the circle nodes
NodeList nodelist = doc.getElementsByTagName("circle");
numberOfCircles = nodelist.getLength();
// retrieve all info about the circles
for(int i=0; i<nodelist.getLength(); i++) {
// get one circle node
Node node = nodelist.item(i);
// get the color attribute
NamedNodeMap attrs = node.getAttributes();
if(attrs.getLength() > 0)
color[i]=(String)attrs.getNamedItem("color").getNodeValue();
// get the child nodes of a circle node
NodeList childnodelist = node.getChildNodes();
// get the x and y value
for(int j=0; j<childnodelist.getLength(); j++) {
Node childnode = childnodelist.item(j);
Node textnode = childnode.getFirstChild();//the only text node
String childnodename=childnode.getNodeName();
if(childnodename.equals("x"))
x[i]= Integer.parseInt(textnode.getNodeValue().trim());
else if(childnodename.equals("y"))
y[i]= Integer.parseInt(textnode.getNodeValue().trim());
else if(childnodename.equals("radius"))
r[i]= Integer.parseInt(textnode.getNodeValue().trim());
}
}
// print the result
System.out.println("circles="+numberOfCircles);
for(int i=0;i<numberOfCircles;i++) {
String line="";
line=line+"(x="+x[i]+",y="+y[i]+",r="+r[i]+",color="+color[i]+")";
System.out.println(line);
}
} catch (Exception e) {e.printStackTrace(System.err);}
}
}
Programmieren Sie mit SAXparser
import java.io.*;
import org.xml.sax.*;
import org.xml.sax.helpers.DefaultHandler;
import org.apache.xerces.parsers.SAXParser;
public class shapes_SAX extends DefaultHandler {
static int numberOfCircles = 0; // total number of circles seen
static int x[] = new int[1000]; // X-coordinates of the centers
static int y[] = new int[1000]; // Y-coordinates of the centers
static int r[] = new int[1000]; // radius of the circle
static String color[] = new String[1000]; // colors of the circles
static int flagX=0; //to remember what element has occurred
static int flagY=0; //to remember what element has occurred
static int flagR=0; //to remember what element has occurred
// main method
public static void main(String[] args) {
try{
shapes_SAX SAXHandler = new shapes_SAX (); // an instance of this class
SAXParser parser=new SAXParser(); // create a SAXParser object
parser.setContentHandler(SAXHandler); // register with the ContentHandler
parser.parse(args[0]);
} catch (Exception e) {e.printStackTrace(System.err);} // catch exeptions
}
// override the startElement() method
public void startElement(String uri, String localName,
String rawName, Attributes attributes) {
if(rawName.equals("circle")) // if a circle element is seen
color[numberOfCircles]=attributes.getValue("color"); // get the color attribute
else if(rawName.equals("x")) // if a x element is seen set the flag as 1
flagX=1;
else if(rawName.equals("y")) // if a y element is seen set the flag as 2
flagY=1;
else if(rawName.equals("radius")) // if a radius element is seen set the flag as 3
flagR=1;
}
// override the endElement() method
public void endElement(String uri, String localName, String rawName) {
// in this example we do not need to do anything else here
if(rawName.equals("circle")) // if a circle element is ended
numberOfCircles += 1; // increment the counter
}
// override the characters() method
public void characters(char characters[], int start, int length) {
String characterData =
(new String(characters,start,length)).trim(); // get the text
if(flagX==1) { // indicate this text is for <x> element
x[numberOfCircles] = Integer.parseInt(characterData);
flagX=0;
}
else if(flagY==1) { // indicate this text is for <y> element
y[numberOfCircles] = Integer.parseInt(characterData);
flagY=0;
}
else if(flagR==1) { // indicate this text is for <radius> element
r[numberOfCircles] = Integer.parseInt(characterData);
flagR=0;
}
}
// override the endDocument() method
public void endDocument() {
// when the end of document is seen, just print the circle info
System.out.println("circles="+numberOfCircles);
for(int i=0;i<numberOfCircles;i++) {
String line="";
line=line+"(x="+x[i]+",y="+y[i]+",r="+r[i]+",color="+color[i]+")";
System.out.println(line);
}
}
}