|
Introduction
JSON is a text file format similar to XML, but less verbose. It has been called "XML lite". This article describes JSON Spirit, a C++ library that reads and writes JSON files or streams. It is written using the Boost Spirit parser generator. If you are already using Boost, you can use JSON Spirit without any additional dependencies.
The library supports Unicode from version 2.0.
The JSON Spirit source code is available as a Microsoft Visual Studio 2005 C++ "solution". However, it should compile and work on any platform compatible with Boost. JSON Spirit has been built and tested with Microsoft Visual Studio C++ 2003, 2005, 2008, and G++ version 4.2.3 on Linux. It has been tested on Windows with Boost versions 1.33.1, 1.34.0, and 1.34.1. It has also been tested with STLPort.
The Microsoft Visual Studio C++ solution consists of three projects:
- The JSON Spirit library
- A small program demonstrating how to use JSON Spirit
- An application running the library's unit tests
Using the Code
The Microsoft Visual Studio solution builds an object library. You can link to this object library or, alternately, you can add the JSON Spirit source files directly to your project. All JSON Spirit declarations are in the namespace json_spirit.
Reading JSON
You can read JSON data from a stream or a string:
bool read( const std::string& s, Value& value );
bool read( const std::wstring& s, wValue& value );
bool read( std::istream& is, Value& value );
bool read( std::wistream& is, wValue& value );
For example:
ifstream is( "json.txt" );
Value value;
read( is, value );
A JSON value can hold either a JSON array, JSON object, string, integer, double, bool , or null. A Value uses std::string to hold JSON names and strings, whereas wValue uses std::wstring. This makes wValue suitable to hold data read from Unicode files and strings. The interface of the JSON Spirit Value class is shown below, and the interface to wValue is analogous; for details, see the section on Unicode support.
enum Value_type{ obj_type, array_type, str_type,
bool_type, int_type, real_type, null_type };
class Value
{
public:
Value();
Value( const char* value );
Value( const std::string& value );
Value( const Object& value );
Value( const Array& value );
Value( bool value );
Value( int value );
Value( double value );
bool operator==( const Value& lhs ) const;
Value_type type() const;
const std::string& get_str() const;
const Object& get_obj() const;
const Array& get_array() const;
bool get_bool() const;
int get_int() const;
double get_real() const;
Object& get_obj();
Array& get_array();
template< typename > T get_value() const;
static const Value null;
private:
...
};
You obtain the Value's type by calling Value::type(). You can then call the appropriate getter function. Generally, you will know a file's format, so you will know what type the JSON values should have.
The template getter function get_value() is an alternative to get_int(), get_real(), etc. Example usage would be:
int i = value_1.get_value< int >();
double d = value_2.get_value< double >();
A top level Value read from a file or stream normally contains an Array or an Object. An Array is an std::vector of values. An Object is an std::vector of JSON pairs.
typedef std::vector< Pair > Object;
typedef std::vector< Value > Array;
A Pair is a structure that holds an std::string and a Value. A wPair holds an std::wstring and a wValue.
struct Pair
{
Pair( const std::string& name, const Value& value );
bool operator==( const Pair& lhs ) const;
std::string name_;
Value value_;
};
JSON Arrays and Objects can themselves contain other Arrays or Objects, forming a tree.
Writing JSON
To output JSON, first create a Value or wValue object containing your data. Then, write the created value object to a stream or string. There are two versions of each function: one outputs the JSON data without any whitespace, the other formats the data by adding whitespace and line breaks.
void write ( const Value& value, std::ostream& os );
void write_formatted( const Value& value, std::ostream& os );
std::string write ( const Value& value );
std::string write_formatted( const Value& value );
std::wstring write ( const wValue& value );
std::wstring write_formatted( const wValue& value );
void write ( const wValue& value, std::wostream& os );
void write_formatted( const wValue& value, std::wostream& os );
The following example shows how to create a small JSON file containing an object with three members:
Object addr_obj;
addr_obj.push_back( Pair( "house_number", 42 ) );
addr_obj.push_back( Pair( "road", "East Street" ) );
addr_obj.push_back( Pair( "town", "Newtown" ) );
ofstream os( "address.txt" );
write_formatted( addr_obj, os );
os.close();
The object addr_obj is automatically converted into a Value as it is passed to write_formatted. The file address.txt will contain:
{
"house_number" : 42,
"road" : "East Street",
"town" : "Newtown"
}
Unicode Support
Unicode support is provided by a std::wstring version of the Value and Pair types of each function. Note that there is no support for reading Unicode files and converting them to wstrings as this is not a task specific to JSON. The Value and wValue classes are actually instantiations of the template class Value_impl. Value_impl takes a string type as its template parameter.
typedef Value_impl< std::string > Value;
typedef Value_impl< std::wstring > wValue;
There are also wString versions of JSON Spirit's Array, Object, and Pair. These are called wArray, wObject, and wPair.
Include Files
To read JSON files, you will need to include json_spirit_reader.h and json_spirit_value.h. To generate JSON files, you will need to include json_spirit_writer.h and json_spirit_value.h. Alternately, you can include json_spirit.h, which includes all three of the above.
Using JSON Spirit with Multiple Threads
If you intend to use JSON Spirit in more than one thread, you will need to uncomment the following line near the top of json_spirit_reader.cpp.
In this case, Boost Spirit will require you to link against Boost Threads.
History
- 10th August 2007, Version 1.00.
- 12th August 2007
- Part of the Boost Spirit Applications Repository.
- 20th August 2007, Version 1.01.
- Fixed bug outputting escape characters.
- 9th October 2007, Version 1.02.
- Fixed bug inputting "\/".
- No longer attaches a semantic action
c_ecscape_ch_p, simplifying the code.
- Speed optimizations.
- 9th November 2007, Version 2.00.
- Unicode support.
- Writes out "/" without a "\" escape character.
- 14th December 2007, Version 2.01.
- Increased precision of floating point number output.
- 12th February 2008, Version 2.02, bug fixes.
- Value construction from explicit
const char*.
- Writes out extended ASCII.
- 1st March 2008, Version 2.03.
- Added support for 64-bit integers.
- 22nd April 2008, Version 2.04.
- Allows the reading of top level values other than
Arrays and Objects, see Daniel Friederich's message thread below.
- Fixed bug where. e.g.. "
[ 1 2 ]" is read as "[ 1, 2 ]".
- Added template getter function
get_value().
- 2nd June 2008, Version 2.05.
- Linux version added.
- Commented out
#define BOOST_SPIRIT_THREADSAFE.
- 12th September 2008, Version 2.06.
- Now works when MSVC 2005 is using STLPort.
| You must Sign In to use this message board. |
|
| | Msgs 1 to 25 of 101 (Total in Forum: 101) (Refresh) | FirstPrevNext |
|
 |
