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

Related tags

JSON picojson
Overview

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.

Issues
  • 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.)

    opened by cdeil 9
  • 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.

    opened by GabrieleGiuseppini 5
  • 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?

    opened by karya0 5
  • 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;
    }
    
    opened by JetForMe 4
  • 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.

    opened by mattn 4
  • 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?

    opened by d-led 4
  • 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.

    opened by ChrisJefferson 3
  • 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

    opened by gnaggnoyil 3
  • 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.)

    opened by cdeil 3
  • 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
    opened by timothysc 3
  • 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.

    opened by ghost 3
  • 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(); }

    opened by shun126 0
  • 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(); }

    opened by shun126 0
  • 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

    opened by cuzdav 0
  • fix: using stream operator not set eofbit

    fix: using stream operator not set eofbit

    In the current version, there are the following issue

    #include <iostream>
    #include "picojson.hpp"
    
    int main()
    {
        while (!std::cin.eof()) // won't break
        {
            picojson::value v;
            std::cin >> v;
            // processing
            const auto &err = picojson::get_last_error();
            std::cout << "err: " << err << std::endl;
            std::cout << "res: " << v << std::endl;
        }
        return 0;
    }
    

    at Line 6, when read eof state from std::cin always return false.

    fix: add beg/end judge in parse(value &out, std::istream &is) at Line 1135

    inline std::string parse(value &out, std::istream &is) {
      std::string err;
      const auto &beg = std::istreambuf_iterator<char>(is.rdbuf());
      const auto &end = std::istreambuf_iterator<char>();
      parse(out, beg, end, &err);
      if (beg == end) {
        is.setstate(std::ios_base::eofbit); // set eof state because stream has no more data available
      }
      return err;
    }
    
    opened by Night12138 0
  • get<int> causes linker error in visual studio, must use int64_t with PICOJSON_USE_INT64

    get causes linker error in visual studio, must use int64_t with PICOJSON_USE_INT64

        if (v.is<picojson::array>()) {
            auto & arr = v.get<picojson::array>();
            for (picojson::array::const_iterator iter = arr.begin();
                iter != arr.end(); ++iter) {
                if (iter->is<picojson::object>()) {
                    iter->get<picojson::object>().at("id_int").get<int>();
                }
            }
        }
    

    This generates a linking error on VS2019.

    Error LNK2019 unresolved external symbol "public: int const & __thiscall picojson::value::get(void)const " ([email protected]@[email protected]@@QBEABHXZ) referenced in function "void __cdecl item_json::parse(void)" ([email protected][email protected]@YAXXZ)

    opened by jokoon 1
Releases(v1.3.0)
  • v1.3.0(Feb 25, 2015)

    Changes:

    • make check is now synonym of make test (#62)
    • operator= is now safe when part of LHS is being assigned, as well as exception-safe (#66)
    Source code(tar.gz)
    Source code(zip)
Owner
Kazuho Oku
Kazuho Oku
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

Viktor Chlumský 8 May 2, 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-

json-c 2.5k Aug 13, 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.

Lucas Müller 27 Jul 26, 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

Neil Henning 506 Aug 2, 2022
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

garrison hinson-hasty 15 May 26, 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

Jeaye Wilkerson 128 Jun 7, 2022
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

The Art of C++ 468 Aug 7, 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

Stefan Bachmann 23 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

Jørgen Lind 238 Aug 6, 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

Stiffstream 99 Aug 11, 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

Dave Gamble 7.8k Aug 15, 2022
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

Cesanta Software 611 Aug 5, 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

Chris Manning 39 May 12, 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

Serge Zaitsev 3k Aug 8, 2022
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

Hong Jiang 485 Jul 23, 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

James McLaughlin 1.2k Aug 12, 2022
Very simple C++ JSON Parser

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

Amir Saboury 65 Jul 25, 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

Vincent Hanquez 262 Aug 6, 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 Tencent is pleased to support the open source community by making RapidJSON available

Tencent 12.3k Aug 16, 2022