読者です 読者をやめる 読者になる 読者になる

Boost.PropertyTree 属性付きXMLの書き込み

C++

以下のようにしてできました。

#include <vector>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
#include <boost/foreach.hpp>

#define foreach BOOST_FOREACH

struct Book {
    std::string title;
    std::string author;

    Book() {}

    Book(const Book& other)
        : title(other.title), author(other.author) {}

    Book(const std::string& title, const std::string& author)
        : title(title), author(author) {}
};

void save(const std::string& filename)
{
    std::vector<Book> books;
    books.reserve(2);
    books.push_back(Book("D&E", "Bjarne Stroustrup"));
    books.push_back(Book("MC++D", "Andrei, Alexandrescu"));

    using boost::property_tree::ptree;

    ptree pt;
    foreach (const Book& book, books) {
        ptree& child = pt.add("bookList.book", "");
        child.put("<xmlattr>.title",    book.title);
        child.put("<xmlattr>.author",   book.author);
    }

    using namespace boost::property_tree::xml_parser;
    const int indent = 2;
    write_xml(filename, pt, std::locale(),
        xml_writer_make_settings(' ', indent, widen<char>("utf-8")));
}

int main()
{
    save("book.xml");
}
<?xml version="1.0" encoding="utf-8"?>
<bookList>
  <book title="D&E" author="Bjarne Stroustrup"/>
  <book title="MC++D" author="Andrei Alexandrescu"/>
</bookList>

write_xmlのところは、後ろの2引数を省略できますが、
writer settingsを設定しない場合、以下のように改行、インデントなしで出力されます。

<?xml version="1.0" encoding="utf-8"?>
<bookList><book title="D&E" author="Bjarne Stroustrup"/><book title="MC++D" author="Andrei Alexandrescu"/></bookList>


ちなみにwriter settingsはアンドキュメントです。
に、
write_xmlの第4引数に指定するxml_writer_settings型、
それを生成するヘルパ関数xml_writer_make_settings()が定義されています。

namespace boost { namespace property_tree { namespace xml_parser {

    ...

    template <class Ch>
    xml_writer_settings<Ch> xml_writer_make_settings(Ch indent_char = Ch(' '),
        typename std::basic_string<Ch>::size_type indent_count = 0,
        const std::basic_string<Ch> &encoding = widen<Ch>("utf-8"))
    {
        return xml_writer_settings<Ch>(indent_char, indent_count, encoding);
    }

} } }


ついでに、さっき出力したXMLの読み込みはこんな感じです。

#include <iostream>
#include <vector>
#include <algorithm>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
#include <boost/foreach.hpp>
#include <boost/mem_fn.hpp>

#define foreach BOOST_FOREACH

struct Book {
    std::string title;
    std::string author;

    Book() {}

    Book(const Book& other)
        : title(other.title), author(other.author) {}

    Book(const std::string& title, const std::string& author)
        : title(title), author(author) {}

    void print() const
        { std::cout << title << "," << author << std::endl; }
};

void load(const std::string& filename)
{
    using boost::property_tree::ptree;

    std::vector<Book> books;

    ptree pt;
    read_xml(filename, pt);

    foreach (const ptree::value_type& child_, pt.get_child("bookList")) {
        const ptree& child = child_.second;
        const std::string title     = child.get<std::string>("<xmlattr>.title");
        const std::string author    = child.get<std::string>("<xmlattr>.author");

        books.push_back(Book(title, author));
    }

    std::for_each(books.begin(), books.end(), boost::mem_fn(&Book::print));
}

int main()
{
    load("book.xml");
}
D&E,Bjarne Stroustrup
MC++D,Andrei Alexandrescu