1. 概要

SAXは、 Simple API for XML とも呼ばれ、XMLドキュメントの解析に使用されます。

このチュートリアルでは、SAXとは何か、SAXを使用する理由、時期、方法について学習します。

2. SAX :XML用のシンプルなAPI

SAXは、XMLドキュメントの解析に使用されるAPIです。 は、ドキュメントの読み取り中に生成されたイベントに基づいています。 コールバックメソッドはこれらのイベントを受け取ります。 カスタムハンドラーには、これらのコールバックメソッドが含まれています。

APIは、コールバックがイベントを受信した直後にイベントをドロップするため、効率的です。 したがって、 SAXは、たとえばDOMとは異なり、効率的なメモリ管理を備えています。

3. SAXとDOM

DOMはDocumentObjectModelの略です。 DOMパーサーはイベントに依存しません。 さらに、XMLドキュメント全体をメモリにロードして解析します。 SAXはDOMよりもメモリ効率が高くなります。

DOMにも利点があります。 たとえば、DOMはXPathをサポートしています。 また、ドキュメントがメモリにロードされるため、ドキュメントツリー全体を一度に操作することも簡単になります。

4. SAXとStAX

StAXはSAXやDOMよりも新しいものです。 Streaming API forXMLの略です。

SAXとの主な違いは、 StAXがSAXのプッシュメカニズム(コールバックを使用)の代わりにプルメカニズムを使用することです。 これは、イベントをプルする必要があるタイミングを決定するための制御がクライアントに与えられることを意味します。 したがって、ドキュメントの一部のみが必要な場合は、ドキュメント全体をプルする義務はありません。

これは、メモリ効率の高い解析方法でXMLを操作するための簡単なAPIを提供します。

SAXとは異なり、その機能の1つとしてスキーマ検証を提供しません。

5. カスタムハンドラーを使用したXMLファイルの解析

ここで、BaeldungWebサイトとその記事を表す次のXMLを使用してみましょう。

<baeldung>
    <articles>
        <article>
            <title>Parsing an XML File Using SAX Parser</title>
            <content>SAX Parser's Lorem ipsum...</content>
        </article>
        <article>
            <title>Parsing an XML File Using DOM Parser</title>
            <content>DOM Parser's Lorem ipsum...</content>
        </article>
        <article>
            <title>Parsing an XML File Using StAX Parser</title>
            <content>StAX's Lorem ipsum...</content>
        </article>
    </articles>
</baeldung>

まず、Baeldungルート要素とその子のPOJOを作成します。

public class Baeldung {
    private List<BaeldungArticle> articleList;
    // usual getters and setters
}
public class BaeldungArticle {
    private String title;
    private String content;
    // usual getters and setters
}

BaeldungHandlerを作成して続行します。 このクラスは、イベントをキャプチャするために必要なコールバックメソッドを実装します。

スーパークラスDefaultHandlerの4つのメソッド、それぞれがイベントを特徴付けるメソッドをオーバーライドします。

    • characters(char []、int、int)は、境界のある文字を受け取ります。 それらをStringに変換し、BaeldungHandlerの変数に格納します。
    • startDocument()は、解析の開始時に呼び出されます。これを使用して、Baeldungインスタンスを構築します。
    • startElement() 要素の解析が開始されると呼び出されます–これを使用していずれかを構築しますリストまた BaeldungArticle インスタンス– qName 両方のタイプを区別するのに役立ちます
    • endElement()は、要素の解析が終了したときに呼び出されます。これは、タグのコンテンツをそれぞれの変数に割り当てるときです。

すべてのコールバックが定義されたので、BaeldungHandlerクラスを記述できます。

public class BaeldungHandler extends DefaultHandler {
    private static final String ARTICLES = "articles";
    private static final String ARTICLE = "article";
    private static final String TITLE = "title";
    private static final String CONTENT = "content";

    private Baeldung website;
    private StringBuilder elementValue;

    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        if (elementValue == null) {
            elementValue = new StringBuilder();
        } else {
            elementValue.append(ch, start, length);
        }
    }

    @Override
    public void startDocument() throws SAXException {
        website = new Baeldung();
    }

    @Override
    public void startElement(String uri, String lName, String qName, Attributes attr) throws SAXException {
        switch (qName) {
            case ARTICLES:
                website.articleList = new ArrayList<>();
                break;
            case ARTICLE:
                website.articleList.add(new BaeldungArticle());
                break;
            case TITLE:
                elementValue = new StringBuilder();
                break;
            case CONTENT:
                elementValue = new StringBuilder();
                break;
        }
    }

    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        switch (qName) {
            case TITLE:
                latestArticle().setTitle(elementValue.toString());
                break;
            case CONTENT:
                latestArticle().setContent(elementValue.toString());
                break;
        }
    }

    private BaeldungArticle latestArticle() {
        List<BaeldungArticle> articleList = website.articleList;
        int latestArticleIndex = articleList.size() - 1;
        return articleList.get(latestArticleIndex);
    }

    public Baeldung getWebsite() {
        return website;
    }
}

読みやすさを向上させるために、文字列定数も追加されました。 最新の記事を取得する方法も便利です。 最後に、Baeldungオブジェクトのゲッターが必要です。

メソッド呼び出しの合間に状態を保持しているため、上記はスレッドセーフではないことに注意してください。

6. パーサーのテスト

パーサーをテストするために、 SaxFactory SaxParser 、およびBaeldungHandlerをインスタンス化します。

SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser saxParser = factory.newSAXParser();
SaxParserMain.BaeldungHandler baeldungHandler = new SaxParserMain.BaeldungHandler();

その後、XMLファイルを解析し、解析されたすべての予期される要素がオブジェクトに含まれていることを表明します。

saxParser.parse("src/test/resources/sax/baeldung.xml", baeldungHandler);

SaxParserMain.Baeldung result = baeldungHandler.getWebsite();

assertNotNull(result);
List<SaxParserMain.BaeldungArticle> articles = result.getArticleList();

assertNotNull(articles);
assertEquals(3, articles.size());

SaxParserMain.BaeldungArticle articleOne = articles.get(0);
assertEquals("Parsing an XML File Using SAX Parser", articleOne.getTitle());
assertEquals("SAX Parser's Lorem ipsum...", articleOne.getContent());

SaxParserMain.BaeldungArticle articleTwo = articles.get(1);
assertEquals("Parsing an XML File Using DOM Parser", articleTwo.getTitle());
assertEquals("DOM Parser's Lorem ipsum...", articleTwo.getContent());

SaxParserMain.BaeldungArticle articleThree = articles.get(2);
assertEquals("Parsing an XML File Using StAX Parser", articleThree.getTitle());
assertEquals("StAX Parser's Lorem ipsum...", articleThree.getContent());

予想どおり、 baeldung は正しく解析され、待機中のサブオブジェクトが含まれています。

7. 結論

SAXを使用してXMLファイルを解析する方法を発見しました。 これは、アプリケーションで軽いメモリフットプリントを生成する強力なAPIです。

いつものように、この記事のコードはGitHubから入手できます。