XML ファイルを解析するときは(それしか知らないので)Ruby を使ってやっていたのですが,C++ のクラスの中に XML の解析部を組み込む必要が出てきたので真面目に C++ の XML パースライブラリを探すことにしました.
togeの日記 でいくつかの XML パースライブラリが紹介されていましたが,最近のものだと以下の 2 つが使いやすいようです.
今回は,これらのうち RapidXML を使ってみました.
サンプルコード
インストールは,ダウンロードして解凍するだけなので特に難しい所はなさそうです.サンプルコードは何にしようかなと悩んだのですが,ちょっと前に Ruby で OpenXML ファイルを整形するスクリプト を書いたので,これを RapidXML を用いて C++ で書いてみる事にします.
#include <iostream> #include <string> #include "rapidxml/rapidxml.hpp" #include "rapidxml/rapidxml_utils.hpp" class format_openxml { public: format_openxml() : level_(0) {} template <class XMLNode> void run(XMLNode* node) { std::string indent; for (int i = 0; i < level_; ++i) indent += '\t'; std::cout << indent << '<' << node->name(); for (rapidxml::xml_attribute<>* attr = node->first_attribute(); attr; attr = attr->next_attribute()) { std::cout << " " << attr->name() << "=\"" << attr->value() << "\""; } XMLNode* child = node->first_node(); if (child && child->name() && child->name_size() > 0) { std::cout << '>' << std::endl; for (; child; child = child->next_sibling()) { ++level_; this->run(child); --level_; } std::cout << indent << "</" << node->name() << '>' << std::endl; } else if (node->value_size() > 0) { std::cout << '>' << node->value() << "</" << node->name() << '>' << std::endl; } else std::cout << " />" << std::endl; } private: int level_; }; int main(int argc, char* argv[]) { if (argc < 2) { std::cerr << "format_openxml filename" << std::endl; std::exit(-1); } rapidxml::file<char> in(argv[1]); try { rapidxml::xml_document<char> doc; doc.parse<0>(in.data()); format_openxml fmt; fmt.run(doc.first_node()); } catch (rapidxml::parse_error& e) { int pos = reinterpret_cast<int>(e.where<char>()) - reinterpret_cast<int>(in.data()); std::cerr << "parse error (" << pos << ") : " << e.what() << std::endl; std::exit(-1); } return 0; }
このように Ruby とほぼ同じような形で書けました.使いやすくて良い感じです.デフォルト (char) は typedef しておいてユーザに <> は書かせない方が良かったのでは,とは思いますが.