# JsonCpp

## Foreword

This book describes the JsonCpp library (also called jsoncpp and json-cpp), JsonCpp is probably the most popular library for working with JSON databases in C++. It can parse and save databases, and provides an extensive library for accessing and manipulating their members. JsonCpp works with both files and strings.

For a library which exists for years, JsonCpp is surprisingly poorly documented. You can find either a very simple example of usage, or a computer-generated list of all classes and methods.

I am not an author, nor a contributor, of the library.

## JSON

JSON (JavaScript Object Notation) is an ASCII format for representing various data structures. It is pretty language-independent, machine-independent, simple, and easy readable by both humans and computers.

JSON is fully described at json.org.

In brief, a JSON value can be one of the following (see json.org for full details):

• null
• true or false
• A number.
• Numbers cannot start with 0 (or -0) followed by another digit (e. g. 0 and 0.14 are valid numbers, while 03, 012.34, and -015 are not).
• If a number contains a decimal point, it should also contain at least one digit both before and after the decimal point (e. g. numbers 15. and .15 are invalid).
• A string. Strings are enclosed in double quotes and may contain the following escape sequences:
```   \" - quote
\\ - backslash
\/ - slash
\n - newline
\t - tabulation
\r - carriage return
\b - backspace
\f - form feed
\uxxxx , where x is a hexadecimal digit - any 2-byte symbol
```
• An array. It is denoted by a comma-separated list of any values in square brackets. Example:
```   [1, 2, 3, "Hello world\n", true]
```
• An object, also called associative array, keyed list etc. It is denoted by comma-separated list of pairs in braces. A pair has a form
```   key : value
```

where key is a string, value is any JSON value. Example:

```   {"foo":1, "bar":2, "baz":3.14, "hello world":[1,2,3]}
```

Whitespaces can be inserted between any tokens.

Array elements are accessed by their number, while object elements are accessed by key. Arrays and objects can be empty. Arrays and objects can recursively contain another arrays or objects.

While strict JSON syntax does not allow any comments, and requires the root value to be array or object, JsonCpp allows both C-style and C++-style comments, and allows the root value to be of any type.

As for February 2016, there are totally hundreds of libraries for parsing and generating JSON on 62 languages, including 22 different libraries for C++.[1]

JsonCpp is probably the most popular C++ library. Another popular library is rapidjson, which is very fast.

## Installation and running

### With apt or apt-get

The easiest way to use it from Ubuntu or another flavor of Debian Linux, is to install is as:

```   sudo apt-get install libjsoncpp-dev
```

(You may use `apt` instead of `apt-get`.)

One drawback is that it will not install the last version. For Ubuntu 18.04.1, the version is 1.7.4, while the last version as per August 2018 is 1.8.4. The problem was much worse for 14.04, which installed 0.6.0, while the last version as per February 2016 was 1.7.4.

To use JsonCpp, include:

```   #include <jsoncpp/json/json.h>
```

To compile a file, add flag

```   -ljsoncpp
```

The header files will be installed to /usr/include/jsoncpp/json. In case you are curious, the libraries will be most probably installed to /usr/lib/x86_64-linux-gnu (but you hardly need their location). If you want to discover, try:

```   ls /usr/lib/*/*jsoncpp*
ls /usr/lib/*jsoncpp*
```

### With amalgamated source

To use JsonCpp with amalgamated source, you don't need to download or make any binary files. You will have a single cpp and two .h files which you should include into your projects. These files will be system-independent.

• Run
```   python amalgamate.py
```

It will create three files

```   dist/jsoncpp.cpp, the source file to be added to your project
dist/json/json-forwards.h, which contains forward declarations of JSON types.
```

You don't need anything except these three files.

### With cmake

• Download and unzip the source from the official repository. Go to the directory.
• Install cmake. Under Ubuntu or another flavour of Debian Linux:
```   sudo apt-get install cmake
```
• Create the build directory and enter it:
```   mkdir -p build
cd build
```
• Run the cmake command
```   cmake -DCMAKE_BUILD_TYPE=release -DBUILD_STATIC_LIBS=ON -DBUILD_SHARED_LIBS=OFF -DARCHIVE_INSTALL_DIR=. -G "Unix Makefiles" ..
```
• Run the make command:
```   make
```

