2

问题

  1. 找不到 Qi JSON 解析器中缺少解析属性的原因。解析器成功解析输入字符串,但输出数据结构 json_object 仅包含第一个属性(attribute_a)但缺少其他属性(attribute_b 和 attribute_c)

软件: 使用 Boost 1.52 提升灵气

平台:Windows 7(64 位)

编译器(Visual Studio 2010)

要求

  1. 帮助找出解析器没有找到所有属性的原因。

  2. 查看调试输出,我发现属性没有被放入单个 std::vector 对象中。我使用在http://www.json.org/上找到的 JSON 语法作为参考。我希望看到的“ members ”的输出是一个 std::vector ,其中包含为该 JSON 对象找到的所有 json_pair 对象的列表。

限制

  1. 解析器不支持 Unicode 字符串。

代码:

    #define BOOST_SPIRIT_DEBUG
    #include <boost/spirit/include/qi.hpp>
    #include <boost/spirit/include/phoenix_core.hpp>
    #include <boost/spirit/include/phoenix_container.hpp>
    #include <boost/spirit/include/phoenix_statement.hpp>
    #include <boost/spirit/include/phoenix_operator.hpp>
    #include <boost/fusion/include/adapt_struct.hpp>
    #include <boost/fusion/include/boost_tuple.hpp>
    #include <boost/variant/recursive_variant.hpp>

    #include <boost/make_shared.hpp>

    #include <vector>

    namespace signal_processing {
      namespace parsing {

        struct json_object;
        struct json_array;

        typedef boost::variant < std::string,
            double,
            boost::recursive_wrapper<json_object>,
            boost::recursive_wrapper<json_array>,
            bool > json_value;

        typedef boost::tuple < std::string, json_value> json_pair;

        struct json_members
        {
            std::vector < json_pair > items;
        };

        struct json_object
        {
            std::vector < json_members > children;
        };

        struct json_array
        {
            std::vector < json_value > list;
        };

        using boost::spirit::qi::bool_;
        using boost::spirit::qi::char_;
        using boost::spirit::qi::double_;
        using boost::spirit::qi::eol;
        using boost::spirit::qi::float_;
        using boost::spirit::qi::int_;
        using boost::spirit::qi::lexeme;
        using boost::spirit::qi::lit;   
        using boost::spirit::qi::space;
        using boost::spirit::qi::_val;
        using boost::spirit::qi::_1;

        template <typename Iterator, typename Skipper>
        struct json_grammar : boost::spirit::qi::grammar < Iterator, json_object(), Skipper>
        {
            json_grammar() : json_grammar::base_type(object)
            {
                object = '{' > *members > '}';

                pair = string > ':' > value;

                members = pair > *( ',' > members );

                element_list = '[' > *elements > ']';

                elements = value > *( ',' > elements );

                value = string |
                    number |
                    object |
                    element_list |
                    bool_ |
                    lit("null");

                char const* exclude = " ();\"\n\r\t";
                string = '"'
                    > +lexeme[char_ - char_(exclude)]
                    > '"';

                // Return: double
                number = double_ |
                    float_ |
                    int_;

                BOOST_SPIRIT_DEBUG_NODE(object);
                BOOST_SPIRIT_DEBUG_NODE(pair);
                BOOST_SPIRIT_DEBUG_NODE(members);
                BOOST_SPIRIT_DEBUG_NODE(element_list);
                BOOST_SPIRIT_DEBUG_NODE(elements);
                BOOST_SPIRIT_DEBUG_NODE(value);
                BOOST_SPIRIT_DEBUG_NODE(string);
                BOOST_SPIRIT_DEBUG_NODE(number);
            }

            boost::spirit::qi::rule < Iterator, json_object(), Skipper > object;
            boost::spirit::qi::rule < Iterator, json_pair(), Skipper > pair;
            boost::spirit::qi::rule < Iterator, json_members(), Skipper > members;
            boost::spirit::qi::rule < Iterator, json_array(), Skipper > element_list;
            boost::spirit::qi::rule < Iterator, json_array(), Skipper > elements;
            boost::spirit::qi::rule < Iterator, json_value(), Skipper > value;
            boost::spirit::qi::rule < Iterator, std::string(), Skipper > string;
            boost::spirit::qi::rule < Iterator, double(), Skipper > number;
        };
      }
    }

    BOOST_FUSION_ADAPT_STRUCT(
        signal_processing::parsing::json_object,
        (std::vector < signal_processing::parsing::json_members >, children)
    )

    BOOST_FUSION_ADAPT_STRUCT(
        signal_processing::parsing::json_members,
        (std::vector < signal_processing::parsing::json_pair >, items)
    )

    BOOST_FUSION_ADAPT_STRUCT(
        signal_processing::parsing::json_array,
        (std::vector < signal_processing::parsing::json_value >, list)
    )

    void parse ( std::string const& file )
    {
        typedef signal_processing::parsing::json_grammar < std::string::const_iterator, boost::spirit::ascii::space_type > configuration_grammar;
        configuration_grammar input; // Input grammar
        signal_processing::parsing::json_object parsed_data;

        std::string::const_iterator iter = file.begin();
        std::string::const_iterator end = file.end();
        bool r = boost::spirit::qi::phrase_parse ( iter, end, input, boost::spirit::ascii::space, parsed_data );

        if ( ! r || iter != end)
        {
            // Report the next 30 characters
            std::string::const_iterator some = iter + 30;

            if ( some > end )
            {
                some = end;
            }

            std::string context(iter, some);
            std::cout << "-------------------------\n";
            std::cout << "Parsing failed\n";
            std::cout << "stopped at: \": " << context << "...\"\n";
            std::cout << "-------------------------\n";
        }
    }

    int main(int,char**)
    {
        std::string input ( "{\r\n       \"Event\": {\r\n                \"attribute_a\": 0.0002,\r\n                \"attribute_b\": 2e-005,\r\n                \"attribute_c\": 0.022\r\n        }\r\n}" );

        parse ( input );

        return 0;
    }
