- LibXML2
- Expat
- MSXML
- TinyXML
- XMLLite
- Xerces-C++
LibXML2 でやろうとしたら、ICU か iconv あたりをなんとかしないといけません。正直 iconv はmsvc でコンパイルするのが困難です。libiconv for windows ありますが、vc で、すんなりコンパイルが通りません。じゃあ ICU だわさ?って、ICUを使おうとすると、icu.lib が無いとか変なリンクエラーが出て萎えてしまいます。ICU も大げさな感じがして、使うのをちょっと躊躇われるのという事情もあります。
おまえ、選り好みが激しすぎと怒られそうですが、Xerces-C++ も、なんか、あんまり好きじゃないんです。
TinyXML もいいんですけど、ちょっと考えてしまう…(こんな事ばかり書いてると、いい加減に袋叩きにあいそう)。
そうすると残されたのは、Expat って事になります。ところが、この Expat って、SJIS に対応していないんですよね…。APIで日本語対応するって事も可能なんですが、なんというか、どうもしっくり来ない。XMLの構文を解析するついでに、文字コード変換もやりましょうという思想なんで、1文字か2文字づつコード変換の処理をしなきゃならない。これ、文字コード変換ライブラリのメンテナンスも考えたら、結構大変です。SJIS に限って言えば、SJIS第一バイトの場合は2バイト処理します。なんつーか、もやもや~とするんですよねー。
で、結論は何かと言うと、そもそも wchar_t が嫌い。これに尽きるんですわ。UTF-8 は、ほんと良く出来てると思います。
結局、自分の好みでやってくと、「文字コード変換」と「expatで遊ぼ」を組み合わせて、こんな感じになってしまいました。ただ、encoding の指定が全然関係ないやん…って部分が気に入りません。
#include <iostream> #include <string> #include <vector> #include <expat.h> #include <boost/shared_ptr.hpp> #include <boost/foreach.hpp> #include "codepage.hpp" #include "wconv.hpp" class xml_node; class xml_node { public: xml_node( const XML_Char* name ) : node_name_(name) {} public: std::basic_string<XML_Char> node_name_; std::basic_string<XML_Char> node_value_; std::vector< boost::shared_ptr<xml_node> > childs_; }; class xml_holder { public: std::vector< boost::shared_ptr<xml_node> > stack_; boost::shared_ptr<xml_node> current_; }; void starter(void* userData, const XML_Char* name, const XML_Char* attrs[]) { xml_holder* holder = reinterpret_cast<xml_holder*>(userData); holder->stack_.push_back( holder->current_ ); boost::shared_ptr<xml_node> element( new xml_node( name ) ); holder->current_->childs_.push_back( element ); holder->current_ = element; } void ender( void* userData, const XML_Char* name) { xml_holder* holder = reinterpret_cast<xml_holder*>(userData); holder->current_ = holder->stack_.back(); holder->stack_.pop_back(); } void data( void* userData, const XML_Char* s, int len ) { xml_holder* holder = reinterpret_cast<xml_holder*>(userData); holder->current_->node_value_.assign( s, s + len ); } void trace( int depth, boost::shared_ptr<xml_node> elem ) { for( int i = 0; i < depth; ++i ) { std::cout << " "; } std::cout << elem->node_name_ << ":" << code_to_code<CP_ACP,CP_UTF8>(elem->node_value_) << std::endl; BOOST_FOREACH( boost::shared_ptr<xml_node> e, elem->childs_ ) { trace( depth+1, e ); } } bool parse_xml( const std::string& xml ) { xml_holder holder; holder.current_ = boost::shared_ptr<xml_node>( new xml_node( "root" ) ); XML_Parser parser = XML_ParserCreate("UTF-8"); if( !parser ) return false; XML_SetUserData( parser, &holder ); XML_SetElementHandler( parser, starter, ender ); XML_SetCharacterDataHandler( parser, data ); int iseof = 0; XML_Parse( parser, xml.c_str(), xml.size(), iseof ); XML_ParserFree( parser ); trace( 0, holder.current_ ); return !iseof; } #include <fstream> int main(int argc, char* argv[] ) { if( argc != 2 ) return 1; std::ifstream ifs( argv[1] ); std::string xml; std::string line; while( ifs.good() ) { std::getline( ifs, line ); xml += line; //std::cout << line << std::endl; } //std::cout << std::endl; parse_xml( code_to_code<CP_UTF8,CP_ACP>(xml) ); return 0; }
0 件のコメント:
コメントを投稿