(You may use `-j` flag to parallelize the building, e.g. `make -j 4`.)

Under Unix, it will create the file src/lib_json/libjsoncpp.a in your build directory. The include files will be in the ../include/json . Install the files (`make install` might help), and use

```   #include <jsoncpp/json/json.h>
```

and

```   -ljsoncpp
```

### With MS Visual Studio

• In this unzipped source tree, under makefiles/msvc2010 (for MS Visual Studio 2010) or vs71 (MS Visual Studio 2003) you will find several Visual Studio project files which you can up convert and build.

## Example

Install JsonCpp.

Create file alice.json with the following contents:

```{
"book":"Alice in Wonderland",
"year":1865,
"characters":
[
{"name":"Jabberwock", "chapter":1},
{"name":"Cheshire Cat", "chapter":6},
]
}
```

Create file alice.cpp with following contents:

```#include <iostream>
#include <fstream>
#include <jsoncpp/json/json.h> // or jsoncpp/json.h , or json/json.h etc.

using namespace std;

int main() {
ifstream ifs("alice.json");
Json::Value obj;
cout << "Book: " << obj["book"].asString() << endl;
cout << "Year: " << obj["year"].asUInt() << endl;
const Json::Value& characters = obj["characters"]; // array of characters
for (int i = 0; i < characters.size(); i++){
cout << "    name: " << characters[i]["name"].asString();
cout << " chapter: " << characters[i]["chapter"].asUInt();
cout << endl;
}
}
```

Compile it:

```   g++ -o alice alice.cpp -ljsoncpp
```

Then run it:

```   ./alice
```

You will hopefully receive the following:

```Book: Alice in Wonderland
Year: 1865
name: Jabberwock chapter: 1
name: Cheshire Cat chapter: 6
```

## Conventions and restrictions of JsonCpp

Everything is in the Json namespace.

Names of classes and other types use upper CamelCase notation (capitalize first letter of each word). Examples: `Int`, `ArrayIndex`, `ValueType`. Names of member functions, fields, enum values use lower camelCase notation (capitalize first letter of each word except the first word). Examples: `stringValue`, `isInt`, `size`.

JsonCpp performs extensive validity checking. If an operation is invalid, it throws the `std::runtime_error` exception with relevant message.

JsonCpp stores each number as either 64-bit integer (`long long int` or `__int64`), or 64-bit unsigned integer (`unsigned long long int` or `unsigned __int64`), or `double`. Below, we are going to call these int, uint, and real respectively.

An array or an object may contain at most ${\displaystyle 2^{32}-1}$ elements. A string may contain at most ${\displaystyle 2^{32}-1}$ characters. An object key may contain at most ${\displaystyle 2^{30}-1}$ characters.

## Auxiliary types

JsonCpp provides several auxillary types.

The following types are defined in `config.h` :

• Int - defined as `int`
• UInt - defined as `unsigned int`
• Int64 - a 64-bit signed integer, defined as `__int64` for Microsoft Visual Studio, otherwise `long long int`
• UInt64 - a 64-bit unsigned integer, defined as `unsigned __int64` for Microsoft Visual Studio, otherwise `unsigned long long int`
• LargestInt - a largest possible signed integer, defined as `Int64`
• LargestUInt - a largest possible unsigned integer, defined as `UInt64`

ArrayIndex is a type for array indices. It is defined as `unsigned int`, which means that an array or object may contain at most ${\displaystyle 2^{32}-1}$ items.

ValueType is an enum describing a type of JSON value. It is defined as:

```   enum ValueType
{
nullValue = 0, ///< 'null' value
intValue,      ///< signed integer value
uintValue,     ///< unsigned integer value
realValue,     ///< double value
stringValue,   ///< UTF-8 string value
booleanValue,  ///< bool value
arrayValue,    ///< array value (ordered list)
objectValue    ///< object value (collection of name/value pairs).
};
```

## Input/output

The simplest way to do input/output is via `operator<<` and `operator>>` . The program below reads a JSON value from standard input and writes it to standard output. In case of syntax error, `operator<<` throws `runtime_error` exception.

```#include <iostream>
#include <jsoncpp/json/json.h> // or something

using namespace std;

int main() {
Json::Value val;
cin >> val;
cout << val;
}
```

For example:

```\$ g++ -o copy-json copy-json.cpp -ljsoncpp
\$ echo '{"a":[1,2],"b":[3,4]}' | ./copy-json

{
"a" : [ 1, 2 ],
"b" : [ 3, 4 ]
}
```

For reading this way from a string, or writing to a string, you may use `std::istringstream` and `std::ostringstream` respectively, but there are alternative ways to do it.

### toStyledString()

The method toStyledString converts any value to a formatted string. Its declaration is:

```std::string toStyledString() const;
```

Another, and more robust, way to read JSON values is via the Reader class. Its most useful public methods are (here and below, comments are mine, and the order of methods is also mine):

```Reader(); // the default constructor

// Read a value from a JSON document and store it to root.
// If collectComments is true, comments are stored, otherwise they are ignored.
// In case of syntax error, it returns false, and the value of root may be arbitrary.
bool parse(const std::string& document, Value& root, bool collectComments = true); // from std::string
bool parse(const char *beginDoc, const char *endDoc, Value &root, bool collectComments=true); // from C-style string
bool parse(std::istream &is, Value &root, bool collectComments=true); // from input stream

// Returns a user friendly string that list errors in the parsed document.
std::string getFormattedErrorMessages() const;
```

Example:

```#include <iostream>
#include <jsoncpp/json/json.h> // or something

using namespace std;

int main() {
Json::Value val;
if (!b)
cout << "Error: " << reader.getFormattedErrorMessages();
else
cout << val;
}
```

### Json::Writer

Unlike `Reader`, the class Writer is abstract. There are two classes which implement it:

• FastWriter produces unformatted, non-human-readable documents. Everything will be written in a single line.
• StyledWriter produces formatted, human-readable documents, similar to `operator<<`, but with less indentation and without empty lines.

`FastWriter` has the following public methods (default constructor and destructor are not shown):

```// omit the word "null" when printing null values
// this contradicts the JSON standard, but accepted by JavaScript
// this function is not avaliable in old versions
void dropNullPlaceholders();

// don't add newline as last character
// this function is not avaliable in old versions
void omitEndingLineFeed();

// print space after ":" in objects
void enableYAMLCompatibility();

// write JSON object to a string
virtual std::string write(const Value &root);
```

`StyledWriter` has the following public method (default constructor and destructor are not shown):

```virtual std::string write(const Value &root); // write JSON object to a string
```

### StyledStreamWriter

Finally, there is also StyledStreamWriter class, for writing to streams. It is directly called by `operator<<` . This class is not a descendant of `Writer` or any other class. Its public methods are:

```StyledStreamWriter(std::string indentation="\t");
~StyledStreamWriter();
void write(std::ostream &out, const Value &root);
```

`StyledStreamWriter` is not very useful, as `operator<<` is more convenient. You may want to use it if you want non-standard indentation.

Example:

```#include <iostream>
#include <jsoncpp/json/json.h> // or something

using namespace std;

int main() {
Json::Value val;
cin >> val;
Json::FastWriter fast;
Json::StyledWriter styled;
string sFast = fast.write(val);
string sStyled = styled.write(val);
cout << "Fast:\n" << sFast << "Styled:\n" << sStyled;
cout << "Styled stream:\n";
Json::StyledStreamWriter styledStream;
styledStream.write(cout, val);
}
```

## Getting value and attributes

### Examining the attributes

The following method of Value returns some info about it:

```// get the type (intValue etc.)
ValueType type() const;

// get the number of elements in array or object (returns 0 for anything else, including string)
ArrayIndex size() const;

// returns true for empty array, empty object, or null
bool empty() const;

// returns true for null only
bool operator!() const;

// returns true for specific type only
bool isNull() const;
bool isBool() const;
bool isString() const;
bool isArray() const;
bool isObject() const;

// see explanations in text
bool isInt() const;
bool isInt64() const;
bool isUInt() const;
bool isUInt64() const;
bool isIntegral() const;
bool isDouble() const;
bool isNumeric() const;
```

`isInt()`, `isInt64()`, `isUInt()`, `isUInt64(`) return `true` only if all the following conditions satisfied:

• the type is numeric (int, uint, or real)
• if the type is real, the value should have zero fractional part
• the value should be within the range of the given type (`Int`, `Int64`, `UInt`, `UInt64` respectively)

