Saya akan memberikan jawaban umum yang berorientasi pada Tanya Jawab untuk pertanyaan ini:
Jawab untuk Pertanyaan
Mengapa kita membutuhkan parser XML?
Kami membutuhkan parser XML karena kami tidak ingin melakukan semuanya dalam aplikasi kami dari awal, dan kami membutuhkan beberapa program atau pustaka "pembantu" untuk melakukan sesuatu yang sangat rendah tetapi sangat diperlukan bagi kami. Hal-hal tingkat rendah tetapi perlu ini termasuk memeriksa kemapanan, memvalidasi dokumen terhadap DTD atau skema (hanya untuk memvalidasi parser), menyelesaikan referensi karakter, memahami bagian CDATA, dan sebagainya. Parser XML hanyalah program "pembantu" dan mereka akan melakukan semua pekerjaan ini. Dengan parser XML, kami dilindungi dari banyak kerumitan ini dan kami dapat berkonsentrasi hanya pada pemrograman tingkat tinggi melalui API yang diimplementasikan oleh parser, dan dengan demikian mendapatkan efisiensi pemrograman.
Mana yang lebih baik, SAX atau DOM?
Pengurai SAX dan DOM memiliki kelebihan dan kekurangan. Mana yang lebih baik harus bergantung pada karakteristik aplikasi Anda (silakan lihat beberapa pertanyaan di bawah).
Parser mana yang bisa mendapatkan kecepatan, DOM atau SAX parser yang lebih baik?
Parser SAX bisa mendapatkan kecepatan yang lebih baik.
Apa perbedaan antara API berbasis pohon dan API berbasis peristiwa?
API berbasis pohon dipusatkan di sekitar struktur pohon dan oleh karena itu menyediakan antarmuka pada komponen pohon (yang merupakan dokumen DOM) seperti antarmuka Dokumen, antarmuka Node, antarmuka NodeList, antarmuka Elemen, antarmuka Attr dan sebagainya. Sebaliknya, API berbasis peristiwa menyediakan antarmuka pada penangan. Ada empat antarmuka handler, antarmuka ContentHandler, antarmuka DTDHandler, antarmuka EntityResolver, dan antarmuka ErrorHandler.
Apa perbedaan antara DOM Parser dan SAX Parser?
Parser DOM dan Parser SAX bekerja dengan berbagai cara:
Pengurai DOM membuat struktur pohon dalam memori dari dokumen input dan kemudian menunggu permintaan dari klien. Tetapi parser SAX tidak membuat struktur internal apa pun. Alih-alih, ia mengambil kejadian komponen input dokumen sebagai peristiwa, dan memberi tahu klien apa yang dibaca saat membaca dokumen input. SEBUAH
Parser DOM selalu melayani aplikasi klien dengan seluruh dokumen tidak peduli berapa banyak sebenarnya yang dibutuhkan oleh klien. Tetapi parser SAX melayani aplikasi klien selalu hanya dengan potongan dokumen pada waktu tertentu.
- Dengan parser DOM, pemanggilan metode dalam aplikasi klien harus eksplisit dan membentuk semacam rantai. Tetapi dengan SAX, beberapa metode tertentu (biasanya ditimpa oleh si cient) akan dipanggil secara otomatis (secara implisit) dengan cara yang disebut "callback" ketika beberapa peristiwa tertentu terjadi. Metode-metode ini tidak harus dipanggil secara eksplisit oleh klien, meskipun kita dapat memanggilnya secara eksplisit.
Bagaimana kita memutuskan parser mana yang bagus?
Idealnya pengurai yang baik harus cepat (hemat waktu), hemat ruang, kaya fungsionalitas, dan mudah digunakan. Namun pada kenyataannya, tidak ada parser utama yang memiliki semua fitur ini pada saat yang sama. Misalnya, DOM Parser kaya fungsionalitas (karena membuat pohon DOM dalam memori dan memungkinkan Anda untuk mengakses bagian mana pun dari dokumen berulang kali dan memungkinkan Anda untuk memodifikasi pohon DOM), tetapi itu adalah ruang yang tidak efisien ketika dokumen sangat besar , dan perlu waktu agak lama untuk mempelajari cara bekerja dengannya. Parser SAX, bagaimanapun, jauh lebih efisien ruang dalam hal dokumen input besar (karena tidak menciptakan struktur internal). Terlebih lagi, ini berjalan lebih cepat dan lebih mudah dipelajari daripada DOM Parser karena API-nya sangat sederhana. Tapi dari sudut pandang fungsionalitas, ini menyediakan lebih sedikit fungsi yang berarti bahwa pengguna itu sendiri harus mengurus lebih banyak, seperti membuat struktur data mereka sendiri. Omong-omong, apa itu pengurai yang baik? Saya pikir jawabannya sangat tergantung pada karakteristik aplikasi Anda.
Apa saja aplikasi dunia nyata di mana menggunakan SAX parser lebih menguntungkan daripada menggunakan DOM parser dan sebaliknya? Apa aplikasi yang biasa untuk parser DOM dan untuk parser SAX?
Dalam kasus berikut, menggunakan parser SAX lebih menguntungkan daripada menggunakan parser DOM.
- Dokumen input terlalu besar untuk memori yang tersedia (sebenarnya dalam hal ini SAX adalah satu-satunya pilihan Anda)
- Anda dapat memproses dokumen dalam potongan input kecil yang berdekatan. Anda tidak perlu seluruh dokumen sebelum dapat melakukan pekerjaan yang bermanfaat
- Anda hanya ingin menggunakan parser untuk mengekstrak informasi yang menarik, dan semua perhitungan Anda akan sepenuhnya didasarkan pada struktur data yang Anda buat sendiri. Sebenarnya di sebagian besar aplikasi kita, kita membuat struktur data kita sendiri yang biasanya tidak serumit pohon DOM. Dari pengertian ini, saya pikir, kesempatan menggunakan parser DOM lebih kecil dari pada menggunakan parser SAX.
Dalam kasus berikut, menggunakan parser DOM lebih menguntungkan daripada menggunakan parser SAX.
- Aplikasi Anda perlu mengakses secara terpisah berbagai bagian dokumen pada saat yang bersamaan.
- Aplikasi Anda mungkin menggunakan struktur data internal yang hampir serumit dokumen itu sendiri.
- Aplikasi Anda harus memodifikasi dokumen berulang kali.
- Aplikasi Anda harus menyimpan dokumen untuk waktu yang signifikan melalui banyak panggilan metode.
Contoh (Gunakan parser DOM atau parser SAX?):
Asumsikan bahwa seorang instruktur memiliki dokumen XML yang berisi semua informasi pribadi siswa serta poin yang dibuat siswa di kelasnya, dan ia sekarang menugaskan nilai akhir untuk siswa menggunakan aplikasi. Apa yang ingin dia hasilkan, adalah daftar dengan SSN dan nilai-nilainya. Kami juga berasumsi bahwa dalam aplikasinya, instruktur tidak menggunakan struktur data seperti array untuk menyimpan informasi pribadi siswa dan poin. Jika instruktur memutuskan untuk memberikan nilai A kepada mereka yang mendapatkan nilai rata-rata kelas atau di atas, dan memberikan nilai B kepada yang lain, maka ia lebih baik menggunakan parser DOM dalam aplikasinya. Alasannya adalah bahwa dia tidak memiliki cara untuk mengetahui berapa rata-rata kelas sebelum seluruh dokumen diproses. Apa yang mungkin perlu dia lakukan dalam lamarannya, adalah pertama-tama memeriksa semua siswa. poin dan menghitung rata-rata, dan kemudian melihat kembali dokumen itu dan menetapkan nilai akhir untuk setiap siswa dengan membandingkan poin yang dia dapatkan dengan rata-rata kelas. Namun, jika instruktur mengadopsi kebijakan penilaian sedemikian rupa sehingga siswa yang mendapat 90 poin atau lebih, diberi nilai A dan yang lain diberi nilai B, maka mungkin ia lebih baik menggunakan parser SAX. Alasannya, untuk menugaskan setiap siswa nilai akhir, ia tidak perlu menunggu seluruh dokumen diproses. Dia bisa segera memberikan nilai kepada siswa setelah parser SAX membaca nilai siswa ini. Dalam analisis di atas, kami berasumsi bahwa instruktur tidak membuat struktur data sendiri. Bagaimana jika dia membuat struktur datanya sendiri, seperti array string untuk menyimpan SSN dan array integer untuk mengembalikan poin? Pada kasus ini, Saya pikir SAX adalah pilihan yang lebih baik, sebelum ini bisa menghemat memori dan waktu juga, namun menyelesaikan pekerjaan. Nah, satu pertimbangan lagi pada contoh ini. Bagaimana jika yang ingin dilakukan oleh instruktur bukanlah mencetak daftar, tetapi untuk menyimpan kembali dokumen asli dengan nilai setiap siswa yang diperbarui? Dalam hal ini, parser DOM harus menjadi pilihan yang lebih baik tidak peduli kebijakan penilaian apa yang ia adopsi. Dia tidak perlu membuat struktur data sendiri. Apa yang perlu dia lakukan adalah memodifikasi pohon DOM terlebih dahulu (yaitu, menetapkan nilai ke simpul 'kelas') dan kemudian menyimpan seluruh pohon yang dimodifikasi. Jika dia memilih untuk menggunakan SAX parser daripada parser DOM, maka dalam hal ini dia harus membuat struktur data yang hampir sama rumitnya dengan pohon DOM sebelum dia bisa menyelesaikan pekerjaan. belum menyelesaikan pekerjaan. Nah, satu pertimbangan lagi pada contoh ini. Bagaimana jika yang ingin dilakukan oleh instruktur bukanlah mencetak daftar, tetapi untuk menyimpan kembali dokumen asli dengan nilai setiap siswa yang diperbarui? Dalam hal ini, parser DOM harus menjadi pilihan yang lebih baik tidak peduli kebijakan penilaian apa yang ia adopsi. Dia tidak perlu membuat struktur data sendiri. Apa yang perlu dia lakukan adalah memodifikasi pohon DOM terlebih dahulu (yaitu, menetapkan nilai ke simpul 'kelas') dan kemudian menyimpan seluruh pohon yang dimodifikasi. Jika dia memilih untuk menggunakan SAX parser daripada parser DOM, maka dalam hal ini dia harus membuat struktur data yang hampir sama rumitnya dengan pohon DOM sebelum dia bisa menyelesaikan pekerjaan. belum menyelesaikan pekerjaan. Nah, satu pertimbangan lagi pada contoh ini. Bagaimana jika yang ingin dilakukan oleh instruktur bukanlah mencetak daftar, tetapi untuk menyimpan kembali dokumen asli dengan nilai setiap siswa yang diperbarui? Dalam hal ini, parser DOM harus menjadi pilihan yang lebih baik tidak peduli kebijakan penilaian apa yang ia adopsi. Dia tidak perlu membuat struktur data sendiri. Apa yang perlu dia lakukan adalah memodifikasi pohon DOM terlebih dahulu (yaitu, menetapkan nilai ke simpul 'kelas') dan kemudian menyimpan seluruh pohon yang dimodifikasi. Jika dia memilih untuk menggunakan SAX parser daripada parser DOM, maka dalam hal ini dia harus membuat struktur data yang hampir sama rumitnya dengan pohon DOM sebelum dia bisa menyelesaikan pekerjaan. tetapi untuk menyimpan dokumen asli kembali dengan nilai setiap siswa diperbarui? Dalam hal ini, parser DOM harus menjadi pilihan yang lebih baik tidak peduli kebijakan penilaian apa yang ia adopsi. Dia tidak perlu membuat struktur data sendiri. Apa yang perlu dia lakukan adalah memodifikasi pohon DOM terlebih dahulu (yaitu, menetapkan nilai ke simpul 'kelas') dan kemudian menyimpan seluruh pohon yang dimodifikasi. Jika dia memilih untuk menggunakan SAX parser daripada parser DOM, maka dalam hal ini dia harus membuat struktur data yang hampir sama rumitnya dengan pohon DOM sebelum dia bisa menyelesaikan pekerjaan. tetapi untuk menyimpan dokumen asli kembali dengan nilai setiap siswa diperbarui? Dalam hal ini, parser DOM harus menjadi pilihan yang lebih baik tidak peduli kebijakan penilaian apa yang ia adopsi. Dia tidak perlu membuat struktur data sendiri. Apa yang perlu dia lakukan adalah memodifikasi pohon DOM terlebih dahulu (yaitu, menetapkan nilai ke simpul 'kelas') dan kemudian menyimpan seluruh pohon yang dimodifikasi. Jika dia memilih untuk menggunakan SAX parser daripada parser DOM, maka dalam hal ini dia harus membuat struktur data yang hampir sama rumitnya dengan pohon DOM sebelum dia bisa menyelesaikan pekerjaan. simpul) dan kemudian menyimpan seluruh pohon yang dimodifikasi. Jika dia memilih untuk menggunakan SAX parser daripada parser DOM, maka dalam hal ini dia harus membuat struktur data yang hampir sama rumitnya dengan pohon DOM sebelum dia bisa menyelesaikan pekerjaan. simpul) dan kemudian menyimpan seluruh pohon yang dimodifikasi. Jika dia memilih untuk menggunakan SAX parser daripada parser DOM, maka dalam hal ini dia harus membuat struktur data yang hampir sama rumitnya dengan pohon DOM sebelum dia bisa menyelesaikan pekerjaan.
Sebuah contoh
Pernyataan masalah : Tulis program Java untuk mengekstrak semua informasi tentang lingkaran yang merupakan elemen dalam dokumen XML yang diberikan. Kami berasumsi bahwa setiap elemen lingkaran memiliki tiga elemen anak (yaitu, x, y dan jari-jari) serta atribut warna. Contoh dokumen diberikan di bawah ini:
<?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 dengan 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);}
}
}
Program dengan 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);
}
}
}