4

2 回答 2

1

解析器

一般来说,您的第一个问题的答案是可能有几种方法可以实现您想要的。具体来说,我可以向您展示一种似乎可行的方法。

关键是正确设置与给定短语或标记的一个或多个实例匹配的规则的属性类型,方法是确保您声明的实际是容器,而不是具有容器成员的结构.

完成后,您需要编写规则,以便 Qi 知道您正在处理一个容器,并且它应该适当地回填。

首先查看成员规则:您将其作为规则提供:

members = pair > *( ',' > members );

我不相信这本身就足以告诉 Qi 你希望它json_members用 s 填充容器pair,特别是因为pairs 和 a members 没有相同的属性类型。因此,我建议您将规则替换为:

members = pair > *( ',' > pair );

甚至:

members = pair % ',';

您需要确定这些规则是否等同于同一件事,但您明白了。

至于json_members类型:我更改了您的结构定义以使结构从容器派生,而不是将容器作为结构的属性:

struct json_members : std::vector < json_pair > {};

而且您不需要对结构进行融合。

在我看来,这是您的代码的工作版本:

#define BOOST_SPIRIT_DEBUG
    #include <boost/spirit/include/qi.hpp>
    #include <boost/spirit/include/phoenix_core.hpp>
    #include <boost/spirit/include/phoenix_container.hpp>
    #include <boost/spirit/include/phoenix_statement.hpp>
    #include <boost/spirit/include/phoenix_operator.hpp>
    #include <boost/fusion/include/adapt_struct.hpp>
    #include <boost/fusion/include/boost_tuple.hpp>
    #include <boost/variant/recursive_variant.hpp>

    #include <boost/make_shared.hpp>

    #include <vector>

    namespace signal_processing {
      namespace parsing {

        struct json_object;
        struct json_array;

        typedef boost::variant < std::string,
            double,
            boost::recursive_wrapper<json_object>,
            boost::recursive_wrapper<json_array>,
            bool > json_value;

        typedef boost::tuple < std::string, json_value> json_pair;

//        struct json_members
//        {
//            std::vector < json_pair > items;
//        };
//
//        struct json_object
//        {
//            std::vector < json_members > children;
//        };
//
//        struct json_array
//        {
//            std::vector < json_value > list;
//        };

        struct json_members : std::vector < json_pair > {};
        struct json_object : std::vector < json_members > {};
        struct json_array : std::vector < json_value > {};

        using boost::spirit::qi::bool_;
        using boost::spirit::qi::char_;
        using boost::spirit::qi::double_;
        using boost::spirit::qi::eol;
        using boost::spirit::qi::float_;
        using boost::spirit::qi::int_;
        using boost::spirit::qi::lexeme;
        using boost::spirit::qi::lit;
        using boost::spirit::qi::space;
        using boost::spirit::qi::_val;
        using boost::spirit::qi::_1;

        template <typename Iterator, typename Skipper>
        struct json_grammar : boost::spirit::qi::grammar < Iterator, json_object(), Skipper>
        {
            json_grammar() : json_grammar::base_type(object)
            {
                object = '{' > *members > '}';

                pair = string > ':' > value;

                members = pair > *( ',' > pair );

                element_list = '[' > *elements > ']';

                elements = value > *( ',' > value );

                value = string |
                    number |
                    object |
                    element_list |
                    bool_ |
                    lit("null");

                char const* exclude = " ();\"\n\r\t";
                string = '"'
                    > +lexeme[char_ - char_(exclude)]
                    > '"';

                // Return: double
                number = double_ |
                    float_ |
                    int_;

                BOOST_SPIRIT_DEBUG_NODE(object);
                BOOST_SPIRIT_DEBUG_NODE(pair);
                BOOST_SPIRIT_DEBUG_NODE(members);
                BOOST_SPIRIT_DEBUG_NODE(element_list);
                BOOST_SPIRIT_DEBUG_NODE(elements);
                BOOST_SPIRIT_DEBUG_NODE(value);
                BOOST_SPIRIT_DEBUG_NODE(string);
                BOOST_SPIRIT_DEBUG_NODE(number);
            }

            boost::spirit::qi::rule < Iterator, json_object(), Skipper > object;
            boost::spirit::qi::rule < Iterator, json_pair(), Skipper > pair;
            boost::spirit::qi::rule < Iterator, json_members(), Skipper > members;
            boost::spirit::qi::rule < Iterator, json_array(), Skipper > element_list;
            boost::spirit::qi::rule < Iterator, json_array(), Skipper > elements;
            boost::spirit::qi::rule < Iterator, json_value(), Skipper > value;
            boost::spirit::qi::rule < Iterator, std::string(), Skipper > string;
            boost::spirit::qi::rule < Iterator, double(), Skipper > number;
        };
      }
    }

