赤紫蘇2.リファレンス

概要

akaxiso2.0-beta2


はじめに

赤紫蘇2は、C++のクラスをXML形式に、シリアライズ、デシリアライズするためのライブラリです。

シリアライザブルな値クラスは、ユーザにより定義され、XMLスキーマに準じたデータの構造をもつことができる上に、データ構造を記述するクラスとして、可能な限り、赤紫蘇2を含め、他のライブラリに依存するクラスを用いないよう設計しています。

また、ライブラリ本体は、STLベースで実装されており、XMLパーサ、エンコーディング変換エンジンも含まれています。このため、標準C++が動作する環境では、そのまま使用することが可能です。

XMLパーサレベルでの、より、厳密な妥当性検証が必要な場合には、妥当性検証XMLパーサであるXerces-C++を使用することも可能です。

シリアライザブルな値クラスへの要請

以下の要請を満たすクラスが、シリアライザブルとなります。

  • DefaultConstructiveであること。
    • A a; などの形でインスタンシングできること。
    • 引数つきのコンストラクタのみを持っている場合はダメ。
  • CopyConstructiveであること。
    • コピーコンストラクタが使えること。
    • class A { private: A(const A&); }; などとして、コピーコンストラクタが遮蔽されている場合はダメ。

値クラスは、通常のクラスです。通常のクラス、構造体が使用可能です。ただし、値クラスのメンバに対し、後述するXML型情報クラス(leafクラス)がアクセスできる必要があります。

上記以外には、特別の制約はなく、自由なクラス定義を行うことが可能です。

赤紫蘇2は、シリアライザブルな値クラスを(デ)シリアライズするための機能を、二つの名前空間aka::、xiso::内に実装しています。

シリアライザブルな値クラスは、任意の名前空間内、もしくは、グローバル名前空間内にて、宣言することができます。
また、値クラスを(デ)シリアライズするためのXML型情報クラスを別個は定義されます。このクラスをleafクラスと呼び、通常は、xiso::名前空間内で定義します。値クラスのデータモデルの構造、タグ名とメンバや要素の対応、出現頻度などの型情報が、leafクラス内で定義されます。

aka::名前空間内には、シリアライザブルな値クラスと、XML型情報クラス(leafクラス)の二つのクラスを結び合わせ、値クラスのメンバ、子要素へのアクセスとタグ名の関連付けを行い、XML形式への変換、逆変換を行うための実装が収められています。また、デシリアライズ時に、赤紫蘇のデータモデルによる妥当性検証を行います。

簡単な定義の例

簡単な例として、以下のクラスfooを値クラスとして用いた場合の、(デ)シリアライズについて説明します。

struct foo {
  long value1_;
  long value2_;
};
上記のクラスが、
<?xml version="1.0"?>
<foo>
 <value1>15</value1>
 <value2>20</value2>
</foo>

とシリアライズされるように、XML型情報クラス(以降 leafクラス)を定義します。

まず、要素が<value1>、<value2>と順に出力されますので、xs:sequence型に対応させます。このための、leafクラスの定義は、以下の二つのスタイルで行うことができます。

  • スタイル1
//宣言
namespace xiso {
  template<>
    struct leaf<foo> : aka::sequence<foo> {
      void model(); // 型定義メソッド
};

//実装
void xiso::leaf<foo>::model() {
  member("value1", &foo::value1_);
  member("value2", &foo::value2_);
};

struct leaf<foo>は、aka::sequence<>テンプレートを継承しており、データモデルをsequence型として処理します。void model()メソッド中で、タグ名とメンバを対応付けています。

赤紫蘇2では、leafクラスを定義するための名前空間として、namespace xiso を定義しています。スタイル1では、これを利用して定義を行っています。
もともとのleafクラスの宣言は、以下の通りです。

namespace xiso {
  template<class T>
  struct leaf<T>;
};

上記のclass Tに、struct fooがテンプレート引数として与えられることにより、struct fooに対するleafクラスとして、xiso::leaf<foo>クラスが対応付けられます。

  • スタイル2
//宣言
struct foo_leaf : aka::sequence<foo, foo_leaf> {
  void model() { // 型定義用メソッド
    member("member1", &foo::member1);
  }
};

//実装
void::model() { 
  member("member1", &foo::member1_);
}

スタイル2では、namespace xisoを用いず、明示的に、leafクラスの型を指定しています。

スタイル2は、ひとつの型を二つ以上の形式で(デ)シリアライズする場合に必須となります。
たとえばchar型のメンバの(デ)シリアライズを行う際に、1文字として扱う場合、-128〜127の数値として扱う場合の両者があります。

スタイル1では、ひとつのクラスに対して、ひとつのleafクラスしか定義できないため、二通りの扱い、つまり、同じクラスに対するleafクラスを、別々に、二つ定義することができません。スタイル2では、ひとつの型に対してleafクラスを二つ以上、別個に定義することができます。char型の例では、値を数値として扱うleafクラス、一文字として扱うleafクラスをそれぞれ定義することにより、ひとつの型に対し、二通りの方法で、(デ)シリアライズを行うことが可能となります。

単純型以外のleafクラスは、常にmodel()メソッドを持ち、内部で、以下の項目を定義します。

  • パーティクル定義(xs:sequence、xs:choice、xs:allなど)
  • タグ名とメンバ値(xs:sequence, xs:all)、子要素値(xs:choice)の対応
  • 出現頻度(minOccurs, maxOccurs)
  • グループ参照(xs:group)

ドキュメントの宣言

ドキュメントの宣言は、aka::doctype()関数をもちいて、leafクラスとドキュメントのタグ名を対応付けることで行います。

たとえば、上述のfooクラスのドキュメントを宣言するには、以下のように、aka::doctype()関数を呼び出します。

  • スタイル1
aka::doctype("foo", xiso::leaf<foo>());
  • スタイル2
aka::doctype("foo", foo_leaf());

シリアライズ・デシリアライズ

以上の準備ができたところで、struct fooは、(デ)シリアライズ可能となります。

シリアライズは、aka::xml_serializerクラスを用いて行います。以下に、fooクラスのインスタンスである f をシリアライズし、std::cout(stdout)に出力する方法を示します。

struct foo f;
 : fの値設定を行う。
aka::xml_serializer serializer;
serializer.serialize(f, "foo", std::cout);

デシリアライズを行うためには、aka::deserialize()関数を用いるか、aka::xml_deserializerクラスを用いることができます。戻り値は、aka::documentクラスのインスタンスとなります。

aka::document doc = aka::deserialize(std::cin);
if (aka::document_of(doc, "foo")) {
  const foo *f = aka::root_cast<foo>(doc);
}
else {
  std::cerr << "Unknown document." << std::endl;
}

aka::document のインスタンスから、デシリアライズされたドキュメントのインスタンスを取得するためには、aka::root_cast<>、もしくは、aka::adopt_root<>を使用します。詳細は、APIリファレンスをご参照ください。

概要・まとめ

以上、簡単ですが、赤紫蘇2におけるXMLを用いたC++クラスの(デ)シリアライズについて、説明しました。

赤紫蘇2は、データ構造の記述を行うための、赤紫蘇データモデルを定義しています。このデータモデルを使用することで、さらに、詳細なデータ構造の構築、(デ)シリアライズを可能とします。以後、本リファレンスでは、赤紫蘇データモデルを詳細に解説します。


リファレンストップへ 赤紫蘇2トップへ sourceforgeプロジェクトページへ