This tutorial introduces Document Object Model(DOM) API of RapidJSON.
This tutorial introduces the basics of the Document Object Model(DOM) API.
As shown in [Usage at a glance](../readme.md#usage-at-a-glance), a JSON text can be parsed into DOM, and then be quried and modfied easily, and finally convert back to JSON text.
As shown in [Usage at a glance](../readme.md#usage-at-a-glance), a JSON text can be parsed into DOM, and then the DOM can be queried and modfied easily, and finally be converted back to JSON text.
## Value
## Value & Document
Each JSON value is stored in a type called `Value`. A `Document`, representing the DOM, contains the root of `Value`.
...
...
@@ -36,9 +36,11 @@ Document document;
document.Parse(json);
```
The JSON text is now parsed into `document` as a DOM tree.
The JSON text is now parsed into `document` as a DOM tree:
The root of a conforming JSON should be either an object or an array. In this case, the root is an object with 7 members.
![tutorial](diagram/tutorial.png?raw=true)
The root of a conforming JSON should be either an object or an array. In this case, the root is an object.
// Using a reference for consecutive access is handy and faster.
constValue&a=document["a"];
...
...
@@ -85,16 +104,132 @@ for (SizeType i = 0; i < a.Size(); i++) // Uses SizeType instead of size_t
printf("a[%d] = %d\n",i,a[i].GetInt());
```
Note that, RapidJSON do not automatically converting between JSON types. if a value is a string, it is invalid to call `GetInt()`. In debug mode it will assert. In release mode, the behavior is undefined.
```
a[0] = 1
a[1] = 2
a[2] = 3
a[3] = 4
```
## Create/Modify Values
Note that, RapidJSON does not automatically convert values between JSON types. If a value is a string, it is invalid to call `GetInt()`, for example. In debug mode it will fail an assertion. In release mode, the behavior is undefined.
In the following, details about querying individual types are discussed.
### Querying Array
By default, `SizeType` is typedef of `unsigned`. In most systems, array is limited to store up to 2^32-1 elements.
You may access the elements in array by integer literal, for example, `a[1]`, `a[2]`. However, `a[0]` will generate a compiler error. It is because two overloaded operators `operator[](SizeType)` and `operator[](const char*)` is avaliable, and C++ can treat `0` as a null pointer. Workarounds:
*`a[SizeType(0)]`
*`a[0u]`
Array is similar to `std::vector`, instead of using indices, you may also use iterator to access all the elements.
Note that, when `operator[](const char*)` cannot find the member, it will fail an assertion.
If we are unsure whether a member exists, we need to call `HasMember()` before calling `operator[](const char*)`. However, this incurs two lookup. A better way is to call `FindMember()`, which can check the existence of member and obtain its value at once:
When querying a number, you can check whether the number can be obtained as target type:
Function | Description
-----------------------------------------------
`IsNumber()` | whether the value is a number
`IsInt()` | whether the number is a int
`IsUint()` | whether the number is a uint
`IsInt64()` | whether the number is a int64_t
`IsUint64()` | whether the number is a uint64_t
`IsDouble()` | whether the number is a double
Note that, an integer value may be obtained in various ways without conversion. For example, A value `x` containing `123` will make `x.IsInt() == x.IsUint() == x.Int64() == x.Uint64() == ture`. But a value `y` containing `-3000000000` will only makes `x.int64() == true`.
When obtaining the numeric values, `GetDouble()` will convert internal integer representation to a `double`. Note that, `int` and `uint` can be safely convert to `double`, but `int64_t` and `uint64_t` may lose precision (since mantissa of `double` is only 52-bits).
### Querying String
In addition to `GetString()`, the `Value` class also contains `GetStringLength()`. Here explains why.
According to RFC 4627, JSON strings can contain unicode character `U+0000`, which must be escaped as `"\u0000"`. The problem is that, C/C++ often uses null-terminated string, which treats ``\0'` as the terminator symbol.
To conform RFC 4627, RapidJSON supports string containing `U+0000`. If you need to handle this, you can use `GetStringLength()` API to obtain the correct length of string.
For example, after parsing a the following JSON string to `Document d`.
```js
{ "s" : "a\u0000b" }
```
The correct length of the value `"a\u0000b"` is 3. But `strlen()` returns 1.
`GetStringLength()` can also improve performance, as user may often need to call `strlen()` for allocating buffer.
Besides, `std::string` also support a constructor:
```cpp
string( const char* s, size_type count);
```
which accepts the length of string as parameter. This constructor supports storing null character within the string, and should also provide better performance.