//    BOOST_FUSION_ADAPT_STRUCT(
//        signal_processing::parsing::json_object,
//        (std::vector < signal_processing::parsing::json_members >, children)
//    )
//
//    BOOST_FUSION_ADAPT_STRUCT(
//        signal_processing::parsing::json_members,
//        (std::vector < signal_processing::parsing::json_pair >, items)
//    )
//
//    BOOST_FUSION_ADAPT_STRUCT(
//        signal_processing::parsing::json_array,
//        (std::vector < signal_processing::parsing::json_value >, list)
//    )

    void parse ( std::string const& file )
    {
        typedef signal_processing::parsing::json_grammar < std::string::const_iterator, boost::spirit::ascii::space_type > configuration_grammar;
        configuration_grammar input; // Input grammar
        signal_processing::parsing::json_object parsed_data;

        std::string::const_iterator iter = file.begin();
        std::string::const_iterator end = file.end();
        bool r = boost::spirit::qi::phrase_parse ( iter, end, input, boost::spirit::ascii::space, parsed_data );

        if ( ! r || iter != end)
        {
            // Report the next 30 characters
            std::string::const_iterator some = iter + 30;

            if ( some > end )
            {
                some = end;
            }

            std::string context(iter, some);
            std::cout << "-------------------------\n";
            std::cout << "Parsing failed\n";
            std::cout << "stopped at: \": " << context << "...\"\n";
            std::cout << "-------------------------\n";
        }
    }

    int main(int,char**)
    {
        std::string input ( "{\r\n       \"Event\": {\r\n                \"attribute_a\": 0.0002,\r\n                \"attribute_b\": 2e-005,\r\n                \"attribute_c\": 0.022\r\n        }\r\n}" );

        parse ( input );

        return 0;
    }

哪个输出:

