Problem:
- Cannot find reason for missing parsed attributes in Qi JSON parser. The parser successfully parses the input string but the output data structure, json_object, only contains the first attribute (attribute_a) but missing the others (attribute_b and attribute_c)
Software: Boost Spirit Qi using Boost 1.52
Platform: Windows 7 (64-bit)
Compiler (Visual Studio 2010)
Request:
Help finding out why the parser is not finding all attributes.
Looking at the debugging output I see that the attributes are not being put into a single std::vector object. I am using JSON grammar I found on http://www.json.org/ as a reference. What I would like to see as the output of the 'members' is a single std::vector containing a list of all json_pair objects found for that JSON object.
Limitations:
- Parser does not support Unicode strings.
Code:
#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; }
vector. If you change the rulesmembersandelementsas suggested by FatalFlaw and make their attributesstd::vector<json_pair>andstd::vector<json_value>respectively, you will get the result you want with that input.\b\f\r\n\0\") and accepting non-JSON-compliant numeric formats (including but not limited to ±∞ and NaN)