nlib
nn::nlib::exi 名前空間

バイナリXMLパーサー(とXMLパーサー)が実装されています。 [詳解]

クラス

class  ExiAllocator
 XMLパーサーが内部で利用するアロケータです。ユーザーが利用することもできます。 [詳解]
 
class  ExiAllocatorEx
 XmlStreamReader, XmlStreamWriter の各インスタンス毎に設定できるアロケータです。 [詳解]
 
class  ExiErrorStatus
 XMLパーサーのエラー状態を設定・格納します。 [詳解]
 
class  Preserve
 読み書きするバイナリXMLのデータ保持オプションです。 [詳解]
 
class  XmlStreamReader
 XMLストリームからの読み出しを行う抽象クラスです。 [詳解]
 
class  XmlStreamReaderSettings
 XmlStreamReaderの初期化オプションとなる構造体です。 [詳解]
 
class  XmlStreamWriter
 XMLのストリームへの書き出しを行う抽象クラスです。 [詳解]
 
class  XmlStreamWriterSettings
 XmlStreamWriter の初期化オプションとなる構造体です。 [詳解]
 

型定義

typedef wchar_t ExiChar
 XMLパーサーの内部文字列型のtypedefです。 [詳解]
 

列挙型

enum  Alignment {
  ALIGNMENT_BIT_PACKED = 0,
  ALIGNMENT_BYTE_ALIGNMENT = 1
}
 読み書きするバイナリXMLのアライメントを指定します。 [詳解]
 
enum  XmlProcessor {
  XML_PROCESSOR_EXI = 0,
  XML_PROCESSOR_TEXT
}
 利用するXmlプロセッサの指定オプションです。 [詳解]
 

関数

bool TransformXml (XmlStreamReader *r, XmlStreamWriter *w) noexcept
 XmlStreamReaderから読み込んで、XmlStreamWriterへ書き出します。 [詳解]
 

詳解

バイナリXMLパーサー(とXMLパーサー)が実装されています。

exiライブラリについて

exiライブラリはXMLの読み書きを効率的に行うためのライブラリで、バイナリ形式とテキスト形式で表現されたXMLを読み書きすることができます。 バイナリ形式にすることによって、XMLを採用した場合に問題となってきたサイズの冗長性や処理の重さといった問題を緩和できるので、XMLを利用するメリットはそのままに、リスクは大幅に減少させることができます。また、ネットワーク帯域の利用を節約することもできます。
読み書きするバイナリフォーマットはW3C EXIという標準化されたもので、exiライブラリはW3C EXIを部分的に実装しています。 W3C EXIについてはこちらを参照してください。

exiライブラリの特長

exiライブラリには以下のような特長があり、ネットワーク帯域やCPUのオーバーヘッドの制約が厳しい条件の中でXMLを取り扱うことに向いています。
XMLをコンパクトに表現できること
XMLの短所としてよく挙げられるのが冗長性ですが、exiライブラリでバイナリ表現を用いることによって、一般的なXMLで大体1/3から1/4程度のサイズにできるようです。 手法としてはXML文書内で出てきた文字列にインデックスを割り当ててデータ量を削減しています。
例で表現すると以下のようになります。 この例は単純化しているので若干正確ではありませんが、その他いろいろな方法でデータサイズが削減されています。
<books>
<book>
<title>...</title>
<author>...</author>
<isbn>...</isbn>
</book>
<book>
<title>...</title>
<author>...</author>
<isbn>...</isbn>
</book>
....
</bools>
上記のXMLは、以下のようにIDを割り当てる形で書き出されています。
<$1=books>
<$2=book>
<$3=title>...</>
<$4=author>...</>
<$5=isbn>...</>
</>
<$2>
<$3>...</>
<$4>...</>
<$5>...</>
</>
....
</>
高速であること
より小さいデータサイズでXMLが表現されているので、同じXMLを取り扱った際のネットワークの転送速度やストレージからの読み取り速度が高速になります。 また、exiライブラリはXMLをメモリにおいてからパースした場合でも、expatやXmlLiteといった一般に高速に動作すると言われているXMLパーサーと同等かそれ以上の動作速度を達成しています。
名前空間をサポートしていること
高速なXMLパーサーの実装では名前空間を全くサポートしていなかったりすることがありますが、exiライブラリは名前空間をサポートしています。 一般にオーサリングツールは名前空間つきのXMLを出力しますが、そのようなXMLを扱うためには名前空間がサポートされていることが必要です。
テキストのXMLを扱うより安全なこと
バイナリXMLのフォーマット自体が、テキストのXMLに比べて改竄やのぞき見といったことが難しくなっています。 また、不正なデータを送りつけてXMLパーサーを落としたり、システムを麻痺させたり、といったことも難しくなっています。
  • テキストのXMLに比べてデータの改竄は難しくなっています。バイナリXMLでは後に来るデータの解析ルール(文法)は既に読み込んでいるデータに依存するので、XML文書の一部だけを改竄する、といったことは難しくなっています。バイト単位ではなくビット単位のフォーマットであることも改竄を難しくしています。
  • 利用前にXMLパーサーが割り当てられるメモリ量を決めるようになっているので、不正なXML(例えば非常に長い要素名をもたせたXML)でシステムのメモリを食い尽くす、といったことができないようになっています。
  • XML属性の解析は \(O(n)\)です。古いXMLパーサーの多くは \(O(n^2)\)で解析していたため、DDOSの標的になっていたこともあります。
  • exiライブラリではDTDはサポートされていません。そのためDTDを利用したXML爆弾を作ることは不可能です。

