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 rulesmembers
andelements
as 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. – user1252091\b\f\r\n\0\"
) and accepting non-JSON-compliant numeric formats (including but not limited to ±∞ and NaN) – sehe