`isDouble()` and `isNumeric()` currently return `true` if the type is int, uint, or real.

`isIntegral()` always returns `true` for an int or uint. For a real value, it returns `true` if the value has zero fractional part, and within the range of `Int64` or `UInt64`. For all other types, it returns `false`.

is... functions are not backwards-compatible. In versions 0.*, `isInt()` and `isUInt()` just checked the type, `isInt64()` and `isUInt64()` did not exist, `isArray()` and `isObject()` also returned true for null value, `isIntegral` also returned true for booleans etc.

Example:

```#include <iostream>
#include <jsoncpp/json/json.h> // or something

using namespace std;

int main() {
Json::Value val;
cin >> val;
switch (val.type()) {
case Json::nullValue: cout << "nullValue\n"; break;
case Json::intValue: cout << "intValue\n"; break;
case Json::uintValue: cout << "uintValue\n"; break;
case Json::realValue: cout << "realValue\n"; break;
case Json::stringValue: cout << "stringValue\n"; break;
case Json::booleanValue: cout << "booleanValue\n"; break;
case Json::arrayValue: cout << "arrayValue\n"; break;
case Json::objectValue: cout << "objectValue\n"; break;
default: cout << "wrong type\n"; break;
}
}
```

### Getting the value

To get the numerical, boolean, or string value itself, the class Value provides following methods:

```  const char* asCString() const;
std::string asString() const;
Int asInt() const;
UInt asUInt() const;
Int64 asInt64() const;
UInt64 asUInt64() const;
LargestInt asLargestInt() const;
LargestUInt asLargestUInt() const;
float asFloat() const;
double asDouble() const;
bool asBool() const;
```

Some of these methods may throw `std::runtime_exception`. A simple rule: if `isFoo()` returns true, then it is safe to call `asFoo()`, but the opposite is not neccessarily true.

Another rule, it is always safe to call

• `asString()` for string
• `asLargestInt()` for int
• `asLargestUInt()` for uint
• `asFloat()` or `asDouble()` for any number (int, uint, or real)
• `asBool()` for boolean

Below are the details.

The methods `asInt()`, `asUInt`, `asInt64()`, `asUInt64(`), `asLargestInt()`, `asLargestUInt()` do the following:

• If the original value is numeric, check if it is within the range of the destination type. If not, throw `std::runtime_error`. Then cast the value to the destination type. The casting is plain, so the real value of 3.9, when sent to `asInt()`, becomes 3.
• If the original value is boolean or null, return 1 for true, 0 for false, and 0 for null.
• For strings, arrays, and objects, throw `std::runtime_error`.

The methods `asFloat()` and `asDouble()` do the following:

• If the original value is numeric, cast it to `float` or `double`.
• If the original value is boolean or null, return 1.0 for true, 0.0 for false, and 0.0 for null.
• For strings, arrays, and objects, throw `std::runtime_error`.

The method `asBool()` accepts anything.

• false, null, 0, 0.0, or empty string/array/object is converted to `false`
• true, non-zero number, or non-empty string/array/object is converted to `true`

The method `asString()` is robust, slow, and high level. It returns `std::string`. It correctly treats strings with zero characters. It accepts everything except arrays and objects. For a null, the method returns `""`; for a boolean, it returns `"true"` or `"false"`; for a number, it returns it's string representation. For arrays and objects, it throws `std::runtime` exception.

The method `asCString()` is the fast, low-level method. It accepts only strings (otherwise it throws `std::runtime` exception), and directly returns the C-style string which is stored internally. The method doesn't allocate anything. Don't call `free()` or `delete[]` on the returned pointer! You should keep in mind two things:

• Since C-style strings should not contain zero characters, the method is only suitable for strings without zero characters.
• For empty strings, it sometimes returns 0.

If you need a C-style string, but don't want to be confused by zero characters, newer versions of JsonCpp add the following method:

```bool getString(char const** begin, char const** end) const;
```

This method stores the pointer to the first character to `*begin`, stores the pointer to the final zero character to `*end`, and returns `true`. For non-strings and sometimes for empty strings, it returns `false`.

Example :

