C++の応用 - XML

提供:MochiuWiki : SUSE, EC, PCB
ナビゲーションに移動 検索に移動

概要

XMLは構造化データを表現するための主要な方式として、現在でも幅広く使用されている。
しかしながら、その状況には変化がみられる。

  • JSONの台頭
    JSONがより簡潔で可読性が高いことから、データ交換フォーマットとしてXMLに代わり人気が高まっている。
    JSONは軽量でパースが簡単なため、Web APIやモバイルアプリ等で多用されている。

  • XMLの用途の変化
    現在、XMLはより特殊な用途に特化する傾向にある。
    例えば、OFFICEファイルの内部フォーマット(OOXML)、SVGグラフィックス、RSSフィード、APIDocs(Swagger等)が挙げられる。
    構造化データフォーマットとしての役割は、JSONに移行しつつある。

  • XMLスキーマの発展
    XMLスキーマ言語の分野では、XMLスキーマ自体に加えてRelaxNG等の新しい選択肢が出てきた。
    リッチでマシンフレンドリーなXMLの定義が可能になり、より発展したスキーマ検証を実現している。

  • 標準化の成熟
    XML自体の基本仕様は成熟しているため、主要な標準規格は安定している。
    XMLに関する新しい提案は減少しつつあり、標準化活動は継続的な改善に移行している。


XMLは構造化データの表現において中核を成す役割を担いつつも、その用途と周辺技術は進化を続けている。

C++で利用可能なXMLライブラリには、以下に示すようなものがある。

  • Xerces-C++
    Apacheプロジェクトによる広く使用されている信頼性の高いXMLライブラリである。
    DOM、SAX等のXMLパーサ、XMLスキーマ検証機能を備えている。

  • TinyXML
    軽量でシンプルなXMLパーサライブラリである。
    単一のC++ソースファイルで構成されるため、簡単に統合できる。
    DOMスタイルのAPIを提供している。

  • RapidXML
    非常に高速で軽量なXMLパーサライブラリである。
    メモリ使用量が少なく、パフォーマンスが高い。
    ヘッダファイルのみで使用できる。

  • Pugi XML
    高速で軽量かつ充実した機能があるXMLライブラリである。
    XPathのサポートやXML編集機能を持つ。
    ヘッダファイルのみで使用できる。



Xerces-C++ライブラリ

Xerces-C++ライブラリとは

Apache XMLプロジェクトにより開発されたXMLパーサライブラリである。
C++で実装されており、XMLドキュメントの解析、生成、変更が可能であり、W3C標準に準拠しており、高度な機能を持つ。

Xerces-C++ライブラリは、以下に示す特徴を持つ。

  • W3C標準準拠
    XML 1.0 / 1.1、DOM Level 1 / 2 / 3、SAX 1 / 2、XInclude、XML Schema、XPath、XSLT、名前空間等のXMLに関連する多くのW3C標準に準拠している。
  • 高機能
    豊富な機能セットを持っており、XMLドキュメントの解析、検証、変更、生成等が可能である。
    また、XPathやXSLT等の高度な機能もサポートしている。
  • 安定性と信頼性
    Apache XMLプロジェクトにより長年開発され続けており、安定性と信頼性が高い。
    エンタープライズアプリケーションでの使用実績がある。
  • 拡張性
    プラグイン機構により、独自の機能を簡単に拡張できる。
    例えば、独自のXMLスキーマや文字エンコーディングを追加することが可能である。
  • マルチスレッド対応
    マルチスレッドプログラミングをサポートしている。


ただし、Xerces-C++ライブラリは大規模なライブラリであるため、導入や習得にコストがかかる可能性がある。
また、パフォーマンス面では軽量なライブラリよりも劣ることがある。

そのため、プロジェクトの要件次第では、TinyXMLやRapidXml等の軽量ライブラリも選択肢として検討する必要がある。

一般的には、Xerces-C++ライブラリは高機能で標準準拠のXMLパーサーライブラリであり、本格的なXMLハンドリングが必要な場合に使用する。

なお、Xerces-C++ライブラリのライセンスは、Apache Software License 2.0の下で利用可能である。

インストール

パッケージ管理システムからインストール
# RHEL
sudo dnf install xerces-c-devel

# SUSE
sudo zypper install libxerces-c-devel


ソースコードからインストール

Xerces-C++ライブラリのビルドに必要なライブラリをインストールする。

# RHEL
sudo dnf install make cmake gcc gcc-c++ libcurl-devel libicu-devel

