tutorial.md 20.9 KB
Newer Older
miloyip's avatar
miloyip committed
1
# Tutorial
miloyip's avatar
miloyip committed
2

3
This tutorial introduces the basics of the Document Object Model(DOM) API.
miloyip's avatar
miloyip committed
4

5
As shown in [Usage at a glance](@ref index), a JSON can be parsed into DOM, and then the DOM can be queried and modified easily, and finally be converted back to JSON.
miloyip's avatar
miloyip committed
6

7 8 9
[TOC]

# Value & Document {#ValueDocument}
miloyip's avatar
miloyip committed
10

Milo Yip's avatar
Milo Yip committed
11
Each JSON value is stored in a type called `Value`. A `Document`, representing the DOM, contains the root `Value` of the DOM tree. All public types and functions of RapidJSON are defined in the `rapidjson` namespace.
miloyip's avatar
miloyip committed
12

13
# Query Value {#QueryValue}
miloyip's avatar
miloyip committed
14

15
In this section, we will use excerpt of `example/tutorial/tutorial.cpp`.
miloyip's avatar
miloyip committed
16

Milo Yip's avatar
Milo Yip committed
17 18
Assumes we have a JSON stored in a C string (`const char* json`):
~~~~~~~~~~js
miloyip's avatar
miloyip committed
19 20 21 22 23 24 25 26 27
{
    "hello": "world",
    "t": true ,
    "f": false,
    "n": null,
    "i": 123,
    "pi": 3.1416,
    "a": [1, 2, 3, 4]
}
Milo Yip's avatar
Milo Yip committed
28
~~~~~~~~~~
miloyip's avatar
miloyip committed
29

Milo Yip's avatar
Milo Yip committed
30
Parse it into a `Document`:
Milo Yip's avatar
Milo Yip committed
31
~~~~~~~~~~cpp
miloyip's avatar
miloyip committed
32 33 34 35 36 37 38
#include "rapidjson/document.h"

using namespace rapidjson;

// ...
Document document;
document.Parse(json);
Milo Yip's avatar
Milo Yip committed
39
~~~~~~~~~~
miloyip's avatar
miloyip committed
40

Milo Yip's avatar
Milo Yip committed
41
The JSON is now parsed into `document` as a *DOM tree*:
miloyip's avatar
miloyip committed
42

43
![DOM in the tutorial](diagram/tutorial.png)
44

Milo Yip's avatar
Milo Yip committed
45
Since the update to RFC 7159, the root of a conforming JSON document can be any JSON value.  In earlier RFC 4627, only objects or arrays were allowed as root values. In this case, the root is an object.
Milo Yip's avatar
Milo Yip committed
46
~~~~~~~~~~cpp
miloyip's avatar
miloyip committed
47
assert(document.IsObject());
Milo Yip's avatar
Milo Yip committed
48
~~~~~~~~~~
miloyip's avatar
miloyip committed
49

Milo Yip's avatar
Milo Yip committed
50
Let's query whether a `"hello"` member exists in the root object. Since a `Value` can contain different types of value, we may need to verify its type and use suitable API to obtain the value. In this example, `"hello"` member associates with a JSON string.
Milo Yip's avatar
Milo Yip committed
51
~~~~~~~~~~cpp
miloyip's avatar
miloyip committed
52 53 54
assert(document.HasMember("hello"));
assert(document["hello"].IsString());
printf("hello = %s\n", document["hello"].GetString());
Milo Yip's avatar
Milo Yip committed
55
~~~~~~~~~~
miloyip's avatar
miloyip committed
56

Milo Yip's avatar
Milo Yip committed
57
~~~~~~~~~~
58
world
Milo Yip's avatar
Milo Yip committed
59
~~~~~~~~~~
60

miloyip's avatar
miloyip committed
61
JSON true/false values are represented as `bool`.
Milo Yip's avatar
Milo Yip committed
62
~~~~~~~~~~cpp
miloyip's avatar
miloyip committed
63 64
assert(document["t"].IsBool());
printf("t = %s\n", document["t"].GetBool() ? "true" : "false");
Milo Yip's avatar
Milo Yip committed
65
~~~~~~~~~~
miloyip's avatar
miloyip committed
66