```#include <iostream>
#include <jsoncpp/json/json.h> // or something

using namespace std;

int main() {
Json::Value val;
cin >> val;
switch (val.type()) {
case Json::nullValue: cout << "null\n"; break;
case Json::intValue: cout << "int " << val.asLargestInt() << "\n"; break;
case Json::uintValue: cout << "uint " << val.asLargestUInt() << "\n"; break;
case Json::realValue: cout << "real " << val.asDouble() << "\n"; break;
case Json::stringValue: cout << "string " << val.asString() << "\n"; break;
/*
-or-
case Json::stringValue: {
const char *begin;
const char *end;
val.getString(&begin, &end);
cout << "string of length " << end - begin << "\n";
}
break;
*/
case Json::booleanValue: cout << "boolean " << val.asBool() << "\n"; break;
case Json::arrayValue: cout << "array of length " << val.size() << "\n"; break;
case Json::objectValue: cout << "object of length " << val.size() << "\n"; break;
default: cout << "wrong type\n"; break;
}
}
```

## Constructors, assignment and comparison

The class Json::Value provides following constructors:

```Value(ValueType type = nullValue);
Value(Int value);
Value(UInt value);
Value(Int64 value);
Value(UInt64 value);
Value(double value);
Value(const char *value);
Value(const char *beginValue, const char *endValue);
Value(const std::string &value);
Value(bool value);
Value(const Value &other);
```

The first constructor creates null, false, 0, 0.0, or empty string/array/object. The other constructors are self-explanatory.

Assignment, swap, and all comparison operators are also provided (as methods).

```Value &operator=(const Value &other);
void swap(Value &other);
bool operator<(const Value &other) const;
bool operator<=(const Value &other) const;
bool operator>=(const Value &other) const;
bool operator>(const Value &other) const;
bool operator==(const Value &other) const;
bool operator!=(const Value &other) const;
int compare(const Value &other) const;
```

## Methods for arrays

Arrays have their own methods. These methods also work for null.

Some of them are similar to C++ STL's vectors:

```ArrayIndex size() const;
bool empty() const;
void clear();
void resize(ArrayIndex size);
Value& operator[](ArrayIndex index);
Value& operator[](int index);
const Value& operator[](const ArrayIndex index) const;
const Value& operator[](const int index) const;
```

Note that ArrayIndex is defined as unsigned int.

`resize()` changes the array size by either removing last values or appending null values.

If `operator[]` receives a negative index, it throws the `std::runtime_error` exception. If it receives `index` which is equal to or greater than the current size,

• non-constant `operator[]` appends `index-size()+1` null values, then returns the last value
• constant `operator[]` returns the null value

To append a value, use append:

```Value &append(const Value &value);
```

This is similar to C++ method `vector::push_back()`. In other words, `foo.append(bar)` is equivalent to `foo[foo.size()]=bar`.

The method get returns `index`-th element, or `defaultValue` if `index` is greater or equal to size:

```Value get(ArrayIndex index, const Value &defaultValue) const;
```

Note that it returns value NOT by reference, so calling this method may be very expensive.

To check validity of an index, you may want to use isValidIndex:

```bool isValidIndex(ArrayIndex index) const;
```

This is not very useful, as `value.isValidIndex(index)` is equivalent to `index < value.size()`.

You can also remove one value with removeIndex:

```bool removeIndex(ArrayIndex i, Value* removed);
```

No miracles, this method takes linear time. If `i` is greater or equal to size, it returns `false`.

### Calling array methods for null value

If `foo` is null, the methods above treat it as an empty array:

• `foo.empty()` returns `true`
• `foo.size()` returns 0
• `foo.clear()` does nothing
• `foo.resize(0)` does nothing
• `foo.resize(size)` for positive size transforms `foo` into an array of `size` nulls.
• `foo[i]` (non-constant) transforms `foo` into an array of `i+1` nulls, then returns the last value
• `foo[i]` (constant) returns the null value
• `foo.isValidIndex(i)` always returns `false`
• `foo.get(index, defaultValue)` always returns `defaultValue`
• `foo.append(bar)` makes `foo` an array of one element, which equals to `bar`
• `foo.removeIndex` always returns false

### Calling array methods for other types

The metods `clear()`, `empty()` and `size()` also work for objects.

Other than this, calling any of the methods above for something which is neither array nor null is pretty useless. They either return something trivial or throw the `std::runtime_error` exception:

