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

BoostのProperty TreeとJSONでハマった話

c++ boost trap

罠があったらハマりたい。thinca です。嘘です。できればハマりたくありません。
さて、Boost Property Tree Library というのを使うと Boost で JSON を読み書きできるらしい!って噂を聞きました。

https://sites.google.com/site/boostjp/tips/json

ちょうどやりたいところだったので、Boost でできるのならこれ幸いと使ってみることに。
で、罠というのは、私がこのライブラリを JSON ライブラリとして使おうとしたところにあります。
実際のところ、「Boost Property Tree LibraryでJSONのデータを扱える」って言うと、半分正解で半分間違いです。
このライブラリはあくまで、まず Property Tree と言うデータ構造があり、ここに JSON を読み書きできるってだけです。なのでデータ構造としては Property Tree の流儀に合わせることになり、正確に JSON のデータとしては扱えない。例えば以下のような問題があります。

値は全て文字列

JSON には値に文字列やら数値やらあるんだけど、Property Tree に突っ込むと全て文字列になります。
ただし、取り出すときは pt.get("key") みたいに型を指定して取り出せるので、そこまで困らないかも。
boost::property_tree::write_json() で書き出すと残念な感じになります。
ちなみにこの辺りのことはドキュメントに書いてある。
http://www.boost.org/doc/libs/1_47_0/doc/html/boost_propertytree/parsers.html#boost_propertytree.parsers.json_parser
ptree の value を boost::variant とかにしてどうにかできないのかなーとか考えたけど私にはよくわからなかった!

ルートは常にオブジェクト

ルートが配列の JSON を boost::property_tree::read_json() に渡すと、オブジェクトをよこせって怒られます。

#include <sstream>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>

int main(int argc, const char *argv[]) {
    std::stringstream s("[1,2,3]");
    boost::property_tree::ptree pt;
    boost::property_tree::read_json(s, pt);
    boost::property_tree::write_json(std::cout, pt, false);
}
terminate called after throwing an instance of 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::property_tree::json_parser::json_parser_error> >'
  what():  <unspecified file>(1): expected object

pretty = false で出力がおかしいことがある

boost::property_tree::write_json() の第3引数は bool で、false を渡すと整形せずに出力してくれるのだけど、なんか出力がおかしいことがある。

#include <sstream>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>

int main(int argc, const char *argv[]) {
    std::stringstream s("{\"foo\": [10]}");
    boost::property_tree::ptree pt;
    boost::property_tree::read_json(s, pt);
    boost::property_tree::write_json(std::cout, pt, false);
}
{"foo":["10"    ]}

おいなんだそのスペースは。
と言うかこれは Property Tree の構造とは関係なさそうだし普通にバグかもしれない。



と言うわけでまとめると、Property Tree は JSON ライブラリではありません!本当にちゃんと JSON を扱いたい場合は専用の JSON ライブラリを使いましょう。