exiライブラリの使い方

バイナリXMLの書き出し
XmlStreamWriterを構築してバイナリXMLを書きだすことができます。
バイナリXMLの読み込み
XmlStreamReaderを構築してバイナリXMLを読み込むことができます。 JavaのStAX(Streaming API for XML)や.NET FrameworkのXmlReaderと同種のPull Parsingが実現されていて、DOMやSAXを使うよりも簡単にプログラミングができます。
Pull Parsingの特長としては、以下を挙げることができます。
  • SAXのようにクラスを作成する必要がなく、while文とswitch文で平易に情報を取り出すことができます。
  • DOMよりも高速でメモリを消費しません。
  • 再帰下降パーサーを実装できます。これは特にXMLを利用して簡易言語を実装したい場合に有利です。
コマンドラインプログラムによるXMLとバイナリXML間の変換
nexiconv.exeを用いることによりXMLとバイナリXMLの相互変換が可能です。 以下のようにすることで、XMLファイルをバイナリXMLファイル(拡張子 .exi)に変換することができます。
nexiconv.exe .xmlを拡張子に持つファイル
また、以下のようにすることでバイナリXMLファイルをXMLファイルに変換することができます。
nexiconv.exe .exiを拡張子に持つファイル
なお、このプログラムは内部でxmllite.dllを利用しています。 大抵の場合、お使いのマシンに既にインストールされているはずです。

今後の開発について

実装されるかどうかは未定ではありますが、XMLの応用範囲はとても広いです。 例えば、以下のようなことが考えられます。
  • XMLスキーマへの対応。XMLスキーマの情報を利用することによって、バイナリXMLのサイズをより小さくすることが可能です。これはW3C EXIの仕様を満たしていく形になります。
  • ポインタや継承に対応した本格的なXMLシリアライザの実装。
  • XML-RPCのサポート。バイナリXMLによりXML-RPCを高効率でサポートすることにより、異なるプロセス・異なるアプリケーション・異なるデバイス・サーバーの機能を同じインターフェイスで呼び出せるようにすることが現実的に可能であると思われます。
  • リッチテキストフォーマット、画面のレイアウト、といった構造化されていないデータの記述に向いています。
  • アプリケーション間で共有するようなデータの記述フォーマットとしての利用に適しています。以下のような理由を挙げることができます。
    • フォーマットの拡張が簡単なことと、フォーマットの拡張に対応できるようなプログラムを作成することが簡単なこと
    • データを読み書きするプログラム(データ構造のヘッダ)を共有しなくても済むこと。
    • (XMLなので)フォーマットの仕様を簡単に記述でき、理解できること。

W3C EXI(Efficient XML Interchange)について

