サーチ…


備考

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}

このサンプルでは、​​いくつかのことを気にする必要があります。

  1. xmlStreamReader.getAttributeValue使用は、パーサがSTART_ELEMENT状態にあることを最初に確認したためにSTART_ELEMENTます。他の状態( ATTRIBUTESを除く)では、パーサーはIllegalStateExceptionをスローしなければなりません。属性は要素の先頭にしか現れないからです。

  2. xmlStreamReader.getTextContent()同じですが、これはSTART_ELEMENTあり、このドキュメントでは<book>要素にテキスト以外の子ノードがないことがわかっているため動作します。

より複雑な文書解析(深く、入れ子になった要素など)は、パーサーをサブメソッドや他のBookParserに「委譲する」( BookParserクラスやメソッドを持つなど)、すべての要素を処理することをおBookParserます書籍のXMLタグのSTART_ELEMENTからEND_ELEMENTまで

Stackオブジェクトを使用して、重要なデータをツリーの上下に保持することもできます。



Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow