【问题标题】:Getting values from a json file using boost/property_tree, with multiple elements/arrays/sub-arrays C++使用 boost/property_tree 从 json 文件中获取值,具有多个元素/数组/子数组 C++
【发布时间】:2015-01-06 12:53:29
【问题描述】:

事实:

  • 我正在使用 VS2013 并使用 C++ 进行开发。
  • 我正在使用 boost API 从标准/合法 json 文件中获取值。
  • 我无法提取 name4.jsname5.jsname6.js 名称。
  • 我在 stackoverflow/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”(boost 网站上的示例)提取“name1.js”、“name2.js”和“name3.js”:

    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 名称,它们是:
    1. name4.js
    2. name5.js
    3. 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&lt;std::string&gt;("js"));,但还是不行。

我也尝试了其他方法,没有成功。

如果我能得到一个工作代码,我将不胜感激,因为我没有想法。

【问题讨论】:

    标签: c++ arrays json boost


    【解决方案1】:

    get&lt;std::string&gt;("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";
    

    应该这样做

    Live On Coliru

    #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
    

    【讨论】:

    • 非常感谢!我花了将近一天的时间来理解这个问题。我已经使用了这段代码(虽然你的也可以): BOOST_FOREACH(boost::property_tree::ptree::value_type& framePair2, doc.get_child("content_scripts")){ BOOST_FOREACH(boost::property_tree::ptree::value_type& framePair3, framePair2.second.get_child("js")){ jsFiles.push_back(framePair3.second.data()); } }
    • @OhadM 它发生了。 IMO,Ptree 到 json 和 xml 的映射非常不直观。下次把它画在纸上,通常会有帮助
    【解决方案2】:

    如果您想使用其他方法,可以使用我在之前的答案 (Reading JSON file with C++ and BOOST) 中发布的临时解析器:

    Live On Coliru

    #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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-05-30
      • 1970-01-01
      • 2011-04-14
      • 1970-01-01
      • 2018-07-02
      • 1970-01-01
      • 1970-01-01
      • 2015-01-12
      相关资源
      最近更新 更多