Milo Yip's avatar
Milo Yip committed
67
~~~~~~~~~~
68
true
Milo Yip's avatar
Milo Yip committed
69
~~~~~~~~~~
70

miloyip's avatar
miloyip committed
71
JSON null can be queryed by `IsNull()`.
Milo Yip's avatar
Milo Yip committed
72
~~~~~~~~~~cpp
miloyip's avatar
miloyip committed
73
printf("n = %s\n", document["n"].IsNull() ? "null" : "?");
Milo Yip's avatar
Milo Yip committed
74
~~~~~~~~~~
miloyip's avatar
miloyip committed
75

Milo Yip's avatar
Milo Yip committed
76
~~~~~~~~~~
77
null
Milo Yip's avatar
Milo Yip committed
78
~~~~~~~~~~
79

miloyip's avatar
miloyip committed
80 81
JSON number type represents all numeric values. However, C++ needs more specific type for manipulation.

Milo Yip's avatar
Milo Yip committed
82
~~~~~~~~~~cpp
miloyip's avatar
miloyip committed
83 84 85 86 87 88 89 90 91 92
assert(document["i"].IsNumber());

// In this case, IsUint()/IsInt64()/IsUInt64() also return true.
assert(document["i"].IsInt());          
printf("i = %d\n", document["i"].GetInt());
// Alternative (int)document["i"]

assert(document["pi"].IsNumber());
assert(document["pi"].IsDouble());
printf("pi = %g\n", document["pi"].GetDouble());
Milo Yip's avatar
Milo Yip committed
93
~~~~~~~~~~
miloyip's avatar
miloyip committed
94

Milo Yip's avatar
Milo Yip committed
95
~~~~~~~~~~
96 97
i = 123
pi = 3.1416
Milo Yip's avatar
Milo Yip committed
98
~~~~~~~~~~
99 100

JSON array contains a number of elements.
Milo Yip's avatar
Milo Yip committed
101
~~~~~~~~~~cpp
miloyip's avatar
miloyip committed
102 103 104 105 106
// Using a reference for consecutive access is handy and faster.
const Value& a = document["a"];
assert(a.IsArray());
for (SizeType i = 0; i < a.Size(); i++) // Uses SizeType instead of size_t
        printf("a[%d] = %d\n", i, a[i].GetInt());
Milo Yip's avatar
Milo Yip committed
107
~~~~~~~~~~
miloyip's avatar
miloyip committed
108

Milo Yip's avatar
Milo Yip committed
109
~~~~~~~~~~
110 111 112 113
a[0] = 1
a[1] = 2
a[2] = 3
a[3] = 4
Milo Yip's avatar
Milo Yip committed
114
~~~~~~~~~~
miloyip's avatar
miloyip committed
115

116 117 118 119
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.

120
## Query Array {#QueryArray}
121 122 123

By default, `SizeType` is typedef of `unsigned`. In most systems, array is limited to store up to 2^32-1 elements.

124
You may access the elements in array by integer literal, for example, `a[0]`, `a[1]`, `a[2]`.
125 126

Array is similar to `std::vector`, instead of using indices, you may also use iterator to access all the elements.
Milo Yip's avatar
Milo Yip committed
127
~~~~~~~~~~cpp
128 129
for (Value::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr)
    printf("%d ", itr->GetInt());
Milo Yip's avatar
Milo Yip committed
130
~~~~~~~~~~
131

132
And other familiar query functions:
133 134 135
* `SizeType Capacity() const`
* `bool Empty() const`

136
## Query Object {#QueryObject}
137

Milo Yip's avatar
Milo Yip committed
138
Similar to array, we can access all object members by iterator:
139

Milo Yip's avatar
Milo Yip committed
140
~~~~~~~~~~cpp
141 142 143 144 145 146 147 148 149
static const char* kTypeNames[] = 
    { "Null", "False", "True", "Object", "Array", "String", "Number" };

for (Value::ConstMemberIterator itr = document.MemberBegin();
    itr != document.MemberEnd(); ++itr)
{
    printf("Type of member %s is %s\n",
        itr->name.GetString(), kTypeNames[itr->value.GetType()]);
}
Milo Yip's avatar
Milo Yip committed
150
~~~~~~~~~~
miloyip's avatar
miloyip committed
151

