README.md 10.0 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, `int` 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
N
Niels 已提交
135 136 137 138 139 140 141 142
std::string s = j.dump();    // {\"happy\": true, \"pi\": 3.141}

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

The value of s could be `{"pi": 3.141, "happy": true}`, but the order of the entries in the object is not fixed.

N
Niels 已提交
147
You can also use streams to serialize and deserialize:
N
Niels 已提交
148

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

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

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

N
Niels 已提交
160 161
### STL-like access

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

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

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

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

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

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

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

N
Niels 已提交
195
// create an object
N
Niels 已提交
196
json o;
N
Niels 已提交
197 198 199 200 201 202 203 204 205 206
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 已提交
207
for (json::iterator it = o.begin(); it != o.end(); ++it) {
N
Niels 已提交
208 209
  std::cout << it.key() << ':' << it.value() << '\n';
}
N
Niels 已提交
210
```
N
Niels 已提交
211 212 213

### Implicit conversions

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

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

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

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

// etc.
N
Niels 已提交
233 234
```

N
Niels 已提交
235 236 237 238 239 240 241 242 243 244 245 246
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 已提交
247
<img align="right" src="http://opensource.org/trademarks/opensource/OSI-Approved-License-100x137.png">
N
Niels 已提交
248

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

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

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 已提交
258

N
Niels 已提交
259 260 261 262
## Thanks

I deeply appreciate the help of the following people.

N
Niels 已提交
263
- [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 已提交
264 265
- [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 已提交
266
- [wancw](https://github.com/wanwc) fixed a bug that hindered the class to compile with Clang.
N
Niels 已提交
267 268 269

Thanks a lot for helping out!

R
Raphael Isemann 已提交
270 271
## Execute unit tests with CMake

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

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

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

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

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

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

## Execute unit tests with automake
N
Niels 已提交
292 293 294 295

To compile the unit tests, you need to execute

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

The unit tests can then be executed with

```sh
N
tidy up  
Niels 已提交
304 305 306
$ ./json_unit

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

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