Bu soru için genel soru-cevap odaklı cevap vereceğim:
Soruların Cevabı
Neden XML ayrıştırıcısına ihtiyacımız var?
XML ayrıştırıcıya ihtiyacımız var çünkü uygulamamızdaki her şeyi sıfırdan yapmak istemiyoruz ve çok düşük seviyeli ama bizim için çok gerekli bir şey yapmak için bazı "yardımcı" programlara veya kütüphanelere ihtiyacımız var. Bu düşük seviyeli ancak gerekli şeyler iyi biçimlendirmeyi kontrol etmek, dokümanı DTD veya şemasına göre doğrulamak (sadece ayrıştırıcıları doğrulamak için), karakter referansını çözümlemek, CDATA bölümlerini anlamak vb. XML ayrıştırıcıları sadece böyle "yardımcı" programlar ve tüm bu işleri yapacaklar. XML ayrıştırıcıyla, bu karmaşıklıkların çoğundan korunuyoruz ve ayrıştırıcılar tarafından uygulanan API'ler aracılığıyla kendimizi sadece yüksek düzeyde programlama yapmaya konsantre edebiliriz ve böylece programlama verimliliği elde edebiliriz.
Hangisi daha iyi, SAX veya DOM?
Hem SAX hem de DOM ayrıştırıcının avantajları ve dezavantajları vardır. Hangisinin daha iyi olduğu, başvurunuzun özelliklerine bağlı olmalıdır (lütfen aşağıdaki bazı sorulara bakın).
Hangi ayrıştırıcı daha iyi hız, DOM veya SAX ayrıştırıcıları alabilir?
SAX ayrıştırıcı daha iyi hız elde edebilirsiniz.
Ağaç tabanlı API ile etkinlik tabanlı API arasındaki fark nedir?
Ağaç tabanlı bir API, bir ağaç yapısının etrafında merkezlenir ve bu nedenle, bir ağacın (DOM belgesi olan) Belge arabirimi, Düğüm arabirimi, DüğümList arabirimi, Öğe arabirimi, Attr arabirimi ve benzeri gibi arabirimler sağlar. Ancak, aksine, olay tabanlı bir API işleyicilere arabirimler sağlar. Dört işleyici arabirimi, ContentHandler arabirimi, DTDHandler arabirimi, EntityResolver arabirimi ve ErrorHandler arabirimi vardır.
DOM Ayrıştırıcı ve SAX Ayrıştırıcı arasındaki fark nedir?
DOM ayrıştırıcıları ve SAX ayrıştırıcıları farklı şekillerde çalışır:
DOM ayrıştırıcısı giriş belgesinden bellekte bir ağaç yapısı oluşturur ve daha sonra istemciden gelen istekleri bekler. Ancak SAX ayrıştırıcısı herhangi bir iç yapı oluşturmaz. Bunun yerine, bir giriş belgesinin bileşenlerinin olaylarını olay olarak alır ve istemciye girdi belgesi boyunca okurken ne okuduğunu söyler. bir
DOM ayrıştırıcısı, istemci tarafından ne kadar gerekli olursa olsun, istemci uygulamasına her zaman tüm belgeyi sunar. Ancak bir SAX ayrıştırıcısı istemci uygulamasına her zaman yalnızca belgenin parçalarıyla birlikte herhangi bir zamanda hizmet eder.
- DOM ayrıştırıcısı ile, istemci uygulamasındaki yöntem çağrıları açık olmalı ve bir tür zincir oluşturmalıdır. Ancak SAX ile, bazı belirli yöntemler (genellikle cilan tarafından geçersiz kılınır), bazı olaylar gerçekleştiğinde "geri arama" adı verilen bir şekilde otomatik olarak (örtük olarak) çağrılır. Bu yöntemlerin istemci tarafından açıkça çağrılması gerekmez, ancak bunları açıkça çağırabiliriz.
Hangi ayrıştırıcının iyi olduğuna nasıl karar veririz?
İdeal olarak iyi bir ayrıştırıcı hızlı (zaman açısından verimli), alan açısından verimli, işlevsel açıdan zengin ve kullanımı kolay olmalıdır. Ancak gerçekte, ana ayrıştırıcıların hiçbiri aynı anda tüm bu özelliklere sahip değildir. Örneğin, bir DOM Ayrıştırıcı işlevsellik açısından zengindir (çünkü bellekte bir DOM ağacı oluşturur ve belgenin herhangi bir bölümüne art arda erişmenize izin verir ve DOM ağacını değiştirmenize izin verir), ancak belge çok büyük olduğunda alan verimsizdir ve bununla nasıl çalışılacağını öğrenmek biraz zaman alır. Bununla birlikte, bir SAX Parser büyük girdi belgesi durumunda çok daha fazla yer tasarrufu sağlar (çünkü iç yapı oluşturmaz). Dahası, API'si gerçekten basit olduğu için DOM Parser'dan daha hızlı çalışır ve öğrenmesi daha kolaydır. Ancak işlevsellik açısından, daha az fonksiyon sağlar, bu da kullanıcıların kendi veri yapılarını oluşturmak gibi daha fazla özen göstermeleri gerektiği anlamına gelir. Bu arada, iyi bir ayrıştırıcı nedir? Cevabın gerçekten uygulamanızın özelliklerine bağlı olduğunu düşünüyorum.
SAX ayrıştırıcı kullanmanın DOM ayrıştırıcı kullanmanın avantajlı olduğu gerçek dünya uygulamaları nelerdir? Bir DOM ayrıştırıcısı ve bir SAX ayrıştırıcısı için genel uygulama nedir?
Aşağıdaki durumlarda, SAX ayrıştırıcısını kullanmak DOM ayrıştırıcısını kullanmaktan daha avantajlıdır.
- Giriş belgesi kullanılabilir bellek için çok büyük (aslında bu durumda SAX tek seçeneğinizdir)
- Belgeyi küçük bitişik girdi yığınlarında işleyebilirsiniz. Yararlı işler yapmadan önce belgenin tamamına ihtiyacınız yoktur
- Ayrıştırıcıyı yalnızca ilgili bilgileri elde etmek için kullanmak istiyorsunuz ve tüm hesaplamanız tamamen sizin tarafınızdan oluşturulan veri yapılarına dayanacaktır. Aslında uygulamalarımızın çoğunda, genellikle DOM ağacı kadar karmaşık olmayan kendi veri yapılarımızı yaratırız. Bu anlamda, bir DOM ayrıştırıcısı kullanma şansının SAX ayrıştırıcısı kullanma şansından daha az olduğunu düşünüyorum.
Aşağıdaki durumlarda, DOM ayrıştırıcısını kullanmak SAX ayrıştırıcısını kullanmaktan daha avantajlıdır.
- Başvurunuzun aynı anda belgenin ayrı ayrı bölümlerine erişmesi gerekir.
- Uygulamanız muhtemelen belgenin kendisi kadar karmaşık olan bir iç veri yapısı kullanabilir.
- Başvurunuz belgeyi tekrar tekrar değiştirmelidir.
- Uygulamanız, birçok yöntem çağrısı aracılığıyla belgeyi önemli bir süre boyunca saklamalıdır.
Örnek (DOM ayrıştırıcısı mı yoksa SAX ayrıştırıcısı mı kullanıyorsunuz?):
Bir eğitmenin, öğrencilerin tüm kişisel bilgilerini ve öğrencilerin sınıfında kazandığı noktaları içeren bir XML belgesine sahip olduğunu ve şimdi bir uygulama kullanan öğrenciler için final notları atadığını varsayın. Üretmek istediği şey, SSN ve notların bir listesidir. Ayrıca uygulamasında öğretim elemanının öğrencinin kişisel bilgilerini ve puanlarını saklamak için diziler gibi bir veri yapısı kullanmadığını varsayıyoruz. Eğitmen A'yı sınıf ortalamasını veya daha fazlasını kazananlara A vermeye ve B'leri diğerlerine vermeye karar verirse, başvurusunda bir DOM ayrıştırıcısı kullanması daha iyi olur. Bunun nedeni, belgenin tamamı işlenmeden önce sınıf ortalamasının ne kadar olduğunu bilmesinin hiçbir yolu olmamasıdır. Muhtemelen başvurusunda yapması gereken şey, önce tüm öğrencilerin ve ortalamayı hesaplayın, ardından belgeyi tekrar gözden geçirin ve kazandığı puanları sınıf ortalamasıyla karşılaştırarak her öğrenciye final notu verin. Bununla birlikte, eğitmen öyle bir notlandırma politikası benimserse, 90 puan veya daha fazla olan öğrencilere A ve diğerlerine B atanırsa, muhtemelen bir SAX ayrıştırıcısı kullanması daha iyi olur. Bunun nedeni, her öğrenciye bir final notu atamak için tüm belgenin işlenmesini beklemesine gerek yoktur. SAX ayrıştırıcısı bu öğrencinin notunu okuduğunda hemen bir öğrenciye not verebilir. Yukarıdaki analizde, eğitmenin kendi veri yapısını oluşturmadığını varsaydık. Ya SSN'yi depolamak için bir dizi dizisi ve noktaları saklamak için bir tamsayı dizisi gibi kendi veri yapısını yaratırsa? Bu durumda, Sanırım SAX daha iyi bir seçim, bu da hem hafızadan hem de zamandan tasarruf etmeden önce işi bitirmeden önce. Peki, bu örnek üzerinde bir kez daha düşünülmelidir. Eğitmenin yapmak istediği şey bir liste yazdırmak değil, orijinal dokümanı güncellenen her öğrencinin notuyla geri kaydetmekse ne olur? Bu durumda, bir DOM ayrıştırıcısı hangi derecelendirme politikasını benimsiyor olursa olsun daha iyi bir seçim olmalıdır. Kendi başına herhangi bir veri yapısı oluşturmasına gerek yoktur. Yapması gereken önce DOM ağacını değiştirmek (yani değeri 'sınıf' düğümüne ayarlamak) ve daha sonra değiştirilmiş ağacın tamamını kaydetmektir. Bir DOM ayrıştırıcı yerine SAX ayrıştırıcı kullanmayı seçerse, bu durumda işi yapmadan önce neredeyse bir DOM ağacı kadar karmaşık bir veri yapısı yaratması gerekir. ama işi hallet. Peki, bu örnek üzerinde bir kez daha düşünülmelidir. Eğitmenin yapmak istediği şey bir liste yazdırmak değil, orijinal dokümanı güncellenen her öğrencinin notuyla geri kaydetmekse ne olur? Bu durumda, bir DOM ayrıştırıcısı hangi derecelendirme politikasını benimsiyor olursa olsun daha iyi bir seçim olmalıdır. Kendi başına herhangi bir veri yapısı oluşturmasına gerek yoktur. Yapması gereken önce DOM ağacını değiştirmek (yani değeri 'sınıf' düğümüne ayarlamak) ve daha sonra değiştirilmiş ağacın tamamını kaydetmektir. Bir DOM ayrıştırıcı yerine SAX ayrıştırıcı kullanmayı seçerse, bu durumda işi yapmadan önce neredeyse bir DOM ağacı kadar karmaşık bir veri yapısı yaratması gerekir. ama işi hallet. Peki, bu örnek üzerinde bir kez daha düşünülmelidir. Eğitmenin yapmak istediği şey bir liste yazdırmak değil, orijinal dokümanı güncellenen her öğrencinin notuyla geri kaydetmekse ne olur? Bu durumda, bir DOM ayrıştırıcısı hangi derecelendirme politikasını benimsiyor olursa olsun daha iyi bir seçim olmalıdır. Kendi başına herhangi bir veri yapısı oluşturmasına gerek yoktur. Yapması gereken önce DOM ağacını değiştirmek (yani değeri 'sınıf' düğümüne ayarlamak) ve daha sonra değiştirilmiş ağacın tamamını kaydetmektir. Bir DOM ayrıştırıcı yerine SAX ayrıştırıcı kullanmayı seçerse, bu durumda işi yapmadan önce neredeyse bir DOM ağacı kadar karmaşık bir veri yapısı yaratması gerekir. ama her öğrencinin notu güncellenerek orijinal belgeyi geri kaydetmek için? Bu durumda, bir DOM ayrıştırıcısı hangi derecelendirme politikasını benimsiyor olursa olsun daha iyi bir seçim olmalıdır. Kendi başına herhangi bir veri yapısı oluşturmasına gerek yoktur. Yapması gereken önce DOM ağacını değiştirmek (yani değeri 'sınıf' düğümüne ayarlamak) ve daha sonra değiştirilmiş ağacın tamamını kaydetmektir. Bir DOM ayrıştırıcı yerine SAX ayrıştırıcı kullanmayı seçerse, bu durumda işi yapmadan önce neredeyse bir DOM ağacı kadar karmaşık bir veri yapısı yaratması gerekir. ama her öğrencinin notu güncellenerek orijinal belgeyi geri kaydetmek için? Bu durumda, bir DOM ayrıştırıcısı hangi derecelendirme politikasını benimsiyor olursa olsun daha iyi bir seçim olmalıdır. Kendi veri yapısını oluşturmasına gerek yoktur. Yapması gereken önce DOM ağacını değiştirmek (yani değeri 'sınıf' düğümüne ayarlamak) ve daha sonra değiştirilmiş ağacın tamamını kaydetmektir. Bir DOM ayrıştırıcı yerine SAX ayrıştırıcı kullanmayı seçerse, bu durumda işi yapmadan önce neredeyse bir DOM ağacı kadar karmaşık bir veri yapısı yaratması gerekir. düğümü) ve ardından değiştirilmiş ağacın tamamını kaydedin. Bir DOM ayrıştırıcı yerine SAX ayrıştırıcı kullanmayı seçerse, bu durumda işi yapmadan önce neredeyse bir DOM ağacı kadar karmaşık bir veri yapısı yaratması gerekir. düğümü) ve ardından değiştirilmiş ağacın tamamını kaydedin. Bir DOM ayrıştırıcı yerine SAX ayrıştırıcı kullanmayı seçerse, bu durumda işi yapmadan önce neredeyse bir DOM ağacı kadar karmaşık bir veri yapısı yaratması gerekir.
Bir örnek
Sorun bildirimi : Belirli bir XML belgesindeki öğeler olan çevreler hakkındaki tüm bilgileri ayıklamak için bir Java programı yazın. Her daire öğesinin bir renk özelliğinin yanı sıra üç alt öğeye (yani, x, y ve yarıçap) sahip olduğunu varsayıyoruz. Örnek bir doküman aşağıda verilmiştir:
<?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>
DOMparser ile Program
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);}
}
}
SAXparser ile Program
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);
}
}
}