Codelogy

XMLライブラリの紹介 (1)

某所からの「Codelogy にエントリを投稿しろ」という圧力が大きくなってきたので、自作の XML ライブラリでも紹介してお茶を濁そうかと思います。 とは言っても、業務に使用しているものなので、ちゃんと使えるレベルには仕上がっています。

XMLファイルの読み込み

まずは、こちらの XML ファイル sample.xml を解析してましょう。 XMLファイルをパース (構文解析) する方法は至極簡単。
クラス xml::Document の静的メンバ関数 load にファイル名を指定するだけです。

#include "xml/xmlDocument.h"
#include "xml/xmlElem.h"
#include "xml/xmlParseException.h"
#include "xml/xmlXMLDecl.h"

int main(){

    try {

        //XML文書の読み込み
        xml::Document* lpDoc =xml::Document::load("sample.xml");

        //文書オブジェクトの開放
        xml::Document::release(lpDoc);
    }
    catch (xml::ParseException& e){
        fprintf(stderr, "%s(%d): %s\n", e.Filename(), e.Line() + 1, e.Message());
    }

    return 0;
}

実行しても画面に何も表示されないので、本当にパース処理ができているか不審に思う方もいるかも知れません。
そこで、あえて「正しくない」XMLを作成し、これを解析させてみます。
ファイル "sample.xml" の25行目にある item 要素の終了タグ

      </item>

を次のように変更してみてください。

      </hoge>

この状態で再度プログラムを実行すると、次のようなエラーメッセージが表示されるはずです。

sample.xml(25): 'hoge' - terminater mismatched to 'item'.

曰く、終了タグ 'hoge' が、開始タグ 'item' と一致しない……ちゃんとパースできていることが分かります。
では、今ほどの変更箇所を元通りに修正して、次に進みましょう。

データの参照

XMLデータをパースできたので、次はその中身を覗いてみましょう。
ルート要素を参照するには、xml::Document オブジェクトから RootElem を呼び出します。
        //ルート要素の参照
        const xml::Elem* lpElem =lpDoc->RootElem();

        //要素名の表示
        printf("Root Element: %s\n", (LPCSTR)lpElem->Name());

        //子ノードの参照
        Array<const xml::Node*> alpNode =lpElem->Children();

        int i;
        for (i=0; i<alpNode.size; ++i){

            if (alpNode[i]->Type() == xml::Elem::ELEMENT){

                const xml::Elem* lpSubelem =dynamic_cast<const xml::Elem>(alpNode[i]);

                printf(
                    "Subelement: %s (type = '%s')\n",
                    (LPCSTR)lpSubelem->Name(),
                    (LPCSTR)lpSubelem->Attr("type"));
            }
        }
Subelement: item (type = 'book')
Subelement: item (type = 'CD')
Subelement: item (type = 'book')
Subelement: item (type = 'videogame')

要素がその内側に持っている子ノードは Children で参照することができます。
要素に含まれるノードには、以下のいずれかになります。

  • 要素 (element)
  • テキストブロック
  • 処理命令 (processing instruction)
  • コメント (comment)

各ノードがこれらのいずれに属するものかは、xml::Node の仮想関数 Type によって知ることができます。

要素が子要素を持ち、その子要素がさらに子 (孫) 要素を持ち……という場合、上記コードのような処理を再帰的に繰り返すことになります。 しかし、それらを何も考えずにだらだらと記述してしまうと、プログラムが長く複雑で見通しの悪いものになるであろうことは想像に難くありません。 そこで次回の記事では、こうした処理をスマートに記述するためのフレームワークを紹介したいと思います。

担当: 成田 (XMLパーサを作ったのは今回で 4度目)

コメントを投稿

コメントの公開は承認制のため、投稿から掲載までに時間がかかることがあります。


About

2007年12月09日 17:00 に投稿されたエントリです。

他にも多くのエントリがあります。
メインページアーカイブページもご覧ください。