README.md 9.9 KB
Newer Older
N
Niels 已提交
1
# JSON for Modern C++
N
Niels 已提交
2

N
tidy up  
Niels 已提交
3
*What if JSON was part of modern C++?*
N
Niels 已提交
4

N
Niels 已提交
5
[![Build Status](https://travis-ci.org/nlohmann/json.png?branch=master)](https://travis-ci.org/nlohmann/json)
N
Niels 已提交
6
[![Coverage Status](https://img.shields.io/coveralls/nlohmann/json.svg)](https://coveralls.io/r/nlohmann/json)
N
Niels 已提交
7
[![Github Issues](https://img.shields.io/github/issues/nlohmann/json.svg)](http://github.com/nlohmann/json/issues)
N
Niels 已提交
8

N
Niels 已提交
9 10 11 12
## Design goals

There are myriads of [JSON](http://json.org) libraries out there, and each may even have its reason to exist. Our class had these design goals:

N
Niels 已提交
13
- **Intuitive syntax**. In languages such as Python, JSON feels like a first class data type. We used all the operator magic of modern C++ to achieve the same feeling in your code. Check out the [examples below](#examples) and the [reference](https://github.com/nlohmann/json/blob/master/doc/Reference.md), and you know, what I mean.
N
Niels 已提交
14

N
Niels 已提交
15
- **Trivial integration**. Our whole code consists of a class in just two files: A header file `json.h` and a source file `json.cc`. That's it. No library, no subproject, no dependencies. The class is written in vanilla C++11. All in all, everything should require no adjustment of your compiler flags or project settings.
N
Niels 已提交
16

N
Niels 已提交
17
- **Serious testing**. Our class is heavily [unit-tested](https://github.com/nlohmann/json/blob/master/test/json_unit.cc) and covers [100%](https://coveralls.io/r/nlohmann/json) of the code, including all exceptional behavior. Furthermore, we checked with [Valgrind](http://valgrind.org) that there are no memory leaks.
N
Niels 已提交
18

N
Niels 已提交
19 20
Other aspects were not so important to us:

N
Niels 已提交
21
- **Memory efficiency**. Each JSON object has an overhead of one pointer (the maximal size of a union) and one enumeration element (1 byte). We use the following C++ data types: `std::string` for strings, `int64_t` or `double` for numbers, `std::map` for objects, `std::vector` for arrays, and `bool` for Booleans. We know that there are more efficient ways to store the values, but we are happy enough right now.
N
Niels 已提交
22

N
Niels 已提交
23
- **Speed**. We currently implement the parser as naive [recursive descent parser](http://en.wikipedia.org/wiki/Recursive_descent_parser) with hand coded string handling. It is fast enough, but a [LALR-parser](http://en.wikipedia.org/wiki/LALR_parser) with a decent regular expression processor should be even faster (but would consist of more files which makes the integration harder).
N
Niels 已提交
24

N
Niels 已提交
25
- **Rigorous standard compliance**. Any [compliant](http://json.org) JSON file can be read by our class, and any output of the class is standard-compliant. However, we do not check for some details in the format of numbers and strings. For instance, `-0` will be treated as `0` whereas the standard forbids this. Furthermore, we allow for more escape symbols in strings as the JSON specification. While this may not be a problem in reality, we are aware of it, but as long as we have a hand-written parser, we won't invest too much to be fully compliant.
N
Niels 已提交
26 27 28

## Integration

29
The two required source files are in the `src` directory. All you need to do is add
N
Niels 已提交
30 31

```cpp
N
Niels 已提交
32
#include "json.h"
N
Niels 已提交
33 34 35

// for convenience
using json = nlohmann::json;
N
Niels 已提交
36 37
```

N
Niels 已提交
38
to the files you want to use JSON objects. Furthermore, you need to compile the file `json.cc` and link it to your binaries. Do not forget to set the necessary switches to enable C++11 (e.g., `-std=c++11` for GCC and Clang).
N
Niels 已提交
39

40 41
If you want a single header file, use the `json.h` file from the `header_only` directory.

N
Niels 已提交
42 43
## Examples

N
Niels 已提交
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
Here are some examples to give you an idea how to use the class.

Assume you want to create the JSON object

```json
{
  "pi": 3.141,
  "happy": true,
  "name": "Niels",
  "nothing": null,
  "answer": {
    "everything": 42
  },
  "list": [1, 0, 2],
  "object": {
    "currency": "USD",
    "value": "42.99"
  }
}
```

With the JSON class, you could write:
N
Niels 已提交
66 67

```cpp
N
Niels 已提交
68
// create an empty structure (null)
N
Niels 已提交
69
json j;
N
Niels 已提交
70

N
Niels 已提交
71
// add a number that is stored as double (note the implicit conversion of j to an object)
N
Niels 已提交
72 73 74 75 76 77 78 79
j["pi"] = 3.141;

// add a Boolean that is stored as bool
j["happy"] = true;

// add a string that is stored as std::string
j["name"] = "Niels";

N
Niels 已提交
80
// add another null object by passing nullptr
N
Niels 已提交
81 82
j["nothing"] = nullptr;

N
Niels 已提交
83
// add an object inside the object
N
Niels 已提交
84
j["answer"]["everything"] = 42;
N
Niels 已提交
85

N
Niels 已提交
86
// add an array that is stored as std::vector (using an initializer list)
N
Niels 已提交
87
j["list"] = { 1, 0, 2 };
N
Niels 已提交
88

N
Niels 已提交
89
// add another object (using an initializer list of pairs)
N
Niels 已提交
90
j["object"] = { {"currency", "USD"}, {"value", "42.99"} };
N
Niels 已提交
91 92

// instead, you could also write (which looks very similar to the JSON above)
N
Niels 已提交
93
json j2 = {
N
Niels 已提交
94 95 96 97 98 99 100 101 102 103 104 105 106
  {"pi", 3.141},
  {"happy", true},
  {"name", "Niels"},
  {"nothing", nullptr},
  {"answer", {
    {"everything", 42}
  }},
  {"list", {1, 0, 2}},
  {"object", {
    {"currency", "USD"},
    {"value", "42.99"}
  }}
};
N
Niels 已提交
107 108
```

N
Niels 已提交
109
Note that in all cases, you never need to "tell" the compiler which JSON value you want to use.
N
Niels 已提交
110

N
Niels 已提交
111 112 113
### Serialization / Deserialization

You can create an object (deserialization) by appending `_json` to a string literal:
N
Niels 已提交
114 115 116

```cpp
// create object from string literal
N
Niels 已提交
117
json j = "{ \"happy\": true, \"pi\": 3.141 }"_json;
118 119

// or even nicer (thanks http://isocpp.org/blog/2015/01/json-for-modern-cpp)
N
Niels 已提交
120 121
auto j2 = R"(
  {
N
Niels 已提交
122 123
    "happy": true,
    "pi": 3.141
N
Niels 已提交
124 125 126 127 128
  }
)"_json;

// or explicitly
auto j3 = json::parse("{ \"happy\": true, \"pi\": 3.141 }");
N
Niels 已提交
129 130
```

N
Niels 已提交
131
You can also get a string representation (serialize):
N
Niels 已提交
132 133 134

```cpp
// explicit conversion to string
135
std::string s = j.dump();    // {\"happy\":true,\"pi\":3.141}
N
Niels 已提交
136 137 138 139 140 141 142

// serialization with pretty printing
std::cout << j.dump(4) << std::endl;
// {
//     "happy": true,
//     "pi": 3.141
// }
N
Niels 已提交
143 144
```

N
Niels 已提交
145
You can also use streams to serialize and deserialize:
N
Niels 已提交
146

N
Niels 已提交
147
```cpp
N
Niels 已提交
148
// deserialize from standard input
N
Niels 已提交
149
json j;
N
Niels 已提交
150
j << std::cin;
N
Niels 已提交
151

N
Niels 已提交
152
// serialize to standard output
N
Niels 已提交
153 154 155
std::cout << j;
```

N
Niels 已提交
156
These operators work for any subclasses of `std::istream` or `std::ostream`.
N
Niels 已提交
157

N
Niels 已提交
158 159
### STL-like access

N
Niels 已提交
160 161
We designed the JSON class to behave just like an STL container:

N
Niels 已提交
162
```cpp
N
Niels 已提交
163
// create an array using push_back
N
Niels 已提交
164
json j;
N
Niels 已提交
165 166 167 168 169
j.push_back("foo");
j.push_back(1);
j.push_back(true);

// iterate the array
N
Niels 已提交
170
for (json::iterator it = j.begin(); it != j.end(); ++it) {
N
Niels 已提交
171 172 173
  std::cout << *it << '\n';
}

N
Niels 已提交
174
// range-based for
N
Niels 已提交
175 176 177 178
for (auto element : j) {
  std::cout << element << '\n';
}

N
Niels 已提交
179
// getter/setter
N
Niels 已提交
180
const std::string tmp = j[0];
N
Niels 已提交
181
j[1] = 42;
N
Niels 已提交
182
bool foo = j.at(2);
N
Niels 已提交
183 184

// other stuff
N
Niels 已提交
185
j.size();     // 3 entries
N
Niels 已提交
186
j.empty();    // false
187
j.type();     // json::value_t::array
N
Niels 已提交
188
j.clear();    // the array is empty again
N
Niels 已提交
189

N
tidy up  
Niels 已提交
190 191 192
// comparison
j == "[\"foo\", 1, true]"_json;  // true

N
Niels 已提交
193
// create an object
N
Niels 已提交
194
json o;
N
Niels 已提交
195 196 197 198 199 200 201 202 203 204
o["foo"] = 23;
o["bar"] = false;
o["baz"] = 3.141;

// find an entry
if (o.find("foo") != o.end()) {
  // there is an entry with key "foo"
}

// iterate the object
N
Niels 已提交
205
for (json::iterator it = o.begin(); it != o.end(); ++it) {
N
Niels 已提交
206 207
  std::cout << it.key() << ':' << it.value() << '\n';
}
N
Niels 已提交
208
```
N
Niels 已提交
209 210 211

### Implicit conversions

N
Niels 已提交
212
The type of the JSON object is determined automatically by the expression to store. Likewise, the stored value is implicitly converted.
N
Niels 已提交
213 214 215 216

```cpp
/// strings
std::string s1 = "Hello, world!";
N
Niels 已提交
217
json js = s1;
N
Niels 已提交
218
std::string s2 = js;
N
Niels 已提交
219 220 221

// Booleans
bool b1 = true;
N
Niels 已提交
222
json jb = b1;
N
Niels 已提交
223 224 225 226
bool b2 = jb;

// numbers
int i = 42;
N
Niels 已提交
227
json jn = i;
N
Niels 已提交
228
double f = jn;
N
Niels 已提交
229 230

// etc.
N
Niels 已提交
231 232
```

N
Niels 已提交
233 234 235 236 237 238 239 240 241 242 243 244
You can also explicitly ask for the value:

```cpp
std::string vs = js.get<std::string>();
bool vb = jb.get<bool>();
int vi = jn.get<int>();

// etc.
```

## License

N
Niels 已提交
245
<img align="right" src="http://opensource.org/trademarks/opensource/OSI-Approved-License-100x137.png">
N
Niels 已提交
246

N
Niels 已提交
247
The class is licensed under the [MIT License](http://opensource.org/licenses/MIT):
N
Niels 已提交
248

N
Niels 已提交
249
Copyright &copy; 2013-2014 [Niels Lohmann](http://nlohmann.me)
N
Niels 已提交
250 251 252 253 254 255

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
N
Niels 已提交
256

N
Niels 已提交
257 258 259 260
## Thanks

I deeply appreciate the help of the following people.

N
Niels 已提交
261
- [Teemperor](https://github.com/Teemperor) implemented CMake support and lcov integration, realized escape and Unicode handling in the string parser, and fixed the JSON serialization.
N
Niels 已提交
262 263
- [elliotgoodrich](https://github.com/elliotgoodrich) fixed an issue with double deletion in the iterator classes.
- [kirkshoop](https://github.com/kirkshoop) made the iterators of the class composable to other libraries.
N
Niels 已提交
264
- [wancw](https://github.com/wanwc) fixed a bug that hindered the class to compile with Clang.
N
Niels 已提交
265 266 267

Thanks a lot for helping out!

R
Raphael Isemann 已提交
268 269
## Execute unit tests with CMake

N
Niels 已提交
270
To compile and run the tests, you need to execute
R
Raphael Isemann 已提交
271 272 273 274 275 276 277

```sh
$ cmake .
$ make
$ ctest
```

278
If you want to generate a coverage report with the lcov/genhtml tools, execute this instead:
R
Raphael Isemann 已提交
279 280 281 282 283 284

```sh
$ cmake .
$ make coverage
```

285 286
**Note: You need to use GCC for now as otherwise the target coverage doesn't exist!**

R
Raphael Isemann 已提交
287 288 289
The report is now in the subfolder coverage/index.html

## Execute unit tests with automake
N
Niels 已提交
290 291 292 293

To compile the unit tests, you need to execute

```sh
N
tidy up  
Niels 已提交
294 295 296
$ autoreconf -i
$ ./configure
$ make
N
Niels 已提交
297 298 299 300 301
```

The unit tests can then be executed with

```sh
N
tidy up  
Niels 已提交
302 303 304
$ ./json_unit

===============================================================================
N
Niels 已提交
305
All tests passed (887 assertions in 10 test cases)
N
Niels 已提交
306 307 308
```

For more information, have a look at the file [.travis.yml](https://github.com/nlohmann/json/blob/master/.travis.yml).