この質問に対する一般的なQ&A指向の回答を提供します。
質問への回答
なぜXMLパーサーが必要なのですか?
アプリケーションのすべてをゼロから実行する必要はないため、XMLパーサーが必要です。また、非常に低レベルでありながら非常に必要な何かを実行するには、いくつかの「ヘルパー」プログラムまたはライブラリが必要です。これらの低レベルだが必要なことには、整形式のチェック、DTDまたはスキーマ(パーサーの検証のみ)に対するドキュメントの検証、文字参照の解決、CDATAセクションの理解などが含まれます。XMLパーサーは、まさにそのような「ヘルパー」プログラムであり、これらすべての仕事を行います。XMLパーサーを使用すると、これらの多くの複雑さから保護され、パーサーによって実装されたAPIを介して高レベルでのプログラミングに集中できるため、プログラミング効率を上げることができます。
SAXとDOMのどちらが良いですか?
SAXとDOMの両方のパーサーには、長所と短所があります。どちらが良いかは、アプリケーションの特性によって異なります(以下の質問を参照してください)。
DOMパーサーとSAXパーサーのどちらが速度を向上させることができますか?
SAXパーサーを使用すると、速度が向上します。
ツリーベースのAPIとイベントベースのAPIの違いは何ですか?
ツリーベースのAPIは、ツリー構造を中心に配置されているため、Documentインターフェース、Nodeインターフェース、NodeListインターフェース、Elementインターフェース、Attrインターフェースなど、DOMコンポーネントであるツリーのコンポーネントにインターフェースを提供します。ただし、対照的に、イベントベースのAPIはハンドラーのインターフェイスを提供します。ContentHandlerインターフェース、DTDHandlerインターフェース、EntityResolverインターフェース、ErrorHandlerインターフェースの4つのハンドラーインターフェースがあります。
DOMパーサーとSAXパーサーの違いは何ですか?
DOMパーサーとSAXパーサーは異なる方法で機能します。
DOMパーサーは、入力ドキュメントからメモリ内にツリー構造を作成し、クライアントからの要求を待ちます。ただし、SAXパーサーは内部構造を作成しません。代わりに、入力ドキュメントのコンポーネントの発生をイベントとして受け取り、入力ドキュメントを読み取るときに何を読み取るかをクライアントに通知します。あ
DOMパーサーは、クライアントが実際にどれだけ必要とするかに関係なく、常にドキュメント全体をクライアントアプリケーションに提供します。しかし、SAXパーサーは常にクライアントアプリケーションに常にドキュメントの一部のみを提供します。
- DOMパーサーでは、クライアントアプリケーションのメソッド呼び出しは明示的である必要があり、一種のチェーンを形成します。しかし、SAXでは、特定のイベントが発生したときに「コールバック」と呼ばれる方法で(通常は科学者によってオーバーライドされる)一部の特定のメソッドが自動的に(暗黙的に)呼び出されます。これらのメソッドは明示的に呼び出すこともできますが、クライアントから明示的に呼び出す必要はありません。
どのパーサーが優れているかをどのように判断するのですか?
理想的には、優れたパーサーは高速(時間効率が良い)、スペース効率がよく、機能が豊富で使いやすいものでなければなりません。しかし、実際には、主要なパーサーのいずれも、これらすべての機能を同時に備えていません。たとえば、DOMパーサーは機能が豊富です(メモリ内にDOMツリーを作成し、ドキュメントの任意の部分に繰り返しアクセスしてDOMツリーを変更できるため)が、ドキュメントが巨大な場合はスペース効率が悪い、それを扱う方法を学ぶのに少し時間がかかります。ただし、大きな入力ドキュメントの場合、SAXパーサーはスペース効率がはるかに高くなります(内部構造を作成しないため)。さらに、APIは非常にシンプルであるため、DOMパーサーよりも実行速度が速く、学習も容易です。しかし、機能の観点からは、提供する機能が少ないため、独自のデータ構造を作成するなど、ユーザー自身がより多くのことを処理する必要があります。ところで、良いパーサーとは何ですか?答えは実際にはアプリケーションの特性に依存すると思います。
DOMパーサーを使用するよりもSAXパーサーを使用する方が有利な実際のアプリケーションとは何ですか?DOMパーサーとSAXパーサーの通常のアプリケーションは何ですか?
次の場合、DOMパーサーを使用するよりもSAXパーサーを使用する方が有利です。
- 入力ドキュメントが利用可能なメモリには大きすぎます(実際には、この場合はSAXが唯一の選択肢です)
- 連続した小さな入力チャンクでドキュメントを処理できます。有用な作業を行う前にドキュメント全体を必要としない
- パーサーを使用して目的の情報を抽出するだけで、すべての計算は完全に自分で作成したデータ構造に基づいて行われます。実際、ほとんどのアプリケーションでは、DOMツリーほど複雑ではない独自のデータ構造を作成しています。この意味から、DOMパーサーを使用する可能性はSAXパーサーを使用する可能性よりも低いと思います。
以下の場合、DOMパーサーを使用する方がSAXパーサーを使用するよりも有利です。
- アプリケーションは、ドキュメントの広く個別の部分に同時にアクセスする必要があります。
- アプリケーションでは、ドキュメント自体と同じくらい複雑な内部データ構造を使用している可能性があります。
- アプリケーションはドキュメントを繰り返し変更する必要があります。
- アプリケーションは、多くのメソッド呼び出しを通じてかなりの時間ドキュメントを保存する必要があります。
例(DOMパーサーまたはSAXパーサーを使用しますか?):
講師が生徒のすべての個人情報とクラスで生徒が作成したポイントを含むXMLドキュメントがあり、アプリケーションを使用して生徒に最終成績を割り当てているとします。彼が作成したいのは、SSNとグレードのリストです。また、彼のアプリケーションでは、インストラクターは学生の個人情報とポイントを格納するために配列などのデータ構造を使用しないと想定しています。インストラクターがクラス平均以上のクラスを獲得した人にAを、他の人にBを与えることを決定した場合、彼のアプリケーションではDOMパーサーを使用することをお勧めします。その理由は、ドキュメント全体が処理される前のクラス平均がどれだけあるかを知る方法がないためです。彼が自分のアプリケーションでおそらく行う必要があるのは、最初にすべての学生の ポイントを計算して平均を計算し、ドキュメントをもう一度調べて、生徒が獲得したポイントをクラスの平均と比較して、各生徒に最終成績を割り当てます。ただし、インストラクターが90点以上を獲得した学生にAを割り当て、他の学生にBを割り当てるようなグレーディングポリシーを採用している場合は、SAXパーサーを使用することをお勧めします。その理由は、各生徒に最終成績を割り当てるために、ドキュメント全体が処理されるのを待つ必要がないためです。SAXパーサーがこの生徒の成績を読み取ったら、すぐに生徒に成績を割り当てることができます。上記の分析では、インストラクターが自分のデータ構造を作成していないと想定しました。SSNを格納するための文字列の配列や、ポイントを復元するための整数の配列など、独自のデータ構造を作成した場合はどうなるでしょうか。この場合、メモリと時間の両方を節約しながら作業を完了する前に、SAXの方が良い選択だと思います。さて、この例についてもう1つ検討します。講師がリストを印刷するのではなく、各生徒の成績を更新して元のドキュメントを保存する場合はどうなりますか?この場合、DOMパーサーは、採用しているグレーディングポリシーに関係なく、より適切な選択肢になるはずです。彼は自分のデータ構造を作成する必要はありません。彼がする必要があるのは、最初にDOMツリーを変更(つまり、値を「グレード」ノードに設定)してから、変更したツリー全体を保存することです。DOMパーサーの代わりにSAXパーサーを使用することを選択した場合、この場合、仕事を完了する前に、DOMツリーと同じくらい複雑なデータ構造を作成する必要があります。まだ仕事を成し遂げる。さて、この例についてもう1つ検討します。講師がリストを印刷するのではなく、各生徒の成績を更新して元のドキュメントを保存する場合はどうなりますか?この場合、DOMパーサーは、採用しているグレーディングポリシーに関係なく、より適切な選択肢になるはずです。彼は自分のデータ構造を作成する必要はありません。彼がする必要があるのは、最初にDOMツリーを変更(つまり、値を「グレード」ノードに設定)してから、変更したツリー全体を保存することです。DOMパーサーの代わりにSAXパーサーを使用することを選択した場合、この場合、仕事を完了する前に、DOMツリーと同じくらい複雑なデータ構造を作成する必要があります。まだ仕事を成し遂げる。さて、この例についてもう1つ検討します。講師がリストを印刷するのではなく、各生徒の成績を更新して元のドキュメントを保存する場合はどうなりますか?この場合、DOMパーサーは、採用しているグレーディングポリシーに関係なく、より適切な選択肢になるはずです。彼は自分のデータ構造を作成する必要はありません。彼がする必要があるのは、最初にDOMツリーを変更(つまり、値を「グレード」ノードに設定)してから、変更したツリー全体を保存することです。DOMパーサーの代わりにSAXパーサーを使用することを選択した場合、この場合、仕事を完了する前に、DOMツリーと同じくらい複雑なデータ構造を作成する必要があります。しかし、各生徒の成績を更新して元のドキュメントを保存するには?この場合、DOMパーサーは、採用しているグレーディングポリシーに関係なく、より適切な選択肢になるはずです。彼は自分のデータ構造を作成する必要はありません。彼がする必要があるのは、最初にDOMツリーを変更(つまり、値を「グレード」ノードに設定)してから、変更したツリー全体を保存することです。DOMパーサーの代わりにSAXパーサーを使用することを選択した場合、この場合、仕事を完了する前に、DOMツリーと同じくらい複雑なデータ構造を作成する必要があります。しかし、各生徒の成績を更新して元のドキュメントを保存するには?この場合、DOMパーサーは、採用しているグレーディングポリシーに関係なく、より適切な選択肢になるはずです。彼は自分のデータ構造を作成する必要はありません。彼がする必要があるのは、最初にDOMツリーを変更(つまり、値を「グレード」ノードに設定)してから、変更したツリー全体を保存することです。DOMパーサーの代わりにSAXパーサーを使用することを選択した場合、この場合、仕事を完了する前に、DOMツリーと同じくらい複雑なデータ構造を作成する必要があります。ノード)、変更されたツリー全体を保存します。DOMパーサーの代わりにSAXパーサーを使用することを選択した場合、この場合、仕事を完了する前に、DOMツリーと同じくらい複雑なデータ構造を作成する必要があります。ノード)、変更されたツリー全体を保存します。DOMパーサーの代わりにSAXパーサーを使用することを選択した場合、この場合、仕事を完了する前に、DOMツリーと同じくらい複雑なデータ構造を作成する必要があります。
例
問題の説明:指定されたXMLドキュメントの要素であるサークルに関するすべての情報を抽出するJavaプログラムを記述します。各円要素には3つの子要素(つまり、x、y、および半径)と色属性があると仮定します。サンプルドキュメントを以下に示します。
<?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を使用したプログラム
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を使用したプログラム
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);
}
}
}