2

問題:

  1. Qi JSON パーサーで解析された属性が欠落している理由が見つかりません。パーサーは入力文字列を正常に解析しますが、出力データ構造 json_object には最初の属性 (attribute_a) のみが含まれ、他の属性 (attribute_b および attribute_c) は欠落しています。

ソフトウェア: Boost 1.52 を使用して Spirit Qi をブーストする

プラットフォーム: Windows 7 (64 ビット)

コンパイラ(Visual Studio 2010)

リクエスト:

  1. パーサーがすべての属性を見つけられない理由を見つけるのに役立ちます。

  2. デバッグ出力を見ると、属性が単一の std::vector オブジェクトに配置されていないことがわかります。http://www.json.org/で見つけた JSON 文法を参照として使用しています。「 members 」の出力として見たいのは、その JSON オブジェクトに対して見つかったすべての json_pair オブジェクトのリストを含む単一の std::vector です。

制限事項:

  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

パーサー

一般的に、最初の質問に対する答えは、目的を達成する方法はおそらくいくつかあるということです。具体的には、うまくいくと思われる方法を紹介できます。

重要なことは、特定のフレーズまたはトークンの 1 つ以上のインスタンスに一致するルールの属性タイプを正しく設定することです。これには、コンテナーであるメンバーを持つ構造体ではなく、実際に宣言するものがコンテナーであることを確認してください。 .

それが終わったら、コンテナを扱っていることを Qi が認識し、必要に応じて埋め戻す必要があることを Qi が認識できるように、ルールを作成する必要があります。

最初にメンバー ルールを確認します。これをルールとして指定しました。

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

特にs と a s は同じ属性タイプを持っていないため、これだけでは Qi にs をjson_membersコンテナにバックスタッフするように指示するのに十分ではないと思います。したがって、ルールを次のように置き換えることをお勧めします。pairpairmember

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。ライブラリのワイド文字列サポートを使用して、「ユニコード」(マイクロソフトが呼んでいるように)を今すぐサポートできます。

免責事項

私は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 に答える