Milo Yip's avatar
Milo Yip committed
152
~~~~~~~~~~
153 154 155 156 157 158 159
Type of member hello is String
Type of member t is True
Type of member f is False
Type of member n is Null
Type of member i is Number
Type of member pi is Number
Type of member a is Array
Milo Yip's avatar
Milo Yip committed
160
~~~~~~~~~~
161 162 163 164 165

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:

Milo Yip's avatar
Milo Yip committed
166
~~~~~~~~~~cpp
167
Value::ConstMemberIterator itr = document.FindMember("hello");
Milo Yip's avatar
Milo Yip committed
168
if (itr != document.MemberEnd())
Milo Yip's avatar
Milo Yip committed
169
    printf("%s\n", itr->value.GetString());
Milo Yip's avatar
Milo Yip committed
170
~~~~~~~~~~
171

172
## Querying Number {#QueryNumber}
173 174 175

JSON provide a single numerical type called Number. Number can be integer or real numbers. RFC 4627 says the range of Number is specified by parser.

Milo Yip's avatar
Milo Yip committed
176
As C++ provides several integer and floating point number types, the DOM tries to handle these with widest possible range and good performance.
177

Milo Yip's avatar
Milo Yip committed
178
When a Number is parsed, it is stored in the DOM as either one of the following type:
179 180

Type       | Description
Milo Yip's avatar
Milo Yip committed
181
-----------|---------------------------------------
182 183 184 185 186 187 188 189
`unsigned` | 32-bit unsigned integer
`int`      | 32-bit signed integer
`uint64_t` | 64-bit unsigned integer
`int64_t`  | 64-bit signed integer
`double`   | 64-bit double precision floating point

When querying a number, you can check whether the number can be obtained as target type:

Milo Yip's avatar
Milo Yip committed
190 191 192 193
Checking          | Obtaining
------------------|---------------------
`bool IsNumber()` | N/A
`bool IsUint()`   | `unsigned GetUint()`
Milo Yip's avatar
Milo Yip committed
194
`bool IsInt()`    | `int GetInt()`
195
`bool IsUint64()` | `uint64_t GetUint64()`
Milo Yip's avatar
Milo Yip committed
196
`bool IsInt64()`  | `int64_t GetInt64()`
Milo Yip's avatar
Milo Yip committed
197
`bool IsDouble()` | `double GetDouble()`
198

