a header-file-only, JSON parser serializer in C++

PicoJSON - a C++ JSON parser / serializer

Copyright © 2009-2010 Cybozu Labs, Inc. Copyright © 2011-2015 Kazuho Oku

Licensed under 2-clause BSD license

Version

1.3.1-dev Build Status

Introduction

PicoJSON is a tiny JSON parser / serializer for C++ with following properties:

  • header-file only
  • no external dependencies (only uses standard C++ libraries)
  • STL-frendly (arrays are represented by using std::vector, objects are std::map)
  • provides both pull interface and streaming (event-based) interface

Reading JSON using the pull interface

There are several ways to use the pull (DOM-like) interface of picojson.

The easiest way is to use the two-argument parse function.

std::string json = "[ \"hello JSON\" ]";
picojson::value v;
std::string err = picojson::parse(v, json);
if (! err.empty()) {
  std:cerr << err << std::endl;
}

Four-argument parse function accepts a pair of iterators, and returns the end position of the input.

const char* json = "{\"a\":1}";
picojson::value v;
std::string err;
const char* json_end = picojson::parse(v, json, json + strlen(json), &err);
if (! err.empty()) {
  std::cerr << err << std::endl;
}
std::istream_iterator input(std::cin);
picojson::value v;
std::string err;
input = picojson::parse(v, input, std::istream_iterator(), &err);
if (! err.empty()) {
  std::cerr << err << std::endl;
}

It is also possible to use the >> operator to parse the input, however this interface is not thread-safe.

picosjon::value v;
std::cin >> v;
std::string err = picojson::get_last_error();

Accessing the values

Values of a JSON object is represented as instances of picojson::value class.

namespace picojson {

  class value {
    ...

  public:

    typedef std::vector<value> array;
    typedef std::map<std::string, value> object;

    value();                               // create a null object
    explicit value(bool b);                // create a boolean object
    explicit value(double n);              // create a number object
    explicit value(const std::string& s);  // create a string object
    explicit value(const array& a);        // create an array object
    explicit value(const object& o);       // create an "object"

    bool is<picojson::null>() const;       // check if the object is "null"

    bool is<bool>() const;                 // check if the object is a boolean
    const bool& get<bool>() const;         // const accessor (usable only if the object is a boolean)
    bool& get<bool>();                     // non-const accessor (usable only if the object is a boolean)

    bool is<double>() const;               // check if the object is a number
    const double& get<double>() const;     // const accessor (usable only if the object is a number)
    double& get<double>();                 // non-const accessor (usable only if the object is a number)

    bool is<std::string>() const;          // check if the object is a string
    const std::string& get<std::string>() const;
                                           // const accessor (usable only if the object is a string)
    std::string& get<std::string>();       // non-const accessor (usable only if the object is a string)

    bool is<array>() const;                // check if the object is an array
    const array& get<array>() const;       // const accessor (usable only if the object is an array)
    array& get<array>();                   // non-const accessor (usable only if the object is an array)

    bool is<object>() const;               // check if the object is an "object"
    const object& get<object>() const;     // const accessor (usable only if the object is an object)
    object& get<object>();                 // non-const accessor (usable only if the object is an array)

    bool evaluate_as_boolean() const;      // evaluates the object as a boolean

    std::string serialize() const;         // returns the object in JSON representation
    template void serialize(Iter os) const;
                                           // serializes the object in JSON representation through an output iterator

    std::string to_str() const;            // returns the object in string (for casual use)

  };

}

The code below parses a JSON string and prints the contents of the object.

picojson::value v;

// parse the input
std::cin >> v;
std::string err = picojson::get_last_error();
if (! err.empty()) {
  std::cerr << err << std::endl;
  exit(1);
}

// check if the type of the value is "object"
if (! v.is<picojson::object>()) {
  std::cerr << "JSON is not an object" << std::endl;
  exit(2);
}

// obtain a const reference to the map, and print the contents
const picojson::value::object& obj = v.get<picojson::object>();
for (picojson::value::object::const_iterator i = obj.begin();
     i != obj.end();
     ++i) {
  std::cout << i->first << ': ' << i->second.to_str() << std::endl;
}

Please note that the type check is mandatory; do not forget to check the type of the object by calling is<type>() before accessing the value by calling get<type>().

Reading JSON using the streaming (event-driven) interface