localhost stov # ./stov
<object>
  <try>{\r\n       "Event": {</try>
  <members>
    <try>\r\n       "Event": {\r</try>
    <pair>
      <try>\r\n       "Event": {\r</try>
      <string>
        <try>\r\n       "Event": {\r</try>
        <success>: {\r\n               </success>
        <attributes>[[E, v, e, n, t]]</attributes>
      </string>
      <value>
        <try> {\r\n                </try>
        <string>
          <try> {\r\n                </try>
          <fail/>
        </string>
        <number>
          <try> {\r\n                </try>
          <fail/>
        </number>
        <object>
          <try>{\r\n                "</try>
          <members>
            <try>\r\n                "a</try>
            <pair>
              <try>\r\n                "a</try>
              <string>
                <try>\r\n                "a</try>
                <success>: 0.0002,\r\n         </success>
                <attributes>[[a, t, t, r, i, b, u, t, e, _, a]]</attributes>
              </string>
              <value>
                <try> 0.0002,\r\n          </try>
                <string>
                  <try> 0.0002,\r\n          </try>
                  <fail/>
                </string>
                <number>
                  <try> 0.0002,\r\n          </try>
                  <success>,\r\n                "</success>
                  <attributes>[0.0002]</attributes>
                </number>
                <success>,\r\n                "</success>
                <attributes>[0.0002]</attributes>
              </value>
              <success>,\r\n                "</success>
              <attributes>[[[a, t, t, r, i, b, u, t, e, _, a], 0.0002]]</attributes>
            </pair>
            <pair>
              <try>\r\n                "a</try>
              <string>
                <try>\r\n                "a</try>
                <success>: 2e-005,\r\n         </success>
                <attributes>[[a, t, t, r, i, b, u, t, e, _, b]]</attributes>
              </string>
              <value>
                <try> 2e-005,\r\n          </try>
                <string>
                  <try> 2e-005,\r\n          </try>
                  <fail/>
                </string>
                <number>
                  <try> 2e-005,\r\n          </try>
                  <success>,\r\n                "</success>
                  <attributes>[2e-05]</attributes>
                </number>
                <success>,\r\n                "</success>
                <attributes>[2e-05]</attributes>
              </value>
              <success>,\r\n                "</success>
              <attributes>[[[a, t, t, r, i, b, u, t, e, _, b], 2e-05]]</attributes>
            </pair>
            <pair>
              <try>\r\n                "a</try>
              <string>
                <try>\r\n                "a</try>
                <success>: 0.022\r\n        }\r\n</success>
                <attributes>[[a, t, t, r, i, b, u, t, e, _, c]]</attributes>
              </string>
              <value>
                <try> 0.022\r\n        }\r\n}</try>
                <string>
                  <try> 0.022\r\n        }\r\n}</try>
                  <fail/>
                </string>
                <number>
                  <try> 0.022\r\n        }\r\n}</try>
                  <success>\r\n        }\r\n}</success>
                  <attributes>[0.022]</attributes>
                </number>
                <success>\r\n        }\r\n}</success>
                <attributes>[0.022]</attributes>
              </value>
              <success>\r\n        }\r\n}</success>
              <attributes>[[[a, t, t, r, i, b, u, t, e, _, c], 0.022]]</attributes>
            </pair>
            <success>\r\n        }\r\n}</success>
            <attributes>[[[[a, t, t, r, i, b, u, t, e, _, a], 0.0002], [[a, t, t, r, i, b, u, t, e, _, b], 2e-05], [[a, t, t, r, i, b, u, t, e, _, c], 0.022]]]</attributes>
          </members>
          <members>
            <try>\r\n        }\r\n}</try>
            <pair>
              <try>\r\n        }\r\n}</try>
              <string>
                <try>\r\n        }\r\n}</try>
                <fail/>
              </string>
              <fail/>
            </pair>
            <fail/>
          </members>
          <success>\r\n}</success>
          <attributes>[[[[[a, t, t, r, i, b, u, t, e, _, a], 0.0002], [[a, t, t, r, i, b, u, t, e, _, b], 2e-05], [[a, t, t, r, i, b, u, t, e, _, c], 0.022]]]]</attributes>
        </object>
        <success>\r\n}</success>
        <attributes>[[[[[a, t, t, r, i, b, u, t, e, _, a], 0.0002], [[a, t, t, r, i, b, u, t, e, _, b], 2e-05], [[a, t, t, r, i, b, u, t, e, _, c], 0.022]]]]</attributes>
      </value>
      <success>\r\n}</success>
      <attributes>[[[E, v, e, n, t], [[[[a, t, t, r, i, b, u, t, e, _, a], 0.0002], [[a, t, t, r, i, b, u, t, e, _, b], 2e-05], [[a, t, t, r, i, b, u, t, e, _, c], 0.022]]]]]</attributes>
    </pair>
    <success>\r\n}</success>
    <attributes>[[[[E, v, e, n, t], [[[[a, t, t, r, i, b, u, t, e, _, a], 0.0002], [[a, t, t, r, i, b, u, t, e, _, b], 2e-05], [[a, t, t, r, i, b, u, t, e, _, c], 0.022]]]]]]</attributes>
  </members>
  <members>
    <try>\r\n}</try>
    <pair>
      <try>\r\n}</try>
      <string>
        <try>\r\n}</try>
        <fail/>
      </string>
      <fail/>
    </pair>
    <fail/>
  </members>
  <success></success>
  <attributes>[[[[[E, v, e, n, t], [[[[a, t, t, r, i, b, u, t, e, _, a], 0.0002], [[a, t, t, r, i, b, u, t, e, _, b], 2e-05], [[a, t, t, r, i, b, u, t, e, _, c], 0.022]]]]]]]</attributes>
