TinyXML2を使ってみる

ダウンロード先
https://github.com/leethomason/tinyxml2/issues/37

XMLパーサーについて

XMLにかかれてあるデータ構造を自分できっちりしっていないと、そのデータにたどり着くことができないので、XMLを読み込んだらなんかいい感じにデータにアクセスできるようになることはない。

コツとしては自分の作ったXMLフォーマットのデータを読み込むのを便利にしてくれるダケのものというイメージでいたほうが良い。実際<>で括られたテキストをパースするのはとても面倒なので、それだけでありがたいモノ。それ以上のことを期待してはいけない。

サーバーから出力される情報を読み取ったりするのに便利

以下、インストールして使うところまで。

error C2872: 'XMLDocument': あいまいなシンボルです。

ソースをダウンロードしてきて、gxLibと同じフォルダに「tinyxml2.cpp」「tinyxml2.h」を配置してコンパイルする。びっくりするほど簡単だが、なぜかエラーが発生。Win32環境では「WIN32_LEAN_AND_MEAN」の定義がないと不都合があるようなので、ソースの一番最初かプリプロセッサに以下を定義するとコンパイルは通る。

#define WIN32_LEAN_AND_MEAN

XMLファイルの読み込み

tinyxml2::XMLDocument xml;
xml.LoadFile( "test.xml" );

XMLファイルを文字列から読み込み

const char * pXMLdoc = "<title>Test Title</title>";
tinyxml2::XMLDocument xml;
xml.Parse( pXMLdoc );

データへのアクセス

XMLデータ

<dir1>
<data1>データ</data1>
<data2>データ</data2>
</dir1>

ソースコード
XMLElement* root = xml.FirstChildElement( dir1 );

とりあえず手持ちのXMLに定義されているしょっぱなのノード名(dir1)を確認して、これで取得できる。ただしXML側の「dir1/data1/」に対して以下の様な記述はダメ(親ノードをすっ飛ばしてる)

XMLElement* root = xml.FirstChildElement( "data1" );

コレもダメ(パスは繋げない)

XMLElement* root = xml.FirstChildElement( "dir1/data1" );

これが正しい

XMLElement* data1 = root ->FirstChildElement( "data1" );

データの取得

基本的に全てテキストで得られる。データがないもの(ディレクトリなど)はNULLが返る

const char* txt = data1->GetText();

次のデータを得る

複数のデータがある場合には、NextSiblingElementを使って取得する。

XML

<food>
  <fruits>
     <data>りんご<data>
  </fruits>

  <fruits>
     <data>めろん<data>
  <fruits>
</food>

プログラム

XMLElement* food   = xml.FirstChildElement( "food" );
XMLElement* fruits = food->FirstChildElement( "fruits" );

fruits = fruits->NextSiblingElement( "fruits" );
gxLib::DebugLog( "%s" , fruits->GetText() );

結果

めろん

こうする。「フルーツ」が自分自身のポインタをつかって次の「フルーツ」を探すイメージ。NextSiblingElementでNULLが返ってくるまではデータがある。

while( gxTrue )
{
 fruits = fruits->NextSiblingElement( "fruits" );
 if( fruits == NULL ) break;
 gxLib::DebugLog( "%s" , fruits->GetText() );
}