• `foo.empty()` returns `false`, unless `foo` is an empty object
• `foo.size()` returns 0, unless `foo` is an object
• `foo.clear()` throws the `std::runtime_error` exception, unless `foo` is an object
• `resize`, `append`, `get`, `operator[]` throw the `std::runtime_error` exception
• `isValidIndex` always returns `false`
• `removeIndex` always returns `false`

## Methods for objects

Objects have their own methods. These methods also work for null.

Some of them are similar to C++ STL's maps:

```ArrayIndex size() const;
bool empty() const;
void clear();
Value& operator[](const char* key);
const Value& operator[](const char* key) const;
Value& operator[](const std::string& key);
const Value& operator[](const std::string& key) const;
```

These are self-explanatory. For `operator[]`, if the key does not exist, non-constant `operator[]` inserts the (key, null) pair and returns the reference to this null, while constant `operator[]` just returns the reference to some null.

The following methods take a key as either C++ string, C string, or a pair of pointers specifying beginning and end of the string. The last form does not exist in old versions of JsonCpp. It is useful, for example, if a string contains zero characters.

The method isMember checks whether there exists a member with given key:

```bool isMember(const char* key) const;
bool isMember(const std::string& key) const;
bool isMember(const char* begin, const char* end) const; // only in newer versions
```

The method removeMember removes an element. The first two forms return the removed value NOT by reference, which may be pretty expensive.

```Value removeMember(const char* key); // deprecated in versions 1.*
Value removeMember(const std::string& key); // deprecated in versions 1.*
bool removeMember(const char* key, Value* removed); // only since versions 1.*
bool removeMember(std::string const& key, Value* removed); // only since versions 1.*
bool removeMember(const char* begin, const char* end, Value* removed); // only since versions 1.*
```

To iterate through the members of an object, you need the full list of their keys. This is performed by getMemberNames:

```Value::Members Value::getMemberNames() const;
```

Value::Members is defined as:

```typedef std::vector<std::string> Members;
```

The method get returns value for the given key, or, in its absence, `defaultValue`. Just like with arrays, it returns value NOT by reference, so calling this method may be very expensive.

```Value get(const char* key, const Value& defaultValue) const;
Value get(const char* begin, const char* end, const Value& defaultValue) const;
Value get(const std::string& key, const Value& defaultValue) const; // only in newer versions
```

The method find exists only in newer versions. It receives the key in (begin, end) form and returns pointer to the found value. If not found, it returns `NULL` pointer.

```const Value* find(const char* begin, const char* end) const; // only in newer versions
```

### Calling object methods for null value

The methods above treat null value as an empty object:

• `clear()` does nothing
• `size()` returns 0
• `empty()` returns true
• non-constant `operator[]` transforms the value into one-element object, with given key and null value
• constant `operator[]` returns null
• `removeMember()` returns null (deprecated variants) or `false` (new variants).
• `getMemberNames()` returns empty vector of strings
• `get()` returns `defaultValue`
• `find()` returns `NULL`

### Calling object methods for other types

The methods `clear()`, `size()`, `empty()` work also for arrays. Other than this, for a value which is neither null nor an object, the methods above return trivial value or throw the `std::runtime_error` exception.

## Examples of work with objects and arrays

Creating a complex structure:

```#include <iostream>
#include <jsoncpp/json/json.h> // or something

using namespace std;

int main() {
// create the characters array
Json::Value ch;
ch[0]["name"] = "Jabberwock";
ch[0]["chapter"] = 1;
ch[1]["name"] = "Cheshire Cat";
ch[1]["chapter"] = 6;
ch[2]["chapter"] = 7;

// create the main object
Json::Value val;
val["book"] = "Alice in Wonderland";
val["year"] = 1865;
val["characters"] = ch;

cout << val << '\n';
}
```

Recursive function for printing any value (of course, it already exists, but we implement it from scratch):

