5,693,062 members and growing! (18,300 online)
Email Password   helpLost your password?
General Programming » Algorithms & Recipes » Parsers     Intermediate License: The Code Project Open License (CPOL)

JSON Spirit: A C++ JSON Parser/Generator Implemented with Boost Spirit

By John W. Wilkinson

A C++ JSON parser/generator written using boost::spirit.
C++, Windows, Visual Studio, Dev

Posted: 15 Aug 2007
Updated: 12 Sep 2008
Views: 80,150
Bookmarked: 53 times
Announcements
Loading...



Search    
Advanced Search
Sitemap
29 votes for this Article.
Popularity: 6.75 Rating: 4.62 out of 5
2 votes, 6.9%
1
1 vote, 3.4%
2
0 votes, 0.0%
3
2 votes, 6.9%
4
24 votes, 82.8%
5

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:

  1. The JSON Spirit library
  2. A small program demonstrating how to use JSON Spirit
  3. 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();  // creates null 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.

//#define BOOST_SPIRIT_THREADSAFE

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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

John W. Wilkinson



Occupation: Software Developer (Senior)
Location: United Kingdom United Kingdom

Other popular Algorithms & Recipes articles:

Article Top
Sign Up to vote for this article
You must Sign In to use this message board.
FAQ FAQ Noise ToleranceSearch Search Messages 
 Layout  Per page   
 Msgs 1 to 25 of 101 (Total in Forum: 101) (Refresh)FirstPrevNext
GeneralSome performance changesmemberMember 99271011:18 21 Nov '08  
GeneralRe: Some performance changesmemberJohn W. Wilkinson10:50 25 Nov '08  
GeneralRe: Some performance changesmemberMember 9927102:34 26 Nov '08  
GeneralRe: Some performance changesmemberMember 9927102:42 26 Nov '08  
GeneralRe: Some performance changesmemberJohn W. Wilkinson10:40 26 Nov '08  
GeneralRe: Some performance changesmemberMember 9927101:33 27 Nov '08  
GeneralReader should not consume all inputmemberDaleKing17:51 14 Nov '08  
GeneralRe: Reader should not consume all inputmemberDaleKing18:13 14 Nov '08  
GeneralRe: Reader should not consume all inputmemberJohn W. Wilkinson10:36 16 Nov '08  
GeneralRe: Reader should not consume all inputmemberDaleKing7:20 17 Nov '08  
GeneralWhy a vector?memberAnderson Wiese19:42 25 Oct '08  
GeneralRe: Why a vector?memberJohn W. Wilkinson5:19 26 Oct '08  
GeneralRe: Why a vector?memberAnderson Wiese6:05 26 Oct '08  
GeneralRe: Why a vector?memberJohn W. Wilkinson10:46 26 Oct '08  
GeneralLinux SupportmemberMark Gerrior7:51 9 Oct '08  
GeneralRe: Linux SupportmemberMark Gerrior15:01 10 Oct '08  
GeneralRe: Linux SupportmemberJohn W. Wilkinson10:40 11 Oct '08  
QuestionDynamically linking to boost.threadmemberJeffrey Stemple9:52 8 Oct '08  
AnswerRe: Dynamically linking to boost.threadmemberJohn W. Wilkinson23:16 8 Oct '08  
Generalstrings without quotesmemberalanscheinine11:40 30 Sep '08  
GeneralRe: strings without quotesmemberJohn W. Wilkinson10:27 1 Oct '08  
GeneralRe: strings without quotesmemberalanscheinine11:08 1 Oct '08  
GeneralRe: strings without quotesmemberalanscheinine20:09 3 Oct '08  
GeneralEfficiency: propose adding a swap c'tor to Valuememberamit_jain6:06 12 Sep '08