199
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.IsInt64() == x.IsUint64() == true`. But a value `y` containing -3000000000 will only makes `x.IsInt64() == true`.
200

Milo Yip's avatar
Milo Yip committed
201
When obtaining the numeric values, `GetDouble()` will convert internal integer representation to a `double`. Note that, `int` and `unsigned` can be safely convert to `double`, but `int64_t` and `uint64_t` may lose precision (since mantissa of `double` is only 52-bits).
202

203
## Query String {#QueryString}
204 205 206

In addition to `GetString()`, the `Value` class also contains `GetStringLength()`. Here explains why.

207
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.
208 209 210

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.

Milo Yip's avatar
Milo Yip committed
211
For example, after parsing a the following JSON to `Document d`:
212

Milo Yip's avatar
Milo Yip committed
213
~~~~~~~~~~js
214
{ "s" :  "a\u0000b" }
Milo Yip's avatar
Milo Yip committed
215
~~~~~~~~~~
216 217 218 219 220 221
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:

Milo Yip's avatar
Milo Yip committed
222
~~~~~~~~~~cpp
223
string(const char* s, size_t count);
Milo Yip's avatar
Milo Yip committed
224
~~~~~~~~~~
225 226 227

which accepts the length of string as parameter. This constructor supports storing null character within the string, and should also provide better performance.

228 229 230 231 232 233 234 235 236 237 238
## Comparing values

You can use `==` and `!=` to compare values. Two values are equal if and only if they are have same type and contents. You can also compare values with primitive types. Here is an example.

~~~~~~~~~~cpp
if (document["hello"] == document["n"]) /*...*/;    // Compare values
if (document["hello"] == "world") /*...*/;          // Compare value with literal string
if (document["i"] != 123) /*...*/;                  // Compare with integers
if (document["pi"] != 3.14) /*...*/;                // Compare with double.
~~~~~~~~~~

Milo Yip's avatar
Milo Yip committed
239
Array/object compares their elements/members in order. They are equal if and only if their whole subtrees are equal.
240 241 242

Note that, currently if an object contains duplicated named member, comparing equality with any object is always `false`.

243
# Create/Modify Values {#CreateModifyValues}
miloyip's avatar
miloyip committed
244

245 246
There are several ways to create values. After a DOM tree is created and/or modified, it can be saved as JSON again using `Writer`.

247
## Change Value Type {#ChangeValueType}
248 249
When creating a Value or Document by default constructor, its type is Null. To change its type, call `SetXXX()` or assignment operator, for example:

Milo Yip's avatar
Milo Yip committed
250
~~~~~~~~~~cpp
251 252 253 254 255 256
Document d; // Null
d.SetObject();

Value v;    // Null
v.SetInt(10);
v = 10;     // Shortcut, same as above
Milo Yip's avatar
Milo Yip committed
257
~~~~~~~~~~
258 259 260 261

### Overloaded Constructors
There are also overloaded constructors for several types:

Milo Yip's avatar
Milo Yip committed
262
~~~~~~~~~~cpp
263 264 265 266
Value b(true);    // calls Value(bool)
Value i(-123);    // calls Value(int)
Value u(123u);    // calls Value(unsigned)
Value d(1.5);     // calls Value(double)
Milo Yip's avatar
Milo Yip committed
267
~~~~~~~~~~
268 269 270

To create empty object or array, you may use `SetObject()`/`SetArray()` after default constructor, or using the `Value(Type)` in one shot:

Milo Yip's avatar
Milo Yip committed
271
~~~~~~~~~~cpp
272 273
Value o(kObjectType);
Value a(kArrayType);
Milo Yip's avatar
Milo Yip committed
274
~~~~~~~~~~
275

276
## Move Semantics {#MoveSemantics}
Milo Yip's avatar
Milo Yip committed
277

278 279
A very special decision during design of RapidJSON is that, assignment of value does not copy the source value to destination value. Instead, the value from source is moved to the destination. For example,

Milo Yip's avatar
Milo Yip committed
280
~~~~~~~~~~cpp
281 282 283
Value a(123);
Value b(456);
b = a;         // a becomes a Null value, b becomes number 123.
Milo Yip's avatar
Milo Yip committed
284
~~~~~~~~~~
285

286
![Assignment with move semantics.](diagram/move1.png)
287 288 289 290 291

Why? What is the advantage of this semantics?

The simple answer is performance. For fixed size JSON types (Number, True, False, Null), copying them is fast and easy. However, For variable size JSON types (String, Array, Object), copying them will incur a lot of overheads. And these overheads are often unnoticed. Especially when we need to create temporary object, copy it to another variable, and then destruct it.

292
For example, if normal *copy* semantics was used:
293

Milo Yip's avatar
Milo Yip committed
294
~~~~~~~~~~cpp
295
Document d;
296 297 298 299 300
Value o(kObjectType);
{
    Value contacts(kArrayType);
    // adding elements to contacts array.
    // ...
301
    o.AddMember("contacts", contacts, d.GetAllocator());  // deep clone contacts (may be with lots of allocations)
302 303
    // destruct contacts.
}
Milo Yip's avatar
Milo Yip committed
304
~~~~~~~~~~
305

306
![Copy semantics makes a lots of copy operations.](diagram/move2.png)
307 308

The object `o` needs to allocate a buffer of same size as contacts, makes a deep clone of it, and then finally contacts is destructed. This will incur a lot of unnecessary allocations/deallocations and memory copying.
309 310 311

There are solutions to prevent actual copying these data, such as reference counting and garbage collection(GC).

312
To make RapidJSON simple and fast, we chose to use *move* semantics for assignment. It is similar to `std::auto_ptr` which transfer ownership during assignment. Move is much faster and simpler, it just destructs the original value, `memcpy()` the source to destination, and finally sets the source as Null type.
313

314
So, with move semantics, the above example becomes:
315

Milo Yip's avatar
Milo Yip committed
316
~~~~~~~~~~cpp
317
Document d;
318 319 320 321
Value o(kObjectType);
{
    Value contacts(kArrayType);
    // adding elements to contacts array.
322
    o.AddMember("contacts", contacts, d.GetAllocator());  // just memcpy() of contacts itself to the value of new member (16 bytes)
323 324
    // contacts became Null here. Its destruction is trivial.
}
Milo Yip's avatar
Milo Yip committed
325
~~~~~~~~~~
326

327
![Move semantics makes no copying.](diagram/move3.png)
328

Milo Yip's avatar
Milo Yip committed
329
This is called move assignment operator in C++11. As RapidJSON supports C++03, it adopts move semantics using assignment operator, and all other modifying function like `AddMember()`, `PushBack()`.
330

331 332 333 334 335 336
### Move semantics and temporary values {#TemporaryValues}

Sometimes, it is convenient to construct a Value in place, before passing it to one of the "moving" functions, like `PushBack()` or `AddMember()`.  As temporary objects can't be converted to proper Value references, the convenience function `Move()` is available:

~~~~~~~~~~cpp
Value a(kArrayType);
Milo Yip's avatar
Milo Yip committed
337 338 339 340
Document::AllocatorType& allocator = document.GetAllocator();
// a.PushBack(Value(42), allocator);       // will not compile
a.PushBack(Value().SetInt(42), allocator); // fluent API
a.PushBack(Value(42).Move(), allocator);   // same as above
341 342
~~~~~~~~~~

343
## Create String {#CreateString}
344 345 346 347 348
RapidJSON provide two strategies for storing string.

1. copy-string: allocates a buffer, and then copy the source data into it.
2. const-string: simply store a pointer of string.

349
Copy-string is always safe because it owns a copy of the data. Const-string can be used for storing string literal, and in-situ parsing which we will mentioned in Document section.
350

Milo Yip's avatar
Milo Yip committed
351
To make memory allocation customizable, RapidJSON requires user to pass an instance of allocator, whenever an operation may require allocation. This design is needed to prevent storing a allocator (or Document) pointer per Value.
352

353
Therefore, when we assign a copy-string, we call this overloaded `SetString()` with allocator:
354

Milo Yip's avatar
Milo Yip committed
355
~~~~~~~~~~cpp
356 357 358 359 360 361 362
Document document;
Value author;
char buffer[10];
int len = sprintf(buffer, "%s %s", "Milo", "Yip"); // dynamically created string.
author.SetString(buffer, len, document.GetAllocator());
memset(buffer, 0, sizeof(buffer));
// author.GetString() still contains "Milo Yip" after buffer is destroyed
Milo Yip's avatar
Milo Yip committed
363
~~~~~~~~~~
364

365
In this example, we get the allocator from a `Document` instance. This is a common idiom when using RapidJSON. But you may use other instances of allocator.
366

367
Besides, the above `SetString()` requires length. This can handle null characters within a string. There is another `SetString()` overloaded function without the length parameter. And it assumes the input is null-terminated and calls a `strlen()`-like function to obtain the length.
368

Milo Yip's avatar
Milo Yip committed
369
Finally, for string literal or string with safe life-cycle can use const-string version of `SetString()`, which lacks allocator parameter.  For string literals (or constant character arrays), simply passing the literal as parameter is safe and efficient:
370

Milo Yip's avatar
Milo Yip committed
371
~~~~~~~~~~cpp
372
Value s;
373
s.SetString("rapidjson");    // can contain null character, length derived at compile time
374
s = "rapidjson";             // shortcut, same as above
Milo Yip's avatar
Milo Yip committed
375
~~~~~~~~~~
376

Milo Yip's avatar
Milo Yip committed
377
For character pointer, the RapidJSON requires to mark it as safe before using it without copying. This can be achieved by using the `StringRef` function:
378 379 380 381 382 383 384 385 386 387 388 389 390

~~~~~~~~~cpp
const char * cstr = getenv("USER");
size_t cstr_len = ...;                 // in case length is available
Value s;
// s.SetString(cstr);                  // will not compile
s.SetString(StringRef(cstr));          // ok, assume safe lifetime, null-terminated
s = StringRef(cstr);                   // shortcut, same as above
s.SetString(StringRef(cstr,cstr_len)); // faster, can contain null character
s = StringRef(cstr,cstr_len);          // shortcut, same as above

~~~~~~~~~

391
## Modify Array {#ModifyArray}
392 393 394 395 396 397 398
Value with array type provides similar APIs as `std::vector`.

* `Clear()`
* `Reserve(SizeType, Allocator&)`
* `Value& PushBack(Value&, Allocator&)`
* `template <typename T> GenericValue& PushBack(T, Allocator&)`
* `Value& PopBack()`
399 400
* `ValueIterator Erase(ConstValueIterator pos)`
* `ValueIterator Erase(ConstValueIterator first, ConstValueIterator last)`
401

402
Note that, `Reserve(...)` and `PushBack(...)` may allocate memory for the array elements, therefore require an allocator.
403 404 405

Here is an example of `PushBack()`:

Milo Yip's avatar
Milo Yip committed
406
~~~~~~~~~~cpp
407 408 409 410
Value a(kArrayType);
Document::AllocatorType& allocator = document.GetAllocator();

for (int i = 5; i <= 10; i++)
411
    a.PushBack(i, allocator);   // allocator is needed for potential realloc().
412 413 414

// Fluent interface
a.PushBack("Lua", allocator).PushBack("Mio", allocator);
Milo Yip's avatar
Milo Yip committed
415
~~~~~~~~~~
416

417 418 419 420 421 422 423 424 425 426 427 428 429
Differs from STL, `PushBack()`/`PopBack()` returns the array reference itself. This is called _fluent interface_.

If you want to add a non-constant string or a string without sufficient lifetime (see [Create String](#CreateString)) to the array, you need to create a string Value by using the copy-string API.  To avoid the need for an intermediate variable, you can use a [temporary value](#TemporaryValues) in place:

~~~~~~~~~~cpp
// in-place Value parameter
contact.PushBack(Value("copy", document.GetAllocator()).Move(), // copy string
                 document.GetAllocator());

// explicit parameters
Value val("key", document.GetAllocator()); // copy string
contact.PushBack(val, document.GetAllocator());
~~~~~~~~~~
430

431
## Modify Object {#ModifyObject}
Milo Yip's avatar
Milo Yip committed
432
Object is a collection of key-value pairs (members). Each key must be a string value. To modify an object, either add or remove members. THe following APIs are for adding members:
433 434

* `Value& AddMember(Value&, Value&, Allocator& allocator)`
435 436
* `Value& AddMember(StringRefType, Value&, Allocator&)`
* `template <typename T> Value& AddMember(StringRefType, T value, Allocator&)`
437 438 439

Here is an example.

Milo Yip's avatar
Milo Yip committed
440
~~~~~~~~~~cpp
441
Value contact(kObject);
442 443
contact.AddMember("name", "Milo", document.GetAllocator());
contact.AddMember("married", true, document.GetAllocator());
444 445
~~~~~~~~~~

Milo Yip's avatar
Milo Yip committed
446
The name parameter with `StringRefType` is similar to the interface of `SetString` function for string values. These overloads are used to avoid the need for copying the `name` string, as constant key names are very common in JSON objects.
447 448 449 450 451 452 453 454 455 456

If you need to create a name from a non-constant string or a string without sufficient lifetime (see [Create String](#CreateString)), you need to create a string Value by using the copy-string API.  To avoid the need for an intermediate variable, you can use a [temporary value](#TemporaryValues) in place:

~~~~~~~~~~cpp
// in-place Value parameter
contact.AddMember(Value("copy", document.GetAllocator()).Move(), // copy string
                  Value().Move(),                                // null value
                  document.GetAllocator());

// explicit parameters
Milo Yip's avatar
Milo Yip committed
457
Value key("key", document.GetAllocator()); // copy string name
458 459
Value val(42);                             // some value
contact.AddMember(key, val, document.GetAllocator());
Milo Yip's avatar
Milo Yip committed
460
~~~~~~~~~~
461

462 463 464 465 466 467 468 469
For removing members, there are several choices: 

* `bool RemoveMember(const Ch* name)`: Remove a member by search its name (linear time complexity).
* `bool RemoveMember(const Value& name)`: same as above but `name` is a Value.
* `MemberIterator RemoveMember(MemberIterator)`: Remove a member by iterator (_constant_ time complexity).
* `MemberIterator EraseMember(MemberIterator)`: similar to the above but it preserves order of members (linear time complexity).
* `MemberIterator EraseMember(MemberIterator first, MemberIterator last)`: remove a range of members, preserves order (linear time complexity).

Milo Yip's avatar
Milo Yip committed
470
`MemberIterator RemoveMember(MemberIterator)` uses a "move-last" trick to achieve constant time complexity. Basically the member at iterator is destructed, and then the last element is moved to that position. So the order of the remaining members are changed.
471

472
## Deep Copy Value {#DeepCopyValue}
Milo Yip's avatar
Milo Yip committed
473
If we really need to copy a DOM tree, we can use two APIs for deep copy: constructor with allocator, and `CopyFrom()`.
474

Milo Yip's avatar
Milo Yip committed
475
~~~~~~~~~~cpp
476 477 478 479 480
Document d;
Document::AllocatorType& a = d.GetAllocator();
Value v1("foo");
// Value v2(v1); // not allowed

Milo Yip's avatar
Milo Yip committed
481 482
Value v2(v1, a);                      // make a copy
assert(v1.IsString());                // v1 untouched
483
d.SetArray().PushBack(v1, a).PushBack(v2, a);
Milo Yip's avatar
Milo Yip committed
484
assert(v1.IsNull() && v2.IsNull());   // both moved to d
485

Milo Yip's avatar
Milo Yip committed
486 487
v2.CopyFrom(d, a);                    // copy whole document to v2
assert(d.IsArray() && d.Size() == 2); // d untouched
488 489
v1.SetObject().AddMember("array", v2, a);
d.PushBack(v1, a);
Milo Yip's avatar
Milo Yip committed
490
~~~~~~~~~~
miloyip's avatar
miloyip committed
491

492
## Swap Values {#SwapValues}
miloyip's avatar
miloyip committed
493

Milo Yip's avatar
Milo Yip committed
494 495
`Swap()` is also provided.

Milo Yip's avatar
Milo Yip committed
496
~~~~~~~~~~cpp
Milo Yip's avatar
Milo Yip committed
497 498 499 500 501
Value a(123);
Value b("Hello");
a.Swap(b);
assert(a.IsString());
assert(b.IsInt());
Milo Yip's avatar
Milo Yip committed
502
~~~~~~~~~~
Milo Yip's avatar
Milo Yip committed
503

504
Swapping two DOM trees is fast (constant time), despite the complexity of the trees.
Milo Yip's avatar
Milo Yip committed
505

506
# What's next {#WhatsNext}
miloyip's avatar
miloyip committed
507

Milo Yip's avatar
Milo Yip committed
508 509
This tutorial shows the basics of DOM tree query and manipulation. There are several important concepts in RapidJSON:

510
1. [Streams](doc/stream.md) are channels for reading/writing JSON, which can be a in-memory string, or file stream, etc. User can also create their streams.
Milo Yip's avatar
Milo Yip committed
511
2. [Encoding](doc/encoding.md) defines which character encoding is used in streams and memory. RapidJSON also provide Unicode conversion/validation internally.
512 513 514 515
3. [DOM](doc/dom.md)'s basics are already covered in this tutorial. Uncover more advanced features such as *in situ* parsing, other parsing options and advanced usages.
4. [SAX](doc/sax.md) is the foundation of parsing/generating facility in RapidJSON. Learn how to use `Reader`/`Writer` to implement even faster applications. Also try `PrettyWriter` to format the JSON.
5. [Performance](doc/performance.md) shows some in-house and third-party benchmarks.
6. [Internals](doc/internals.md) describes some internal designs and techniques of RapidJSON.
Milo Yip's avatar
Milo Yip committed
516

517
You may also refer to the [FAQ](doc/faq.md), API documentation, examples and unit tests.