</object>

统一码

我知道 boost::spirit 的 SVN 版本现在支持 UTF8;尝试谷歌搜索BOOST_SPIRIT_UNICODE。您现在可以使用库中的宽字符串支持来支持“unicode”(微软称之为)。

免责声明

我在 Linux 上工作。YMMV。

于 2013-01-22T17:40:48.823 回答
0

我碰巧最近在 Spirit v2 中编写了一个支持 UNICODE 的 JSON 解析器,这是一个解析您的示例的测试用例:

#include <sstream>
#include "JSON.hpp"

// util
static JSON::Value roundtrip(JSON::Value const& given) {
    return JSON::parse(to_wstring(given));
}

void roundtrip_test()
{
    auto 
        document = JSON::readFrom(std::istringstream(
                    "{\r\n"
                    "       \"Event\": {\r\n"
                    "             \"attribute_a\": 0.0002,\r\n"
                    "\"attribute_b\": 2e-005,\r\n"
                    "\"attribute_c\": 0.022\r\n"
                    "}\r\n}")),
        verify = roundtrip(document);

    std::cout << verify << "\n";
    std::cout << "document <=> verify equal:     \t" << std::boolalpha << (document == verify)                       << "\n";
    std::cout << "document <=> verify text match:\t" << std::boolalpha << (to_string(document) == to_string(verify)) << "\n";
}

这打印:

{"Event":{"attribute_a":0.0002,"attribute_b":2e-05,"attribute_c":0.022}}
document <=> verify equal:      true
document <=> verify text match: true

更多 API 示例:

  1. '立即' JSON 文档的对象初始化表达式:

    void initializer_test()
    {
        using namespace JSON;
    
        const Array arr { 
            L"text", 
            42,
            Object { { L"dummy", Null() } } 
        };
    
        auto radius = as_double(arr[1]);
    
        auto const document = Object {
                { L"number", 314e-2 },
                { L"string", L"hello\ngoodbye" },
                { L"array" , arr },
                { L"bool" , False() },
                { L"radius", radius },
                { L"area", radius * radius * 3.14 },
                { String { 10, L'=' }, String { 10, L'*' } }
        };
    
        std::cout << document[L"bool"]   << std::endl;
        std::cout << document[L"number"] << std::endl;
        std::cout << document[L"string"] << std::endl;
        std::cout << document[L"array"]  << std::endl;
        std::cout << document[L"bool"]   << std::endl;
        std::cout << document[L"radius"] << std::endl;
        std::cout << document[L"area"]   << std::endl;
        std::cout << document            << std::endl;
    }
    
  2. 例如这个通过往返测试的样本输入:

    {
        "Image": {
            "Width":  800,
            "Height": 600,
            "Title":  "View from 15th Floor",
            "Thumbnail": {
                "Russian":  "На берегу пустынных волн",
                "Escapes": "Ha \"\u0431\u0435\u0440\u0435\u0433\u0443\" shows up \\similar\\.\r\b\n",
                "берегу": "Russian",
                "Dummy": null,
                "Yummy": false,
                "Tummy": true,
                "Url":    "http://www.example.com/image/481989943",
                "Height": 125,
                "Width":  "100"
            },
            "IDs": [116, 943, 234, 38793]
    
        }
    }
    
  3. 这个转换一些 JSON 节点的访问者示例:如何操作 JSON 树的叶子

于 2013-04-26T02:43:13.687 回答