```#include <cstdlib>
#include <iostream>
#include <fstream>
#include <jsoncpp/json/json.h> // or something

using namespace std;

void Indent(ostream& ofs, int indent) {
for (int i=0; i<indent; i++)
ofs << ' ';
}

void MyPrint(ostream& ofs, const Json::Value& val, int indent=0) {
switch (val.type()) {
case Json::nullValue: ofs << "null"; break;
case Json::booleanValue: ofs << (val.asBool() ? "true" : "false"); break;
case Json::intValue: ofs << val.asLargestInt(); break;
case Json::uintValue: ofs << val.asLargestUInt(); break;
case Json::realValue: ofs << val.asDouble(); break;
case Json::stringValue: ofs << '"' << val.asString() << '"'; break;
case Json::arrayValue: {
Json::ArrayIndex size = val.size();
if (size == 0)
ofs << "[]";
else {
ofs << "[\n";
int newIndent = indent + 4;
for (Json::ArrayIndex i=0; i<size; i++) {
Indent(ofs, newIndent);
MyPrint(ofs, val[i], newIndent);
ofs << (i + 1 == size ? "\n" : ",\n");
}
Indent(ofs, indent);
ofs << ']';
}
break;
}
case Json::objectValue: {
if (val.empty())
ofs << "{}";
else {
ofs << "{\n";
int newIndent = indent + 4;
vector<string> keys = val.getMemberNames();
for (size_t i=0; i<keys.size(); i++) {
Indent(ofs, newIndent);
const string& key = keys[i];
ofs << '"' << key << '"' << " : ";
MyPrint(ofs, val[key], newIndent);
ofs << (i + 1 == keys.size() ? "\n" : ",\n");
}
Indent(ofs, indent);
ofs << '}';
}
break;
}
default :
cerr << "Wrong type!" << endl;
exit(0);
}
}

int main() {
ifstream ifs("alice.json");
Json::Value val;
ifs >> val;
MyPrint(cout, val);
cout << '\n';
}
```

## Iterators

Iterators have types Json::Value::iterator and Json::Value::const_iterator. They are bidirectional, but not random. The methods of Json::Value are

```const_iterator begin() const;
const_iterator end() const;
iterator begin();
iterator end();
```

Only arrays and objects have non-trivial iterators. If `foo` is neither array nor object, then `foo.begin()` equals to `foo.end()`.

Iterators have the full set of operators: incrementing and decrementing (postfix and prefix `++` and `--`), comparison to equality and inequality, assigment, default constructor and copy constructor. Iterators are not random, so adding an integer number to iterator is not possible. Subtracting iterator from another iterator is possible, but takes linear time.

If `foo` is an iterator to an array, then `*foo` is a reference to the respective array's element. If `foo` is an iterator to an object, then `*foo` is NOT a reference to the (key, value) pair. It is a reference to the value itself.

`operator->` is avaliable since versions 1.* .

Example:

```#include <iostream>
#include <fstream>
#include <jsoncpp/json/json.h> // or something

using namespace std;

int main() {
Json::Value val;
for(Json::Value::const_iterator it=val.begin(); it!=val.end(); ++it)
cout << it->asInt() << '\n';
}
```

will print:

```1
3
2
```

To receive key (for iterator to object) or index (for iterator to array), `Json::Value::iterator` and `Json::Value::const_iterator` provide three methods:

```// For iterator to array, returns the index
// For iterator to object, returs the key.
Value key() const;

// Return the index, or -1 if it is not an array iterator
UInt index() const;

// Return the key, or "" if it is not an object iterator.
const char *memberName() const;
```

As explained in comments, `key()` returns the key for an object element or the index for an array element; `index()` returns the index for an array element, otherwise `UInt(-1)`; `memberName()` returns the key for an object element, otherwise empty string (`""`).

Example:

This works for newer version only.

```#include <iostream>
#include <fstream>
#include <jsoncpp/json/json.h> // or something

using namespace std;

int main() {
Json::Value val;
for (Json::Value::const_iterator it=val.begin(); it!=val.end(); ++it)
cout << it.key().asString() << ':' << it->asInt() << '\n';
}
```

This prints:

```one:1
three:3
two:2
```

For an older version, we cannot initialize Json::Value::const_iterator as Json::Value::iterator, and there is no operator->.

### Iterators in old versions

In versions 0.*, casting from `const_iterator` to iterator is not possible, while the corresponding assignment is possible. For example, if `val` is not constant, we cannot write

```Json::Value::const_iterator it = val.begin();
```

Instead, we should use `JSon::Value::iterator`. Besides, there is no `operator->` .

Therefore, instead of the program above, we should write:

```#include <iostream>
#include <fstream>
#include <jsoncpp/json/json.h> // or something

using namespace std;

int main() {