さんざん嵌ったのでメモ。
以前、id:tt_clownさんがHello, Boost.PropertyTree!というエントリを書いていましたが
PropertyMapが正式リリースされたときに以下の破壊的な変更がありました。
boost/libs/property_map/breaking_changes.txt
- find
find() returns an assoc_iterator.
Impact: If you use find, you may have to change your code. Most importantly,
you need to compare against not_found() instead of end().
Rationale: equal_range() also returns assoc_iterators. equal_range() cannot
return normal iterators, since the conversion would not preserve
the equal range or even the range property.
find()の戻り値で、見つかったかどうかの判定をit != pt.end()ではなくit != pt.not_found()と書くようになり、
find()の戻り値の型もiteratorからassoc_iteratorに変更されています。
この辺りは、Boost 1.42.0時点ではドキュメントが古いままなので注意してください。
それと、Property Mapのtest/exampleのどちらにも、XMLの属性読み込みのサンプルがなかったので
以下のコードのget_childに指定するパスとキー名のあたりを参考にしてください。
<bookList> <book title="Design and Evolution of C++" author="Bjarne Stroustrup"> <localize locale="Japanese" title="C++の設計と進化"/> </book> <book title="C++ Template Metaprogramming" author="Dave Abrahams"> <localize locale="Japanese" title="C++テンプレートメタプログラミング"/> </book> </bookList>
BookList.h
#ifndef BOOK_LIST_INCLUDE #define BOOK_LIST_INCLUDE #include <string> #include <boost/unordered_map.hpp> #include <boost/multi_index_container.hpp> #include <boost/multi_index/member.hpp> #include <boost/multi_index/ordered_index.hpp> #include <boost/property_tree/ptree_fwd.hpp> struct LocalizeMap { typedef std::string locale_type; typedef std::string name_type; typedef boost::unordered_map<locale_type, name_type> type; }; struct Book { std::string title; std::string author; LocalizeMap::type localize; Book() {} Book(const std::string& title, const std::string& author) : title(title), author(author) {} }; namespace mulidx { using namespace boost::multi_index; } class BookList { typedef mulidx::multi_index_container< Book, mulidx::indexed_by< mulidx::ordered_unique<mulidx::member<Book, std::string, &Book::title> >, mulidx::ordered_unique<mulidx::member<Book, std::string, &Book::author> > > > dictionary; dictionary bookList_; public: void Load(); dictionary& get() { return bookList_; } const dictionary& get() const { return bookList_; } private: Book ReadBook(const boost::property_tree::ptree& book); void ReadLocalize(const boost::property_tree::ptree& localize, Book& data); }; #endif // BOOK_LIST_INCLUDE
BookList.cpp
#include "BookList.h" #include <boost/property_tree/ptree.hpp> #include <boost/property_tree/xml_parser.hpp> #include <boost/foreach.hpp> #include <boost/optional.hpp> #define foreach BOOST_FOREACH using boost::property_tree::ptree; namespace { const std::string fileName_ = "book.xml"; } inline boost::optional<const ptree&> FindAttr(const ptree& pt) { ptree::const_assoc_iterator p = pt.find("<xmlattr>"); return p != pt.not_found() ? p->second : boost::optional<const ptree&>(); } inline std::string GetAttr(const ptree& pt, const std::string& name) { return pt.find(name)->second.data(); } void BookList::Load() { bookList_.clear(); ptree root; read_xml(fileName_, root); foreach (const ptree::value_type& pt, root.get_child("bookList")) { const ptree book = pt.second; Book data = ReadBook(book); foreach (const ptree::value_type& localize, book) { ReadLocalize(localize.second, data); } bookList_.insert(data); } } Book BookList::ReadBook(const ptree& book) { boost::optional<const ptree&> p = FindAttr(book); if (!p) return Book(); const ptree& attr = p.get(); return Book(GetAttr(attr, "title"), GetAttr(attr, "author")); } void BookList::ReadLocalize(const ptree& localize, Book& data) { boost::optional<const ptree&> p = FindAttr(localize); if (!p) return; const ptree& attr = p.get(); data.localize["locale"] = GetAttr(attr, "locale"); data.localize["title"] = GetAttr(attr, "title"); }
main.cpp
#include "BookList.h" #include <iostream> #include <boost/foreach.hpp> #include <boost/tuple/tuple.hpp> #define foreach BOOST_FOREACH int main() { BookList bookList; bookList.Load(); foreach (const Book& book, bookList.get()) { std::cout << book.title << "," << book.author << "," << book.localize.at("locale") << "," << book.localize.at("title") << std::endl; } }
C++ Template Metaprogramming,Dave Abrahams,Japanese,C++テンプレートメタプログラミング Design and Evolution of C++,Bjarne Stroustrup,Japanese,C++の設計と進化