私は常にXMLの処理がやや面倒だと感じてきました。私はXMLパーサーの実装について話しているのではなく、ノードごとにXMLを処理するSAXパーサーのような既存のストリームベースのパーサーの使用について話しているのです。
はい、これらのパーサーのさまざまなAPIを学ぶのは非常に簡単ですが、XMLを処理するコードを見ると、常に多少複雑になることがわかります。本質的な問題は、XMLドキュメントが個々のノードに論理的に分離されているにもかかわらず、データの種類と属性が実際のデータから分離されていることが多いことです。したがって、特定のノードを個別に処理する場合、現在の場所と次に何をする必要があるかを判断するために、多くの余分な状態を維持する必要があります。
たとえば、典型的なXMLドキュメントからスニペットが与えられた場合:
<book>
<title>Blah blah</title>
<author>Blah blah</author>
<price>15 USD</price>
</book>
...本のタイトルを含むテキストノードに出会ったとき、どのように判断しますか?イテレータのように動作し、を呼び出すたびにXMLドキュメントの次のノードを提供する単純なXMLパーサーがあるとしますXMLParser.getNextNode()
。私は必然的に次のようなコードを書くことに気づきます。
boolean insideBookNode = false;
boolean insideTitleNode = false;
while (!XMLParser.finished())
{
....
XMLNode n = XMLParser.getNextNode();
if (n.type() == XMLTextNode)
{
if (insideBookNode && insideTitleNode)
{
// We have a book title, so do something with it
}
}
else
{
if (n.type() == XMLStartTag)
{
if (n.name().equals("book")) insideBookNode = true
else if (n.name().equals("title")) insideTitleNode = true;
}
else if (n.type() == XMLEndTag)
{
if (n.name().equals("book")) insideBookNode = false;
else if (n.name().equals("title")) insideTitleNode = false;
}
}
}
基本的に、XML処理はすぐに巨大なステートマシンドリブンループに変わり、以前に見つけた親ノードを示すために多くの状態変数が使用されます。それ以外の場合は、ネストされたすべてのタグを追跡するために、スタックオブジェクトを維持する必要があります。これはすぐにエラーが発生しやすく、保守が困難になります。
繰り返しますが、問題は、関心のあるデータが個々のノードに直接関連付けられていないことです。もちろん、XMLを次のように記述した場合、可能性があります。
<book title="Blah blah" author="blah blah" price="15 USD" />
...しかし、これはXMLが実際にどのように使用されるかということはめったにありません。ほとんどの場合、親ノードの子としてテキストノードがあり、テキストノードが何を参照しているかを判断するために、親ノードを追跡する必要があります。
だから...私は何か間違っていますか?もっと良い方法はありますか?どの時点でXMLストリームベースのパーサーを使用するのが面倒になり、完全なDOMパーサーが必要になりますか?他のプログラマーから、ストリームベースのパーサーでXMLを処理する際にどのようなイディオムを使用するかを聞きたいです。ストリームベースのXML解析は常に巨大なステートマシンに変換する必要がありますか?