Java Language
JAXP APIを使用したXML解析
サーチ…
備考
XML構文解析は、XML文書を、「ノード」、「属性」、「文書」、「名前空間」、またはこれらの構文に関連するイベントのような分かりやすい構文を使用して操作するためのものです。
Javaには、 JAXPと呼ばれるXML文書処理用のネイティブAPI 、またはXML処理用のJava APIがあります 。 JAXPとリファレンス実装は、Java 1.4(JAXP v1.1)以降のすべてのJavaリリースにバンドルされて以来進化を遂げています。 Java 8には、JAXPバージョン1.6が付属しています。
APIは、XML文書と相互作用するさまざまな方法を提供します。
- DOMインタフェース(Document Object Model)は、
- SAXインターフェース(Simple API for XML)
- StAXインターフェイス(XML用ストリーミングAPI)
DOMインタフェースの原則
DOMインタフェースは、XMLを解釈するW3C DOM準拠の方法を提供することを目的としています。 JAXPのさまざまなバージョンでは、さまざまなDOMレベルの仕様(レベル3まで)がサポートされています。
ドキュメントオブジェクトモデルインタフェースの下では、XMLドキュメントはツリーとして表され、「ドキュメント要素」から始まります。 APIの基本型があるNode
タイプ、それから移動することを可能にするNode
ではないすべて、が(親、子、または兄弟をNode
Sは子供を持つことができ、例えば、 Text
ノードは、ツリー中の最終であり、子供を持つことはない)。 XMLタグはElement
として表され、特に属性関連のメソッドでNode
を拡張します。
DOMインタフェースは、XMLドキュメントをツリーとして「1行」解析し、構築されたツリー(ノードの追加、抑制、コピーなど)の簡単な変更を可能にし、最後にそのシリアル化(ディスクに戻す)後の変更。しかし、これは価格がかかります:ツリーはメモリに常駐しているため、DOMツリーは膨大なXML文書には必ずしも実用的ではありません。さらに、ツリーの構築は、特にXML文書のすべての部分に興味がない場合に、XMLコンテンツを処理する最速の方法であるとは限りません。
SAXインタフェースの原則
SAX APIは、XMLドキュメントを処理するイベント指向のAPIです。このモデルでは、XMLドキュメントのコンポーネントはイベントとして解釈されます(たとえば、「タグが開かれた」、「タグが閉じられた」、「テキストノードに遭遇しました」、「コメントが発生しました」など)。 ..
SAX APIは、「プッシュ・パース」アプローチを使用します。このアプローチでは、SAX Parser
がXMLドキュメントの解釈を担当し、デリゲート( ContentHandler
)のメソッドを呼び出してXMLドキュメント内のイベントを処理します。通常、パーサを書くことはありませんが、XMLドキュメントから必要な情報をすべて収集するハンドラが用意されています。
SAXインターフェイスは、パーサーレベル(たとえば、名前空間のコンテキスト、検証状態)で必要最小限のデータのみを保持することによってDOMインターフェイスの制限を克服します。したがって、開発者が責任を負うContentHandler
によって保持される情報のみメモリに保持される。このようなアプローチでは、「時間を遡って/ XML文書に戻る」方法がないというトレードオフがあります。DOMではNode
が親に戻ることができますが、SAXにはそのような可能性はありません。
StAXインターフェイスの原則
StAX APIは、SAX API(つまりイベント駆動型)と同様にXML処理に似たアプローチを採用していますが、StAXはプル・パーサー(SAXはプッシュ・パーサー)です。 SAXでは、 Parser
は制御され、 ContentHandler
コールバックを使用します。 Staxでは、パーサを呼び出し、次のXML "イベント"を取得するかどうかを制御します。
APIはXMLStreamReader (またはXMLEventReader )で始まります。これは、開発者がイテレータースタイルの方法でnextEvent()
ことができるゲートウェイです。
DOM APIを使用してドキュメントを解析およびナビゲートする
次の文書を検討してください。
<?xml version='1.0' encoding='UTF-8' ?>
<library>
<book id='1'>Effective Java</book>
<book id='2'>Java Concurrency In Practice</book>
</library>
次のコードを使用して、 String
からDOMツリーを構築できます。
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.StringReader;
public class DOMDemo {
public static void main(String[] args) throws Exception {
String xmlDocument = "<?xml version='1.0' encoding='UTF-8' ?>"
+ "<library>"
+ "<book id='1'>Effective Java</book>"
+ "<book id='2'>Java Concurrency In Practice</book>"
+ "</library>";
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
// This is useless here, because the XML does not have namespaces, but this option is usefull to know in cas
documentBuilderFactory.setNamespaceAware(true);
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
// There are various options here, to read from an InputStream, from a file, ...
Document document = documentBuilder.parse(new InputSource(new StringReader(xmlDocument)));
// Root of the document
System.out.println("Root of the XML Document: " + document.getDocumentElement().getLocalName());
// Iterate the contents
NodeList firstLevelChildren = document.getDocumentElement().getChildNodes();
for (int i = 0; i < firstLevelChildren.getLength(); i++) {
Node item = firstLevelChildren.item(i);
System.out.println("First level child found, XML tag name is: " + item.getLocalName());
System.out.println("\tid attribute of this tag is : " + item.getAttributes().getNamedItem("id").getTextContent());
}
// Another way would have been
NodeList allBooks = document.getDocumentElement().getElementsByTagName("book");
}
}
コードは次のようになります。
Root of the XML Document: library
First level child found, XML tag name is: book
id attribute of this tag is : 1
First level child found, XML tag name is: book
id attribute of this tag is : 2
StAX APIを使用した文書の解析
次の文書を検討してください。
<?xml version='1.0' encoding='UTF-8' ?>
<library>
<book id='1'>Effective Java</book>
<book id='2'>Java Concurrency In Practice</book>
<notABook id='3'>This is not a book element</notABook>
</library>
次のコードを使用して、それを解析し、書籍IDごとに書籍タイトルの地図を作成することができます。
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamReader;
import java.io.StringReader;
import java.util.HashMap;
import java.util.Map;
public class StaxDemo {
public static void main(String[] args) throws Exception {
String xmlDocument = "<?xml version='1.0' encoding='UTF-8' ?>"
+ "<library>"
+ "<book id='1'>Effective Java</book>"
+ "<book id='2'>Java Concurrency In Practice</book>"
+ "<notABook id='3'>This is not a book element </notABook>"
+ "</library>";
XMLInputFactory xmlInputFactory = XMLInputFactory.newFactory();
// Various flavors are possible, e.g. from an InputStream, a Source, ...
XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(new StringReader(xmlDocument));
Map<Integer, String> bookTitlesById = new HashMap<>();
// We go through each event using a loop
while (xmlStreamReader.hasNext()) {
switch (xmlStreamReader.getEventType()) {
case XMLStreamConstants.START_ELEMENT:
System.out.println("Found start of element: " + xmlStreamReader.getLocalName());
// Check if we are at the start of a <book> element
if ("book".equals(xmlStreamReader.getLocalName())) {
int bookId = Integer.parseInt(xmlStreamReader.getAttributeValue("", "id"));
String bookTitle = xmlStreamReader.getElementText();
bookTitlesById.put(bookId, bookTitle);
}
break;
// A bunch of other things are possible : comments, processing instructions, Whitespace...
default:
break;
}
xmlStreamReader.next();
}
System.out.println(bookTitlesById);
}
これは、
Found start of element: library
Found start of element: book
Found start of element: book
Found start of element: notABook
{1=Effective Java, 2=Java Concurrency In Practice}
このサンプルでは、いくつかのことを気にする必要があります。
xmlStreamReader.getAttributeValue
使用は、パーサがSTART_ELEMENT
状態にあることを最初に確認したためにSTART_ELEMENT
ます。他の状態(ATTRIBUTES
を除く)では、パーサーはIllegalStateException
をスローしなければなりません。属性は要素の先頭にしか現れないからです。xmlStreamReader.getTextContent()
同じですが、これはSTART_ELEMENT
あり、このドキュメントでは<book>
要素にテキスト以外の子ノードがないことがわかっているため動作します。
より複雑な文書解析(深く、入れ子になった要素など)は、パーサーをサブメソッドや他のBookParser
に「委譲する」( BookParser
クラスやメソッドを持つなど)、すべての要素を処理することをおBookParser
ます書籍のXMLタグのSTART_ELEMENTからEND_ELEMENTまで
Stack
オブジェクトを使用して、重要なデータをツリーの上下に保持することもできます。