Please refer to the implementation of picojson::default_parse_context and picojson::null_parse_context. There is also an example (examples/streaming.cc) .

Serializing to JSON

Instances of the picojson::value class can be serialized in three ways, to ostream, to std::string, or to an output iterator.

picojson::value v;
...
std::cout << v;
picojson::value v;
...
std::string json = v.serialize();
picojson::value v;
...
v.serialize(std::ostream_iterator<char>(std::cout));

Experimental support for int64_t

Experimental suport for int64_t becomes available if the code is compiled with preprocessor macro PICOJSON_USE_INT64.

Turning on the feature will cause following changes to picojson:

  • new constructor picojson::value(int64_t) is defined
  • is<int64_t>() and get<int64_t>() become available
  • numerics in JSON within the bounds of int64_t and not using . nor e/E are considered as int64 type
  • the values are also avaliable as doubles as well (i.e. all values which are .is<int64_t>() == true are also .is<double>() == true)
  • int64 values are converted to double once get<double>() is called

Enabling the feature should not cause compatibility problem with code that do not use the feature.

Further reading

Examples can be found in the examples directory, and on the Wiki. Please add your favorite examples to the Wiki.

Comments
  • Add example how to serialize C++ data to JSON

    Add example how to serialize C++ data to JSON

    I don't need to parse JSON, but want to write some data I have as std::string, std:vector<float>, int, ... to JSON.

    Is it possible to create and fill a picojson::value object programatically? (I think this is not covered by the README and the examples ... sorry if I missed it.)

  • value::operator= does not allow for navigation

    value::operator= does not allow for navigation

    The current implementation of value::operator= first destroys the current value and then assigns the new value.

    This breaks cases in which you want to descend iteratively down an object hiearchy, as in the following example:

    for (auto k : paths) // paths is an iterator of keys
    {
        if (branchV.is<picojson::null>()
            || !branchV.is<picojson::object>())
        {
            throw JSONFieldConversionException("JSON value is null or not an object");
        }
    
        const picojson::value::object & obj = branchV.get<picojson::object>();
        const auto & it = obj.find(k);
        if (it == obj.end())
        {
                throw JSONFieldConversionException("Cannot find element \"" + k + "\" in JSON object");
        }
    
        branchV = it->second; // this breaks
    }
    

    The last statement breaks because the assignment first destroys the current value, which ends up invalidating the iterator.

  • Consider adding picotest/picotest.[ch] to the release tarball

    Consider adding picotest/picotest.[ch] to the release tarball

    The 1.2.0 tarball doesn't have picotest/picotest.[ch] files causing 'make test' to fail with missing files error. Is there a possibility to do tag another release (1.2.1) with those files included in the tarball?

  • Crashes parsing end of array or empty array

    Crashes parsing end of array or empty array

    The following JSON causes the code below it to fail when it gets to the end of the array. Specifically, I get a bad_alloc exception (on OS X):

    Podtique(44576,0x7fff7c44d300) malloc: *** mach_vm_map(size=107202383921152) failed (error code=3)
    *** error: can't allocate region
    *** set a breakpoint in malloc_error_break to debug
    

    This happens on the line with " <===== bad_alloc" below.

    [
        {
            "freq" : 0.1,
            "desc" : "Desc1",
            "playlist" :
            [
            ]
        }
    ]
    
    [
        {
            "freq" : 0.1,
            "desc" : "Desc2",
            "playlist" :
            [
                "one",
                "two"
            ]
        }
    ]
    
    bool
    getFromJSONIter(picojson::value::array::const_iterator& inIter, const std::string& inKey, std::string& outVal)
    {
        if (!inIter->is<picojson::value::object>())
        {
            return false;
        }
    
        picojson::value::object obj = inIter->get<picojson::value::object>();
        const picojson::value& v = obj[inKey];
        if (!v.is<std::string>())
        {
            return false;
        }
        outVal = v.get<std::string>();
    
        return true;
    }
    
    bool
    getFromJSONIter(picojson::value::array::const_iterator& inIter, const std::string& inKey, double& outVal)
    {
        if (!inIter->is<picojson::value::object>())
        {
            return false;
        }
    
        picojson::value::object obj = inIter->get<picojson::value::object>();
        const picojson::value& v = obj[inKey];
        if (!v.is<double>())
        {
            return false;
        }
        outVal = v.get<double>();
    
        return true;
    }
    
    bool
    getFromJSONIter(picojson::value::array::const_iterator& inIter, const std::string& inKey, picojson::value::array& outVal)
    {
        if (!inIter->is<picojson::value::object>())
        {
            return false;
        }
    
        picojson::value::object obj = inIter->get<picojson::value::object>();
        const picojson::value& v = obj[inKey];
        if (!v.is<picojson::value::array>())
        {
            return false;
        }
        outVal = v.get<picojson::value::array>();
    
        return true;
    }
    
    bool
    Spectrum::parseSpectrum(const picojson::value& inJSON)
    {
        //  Top level is an array…
    
        if (!inJSON.is<picojson::array>())
        {
            return false;
        }
    
        const picojson::value::array& stations = inJSON.get<picojson::array>();
        for (picojson::value::array::const_iterator iter = stations.begin(); iter != stations.end(); ++iter)
        {
            std::string desc;
            if (!getFromJSONIter(iter, "desc", desc)) { continue; }
    
            double freq;
            if (!getFromJSONIter(iter, "freq", freq)) { continue; }
    
            picojson::value::array playlist;
            if (!getFromJSONIter(iter, "playlist", playlist)) { continue; }
    
            LogDebug("Station: %s, freq: %f, tracks: %lu", desc.c_str(), freq, playlist.size());
    
            int i = 0;
            for (picojson::value::array::const_iterator trackIter = playlist.begin(); iter != playlist.end(); ++trackIter)
            {
                if (!trackIter->is<std::string>()) { continue; }
                std::string track = trackIter->get<std::string>();      <===== bad_alloc
                LogDebug("Track %02d: %s", i++, track.c_str());
            }
    
    
        }
        return true;
    }
    
  • fix build error

    fix build error

    I got build error on mingw32/windows.

    https://gist.github.com/mattn/2652a97bc8c8d733e525

    This mean, if compiler doesn't have c++11(or doesn't specified -std=c++11), cmath won't provide isanf/isnan to "C" namespace.

    https://github.com/kazuho/picojson/blob/master/picojson.h#L168-L172

    If __cplusplus less than 201103L, we should define isnan/isinf.

  • allow indentation

    allow indentation

    I was thinking of implementing the feature myself, but found this modification: https://code.google.com/p/tmlib-cpp/source/browse/trunk/samples/picojson-sample/picojson.h

    do you think, it is viable in the picojson master?

  • picojson eats one too many characters when parsing a number

    picojson eats one too many characters when parsing a number

    Error: When the string begins with a number, parsing eats one too many characters.

    Consider the string 2x. When picojson parses this it does:

    Start reading number: Get 2, fine. Get x, end of number, call ungetc, return. However, the character in the ungetc buffer gets dropped, and I have no way to access it. The return pointer points one past the x, so when I use to check if my whole buffer was parsed correctly, everything is fine.

  • Add modification methods

    Add modification methods

    Add a set of modification methods for picojson::value so that it can modify json DOM trees besides parsing and serializing them. Also added a test case in test.cc

  • Add utility `parse` function that takes a `std::string` as input

    Add utility `parse` function that takes a `std::string` as input

    In my application I always have a std::string and want to parse it into a picojson::value.

    @kazuho How about adding this utility function?

    #include <string>
    #include <sstream>
    #include "picojson.h"
    
    std::string parse(picojson::value& out, const std::string& in) {
        std::istringstream is(in);
        std::string err = picojson::parse(out, is);
        return err;
    }
    
    int main() {
        // Say you have a `std::string`
        std::string input = "[1, 2, ,3]";
    
        // Wouldn't it be nice to have a convenience function to parse
        // it without having to add an `sstream` include 
        // and creating a temp `istringstream` variable?
        picojson::value val;
        std::string err = parse(val, input);
    
        std::cout << err << std::endl;
        std::cout << val.serialize() << std::endl;
        return 0;
    }
    

    Actually often I don't care about the error ... in this case the most convenient thing would be

    picojson::value val = picojson::parse(std::string input);
    

    so this is a second utility function I'm proposing.

    (for my applications performance doesn't matter ... I just don't want to type a lot and spend time looking up which include I need for istringstream.)

  • Adding license clause to example files.

    Adding license clause to example files.

    https://bugzilla.redhat.com/show_bug.cgi?id=1112337

    • Should add license/copyright text to the four example-code files under /usr/share/doc/picojson-devel/examples
  • MSVC10: _isinf missing

    MSVC10: _isinf missing

    Line 166 of picojson.h, MSVC10 doesn't seem to define _isinf. A possible fix is to use !_finite(n) instead. I suggest using this one as it seems to be defined by all major Visual Studio compiler versions.

  • Is it ok if I publish a NuGet package?

    Is it ok if I publish a NuGet package?

    Hi folks, I am happily using picojson and loving it! My current project heavily uses NuGet packages, so here I am asking: is it ok if I package picojson and publish it to nuget.org? Of course, the package metadata would point to this repo, the existing readme/license, and have @kazuho as owner.

  • Fix warnings with gcc-12 & improve Makefile

    Fix warnings with gcc-12 & improve Makefile

    Valijson uses picojson as a driver, and we found that building with gcc-12 and optimization (e.g. -O2) causes picojson to emit warnings, see the long story here. The most important is the uninitialized storage warning, which only appears with optimization and gcc-12. Since master had a few updates sine the last release, the changes in this PR are fewer than for valijson, but they are still necessary to compile cleanly e.g. in projects that use -Werror (which is generally not recommended, but still..). The Makefile fix allows to pass in CXXFLAGS to build/test with different optimization flags.

  • Proposed macro to override throw #148

    Proposed macro to override throw #148

    The issue of switching throw to abort is similar to #117 and #118. In this assignment, replace throw with a macro so that exception messages can be handled by the application.

    Prepare a macro named PICOJSON_THROW.

    // add new macro
    #ifndef PICOJSON_THROW
    #define PICOJSON_THROW(e, m) throw e(m)
    #endif
    
    // replace throw
    #ifndef PICOJSON_ASSERT
    #define PICOJSON_ASSERT(e) \
      do { \
        if (!(e)) \
          PICOJSON_THROW(std::runtime_error, #e); \
      } while (0)
    #endif
    

    The application side overwrites abort and assert to use it. #define PICOJSON_THROW(e, m) { puts(#e ":" m); abort(); }

  • Proposed macro to override throw

    Proposed macro to override throw

    The issue of switching throw to abort is similar to #117 and #118. In this assignment, replace throw with a macro so that exception messages can be handled by the application.

    Prepare a macro named PICOJSON_THROW.

    // add new macro
    #ifndef PICOJSON_THROW
    #define PICOJSON_THROW(e, m) throw e(m)
    #endif
    
    // replace throw
    #ifndef PICOJSON_ASSERT
    #define PICOJSON_ASSERT(e) \
      do { \
        if (!(e)) \
          PICOJSON_THROW(std::runtime_error, #e); \
      } while (0)
    #endif
    

    The application side overwrites abort and assert to use it. #define PICOJSON_THROW(e, m) { puts(#e ":" m); abort(); }

  • value.set(T&&) is problematic

    value.set(T&&) is problematic

    This fixes an issue where we cannot call myValue.set(1.5) or double d=1.5; myValue.set(d); because both versions fail to link. They both match the forwarding reference set(T&&) function better than the expected set(T const&) version, and it is not defined for several types. Problems occur with double, bool, int64, and std::string. The problem with std::string is only with lvalues, in that the "non-const to const" conversion makes the set(std::string const&) a worse match than the rvalue forwardig reference, which was not defined.

    I changed the forwarding reference from a template to three explicit function declarations, so we don't have such a large set of interfaces inadvertently caught by the template.

    I also ran clang-format in another commit, prior to making the change, since the code did not match its own .clang-format file format.

    The changes in the tests will show the link failures mentioned in the commit message, if run with the original picojson header, but it passes after my changes.

    undefined reference to `void picojson::value::set<bool>(bool&&)'
    undefined reference to `void picojson::value::set<bool&>(bool&)'
    undefined reference to `void picojson::value::set<bool>(bool&&)'
    undefined reference to `void picojson::value::set<bool&>(bool&)'
    undefined reference to `void picojson::value::set<double>(double&&)'
    undefined reference to `void picojson::value::set<double&>(double&)'
    undefined reference to `void picojson::value::set<double>(double&&)'
    undefined reference to `void picojson::value::set<double&>(double&)'
    undefined reference to `void picojson::value::set<std::string&>(std::string&)'
    

    The issue with std::string& is that an lvalue

Related tags
A generator of JSON parser & serializer C++ code from structure header files

JSON-CPP-gen This is a program that parses C++ structures from a header file and automatically generates C++ code capable of serializing said structur

Oct 13, 2022
https://github.com/json-c/json-c is the official code repository for json-c. See the wiki for release tarballs for download. API docs at http://json-c.github.io/json-c/

\mainpage json-c Overview and Build Status Building on Unix Prerequisites Build commands CMake options Testing Building with vcpkg Linking to libjson-

Dec 31, 2022
json-build is a zero-allocation JSON serializer compatible with C89

json-build is a zero-allocation JSON serializer compatible with C89. It is inspired by jsmn, a minimalistic JSON tokenizer.

Nov 16, 2022
🗄️ single header json parser for C and C++

??️ json.h A simple single header solution to parsing JSON in C and C++. JSON is parsed into a read-only, single allocation buffer. The current suppor

Jan 7, 2023
single-header json parser for c99 and c++

ghh_json.h a single-header ISO-C99 (and C++ compatible) json loader. why? obviously this isn't the first json library written for C, so why would I wr

Dec 1, 2022
A very sane (header only) C++14 JSON library

JeayeSON - a very sane C++14 JSON library JeayeSON was designed out of frustration that there aren't many template-based approaches to handling JSON i

Nov 28, 2022
C++ header-only JSON library
C++ header-only JSON library

Welcome to taoJSON taoJSON is a C++ header-only JSON library that provides a generic Value Class, uses Type Traits to interoperate with C++ types, use

Dec 27, 2022
A small header-only json library in C.

xjson A small header-only json library for C. The "unique" feature is that it allows use of the same code to serialize as well as deserialize, greatly

Jul 19, 2022
json_struct is a single header only C++ library for parsing JSON directly to C++ structs and vice versa

Structurize your JSON json_struct is a single header only library that parses JSON to C++ structs/classes and serializing structs/classes to JSON. It

Dec 28, 2022
A small header-only library for converting data between json representation and c++ structs

Table of Contents Table of Contents What Is json_dto? What's new? v.0.3.0 v.0.2.14 v.0.2.13 v.0.2.12 v.0.2.11 v.0.2.10 v.0.2.9 v.0.2.8 v.0.2.7 v.0.2.6

Dec 27, 2022
Ultralightweight JSON parser in ANSI C

cJSON Ultralightweight JSON parser in ANSI C. Table of contents License Usage Welcome to cJSON Building Copying the source CMake Makefile Vcpkg Includ

Jan 4, 2023
JSON parser and generator for C/C++ with scanf/printf like interface. Targeting embedded systems.

JSON parser and emitter for C/C++ Features ISO C and ISO C++ compliant portable code Very small footprint No dependencies json_scanf() scans a string

Dec 30, 2022
JSON & BSON parser/writer

jbson is a library for building & iterating BSON data, and JSON documents in C++14. \tableofcontents Features # {#features} Header only. Boost license

Sep 14, 2022
Jsmn is a world fastest JSON parser/tokenizer. This is the official repo replacing the old one at Bitbucket

JSMN jsmn (pronounced like 'jasmine') is a minimalistic JSON parser in C. It can be easily integrated into resource-limited or embedded projects. You

Jan 9, 2023
A JSON parser in C++

JSON++ Introduction JSON++ is a light-weight JSON parser, writer and reader written in C++. JSON++ can also convert JSON documents into lossless XML d

Dec 28, 2022
Very low footprint JSON parser written in portable ANSI C

Very low footprint JSON parser written in portable ANSI C. BSD licensed with no dependencies (i.e. just drop the C file into your project) Never recur

Jan 5, 2023
Very simple C++ JSON Parser

Very simple JSON parser for c++ data.json: { "examples": [ { "tag_name": "a", "attr": [ { "key":

Nov 20, 2022
a JSON parser and printer library in C. easy to integrate with any model.

libjson - simple and efficient json parser and printer in C Introduction libjson is a simple library without any dependancies to parse and pretty prin

Nov 21, 2022
A fast JSON parser/generator for C++ with both SAX/DOM style API
A fast JSON parser/generator for C++ with both SAX/DOM style API

A fast JSON parser/generator for C++ with both SAX/DOM style API Tencent is pleased to support the open source community by making RapidJSON available

Dec 30, 2022