XMLは強力なデータ表現形式ですが、冗長なためデータサイズが肥大化しやすく処理の負荷が高いのが難点でした。 そのため、オーバーヘッドが許容されにくい環境では今まで利用が遅れていました。
このような問題を解決するために、以下のような対策が取られてきました。
  • XMLをgzipで固めてやりとりする。
  • 各種の独自バイナリXML表現を利用する。
    • WBXML(Wireless Binary XML)。WAPでサポートされた。
    • AMF3(Action Message Format 3)。Adobeによる。
    • FastInfoset(Java)
    • 各社データベース製品でのサポート(Oracle, Microsoft)
しかしながら、標準的なバイナリXMLフォーマットは存在していませんでした。
そのような中、バイナリXMLのフォーマットであるEXI(Efficient XML Interchange Format 1.0)が2011年3月にWeb技術の標準化団体であるW3C(World Wide Web Consortium)により正式に勧告されました。 EXIは「エクシィ」と読むようです。
フォーマットの仕様は http://www.w3.org/TR/exi/ に記載されています。
残念ながら日本語訳は現在のところ存在しないようです。 日本語の紹介記事は、 http://www.publickey1.jp/blog/11/xmlexiw3c_1.html にあります。
W3C EXIのが利用されている、これから利用される例としては、 http://www.w3.org/2011/03/exi-pr.html.en に、以下のようなことが書かれています。
  • スマートグリッド内のメーターや電気自動車間のデータのやりとり
  • 証券取引システム内でのデータのやりとりのスピードアップ
  • 軍事関係のアプリケーション

テキストXMLパーサーについて

バイナリXMLパーサーのフロントエンドを置き換えることでテキストXMLパーサーが実装されています。 この方法によりexiライブラリではコードサイズをあまり増やすことなく、バイナリXMLパーサーとテキストXMLパーサーの両方をサポートしています。
テキストXMLパーサーは非検証XMLパーサーで、XML 1.0に概ね準拠しています。 以下にXML 1.0に準拠していない項目で現在知られているものを列挙しておきます。
  • UTF-16の読み込みはサポートされていません。UTF-8のみで動作します。
  • XML宣言内のエンコーディング宣言は無視されます。
  • 文書型定義を読み飛ばしますが、文書型定義内部でのエラーチェックは省略される場合があります。 http://www.w3.org/XML/Test/ からダウンロードできるテストデータのパース結果は次の通りです。
0がパース成功(文法エラーを報告しなかった)、1がパース失敗(文法エラーを報告した)です。

型定義詳解

§ ExiChar

XMLパーサーの内部文字列型のtypedefです。

説明
chartypedefされている場合はUTF-8, wchar_ttypedefされている場合はUTF-16又はUTF-32です。
各種例:
exi/script/script.cpp, exi/serializer/serializer.cpp, exi/simple1/simple1.cpp, exi/simple2/simple2.cpp.

Types.h23 行目に定義があります。

列挙型詳解

§ Alignment

読み書きするバイナリXMLのアライメントを指定します。

説明
詳細は、 http://www.w3.org/TR/exi/#options を参照してください。
列挙値
ALIGNMENT_BIT_PACKED 

ビット単位にデータが詰められたEXIストリームを読み書きします(デフォルト)。

ALIGNMENT_BYTE_ALIGNMENT 

バイトアラインされたEXIストリームを読み書きします。

Types.h32 行目に定義があります。

§ XmlProcessor

利用するXmlプロセッサの指定オプションです。

列挙値
XML_PROCESSOR_EXI 

バイナリXMLの利用

XML_PROCESSOR_TEXT 

テキストXMLの利用

Types.h49 行目に定義があります。

関数詳解

§ TransformXml()

nn::nlib::exi::TransformXml ( XmlStreamReader r,
XmlStreamWriter w 
)
noexcept

XmlStreamReaderから読み込んで、XmlStreamWriterへ書き出します。

引数
[in]r入力となるXMLを読み込むストリーム
[in]wXMLの出力先となるストリーム
戻り値
成功した場合はtrue
説明
この関数を使うことにより、バイナリのXMLを読み込んでテキストのXMLに変換したり、その逆の操作を行うことが可能です。