# SUSE
sudo zypper install make cmake gcc gcc-c++ libcurl-devel libicu-devel


Xerces-C++ライブラリの公式Webサイトにアクセスして、ソースコードをダウンロードする。
ダウンロードしたファイルを解凍する。

tar xf xerces-c-<バージョン>.tar.xz
cd xerces-c-<バージョン>


Xerces-C++ライブラリをビルドおよびインストールする。

mkdir build && cd build

cmake .. \
      -DCMAKE_INSTALL_PREFIX=<Xerces-C++ライブラリのインストールディレクトリ> \
      -DCMAKE_BUILD_TYPE=Release \
      -Dmessage-loader=icu       \  # オプション : 内部UTF-16と他のエンコーディングとの変換に使用するトランスコーダを指定する
                                    # 他に、inmemoryまたはiconv等も指定することができる
      -Dmessage-loader=icu          # オプション : 診断メッセージへのアクセスに使用するメッセージローダを指定する
                                    # 他に、gnuiconvまたはiconvを指定することもできる
      -Dnetwork-accessor=curl       # オプション : ネットワークリソースへのアクセスに使用するライブラリを指定する
                                    # 他に、"socket"を指定することもできる

make -j $(nproc)
make install


サンプルコード

サンプルコードでは、以下に示すような手順を行っている。

  1. まず、XMLPlatformUtils::Initializeメソッドを実行して、Xerces-C++ライブラリを初期化する。
  2. 次に、XercesDOMParserクラスのインスタンスを生成して、XMLドキュメントを解析する。
  3. getDocumentメソッドを実行してDOMドキュメントを取得して、getDocumentElementメソッドを実行してルート要素を取得する。
  4. ルート要素の名前を出力する。
  5. getChildNodesメソッドを実行してルート要素の子要素のリストを取得する。(各子要素の名前を出力)
  6. XMLPlatformUtils::Terminateメソッドを実行して、Xerces-C++ライブラリを解放する。


以下の例で使用しているXMLファイルの内容を示す。

 <?xml version="1.0" encoding="UTF-8"?>
 <root>
    <child1>
       <grandchild>Value1</grandchild>
    </child1>
    <child2 attr="value">
       <grandchild>Value2</grandchild>
    </child2>
    <child3/>
 </root>


 #include <iostream>
 #include <string>
 #include <xercesc/util/PlatformUtils.hpp>
 #include <xercesc/dom/DOM.hpp>
 #include <xercesc/parsers/XercesDOMParser.hpp>
 
 using namespace xercesc;
 
 int main(int argc, char* argv[])
 {
    try {
       // Xerces-C++ライブラリの初期化
       XMLPlatformUtils::Initialize();
 
       // XMLドキュメントを解析するパーサーを作成
       XercesDOMParser parser;
       parser.setValidationScheme(XercesDOMParser::Val_Always); // オプションでXMLスキーマ検証を行う
 
       // XMLファイルを指定してパースする
       parser.parse("example.xml");
 
       // ルート要素を取得
       DOMDocument* document = parser.getDocument();
       DOMElement* rootElement = document->getDocumentElement();
 
       // ルート要素の名前を出力
       char* rootName = XMLString::transcode(rootElement->getTagName());
       std::cout << "Root element name: " << rootName << std::endl;
       XMLString::release(&rootName);
 
       // 子要素を取得して出力
       DOMNodeList* childNodes = rootElement->getChildNodes();
       for (XMLSize_t i = 0; i < childNodes->getLength(); i++) {
          DOMNode* childNode = childNodes->item(i);
          if (childNode->getNodeType() == DOMNode::ELEMENT_NODE) {
             DOMElement* childElement = static_cast<DOMElement*>(childNode);
             char* childName = XMLString::transcode(childElement->getTagName());
             std::cout << "Child element name: " << childName << std::endl;
             XMLString::release(&childName);
          }
       }
 
       // Xerces-C++ライブラリの終了処理
       XMLPlatformUtils::Terminate();
    }
    catch (const XMLException& e) {
       char* message = XMLString::transcode(e.getMessage());
       std::cout << "Error: " << message << std::endl;
       XMLString::release(&message);
    }
    catch (const DOMException& e) {
       char* message = XMLString::transcode(e.msg);
       std::cout << "Error: " << message << std::endl;
       XMLString::release(&message);
    }
    catch (...) {
       std::cout << "Unexpected error occurred" << std::endl;
    }
 
    return 0;
 }