伟明部落格

一个比dropbox-json11好太多的C++ JSON库

--发布于 2023-04-22 09:32:04

在C++中,之前一直使用的是dropbox的json11这个库来解析json,感觉功能还是挺强大的。但直到,发现它不能修改json里面的字段值,不能动态添加,删除字段,只能简单地解析和生成json。它原先高大上的形象立马烟消云散了。

然后,又找到了一个比dropbox-json11库更为强大的库,github链接 json11

源码在这 json11-master.zip

// 一些示例代码
Json arr { 1, 2, "three", Json::null };

// 获取int值(初始化时)
int a = arr[0];
// 获取int值(赋值时,须加强制转换)
int b;
b = (int)arr[1];

// 获取string值(赋值时,须加强制转换)
string c;
c = (string)arr[2];

// 获取null值(须加强制转换)
Json jnull = (Json)arr[3];

下面是README.md的原文

Introduction

Json-11 is yet another C++ class implementing JSON data interchange format. It is designed with the (currenly) latest C++11 standard in mind. The code fits in a single file, reasonably fast, and the interface is made as simple as possible. Implements parsing, formatting, traversing and editing, schema validation.

Usage

#include "json11.h"

Then drop json11.cpp into your project to compile. Note that you need a compiler that supports C++11. I only tested it with GCC 4.8.1 on Linux. For GCC don't forget to add -std=c++11 to compiler flags.

The basics

Json jnull; // creates a null Json object.
Json jtrue = true, pi = 3.14, str = "Hello";  // scalar objects
Json arr { 1, 2, str };   // array object, using initializer list
arr << false;  // do you prefer 'push_back' ?

To create key-value objects, start with a null object. Then use method set(key,value) or operator[] to populate it.

    Json obj;
    obj.set("one", 1).set("pi", pi);
    obj["arr"] = arr;   // nice, but cannot be chained
    Json hello = arr[2];
    arr[2] = "bye";     // will affect obj["arr"], but not hello
    cout << obj << endl;   // prints {"one":1,"pi":3.14,"arr":[1,2,"bye",false]}
    cout << hello << endl; // still prints "hello"

To extract scalar value from a Json instance, assign it to a scalar variable of matching type or use a cast. For collections use operator[] with either integer or string indexes.

    string text = str;     // text is Hello (without quotes)
    double num_pi = pi;
    int one = obj["one"];
    string hello = obj["arr"][2];

To 'stringify' a Json instance, write it to a std::ostream. To get it as a std::string use method stringify() or its alias format():

string jsontext = obj.format();

To parse a JSON text, read it from a std::istream. To parse it from std::string use static method parse():

    Json obj2 = Json::parse(jsontext);
    cout << (obj == obj2) << endl;   // prints true; yes, Jsons are comparable
    ifstream fs("big.json");
    Json big(fs);

To determine the type and size of a Json instance use methods type() and size(). The first one returns one of enum Json::Type values:

enum Json::Type { JSNULL, BOOL, NUMBER, STRING, ARRAY, OBJECT };

The second one returns either number of array elements or number of properties of an object. Property names are returned by keys() as vector<string>. These methods, together with operator[] allow to fully traverse an object.

Exceptions

The Json class defines two exception classes, parse_error and use_error. The first one can be thrown only from Json(istream&). The second is thrown when the class methods are used inappropriately, for example when operator<< is used for an object. It is also thrown when adding to a container would lead to circular dependency, like in this example:

    Json js1, js2;
    js1 << 1 << 2;
    js2 << js1;
    js1 << js2;   // error

The Json class methods can also throw standard exceptions out_of_range (from operator[]) and bad_cast.

Constructors and initializers

Json()
Default constructor creates a Json null instance.
Json(const Json&)
Copy contructor.
Json(Json&&)
Move contructor.
Json(std::istream&, bool full = true)
Reads and parses well-formed JSON UTF-8 text. By default tries to parse until end of file. If not full, leaves input stream where all brackets are closed, so there may be more text.
Json(T x)
Conversions from scalar type T, where T is one of bool, int, long, long long, float, double, long double, const char*, std::string. Internally all numbers are stored as long double.
Json& operator = (const Json&)
Copy initializer.
Json& operator = (Json&&)
Move initializer.
Json(std::initializer_list)
Creates an instance representing JSON array. Elements of the initializer_list must be either Json instances or convertible to Json.
virtual ~Json()
Destructor.

Casts

Type type() const
Returns JSON type of this instance, one of enum Json::Type
operator T() const
If this instance represents a scalar value, returns it. T is one of bool, int, long, long long, float, double, long double, std::string. Throws std::bad_cast if wrong type is requested.