|
|
Hello, i'm using your library in a backend server application. I've made some tweaks to improve performance and i'd like to share them and know your opinion.
1) Value_Impl Created an union whith the bool_, i_ and d_ union{ bool bool_; boost::int64_t i_; double d_; }; this change improved performance more than i expected.
2) Rules. Rewrote some rules avoiding confix_p. object_ = ch_p('{')[ begin_obj ] >> !members_ >> ch_p('}')[ end_obj ] ; array_ = ch_p('[')[ begin_array ] >> !elements_ >> ch_p(']')[ end_array ]; string_ = lexeme_d [Char_t('"') >> *(lex_escape_ch_p - '"') >> Char_t('"')];
This change improved performance by 10% in my test case (a lot of arrays and strings).
The other changes are related to trim copy and creation of values (swap, setters for values in Value_Impl, etc.)
Do you think the rules are correct?
Thanks
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Thanks for the info. Using a union reduced the size of a Value from 72 to 56 bytes which is a good improvement. The use of confix_p for objects and arrays does seem unnecessary as a member cannot be "}" and an element cannot be "]", so I will remove them for code clarity. However without using confix_p for strings you need to add the " - '"'" as per your code above so perhaps it is worth retaining in this case.
I have however failed to get any speed improvements from the above changes. This is using the simple speed test at the end of json_spirit::test_reader(). It it possible to post your test cases?
Regards
John
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hello, i have a small test project showing the test case and the improvement for the grammer case. It is a simple loop (1000) parsing a given string.
The improvement is about 5% in my configuration (Intel T1350, XP, 2GB, VS2005 SP1) and if you think that the test total time is built from parse + construct objects + delete objects, the parsing time has to be improved more than that.
I don't know how to post this test project here so you can view it. If there is a way to attach here a zip with the source code, i''ll post it.
The data i've used for this test is (a lot of arrays of pairs of string) has this pattern. [ [ ["" , ""], .. 60 ], .. 2 ] .. 1
Data:
[[["Field_1_0", "Field_2_0"], ["Field_1_1", "Field_2_1"], ["Field_1_2", "Field_2_2"], ["Field_1_3", "Field_2_3"], ["Field_1_4", "Field_2_4"], ["Field_1_5", "Field_2_5"], ["Field_1_6", "Field_2_6"], ["Field_1_7", "Field_2_7"], ["Field_1_8", "Field_2_8"], ["Field_1_9", "Field_2_9"], ["Field_1_10", "Field_2_10"], ["Field_1_11", "Field_2_11"], ["Field_1_12", "Field_2_12"], ["Field_1_13", "Field_2_13"], ["Field_1_14", "Field_2_14"], ["Field_1_15", "Field_2_15"], ["Field_1_16", "Field_2_16"], ["Field_1_17", "Field_2_17"], ["Field_1_18", "Field_2_18"], ["Field_1_19", "Field_2_19"], ["Field_1_20", "Field_2_20"], ["Field_1_21", "Field_2_21"], ["Field_1_22", "Field_2_22"], ["Field_1_23", "Field_2_23"], ["Field_1_24", "Field_2_24"], ["Field_1_25", "Field_2_25"], ["Field_1_26", "Field_2_26"], ["Field_1_27", "Field_2_27"], ["Field_1_28", "Field_2_28"], ["Field_1_29", "Field_2_29"], ["Field_1_30", "Field_2_30"], ["Field_1_31", "Field_2_31"], ["Field_1_32", "Field_2_32"], ["Field_1_33", "Field_2_33"], ["Field_1_34", "Field_2_34"], ["Field_1_35", "Field_2_35"], ["Field_1_36", "Field_2_36"], ["Field_1_37", "Field_2_37"], ["Field_1_38", "Field_2_38"], ["Field_1_39", "Field_2_39"], ["Field_1_40", "Field_2_40"], ["Field_1_41", "Field_2_41"], ["Field_1_42", "Field_2_42"], ["Field_1_43", "Field_2_43"], ["Field_1_44", "Field_2_44"], ["Field_1_45", "Field_2_45"], ["Field_1_46", "Field_2_46"], ["Field_1_47", "Field_2_47"], ["Field_1_48", "Field_2_48"], ["Field_1_49", "Field_2_49"], ["Field_1_50", "Field_2_50"], ["Field_1_51", "Field_2_51"], ["Field_1_52", "Field_2_52"], ["Field_1_53", "Field_2_53"], ["Field_1_54", "Field_2_54"], ["Field_1_55", "Field_2_55"], ["Field_1_56", "Field_2_56"], ["Field_1_57", "Field_2_57"], ["Field_1_58", "Field_2_58"], ["Field_1_59", "Field_2_59"]],[["Field_1_0", "Field_2_0"], ["Field_1_1", "Field_2_1"], ["Field_1_2", "Field_2_2"], ["Field_1_3", "Field_2_3"], ["Field_1_4", "Field_2_4"], ["Field_1_5", "Field_2_5"], ["Field_1_6", "Field_2_6"], ["Field_1_7", "Field_2_7"], ["Field_1_8", "Field_2_8"], ["Field_1_9", "Field_2_9"], ["Field_1_10", "Field_2_10"], ["Field_1_11", "Field_2_11"], ["Field_1_12", "Field_2_12"], ["Field_1_13", "Field_2_13"], ["Field_1_14", "Field_2_14"], ["Field_1_15", "Field_2_15"], ["Field_1_16", "Field_2_16"], ["Field_1_17", "Field_2_17"], ["Field_1_18", "Field_2_18"], ["Field_1_19", "Field_2_19"], ["Field_1_20", "Field_2_20"], ["Field_1_21", "Field_2_21"], ["Field_1_22", "Field_2_22"], ["Field_1_23", "Field_2_23"], ["Field_1_24", "Field_2_24"], ["Field_1_25", "Field_2_25"], ["Field_1_26", "Field_2_26"], ["Field_1_27", "Field_2_27"], ["Field_1_28", "Field_2_28"], ["Field_1_29", "Field_2_29"], ["Field_1_30", "Field_2_30"], ["Field_1_31", "Field_2_31"], ["Field_1_32", "Field_2_32"], ["Field_1_33", "Field_2_33"], ["Field_1_34", "Field_2_34"], ["Field_1_35", "Field_2_35"], ["Field_1_36", "Field_2_36"], ["Field_1_37", "Field_2_37"], ["Field_1_38", "Field_2_38"], ["Field_1_39", "Field_2_39"], ["Field_1_40", "Field_2_40"], ["Field_1_41", "Field_2_41"], ["Field_1_42", "Field_2_42"], ["Field_1_43", "Field_2_43"], ["Field_1_44", "Field_2_44"], ["Field_1_45", "Field_2_45"], ["Field_1_46", "Field_2_46"], ["Field_1_47", "Field_2_47"], ["Field_1_48", "Field_2_48"], ["Field_1_49", "Field_2_49"], ["Field_1_50", "Field_2_50"], ["Field_1_51", "Field_2_51"], ["Field_1_52", "Field_2_52"], ["Field_1_53", "Field_2_53"], ["Field_1_54", "Field_2_54"], ["Field_1_55", "Field_2_55"], ["Field_1_56", "Field_2_56"], ["Field_1_57", "Field_2_57"], ["Field_1_58", "Field_2_58"], ["Field_1_59", "Field_2_59"]]]
Regards
Juan
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I've forgot to say that i've used a home made replacement for std::wstring in the tests because i need to work with OLE strings (SysAllocString & friends).
Sorry about my english 
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I am getting a nice 10% speed increase using your test data. As you said the biggest improvement is due to removing the array and object confix parses.
Thanks again
John
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
I used json_spirit for a demo where we were only generating JSON. Since it seems to be the only JSON API supporting wide characters it was pretty much the only choice.
Now we are looking to add reading of JSON messages and I ran into a problem here. In this application I want to be able to have a sequence of JSON objects concatenated together. I want to read each one, process it, then move on to the next one. I'm sure you're asking why don't I put them into a JSON Array. The problem there is that would require parsing the entire array of objects before I can process any of them.
In other JSON parsers (e.g. org.JSON parser for Java) you can read a JSON object from an input stream then read another and so on. The JSONTokener object even provides a convenient more() method to check to see if there are more objects in the stream.
json_spirit on the other hand always consumes its entire input. When you pass it a stream it reads the entire stream into a string and sends the string to the parser. The return value will only say it successfully parsed if all of the input was consumed.
I would like to suggest that:
- end_p be removed from the grammar as you should not have to read to the end of the input. - It would be nice if the parser could consume all whitespace after the value. Perhaps replacing the end_p with *space_p would do it. - You should add new read calls that take an iterator pair (reference to begin iterator and end iterator value). - This iterator-based read call should return parse_info.hit not parse_info.full because it does not have to consume the entire input. - The reader calls that take input stream should call the iterator-based read call passing in an instance of istream_iterator.
That would then allow you to read a value without consuming all input. The string call should probably still return parse_info.full since you have no way to read further values. If you need to read a sequence of values then you can use the iterator call.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Reading about spirit a little further I see that this will require using a multi-pass iterator:
http://spirit.sourceforge.net/distrib/spirit_1_6_3/libs/spirit/doc/multi_pass.html
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I know this is a current limitation. I will look into a solution and into multi-pass iterators.
Could you confirm the rational for using a pair of iterators, i.e. after a read the begin iterator would be advanced, the end iterator being passed by value and used by the parse to determine the end of data?
Regards
John
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
The pair of iterators is just how iterators in STL work. You have one that is the current position and the other one is the one you compare to using == to see if you are done reading. Having a pair of iterators makes more sense when using a string where you might want to iterate over a substring. For a stream of data like istream it seems a little wierd but is still done the same way. The end iterator is just a special instance constructed with no parameter constructor.
If you look at the source code for istream_iterator it might make more sense.
I threw together my own parser and will probably use that instead. But in general you should support this mode of operation.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I'm curious about the choice of a std::vector for an Object. Property lookups in constant time pretty much rules out JSON Spirit for me. Nice clean API though, I would like to use it and I'm sure it is very handy for many. Thanks for your contribution.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
That's a good question that has been asked before. I did consider using the std::map for JSON Objects instead of std::vector. Using map means that you cannot have the same property twice which is a very strong point in its favour. It would also be faster for Objects with many fields, although the reverse would be true for small objects. However the main reason to uses a vector, if I remember correctly, was to enable object fields to be written out in the same order they were read in. Map would sort the pairs alphabetically.
You can of course convert a vector of pairs to a name/value map pretty easily:
template< class Obj_t, class Map_t > void obj_to_map( const Obj_t& obj, Map_t& mp_obj ) { mp_obj.clear();
for( typename Obj_t::const_iterator i = obj.begin(); i != obj.end(); ++i ) { mp_obj[ i->name_ ] = i->value_; } }
The above utility function will be in the next JSON Spirit release.
Regards
John
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Ah... Ordering is a very good reason I had not considered. I agree humans reading the data will be much more comfortable if the pairs maintain order.
The example above copies the values from the vector into the map, so you've got two copies of the JSON object, plus you also have to synchronize changes to both structures if you really want to use the vector to serialize the object in the same order it was parsed. Sounds like some delicate API design. Which is why I was looking to borrow someone else's work for this bit! 
Regarding "...same property twice...", that is also an interesting issue. I just looked at the spec, and it says that names SHOULD be unique, implying that there are circumstances in which it might be ok to have multiple pairs with the same name. I can think of one--using JSON to represent RDF, where a resource (the JSON object) may be the subject of many statements with the same predicate (the pair name).
I'm just exploring, not advocating for a multi-map! As a practical matter, it seems unwieldy and I personally I can't imagine wanting to use JSON with non-unique pair names.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I can't think of a solution that would work in all situations, perhaps a multi-index multi-map, with two keys, names and position. However such a solution would be complex and very difficult to make backwards compatible.
|
| Sign In·View Thread·PermaLink | 2.00/5 (1 vote) |
|
|
|
 |
