Udzielę ogólnej odpowiedzi na pytania i odpowiedzi dotyczące tego pytania:
Odpowiedz na pytania
Dlaczego potrzebujemy parsera XML?
Potrzebujemy parsera XML, ponieważ nie chcemy robić wszystkiego w naszej aplikacji od zera i potrzebujemy programów pomocniczych lub bibliotek, aby zrobić coś bardzo niskiego, ale dla nas bardzo potrzebnego. Te niskiego poziomu, ale niezbędne rzeczy, obejmują sprawdzanie poprawności sformułowania, sprawdzanie poprawności dokumentu pod kątem jego DTD lub schematu (tylko w celu sprawdzania poprawności parserów), rozwiązywanie odniesień do znaków, zrozumienie sekcji CDATA i tak dalej. Parsery XML są właśnie takimi „programami pomocniczymi” i wykonają wszystkie te zadania. Dzięki parserowi XML jesteśmy chronieni przed wieloma z tych złożoności i moglibyśmy skoncentrować się na samym programowaniu na wysokim poziomie za pośrednictwem interfejsów API implementowanych przez parsery, a tym samym uzyskać wydajność programowania.
Który z nich jest lepszy, SAX lub DOM?
Parser SAX i DOM mają swoje zalety i wady. Który z nich jest lepszy, powinien zależeć od cech twojej aplikacji (zapoznaj się z niektórymi pytaniami poniżej).
Który parser może uzyskać lepszą parser prędkości, DOM lub SAX?
Parser SAX może uzyskać lepszą prędkość.
Jaka jest różnica między interfejsem API opartym na drzewie a interfejsem API opartym na zdarzeniach?
Interfejs API oparty na drzewie jest skoncentrowany wokół struktury drzewa i dlatego zapewnia interfejsy na komponentach drzewa (którym jest dokument DOM), takich jak interfejs dokumentu, interfejs węzła, interfejs NodeList, interfejs elementu, interfejs Attr i tak dalej. Natomiast interfejs API oparty na zdarzeniach zapewnia interfejsy w modułach obsługi. Istnieją cztery interfejsy obsługi, interfejs ContentHandler, interfejs DTDHandler, interfejs EntityResolver i interfejs ErrorHandler.
Jaka jest różnica między parserem DOM a parserem SAX?
Parsery DOM i parsery SAX działają na różne sposoby:
Analizator składni DOM tworzy strukturę drzewa w pamięci z dokumentu wejściowego, a następnie czeka na żądania od klienta. Ale parser SAX nie tworzy żadnej wewnętrznej struktury. Zamiast tego przyjmuje występowanie elementów dokumentu wejściowego jako zdarzenia i informuje klienta, co czyta, czytając dokument wejściowy. ZA
Analizator składni DOM zawsze obsługuje aplikację kliencką z całym dokumentem, bez względu na to, ile tak naprawdę jest potrzebne klientowi. Ale parser SAX obsługuje aplikację kliencką zawsze tylko z fragmentami dokumentu w danym momencie.
- W parserze DOM wywołania metod w aplikacji klienckiej muszą być jawne i tworzą rodzaj łańcucha. Ale w SAX niektóre pewne metody (zwykle zastępowane przez klienta) będą wywoływane automatycznie (domyślnie) w sposób, który nazywa się „callback”, gdy wystąpią pewne określone zdarzenia. Te metody nie muszą być jawnie wywoływane przez klienta, chociaż możemy je wywoływać jawnie.
Jak decydujemy, który parser jest dobry?
Idealnie dobry parser powinien być szybki (oszczędny czasowo), zajmujący mało miejsca, bogaty w funkcjonalność i łatwy w użyciu. Ale w rzeczywistości żaden z głównych parserów nie ma wszystkich tych funkcji jednocześnie. Na przykład, parser DOM ma bogatą funkcjonalność (ponieważ tworzy drzewo DOM w pamięci i pozwala na wielokrotny dostęp do dowolnej części dokumentu oraz pozwala modyfikować drzewo DOM), ale jest mało miejsca, gdy dokument jest ogromny , a nauka jego obsługi zajmuje trochę czasu. Parser SAX jest jednak znacznie bardziej wydajny w przypadku dużego dokumentu wejściowego (ponieważ nie tworzy wewnętrznej struktury). Co więcej, działa szybciej i jest łatwiejszy do nauki niż DOM Parser, ponieważ jego interfejs API jest naprawdę prosty. Ale z punktu widzenia funkcjonalności zapewnia mniej funkcji, co oznacza, że sami użytkownicy muszą więcej się zajmować, na przykład tworzenie własnych struktur danych. Nawiasem mówiąc, co to jest dobry parser? Myślę, że odpowiedź naprawdę zależy od cech twojej aplikacji.
Jakie są niektóre aplikacje w świecie rzeczywistym, w których korzystanie z analizatora składni SAX jest korzystniejsze niż w przypadku analizatora składni DOM i odwrotnie? Jaka jest typowa aplikacja dla analizatora składni DOM i analizatora składni SAX?
W następujących przypadkach użycie parsera SAX jest korzystniejsze niż użycie parsera DOM.
- Dokument wejściowy jest zbyt duży, aby pomieścić dostępną pamięć (w tym przypadku jedynym wyborem jest SAX)
- Możesz przetwarzać dokument w małych, ciągłych fragmentach danych wejściowych. Nie potrzebujesz całego dokumentu, zanim będziesz mógł wykonać przydatną pracę
- Po prostu chcesz użyć parsera do wyodrębnienia interesujących informacji, a całe twoje obliczenia będą całkowicie oparte na strukturach danych stworzonych przez ciebie. W rzeczywistości w większości naszych aplikacji tworzymy własne struktury danych, które zwykle nie są tak skomplikowane jak drzewo DOM. Z tego punktu widzenia myślę, że szansa na użycie parsera DOM jest mniejsza niż przy użyciu parsera SAX.
W następujących przypadkach użycie parsera DOM jest korzystniejsze niż użycie parsera SAX.
- Twoja aplikacja musi jednocześnie uzyskiwać dostęp do osobnych części dokumentu.
- Twoja aplikacja prawdopodobnie korzysta z wewnętrznej struktury danych, która jest prawie tak skomplikowana jak sam dokument.
- Twoja aplikacja musi wielokrotnie modyfikować dokument.
- Twoja aplikacja musi przechowywać dokument przez dłuższy czas za pomocą wielu wywołań metod.
Przykład (użyć parsera DOM lub parsera SAX?):
Załóżmy, że instruktor ma dokument XML zawierający wszystkie dane osobowe uczniów, a także punkty, które jego uczniowie zrobili w swojej klasie, i teraz przypisuje końcowe oceny uczniom używającym aplikacji. To, co chce stworzyć, to lista z SSN i ocenami. Zakładamy również, że w swojej aplikacji instruktor nie używa struktury danych, takiej jak tablice, do przechowywania danych osobowych uczniów i punktów. Jeśli instruktor zdecyduje się dać A tym, którzy zdobyli klasę średnią lub wyższą, i dać B innym, wtedy lepiej użyć parsera DOM w swojej aplikacji. Powodem jest to, że nie ma sposobu, aby dowiedzieć się, ile wynosi średnia klasowa, zanim cały dokument zostanie przetworzony. To, co prawdopodobnie powinien zrobić w swoim zgłoszeniu, to najpierw przejrzeć listę wszystkich uczniów punktów i oblicz średnią, a następnie ponownie przejrzyj dokument i przypisz ocenę końcową każdemu uczniowi, porównując zdobyte punkty ze średnią klasową. Jeśli jednak instruktor przyjmie takie zasady oceniania, że uczniom, którzy uzyskali 90 punktów lub więcej, przypisuje się A, a pozostałym przypisuje się B, to prawdopodobnie lepiej użyje parsera SAX. Powodem jest to, że aby przypisać każdemu uczniowi ocenę końcową, nie musi on czekać na przetworzenie całego dokumentu. Mógłby natychmiast przypisać ocenę uczniowi, gdy parser SAX odczyta ocenę tego ucznia. W powyższej analizie przyjęliśmy, że instruktor nie stworzył własnej struktury danych. Co jeśli utworzy własną strukturę danych, taką jak tablica ciągów do przechowywania SSN i tablica liczb całkowitych do przechowywania punktów? W tym przypadku, Myślę, że SAX jest lepszym wyborem, zanim pozwoli to zaoszczędzić zarówno pamięć, jak i czas, a jednocześnie wykonać zadanie. Cóż, jeszcze jedna uwaga na tym przykładzie. Co jeśli instruktor chce nie wydrukować listy, ale zapisać oryginalny dokument z aktualizacją ocen każdego ucznia? W takim przypadku parser DOM powinien być lepszym wyborem, bez względu na to, jakie zasady oceniania przyjmuje. Nie musi tworzyć własnej struktury danych. To, co musi zrobić, to najpierw zmodyfikować drzewo DOM (tj. Ustawić wartość w węźle „ocena”), a następnie zapisać całe zmodyfikowane drzewo. Jeśli zdecyduje się użyć parsera SAX zamiast parsera DOM, wówczas w tym przypadku musi utworzyć strukturę danych, która jest prawie tak skomplikowana jak drzewo DOM, zanim będzie mógł wykonać zadanie. ale załatw robotę. Cóż, jeszcze jedna uwaga na tym przykładzie. Co jeśli instruktor chce nie wydrukować listy, ale zapisać oryginalny dokument z aktualizacją ocen każdego ucznia? W takim przypadku parser DOM powinien być lepszym wyborem, bez względu na to, jakie zasady oceniania przyjmuje. Nie musi tworzyć własnej struktury danych. To, co musi zrobić, to najpierw zmodyfikować drzewo DOM (tj. Ustawić wartość w węźle „ocena”), a następnie zapisać całe zmodyfikowane drzewo. Jeśli zdecyduje się użyć parsera SAX zamiast parsera DOM, wówczas w tym przypadku musi utworzyć strukturę danych, która jest prawie tak skomplikowana jak drzewo DOM, zanim będzie mógł wykonać zadanie. ale załatw robotę. Cóż, jeszcze jedna uwaga na tym przykładzie. Co jeśli instruktor chce nie wydrukować listy, ale zapisać oryginalny dokument z aktualizacją ocen każdego ucznia? W takim przypadku parser DOM powinien być lepszym wyborem, bez względu na to, jakie zasady oceniania przyjmuje. Nie musi tworzyć własnej struktury danych. To, co musi zrobić, to najpierw zmodyfikować drzewo DOM (tj. Ustawić wartość w węźle „ocena”), a następnie zapisać całe zmodyfikowane drzewo. Jeśli zdecyduje się użyć parsera SAX zamiast parsera DOM, wówczas w tym przypadku musi utworzyć strukturę danych, która jest prawie tak skomplikowana jak drzewo DOM, zanim będzie mógł wykonać zadanie. ale żeby zapisać oryginalny dokument z powrotem z oceną każdego ucznia? W takim przypadku parser DOM powinien być lepszym wyborem, bez względu na to, jakie zasady oceniania przyjmuje. Nie musi tworzyć własnej struktury danych. To, co musi zrobić, to najpierw zmodyfikować drzewo DOM (tj. Ustawić wartość w węźle „ocena”), a następnie zapisać całe zmodyfikowane drzewo. Jeśli zdecyduje się użyć parsera SAX zamiast parsera DOM, wówczas w tym przypadku musi utworzyć strukturę danych, która jest prawie tak skomplikowana jak drzewo DOM, zanim będzie mógł wykonać zadanie. ale żeby zapisać oryginalny dokument z powrotem z oceną każdego ucznia? W takim przypadku parser DOM powinien być lepszym wyborem, bez względu na to, jakie zasady oceniania przyjmuje. Nie musi tworzyć własnej struktury danych. To, co musi zrobić, to najpierw zmodyfikować drzewo DOM (tj. Ustawić wartość w węźle „ocena”), a następnie zapisać całe zmodyfikowane drzewo. Jeśli zdecyduje się użyć parsera SAX zamiast parsera DOM, wówczas w tym przypadku musi utworzyć strukturę danych, która jest prawie tak skomplikowana jak drzewo DOM, zanim będzie mógł wykonać zadanie. węzeł), a następnie zapisz całe zmodyfikowane drzewo. Jeśli zdecyduje się użyć parsera SAX zamiast parsera DOM, wówczas w tym przypadku musi utworzyć strukturę danych, która jest prawie tak skomplikowana jak drzewo DOM, zanim będzie mógł wykonać zadanie. węzeł), a następnie zapisz całe zmodyfikowane drzewo. Jeśli zdecyduje się użyć parsera SAX zamiast parsera DOM, wówczas w tym przypadku musi utworzyć strukturę danych, która jest prawie tak skomplikowana jak drzewo DOM, zanim będzie mógł wykonać zadanie.
Przykład
Opis problemu : Napisz program Java, aby wyodrębnić wszystkie informacje o kręgach, które są elementami w danym dokumencie XML. Zakładamy, że każdy element koła ma trzy elementy potomne (tj. X, y i promień), a także atrybut koloru. Przykładowy dokument podano poniżej:
<?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>
Program z DOMparserem
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);}
}
}
Program z 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);
}
}
}