使用 boost/property_tree 从 json 文件获取值,使用多个 elements/arrays/sub-arrays C++
Getting values from a json file using boost/property_tree, with multiple elements/arrays/sub-arrays C++
事实:
- 我正在使用 VS2013 并使用 C++ 进行开发。
- 我正在使用 boost API 从 standard/legit json 文件中获取值。
- 我无法提取name4.js、name5.js和name6.js 个名字。
- 我搜索了整个 Whosebug/Google,但没有找到我正在使用的以下 json 文件的任何解释。
json 文件:
{
"background": {
"scripts": [ "name1.js", "name2.js", "name3.js" ]
},
"default_popup": "popup.html",
"default_title": "__MSG_name__",
"content_scripts": [ {
"all_frames": true,
"js": [ "name4.js", "name5.js", "name6.js" ],
"match_about_blank": true,
"matches": [ "http://*/*", "https://*/*" ],
"run_at": "document_start"
}, {
"all_frames": true,
"js": [ "include.postload.js" ],
"match_about_blank": true,
"matches": [ "http://*/*", "https://*/*" ],
"run_at": "document_end"
} ]
}
什么有效:
正如您在下面的代码中看到的,我能够使用 "background.scripts" 提取 "name1.js"、"name2.js" 和 "name3.js"(示例在 boost 网站):
boost::property_tree::ptree doc;
boost::property_tree::read_json("C:/Temp\manifest.json", doc);
std::vector<string> jsFiles;
try{
BOOST_FOREACH(boost::property_tree::ptree::value_type& framePair, doc.get_child("background.scripts")){
jsFiles.push_back(framePair.second.data());
}
}
catch (boost::exception const &ex){}
什么不起作用:
- 我想提取其余的 js 名称,它们是:
- name4.js
- name5.js
- name6.js
我无法使用以下代码让它工作:
BOOST_FOREACH(boost::property_tree::ptree::value_type& framePair2, doc.get_child("content_scripts")){
jsFiles.push_back(framePair2.second.data());
我得到的是矢量字符串中的""
。
我什至试过了jsFiles.push_back(framePair2.second.get<std::string>("js"));
,但还是不行。
我也试过其他方法都没有成功。
如果我能得到一个工作代码,我将不胜感激,因为我没有想法。
get<std::string>("js")
无法工作,因为 "js"
有一个数组值。
for(auto& e : pt.get_child("content_scripts"))
for(auto& r : e.second.get_child("js"))
std::cout << r.second.get_value<std::string>() << "\n";
应该做
#include <sstream>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <iostream>
std::string const sample = R"(
{
"background": {
"scripts": [ "name1.js", "name2.js", "name3.js" ]
},
"default_popup": "popup.html",
"default_title": "__MSG_name__",
"content_scripts": [ {
"all_frames": true,
"js": [ "name4.js", "name5.js", "name6.js" ],
"match_about_blank": true,
"matches": [ "http://*/*", "https://*/*" ],
"run_at": "document_start"
}, {
"all_frames": true,
"js": [ "include.postload.js" ],
"match_about_blank": true,
"matches": [ "http://*/*", "https://*/*" ],
"run_at": "document_end"
} ]
})";
using boost::property_tree::ptree;
namespace j = boost::property_tree::json_parser;
int main() {
std::istringstream iss(sample);
ptree pt;
j::read_json(iss, pt);
for(auto& e : pt.get_child("content_scripts"))
for(auto& r : e.second.get_child("js"))
std::cout << r.second.get_value<std::string>() << "\n";
}
版画
name4.js
name5.js
name6.js
include.postload.js
如果您想使用替代方法,可以使用我在之前的回答中发布的临时解析器 ():
#include <boost/fusion/adapted/std_pair.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <map>
namespace qi = boost::spirit::qi;
std::string const sample = R"(
{
"background": {
"scripts": [ "name1.js", "name2.js", "name3.js" ]
},
"default_popup": "popup.html",
"default_title": "__MSG_name__",
"content_scripts": [ {
"all_frames": true,
"js": [ "name4.js", "name5.js", "name6.js" ],
"match_about_blank": true,
"matches": [ "http://*/*", "https://*/*" ],
"run_at": "document_start"
}, {
"all_frames": true,
"js": [ "include.postload.js" ],
"match_about_blank": true,
"matches": [ "http://*/*", "https://*/*" ],
"run_at": "document_end"
} ]
})";
namespace qd_json { // quick and dirty JSON handling
struct null {};
using text = std::string;
using value = boost::make_recursive_variant<
null,
text, // "string" (roughly!)
double, // number
std::map<text, boost::recursive_variant_>, // object
std::vector<boost::recursive_variant_>, // array
bool
>::type;
using member = std::pair<text, value>;
using object = std::map<text, value>;
using array = std::vector<value>;
template <typename It, typename Skipper = qi::space_type>
struct grammar : qi::grammar<It, value(), Skipper>
{
grammar() : grammar::base_type(value_) {
using namespace qi;
text_ = '"' >> raw [*('\' >> char_ | ~char_('"'))] >> '"';
null_ = "null" >> attr(null{});
bool_ = "true" >> attr(true) | "false" >> attr(false);
value_ = null_ | bool_ | text_ | double_ | object_ | array_;
member_ = text_ >> ':' >> value_;
object_ = '{' >> -(member_ % ',') >> '}';
array_ = '[' >> -(value_ % ',') >> ']';
////////////////////////////////////////
// Bonus: properly decoding the string:
text_ = lexeme [ '"' >> *ch_ >> '"' ];
ch_ = +(
~char_("\"\")) [ _val += _1 ] |
qi::lit("\x5C") >> ( // \ (reverse solidus)
qi::lit("\x22") [ _val += '"' ] | // " quotation mark U+0022
qi::lit("\x5C") [ _val += '\' ] | // \ reverse solidus U+005C
qi::lit("\x2F") [ _val += '/' ] | // / solidus U+002F
qi::lit("\x62") [ _val += '\b' ] | // b backspace U+0008
qi::lit("\x66") [ _val += '\f' ] | // f form feed U+000C
qi::lit("\x6E") [ _val += '\n' ] | // n line feed U+000A
qi::lit("\x72") [ _val += '\r' ] | // r carriage return U+000D
qi::lit("\x74") [ _val += '\t' ] | // t tab U+0009
qi::lit("\x75") // uXXXX U+XXXX
>> _4HEXDIG [ append_utf8(qi::_val, qi::_1) ]
);
BOOST_SPIRIT_DEBUG_NODES((text_)(value_)(member_)(object_)(array_)(null_)(bool_))
}
private:
qi::rule<It, text()> text_, ch_;
qi::rule<It, null()> null_;
qi::rule<It, bool()> bool_;
qi::rule<It, value(), Skipper> value_;
qi::rule<It, member(), Skipper> member_;
qi::rule<It, object(), Skipper> object_;
qi::rule<It, array(), Skipper> array_;
struct append_utf8_f {
template <typename...> struct result { typedef void type; };
template <typename String, typename Codepoint>
void operator()(String& to, Codepoint codepoint) const {
auto out = std::back_inserter(to);
boost::utf8_output_iterator<decltype(out)> convert(out);
*convert++ = codepoint;
}
};
boost::phoenix::function<append_utf8_f> append_utf8;
qi::uint_parser<uint32_t, 16, 4, 4> _4HEXDIG;
};
template <typename Range, typename It = typename boost::range_iterator<Range const>::type>
value parse(Range const& input) {
grammar<It> g;
It first(boost::begin(input)), last(boost::end(input));
value parsed;
bool ok = qi::phrase_parse(first, last, g, qi::space, parsed);
if (ok && (first == last))
return parsed;
throw std::runtime_error("Remaining unparsed: '" + std::string(first, last) + "'");
}
namespace accessors {
static double dbl_(qd_json::value const&v) { return boost::get<double>(v); };
static int int_(qd_json::value const&v) { return boost::get<double>(v); };
static std::string txt_(qd_json::value const&v) { return boost::get<qd_json::text>(v); };
static qd_json::array arr_(qd_json::value const&v) { return boost::get<qd_json::array>(v); };
static qd_json::object obj_(qd_json::value const&v) { return boost::get<qd_json::object>(v); };
}
}
using It = std::string::const_iterator;
int main()
{
using namespace qd_json::accessors;
auto root = obj_(qd_json::parse(sample));
for(auto& o : arr_(root["content_scripts"]))
for(auto& f : arr_(obj_(o)["js"]))
std::cout << txt_(f) << "\n";
}
版画
name4.js
name5.js
name6.js
include.postload.js
事实:
- 我正在使用 VS2013 并使用 C++ 进行开发。
- 我正在使用 boost API 从 standard/legit json 文件中获取值。
- 我无法提取name4.js、name5.js和name6.js 个名字。
- 我搜索了整个 Whosebug/Google,但没有找到我正在使用的以下 json 文件的任何解释。
json 文件:
{
"background": {
"scripts": [ "name1.js", "name2.js", "name3.js" ]
},
"default_popup": "popup.html",
"default_title": "__MSG_name__",
"content_scripts": [ {
"all_frames": true,
"js": [ "name4.js", "name5.js", "name6.js" ],
"match_about_blank": true,
"matches": [ "http://*/*", "https://*/*" ],
"run_at": "document_start"
}, {
"all_frames": true,
"js": [ "include.postload.js" ],
"match_about_blank": true,
"matches": [ "http://*/*", "https://*/*" ],
"run_at": "document_end"
} ]
}
什么有效:
正如您在下面的代码中看到的,我能够使用 "background.scripts" 提取 "name1.js"、"name2.js" 和 "name3.js"(示例在 boost 网站):
boost::property_tree::ptree doc; boost::property_tree::read_json("C:/Temp\manifest.json", doc); std::vector<string> jsFiles; try{ BOOST_FOREACH(boost::property_tree::ptree::value_type& framePair, doc.get_child("background.scripts")){ jsFiles.push_back(framePair.second.data()); } } catch (boost::exception const &ex){}
什么不起作用:
- 我想提取其余的 js 名称,它们是:
- name4.js
- name5.js
- name6.js
我无法使用以下代码让它工作:
BOOST_FOREACH(boost::property_tree::ptree::value_type& framePair2, doc.get_child("content_scripts")){ jsFiles.push_back(framePair2.second.data());
我得到的是矢量字符串中的""
。
我什至试过了jsFiles.push_back(framePair2.second.get<std::string>("js"));
,但还是不行。
我也试过其他方法都没有成功。
如果我能得到一个工作代码,我将不胜感激,因为我没有想法。
get<std::string>("js")
无法工作,因为 "js"
有一个数组值。
for(auto& e : pt.get_child("content_scripts"))
for(auto& r : e.second.get_child("js"))
std::cout << r.second.get_value<std::string>() << "\n";
应该做
#include <sstream>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <iostream>
std::string const sample = R"(
{
"background": {
"scripts": [ "name1.js", "name2.js", "name3.js" ]
},
"default_popup": "popup.html",
"default_title": "__MSG_name__",
"content_scripts": [ {
"all_frames": true,
"js": [ "name4.js", "name5.js", "name6.js" ],
"match_about_blank": true,
"matches": [ "http://*/*", "https://*/*" ],
"run_at": "document_start"
}, {
"all_frames": true,
"js": [ "include.postload.js" ],
"match_about_blank": true,
"matches": [ "http://*/*", "https://*/*" ],
"run_at": "document_end"
} ]
})";
using boost::property_tree::ptree;
namespace j = boost::property_tree::json_parser;
int main() {
std::istringstream iss(sample);
ptree pt;
j::read_json(iss, pt);
for(auto& e : pt.get_child("content_scripts"))
for(auto& r : e.second.get_child("js"))
std::cout << r.second.get_value<std::string>() << "\n";
}
版画
name4.js
name5.js
name6.js
include.postload.js
如果您想使用替代方法,可以使用我在之前的回答中发布的临时解析器 (
#include <boost/fusion/adapted/std_pair.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <map>
namespace qi = boost::spirit::qi;
std::string const sample = R"(
{
"background": {
"scripts": [ "name1.js", "name2.js", "name3.js" ]
},
"default_popup": "popup.html",
"default_title": "__MSG_name__",
"content_scripts": [ {
"all_frames": true,
"js": [ "name4.js", "name5.js", "name6.js" ],
"match_about_blank": true,
"matches": [ "http://*/*", "https://*/*" ],
"run_at": "document_start"
}, {
"all_frames": true,
"js": [ "include.postload.js" ],
"match_about_blank": true,
"matches": [ "http://*/*", "https://*/*" ],
"run_at": "document_end"
} ]
})";
namespace qd_json { // quick and dirty JSON handling
struct null {};
using text = std::string;
using value = boost::make_recursive_variant<
null,
text, // "string" (roughly!)
double, // number
std::map<text, boost::recursive_variant_>, // object
std::vector<boost::recursive_variant_>, // array
bool
>::type;
using member = std::pair<text, value>;
using object = std::map<text, value>;
using array = std::vector<value>;
template <typename It, typename Skipper = qi::space_type>
struct grammar : qi::grammar<It, value(), Skipper>
{
grammar() : grammar::base_type(value_) {
using namespace qi;
text_ = '"' >> raw [*('\' >> char_ | ~char_('"'))] >> '"';
null_ = "null" >> attr(null{});
bool_ = "true" >> attr(true) | "false" >> attr(false);
value_ = null_ | bool_ | text_ | double_ | object_ | array_;
member_ = text_ >> ':' >> value_;
object_ = '{' >> -(member_ % ',') >> '}';
array_ = '[' >> -(value_ % ',') >> ']';
////////////////////////////////////////
// Bonus: properly decoding the string:
text_ = lexeme [ '"' >> *ch_ >> '"' ];
ch_ = +(
~char_("\"\")) [ _val += _1 ] |
qi::lit("\x5C") >> ( // \ (reverse solidus)
qi::lit("\x22") [ _val += '"' ] | // " quotation mark U+0022
qi::lit("\x5C") [ _val += '\' ] | // \ reverse solidus U+005C
qi::lit("\x2F") [ _val += '/' ] | // / solidus U+002F
qi::lit("\x62") [ _val += '\b' ] | // b backspace U+0008
qi::lit("\x66") [ _val += '\f' ] | // f form feed U+000C
qi::lit("\x6E") [ _val += '\n' ] | // n line feed U+000A
qi::lit("\x72") [ _val += '\r' ] | // r carriage return U+000D
qi::lit("\x74") [ _val += '\t' ] | // t tab U+0009
qi::lit("\x75") // uXXXX U+XXXX
>> _4HEXDIG [ append_utf8(qi::_val, qi::_1) ]
);
BOOST_SPIRIT_DEBUG_NODES((text_)(value_)(member_)(object_)(array_)(null_)(bool_))
}
private:
qi::rule<It, text()> text_, ch_;
qi::rule<It, null()> null_;
qi::rule<It, bool()> bool_;
qi::rule<It, value(), Skipper> value_;
qi::rule<It, member(), Skipper> member_;
qi::rule<It, object(), Skipper> object_;
qi::rule<It, array(), Skipper> array_;
struct append_utf8_f {
template <typename...> struct result { typedef void type; };
template <typename String, typename Codepoint>
void operator()(String& to, Codepoint codepoint) const {
auto out = std::back_inserter(to);
boost::utf8_output_iterator<decltype(out)> convert(out);
*convert++ = codepoint;
}
};
boost::phoenix::function<append_utf8_f> append_utf8;
qi::uint_parser<uint32_t, 16, 4, 4> _4HEXDIG;
};
template <typename Range, typename It = typename boost::range_iterator<Range const>::type>
value parse(Range const& input) {
grammar<It> g;
It first(boost::begin(input)), last(boost::end(input));
value parsed;
bool ok = qi::phrase_parse(first, last, g, qi::space, parsed);
if (ok && (first == last))
return parsed;
throw std::runtime_error("Remaining unparsed: '" + std::string(first, last) + "'");
}
namespace accessors {
static double dbl_(qd_json::value const&v) { return boost::get<double>(v); };
static int int_(qd_json::value const&v) { return boost::get<double>(v); };
static std::string txt_(qd_json::value const&v) { return boost::get<qd_json::text>(v); };
static qd_json::array arr_(qd_json::value const&v) { return boost::get<qd_json::array>(v); };
static qd_json::object obj_(qd_json::value const&v) { return boost::get<qd_json::object>(v); };
}
}
using It = std::string::const_iterator;
int main()
{
using namespace qd_json::accessors;
auto root = obj_(qd_json::parse(sample));
for(auto& o : arr_(root["content_scripts"]))
for(auto& f : arr_(obj_(o)["js"]))
std::cout << txt_(f) << "\n";
}
版画
name4.js
name5.js
name6.js
include.postload.js