前回の記事でXMLファイルの書き込みは難しくなくできそうでしたネ。
今回はXMLファイルの書き込みを行い、出力してみましょう。
読み込みと同じくライブラリファイルは不要で、ヘッダーファイルのみで利用できます!
何が必要なのか確認しよう!
冒頭でも述べましたがライブラリファイル不要で、ヘッダーファイルのみが必要です。
ヘッダーファイルの準備などはこちらの記事も参照してください!
ヘッダーファイル | boost/property_tree/xml_parser.hpp |
サンプルプログラムを作ってみよう!
とりあえずサンプルプログラムを作って動作を確認してみましょう。
以下のようなXMLファイルを作成できれば完成とします。
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<?xml version="1.0" encoding="utf-8"?> <book-list> <book ISBN="9784873117362"> <title>Effective Modern C++</title> <author>Scott Meyers</author> </book> <book ISBN="9784774185194"> <title>栢木先生の基本情報技術者教室</title> <author>栢木厚</author> </book> <book ISBN="9784103534327"> <title>騎士団長殺し</title> <author>村上春樹</author> </book> </book-list> |
では、プログラムを作ります!
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
#include <iostream> #include <string> #include <vector> #include <codecvt> #include <boost/property_tree/xml_parser.hpp> /** * XMLデータ */ struct Book { long long isbn; std::wstring title; std::wstring author; Book(const long long isbn, const std::wstring& title, const std::wstring& author) : isbn(isbn) , title(title) , author(author) { } }; int main() { std::vector<Book> books; books.push_back(Book(9784873117362, L"Effective Modern C++", L"Scott Meyers")); books.push_back(Book(9784774185194, L"栢木先生の基本情報技術者教室", L"栢木厚")); books.push_back(Book(9784103534327, L"騎士団長殺し", L"村上春樹")); // UTF-8 と wchar_t のコンバーター std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> cvt; boost::property_tree::ptree pt; for (auto book : books) { boost::property_tree::ptree& child = pt.add("book-list.book", ""); child.add("<xmlattr>.isbn", book.isbn); child.add("title", cvt.to_bytes(book.title)); child.add("author", cvt.to_bytes(book.author)); } const int indent = 2; boost::property_tree::write_xml("booklist.xml", pt, std::locale(), boost::property_tree::xml_writer_make_settings<std::string>(' ', indent)); return 0; } |
実行してみると、正しくXMLファイルが作成できていそうですネ。
やっぱり文字コードが気になる!
前回の読み込みについても文字コードを意識していないと日本語の文字化けが発生していました。
今回も同様に変換を行わずに、std::stringに文字列を入れて出力するとしっかり文字化けします。
また、std::wstringに文字列を入力してUTF-8への変換を行わずに出力しようとするとテンプレートライブラリ特有の難しいエラーコードが量産されます…;;
何か方法はないのか…
こういった動作を回避するためには、std::string に文字列リテラルを入力するときに u8″栢木先生の…” と代入する方法もあります。
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
int main() { std::vector<Book> books; books.push_back(Book(9784873117362, u8"Effective Modern C++", u8"Scott Meyers")); books.push_back(Book(9784774185194, u8"栢木先生の基本情報技術者教室", u8"栢木厚")); books.push_back(Book(9784103534327, u8"騎士団長殺し", u8"村上春樹")); boost::property_tree::ptree pt; for (auto book : books) { boost::property_tree::ptree& child = pt.add("book-list.book", ""); child.add("<xmlattr>.isbn", book.isbn); child.add("title", book.title); child.add("author", book.author); } const int indent = 2; boost::property_tree::write_xml("booklist.xml", pt, std::locale(), boost::property_tree::xml_writer_make_settings<std::string>(' ', indent)); return 0; } |
この場合は変換は不要ですが、デバッガーで変数の値をウォッチしたいといった場合にはうまく取得できませんでした。
(きっと何か一手間を加えたら確認できるのでしょう…。)
また、前回の記事のように読み取ったデータを保持して、アプリケーションの終了時に出力する。といった動作を考えるとやっぱり変換を行うのが手間がかからなそうです。
まとめ
まだ課題はありますが、XMLファイルの書き込み自体には大きく困る部分はありませんでしたネ。
XMLファイルの構成が複雑になってくると、今回使用した boost::property_tree::ptree::add() ではなく、boost::property_tree::ptree::put() を使用する場面なども出てきます。
get_optional/get, add/put, 引数の指定など混乱してしまうこともありますが、できる限りシンプルに考えてスマートに実装していきたいです!