Arrays

Json& operator << (const Json&)
Appends an element to the array. To create a new array just append something to a null instance, or use the constructor with initializer list.
Json::Property operator [] (int) const
Retrieves array element by index, as in `int x = arr[0]`, or replaces it, as in `arr[0] = "zero"`
void insert(int index, const Json& that)
Inserts that into array before index, so it becomes the one at index. If index < 0, counts from the end.
Json& replace(int index, const Json& that)
Replaces array element at index by that. If index < 0, counts from the end.
void erase(int index)
Removes element at index from the array. If index < 0, counts from the end.

These methods throw use_error if this Json instance is not an array.

Objects

Json& set(std::string key, const Json& value)
Adds property "key:value" to this object, or replaces the value if key is already there. To create a new object, start from a null Json instance.
Json get(const std::string& key) const
Returns value for the given key, or `Json::undefined` if this instance does not have such property.
Json::Property operator [] (std::string&)
Returns value for the given key, or `Json::undefined` if this instance does not have such property. When used on the left of assignment operator as in `obj["key"] = value`, adds a key with given value or replaces existing one.
Json::Property operator [] (const char*)
Same as the previous one.
bool has(const std::string& key) const
Returns `true` if this instance has propery with given key.
std::vector keys()
Returns all property keys for this instance.

These methods throw use_error if this Json instance is not an key-value object.

Subscript operator

Technically, operator[] returns and instance of internal class Json::Property. Instances of this class behave very much like Jsons, so in practice you don't have to remember about it.

Comparison

bool operator == (const Json&)
Compares Json instances. Scalars are equal if and only if they have same types and same values. Arrays are equal if their elements and order of them are the same. Objects are equal if their property keys and corresponding values are equal, regardless of order.
bool operator != (const Json&)
The opposite.

Parsing and formatting

static Json parse(const std::string&)
Returns a Json instance built from well-formed JSON text. UTF-8 encoding is assumed. See also Json(std::istream&).
std::string stringify()
Returns well-formed JSON text representing this object as a string.
std::string format()
Same as stringify().
friend std::ostream& operator << (std::ostream&, const Json&)
Writes well-formed JSON text representing this object into std::ostream.
friend std::istream& operator >> (std::istream&, Json&)
Reads well-formed JSON text into given instance, replacing previous content.
static int indent
If not 0, result of formatting looks prettier.

Validation

bool valid(Json& schema, std::string* reason = nullptr)
Validates this instance against schema. If not valid and reason is not a null pointer, fills it with a short explanation of the problem.
bool to_schema(std::string* reason)
If this instance is a schema, tries to "compile" it, returning `false` and filling in reason if this is not a valid schema. Useful if this schema will be used for validation several times, otherwise every call of `valid()` will compile its argument again.

Etc.

size_t size() const
Returns size of an array or number of properties for an object.
static Json null
The null instance.
static Json array()
Returns an empty array, that is [].
static Json object()
Returns an empty object, that is {}

Miscellaneous notes

Json class has value semantics. The following code:

Json arr { 1, 2, "three" };
Json three = arr[2];
arr.replace(2, 3);   // or:  arr.erase(2);
cout << three;

still prints "three". I hope this is what one would expect. On the other hand, if an array or object is a component of another array or object, changes in the component are visible "through", e.g.:

Json arr { 1, 2, "three" };
Json obj;
obj["arr"] = arr;
arr[2] = 3;
cout << obj["arr"][2];   // prints 3

Json class defines a static member Json::null of type JSNULL. It can be used to test for 'nullity' and for removing all contents from an object:

if (js == Json::null)
    big_object = Json::null;

There is a difference between s1 and s2 in the following example:

Json hello = "hello";
string s1 = hello;
string s2 = hello.format();

The assignment to s1 is a cast, so the value of s1 is hello. The value of s2 is "hello" (with double quotes) because format creates a well-formed JSON text and returns it as a string.


The project contains a toy command line application for viewing and editing JSON files. Just compile and run clison.cpp. The dialog looks like this:

at top: object
  0. web-app {3}
> 0
.web-app: object
  0. servlet [5]
  1. servlet-mapping {5}
  2. taglib {2}
> 2
.web-app.taglib: object
  0. taglib-uri: "cofax.tld"
  1. taglib-location: "/WEB-INF/tlds/cofax.tld"
> h
enter a number to select an object, q to go back
.             : list current object
p [file.json] : print out current object [into file]
s file.json   : load file as a json schema
= text        : replace current object by parsed text
>

--更新于 2023-04-22 15:21:41