|
|
Version 2.05 notes, "Linux version added". I don't see anything in 2.06 specific to Linux. Did it get omitted from build 2.06? Anyone have a copy of 2.05 I could get?
I have been trying to build in both Fedora 8 and 9 and haven't had any luck. If someone has a make file or script I would appreciate it.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I followed Johan Euphrosine's lead and tried CMake to try and get past my compilation problems.
Here they are in brief.
json_spirit_value_test.cpp: In function ‘void::test_copying()’: json_spirit_value_test.cpp:176: error: call of overloaded ‘vector(boost::assign_detail::generic_list&)’ is ambiguous std::vector<_Tp, _Alloc>::vector(const std::vector<_Tp, _Alloc>&) std::vector<_Tp, _Alloc>::vector(size_t, const _Tp&, const _Alloc&) std::vector<_Tp, _Alloc>::vector(const _Alloc&)
I get 3 more ambigous erros on lines 190, 211, and 212.
The gory details can be found here.
g++ v4.1.2 <- the latest my Fedora 8 will give me. Boost v1.34.1 <- the latest my Fedora 8 will give me.
I was successful getting this to work in XP with Visual Studio but ultimately I need this in Fedora.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Apologies, I forgot to check v2.06 compiles with G++. The fix however is to replace
const Array array_1( list_of(1)(2) ); with
const Array array_1 = list_of(1)(2); and to make corresponding changes for the other 3 errors.
I will release a fix shortly.
Regards John
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
We are hoping to use this package in a multithreaded application. We also want to leave the source code as untouched as possible so that any future upgrades will be as easy as downloading new source files and rebuilding the library. So, the 2 challenges I see are 1) defining BOOST_SPIRIT_THREADSAFE. Since we are building with a Makefile I suppose we can put a define for this in there and leave the one in the code commented out? 2) Linking to boost.thread. We would like to also take case of this without modifying any source files. Is there any way to dynamically link to boost.thread (using a makefile or otherwise)?
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
I have studies the code and boost spirit but I still do not understand the treatment of names without quotes. In the code the definition of string_ is string_ = lexeme_d // this causes white space inside a string to be retained [ confix_p ( '"', *lex_escape_ch_p, '"' ) ] ; but of course strings are not only escaped characters. I cannot find any other definition of string_ , I am very, very perplexed.
I need a language that easily defines structure for people who want to spend the minimum amount of time writing: biologists who describe how genes or metabolites interact. I read many discussions that made reference to XML and JSON. The only disadvantage of JSON is that every string needs to be surrounded by quotes. This disadvantage is not only my own opinion. That is the reason why I am trying to understand the parser.
For demo.txt I removed quotes around words without blanks, the parser JSON Spirit had no problem reading the demo.txt . I've made an effort to read and understand the C++ program but what I see is perplexing as described in the first paragraph. I need a confirmation by the author of the code, if I leave out most nearly all quotes aside from imbedded space (which in fact I will not be using in strings), will the parser read correctly.
If that is the case, JSON would be ideal for my purposes.
Best regards, Alan Scheinine
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi Alan,
lex_escape_ch_p also parses non escaped characters so "string_" handles all strings whether they contain escape characters or not.
Sorry but the parser will only read strings if they are in quotes. Without the quotes there is no telling where the string will end, ':' could be part of the string. I don't know how you got it to read demo.txt, perhaps you are unaware that the demo program first creates the file then reads it.
Best regards John
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
John W. Wilkinson wrote: > don't know how you got it to read demo.txt My mistake, I studied the demo program further this afternoon and I see that demo.txt was first constructed then read. Making a modification to the program to create a test, I see that quotes are necessary.
With regard to > lex_escape_ch_p also parses non escaped characters your remark is very valuable. I read the definition several times yesterday, on the web page of boost spirit one reads, > lex_escape_ch_p all C/C++ escaped character sequences as described > above and additionally any other character, which follows a backslash which left me perplexed because of the last four words of the sentence. Your explanation was very helpful.
For a long time, 20 years more or less, I've thought about how to organize data and parameters for programs -- but at a very simple level. For years I used 12.2 10.8 3 max min iter where the order was fixed and every second line skipped. I made an effort to convert to XML with C++ that could feed parameter values to C, C++ and Fortran and it worked. But for anyone else my XML solution was ugly in comparison to the old-fashion way. I've also done more complicated projects, in particular organizing a bibliography and organizing notes on an application description. The overall thread is the need to organize a bit a collection of info so it can be parsed without scaring away colleagues due to a complex syntax. Now I need to describe graphs (vertices and edges) that have attributes and nested structures. I need to propose the syntax to others who balk at anything complicated. For most programming languages the character set of a variable name excludes special operators, such as ":" in your example, thereby avoiding confusion. Since I'll be describing a structure between "variable names" with the restricted character set, JSON without the requirement of quotes seems to me to be an ideal language.
I'm not asking for help. I'm reading the Boost Spirit documentation and I plan on testing modifications to your program. I see that the use of quotes is relevant to only a few places in the program, I've found the parser definition and new_name were the first and last characters (being ") are eliminated before a function call. Perhaps I will succeed in making the change for my specific needs. I was really stuck due to the misleading (IMHO) definition in the boost.org documentation, so thanks again for your help.
Alan
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Imagine how difficult it would be to write a computer program if every variable name needed to be placed between quotes. Perhaps the following changes would be useful for some people. I realize that the following is no longer JSON, but as a language for describing structure it may be useful.
Quite simply, words similar to program variables do not require being surrounded by quote marks.
In file json_spirit_reader.cpp
Added at top:
namespace { // Added by A.L.S. chset<> varstart("a-zA-Z"); chset<> varname("0-9a-zA-Z$%_.+"); chset<> dashch('-');
New definition of string:
string_ = lexeme_d // this causes white space inside a string to be retained [ confix_p ( '"', *lex_escape_ch_p, '"' ) ] | // Added by A.L.S. ( varstart >> *( varname | dashch ) ) - ( str_p( "true" ) | str_p( "false" ) | str_p( "null" ) ) ;
Modified subroutine:
// Changed by A.L.S. static String_t get_str( Iter_t str, Iter_t end ) { Iter_t str_without_quotes; Iter_t end_without_quotes; if ( *str == '"' && *( end - 1 ) == '"' ) { assert( end - str >= 2 ); str_without_quotes = str + 1; end_without_quotes = end - 1; } else if ( *str != '"' && *( end - 1 ) != '"' ) { str_without_quotes = str; end_without_quotes = end; } else { assert( false ); }
/* Iter_t str_without_quotes( str + 1 ); Iter_t end_without_quotes( end - 1 ); */
return substitute_esc_chars( str_without_quotes, end_without_quotes ); }
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi,
First of all, thanks for a very useful library.
However, when integrating it into my project, I noticed some areas for improvement (I might be wrong, but thought I'd make the suggestion anyway):
1. Value always copies the string it is created with. This is fine when reading in a JSON stream, but not s | | | | | |