Xerces/Xalan-C++ で XML

XMLCh 型と char 型の変換をカプセル化しよう

最終更新: 2015-03-31 (火) 22:05:09 (1359d)

概要

このページで説明するコード

注意

unsigned int 型となっている箇所を XMLSize_t に変更した。

これは Xerces-C++ 3.0.0 以降のリリースに影響しての変更である。

Xerces-C++ 2 系の利用者は、XMLSize_t を unsigned int と読み替えること。

XMLSize_t 型について調査した結果は以下のブログ記事にて言及している

fileフルセット(VC++ 6.0/Xerces-C++ 2 系用)では unsigned int を用いているが、それ以外のファイルは XMLSize_t を利用している。

補足

本コンテンツ内で技術的解説を加えた上で公開しているクラスをユーティリティーとしてオープンソースとして sourceforge.jp で公開する。

利用を検討する方は以下のサイトを参考のこと。

XMLCh型からchar型へ変換するクラスを作る

変換そして破棄

XMLCh 型から char 型への変換は、通常 XMLString::transcode メソッドを使って行う。 変換後に得られた char 型の文字列は、使い終わった後に XMLString::release メソッドを使って破棄しなければならない。 Xerces-C++ を使ったプログラムでは頻繁に文字列の変換を行う必要があるため、 変換・破棄の繰り返し記述が面倒だ。 そこでこの変換・破棄を XMLCh2Char というクラスに隠蔽してしまおう。 XMLCh2Char クラスの定義として、fileXMLCh2Char.hpp の一部を以下に示す。

class XMLCh2Char {
private:
  char* buffer_;

public:
  explicit XMLCh2Char(const XMLCh* const buffer) {
    buffer_=xercesc::XMLString::transcode(buffer);
  }

  ~XMLCh2Char() {
    xercesc::XMLString::release(&buffer_);
  }

  // ...
};

XMLCh2Char クラスは、コンストラクタで XMLCh 型のデータを char 型のデータに変換し、 デストラクタでそのデータを破棄する。

便利なメソッドの追加

このままでは使いづらいので、使い勝手を良くするために二つのメソッドを追加する。 XMLCh2Char クラスの定義として、fileXMLCh2Char.hpp の一部を以下に示す。

class XMLCh2Char {
public:
  // ...

  operator const char* const () const {
    return buffer_;
  }

  friend static std::ostream& operator<<(std::ostream& stream, const XMLCh2Char& buffer) {
    return stream << (const char* const)buffer;
  }
};

一つは char* 型へのキャスト演算子で、もう一つは出力ストリームへの << 演算子だ。 これを定義しておくことで、XMLCh 型から char 型への変換関数みたいない感じで XMLCh2Char クラスを使うことが可能になる。

strcat(buffer, XMLCh2Char(xmlch));   // strcat(buffer, XMLCh2Char(xmlch).buffer);と同じ
std::cout << XMLCh2Char(xmlch);  // std::cout << XMLCh2Char(xmlch).buffer;と同じ

コピーコンストラクタと代入演算子の禁止

最後に、buffer_ の二重解放が行われないようにするためにコピーコンストラクタと代入演算子を禁止する。

class XMLCh2Char {
private:
  explicit XMLCh2Char(const XMLCh2Char& ch);
  XMLCh2Char& operator=(const XMLCh2Char& ch);
};

XMLCh2Char クラスを使う

SAXで単純なプログラミングで紹介したプログラムを XMLCh2Char クラスを使って書き直してみよう。 SampleHandler クラスの startElement メソッドの定義として、 fileSampleHandler.cpp の一部を以下に示す。

void SampleHandler::startElement(const XMLCh* const uri, const XMLCh* const localname,
                                 const XMLCh* const qname, const Attributes& attrs) {
  cout << "start  : " << XMLCh2Char(localname) << endl;
}

とってもすっきりした。

char 型から XMLCh 型へ変換するクラスを作る

XMLCh 型から char 型への変換をカプセル化するクラスとして XMLCh2Char クラスを作ったが、 その逆、char 型から XMLCh 型への変換も同じようにカプセル化する Char2XMLCh クラスを作ることができる。 Char2XMLCh クラスがあると、

void SampleHandler::startElement(const XMLCh* const uri, const XMLCh* const localname,
                                 const XMLCh* const qname, const Attributes& attrs) {
  XMLCh* attributeName=XMLString::transcode("attribute1");
  const XMLCh* value=attrs.getValue(attributeName);
  XMLString::release(attributeName);
  if(value!=0) {
    cout << "attribute1 : " << XMLCh2Char(value) << endl;
  }
}

のようにタグの属性名を指定して属性値を取得するようなプログラムを、 以下のように書けるようになる。

void SampleHandler::startElement(const XMLCh* const uri, const XMLCh* const localname,
                                 const XMLCh* const qname, const Attributes& attrs) {
  const XMLCh* value=attrs.getValue(Char2XMLCh("attribute1"));
  if(value!=0) {
    cout << "attribute1 : " << XMLCh2Char(value) << endl;
  }
}

以上の例は、attribute1 属性を出力するプログラムであるが、 属性を取得には Attributes クラスの getValue メソッドを使う。 getValue メソッドは、XMLCh 型の文字列で属性名を指定しなければいけないことから char 型の文字列を XMLCh 型に変換するための処理を Char2XMLCh クラスにカプセル化することで 記述を簡潔に済ますことができる。

コメント

コメントはありません。 コメント/xerces/capsulize/string

お名前: