Welcome to mirror list, hosted at ThFree Co, Russian Federation.

md_doc_sax_8zh-cn.html « zh-cn - github.com/miloyip/rapidjson.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: af2817ee5495ced34ba218373fbe1d2b8d9f4db5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
<!-- HTML header for doxygen 1.8.7-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.8.7"/>
<title>RapidJSON: SAX</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="dynsections.js"></script>
<link href="navtree.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="resize.js"></script>
<script type="text/javascript" src="navtree.js"></script>
<script type="text/javascript">
  $(document).ready(initResizable);
  $(window).load(resizeHeight);
</script>
<link href="search/search.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="search/search.js"></script>
<script type="text/javascript">
  $(document).ready(function() { searchBox.OnSelectItem(0); });
</script>
<link href="doxygen.css" rel="stylesheet" type="text/css" />
<link href="doxygenextra.css" rel="stylesheet" type="text/css"/>
</head>
<script>
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
  ga('create', 'UA-63929386-1', 'auto');
  ga('send', 'pageview');
</script>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="topbanner"><a href="https://github.com/miloyip/rapidjson" title="RapidJSON GitHub"><i class="githublogo"></i></a></div>
        <div id="MSearchBox" class="MSearchBoxInactive">
        <span class="left">
          <img id="MSearchSelect" src="search/mag_sel.png"
               onmouseover="return searchBox.OnSearchSelectShow()"
               onmouseout="return searchBox.OnSearchSelectHide()"
               alt=""/>
          <input type="text" id="MSearchField" value="搜索" accesskey="S"
               onfocus="searchBox.OnSearchFieldFocus(true)" 
               onblur="searchBox.OnSearchFieldFocus(false)" 
               onkeyup="searchBox.OnSearchFieldChange(event)"/>
          </span><span class="right">
            <a id="MSearchClose" href="javascript:searchBox.CloseResultsWindow()"><img id="MSearchCloseImg" border="0" src="search/close.png" alt=""/></a>
          </span>
        </div>
<!-- end header part -->
<!-- 制作者 Doxygen 1.8.7 -->
<script type="text/javascript">
var searchBox = new SearchBox("searchBox", "search",false,'搜索');
</script>
</div><!-- top -->
<div id="side-nav" class="ui-resizable side-nav-resizable">
  <div id="nav-tree">
    <div id="nav-tree-contents">
      <div id="nav-sync" class="sync"></div>
    </div>
  </div>
  <div id="splitbar" style="-moz-user-select:none;" 
       class="ui-resizable-handle">
  </div>
</div>
<script type="text/javascript">
$(document).ready(function(){initNavTree('md_doc_sax_8zh-cn.html','');});
</script>
<div id="doc-content">
<!-- window showing the filter options -->
<div id="MSearchSelectWindow"
     onmouseover="return searchBox.OnSearchSelectShow()"
     onmouseout="return searchBox.OnSearchSelectHide()"
     onkeydown="return searchBox.OnSearchSelectKey(event)">
<a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(0)"><span class="SelectionMark">&#160;</span>全部</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(1)"><span class="SelectionMark">&#160;</span>类</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(2)"><span class="SelectionMark">&#160;</span>命名空间</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(3)"><span class="SelectionMark">&#160;</span>文件</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(4)"><span class="SelectionMark">&#160;</span>函数</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(5)"><span class="SelectionMark">&#160;</span>变量</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(6)"><span class="SelectionMark">&#160;</span>类型定义</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(7)"><span class="SelectionMark">&#160;</span>枚举</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(8)"><span class="SelectionMark">&#160;</span>枚举值</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(9)"><span class="SelectionMark">&#160;</span>友元</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(10)"><span class="SelectionMark">&#160;</span>宏定义</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(11)"><span class="SelectionMark">&#160;</span>组</a><a class="SelectItem" href="javascript:void(0)" onclick="searchBox.OnSelectItem(12)"><span class="SelectionMark">&#160;</span>页</a></div>

<!-- iframe showing the search results (closed by default) -->
<div id="MSearchResultsWindow">
<iframe src="javascript:void(0)" frameborder="0" 
        name="MSearchResults" id="MSearchResults">
</iframe>
</div>

<div class="header">
  <div class="headertitle">
<div class="title">SAX </div>  </div>
</div><!--header-->
<div class="contents">
<div class="toc"><h3>目录</h3>
<ul><li class="level1"><a href="#Reader">Reader</a><ul><li class="level2"><a href="#Handler">处理器</a></li>
<li class="level2"><a href="#GenericReader">GenericReader</a></li>
</ul>
</li>
<li class="level1"><a href="#Writer">Writer</a><ul><li class="level2"><a href="#PrettyWriter">PrettyWriter</a></li>
<li class="level2"><a href="#CompletenessReset">完整性及重置</a></li>
<li class="level2"><a href="#CustomDataStructure">解析JSON至自定义结构</a></li>
<li class="level2"><a href="#Filtering">过滤JSON</a></li>
</ul>
</li>
</ul>
</div>
<div class="textblock"><p>"SAX"此术语源于<a href="http://en.wikipedia.org/wiki/Simple_API_for_XML">Simple API for XML</a>。我们借了此术语去套用在JSON的解析及生成。</p>
<p>在RapidJSON中,<code>Reader</code>(<code>GenericReader&lt;...&gt;</code>的typedef)是JSON的SAX风格解析器,而<code>Writer</code>(<code>GenericWriter&lt;...&gt;</code>的typedef)则是JSON的SAX风格生成器。</p>
<h1><a class="anchor" id="Reader"></a>
Reader</h1>
<p><code>Reader</code>从输入流解析一个JSON。当它从流中读取字符时,它会基于JSON的语法去分析字符,并向处理器发送事件。</p>
<p>例如,以下是一个JSON。</p>
<div class="fragment"><div class="line">{</div>
<div class="line">    <span class="stringliteral">&quot;hello&quot;</span>: <span class="stringliteral">&quot;world&quot;</span>,</div>
<div class="line">    <span class="stringliteral">&quot;t&quot;</span>: true ,</div>
<div class="line">    <span class="stringliteral">&quot;f&quot;</span>: <span class="keyword">false</span>,</div>
<div class="line">    <span class="stringliteral">&quot;n&quot;</span>: null,</div>
<div class="line">    <span class="stringliteral">&quot;i&quot;</span>: 123,</div>
<div class="line">    <span class="stringliteral">&quot;pi&quot;</span>: 3.1416,</div>
<div class="line">    <span class="stringliteral">&quot;a&quot;</span>: [1, 2, 3, 4]</div>
<div class="line">}</div>
</div><!-- fragment --><p>当一个<code>Reader</code>解析此JSON时,它会顺序地向处理器发送以下的事件:</p>
<div class="fragment"><div class="line">StartObject()</div>
<div class="line">Key(&quot;hello&quot;, 5, true)</div>
<div class="line">String(&quot;world&quot;, 5, true)</div>
<div class="line">Key(&quot;t&quot;, 1, true)</div>
<div class="line">Bool(true)</div>
<div class="line">Key(&quot;f&quot;, 1, true)</div>
<div class="line">Bool(false)</div>
<div class="line">Key(&quot;n&quot;, 1, true)</div>
<div class="line">Null()</div>
<div class="line">Key(&quot;i&quot;)</div>
<div class="line">UInt(123)</div>
<div class="line">Key(&quot;pi&quot;)</div>
<div class="line">Double(3.1416)</div>
<div class="line">Key(&quot;a&quot;)</div>
<div class="line">StartArray()</div>
<div class="line">Uint(1)</div>
<div class="line">Uint(2)</div>
<div class="line">Uint(3)</div>
<div class="line">Uint(4)</div>
<div class="line">EndArray(4)</div>
<div class="line">EndObject(7)</div>
</div><!-- fragment --><p>除了一些事件参数需要再作解释,这些事件可以轻松地与JSON对上。我们可以看看<code>simplereader</code>例子怎样产生和以上完全相同的结果:</p>
<div class="fragment"><div class="line"><span class="preprocessor">#include &quot;<a class="code" href="reader_8h.html">rapidjson/reader.h</a>&quot;</span></div>
<div class="line"><span class="preprocessor">#include &lt;iostream&gt;</span></div>
<div class="line"></div>
<div class="line"><span class="keyword">using namespace </span>rapidjson;</div>
<div class="line"><span class="keyword">using namespace </span>std;</div>
<div class="line"></div>
<div class="line"><span class="keyword">struct </span>MyHandler {</div>
<div class="line">    <span class="keywordtype">bool</span> Null() { cout &lt;&lt; <span class="stringliteral">&quot;Null()&quot;</span> &lt;&lt; endl; <span class="keywordflow">return</span> <span class="keyword">true</span>; }</div>
<div class="line">    <span class="keywordtype">bool</span> Bool(<span class="keywordtype">bool</span> b) { cout &lt;&lt; <span class="stringliteral">&quot;Bool(&quot;</span> &lt;&lt; boolalpha &lt;&lt; b &lt;&lt; <span class="stringliteral">&quot;)&quot;</span> &lt;&lt; endl; <span class="keywordflow">return</span> <span class="keyword">true</span>; }</div>
<div class="line">    <span class="keywordtype">bool</span> Int(<span class="keywordtype">int</span> i) { cout &lt;&lt; <span class="stringliteral">&quot;Int(&quot;</span> &lt;&lt; i &lt;&lt; <span class="stringliteral">&quot;)&quot;</span> &lt;&lt; endl; <span class="keywordflow">return</span> <span class="keyword">true</span>; }</div>
<div class="line">    <span class="keywordtype">bool</span> Uint(<span class="keywordtype">unsigned</span> u) { cout &lt;&lt; <span class="stringliteral">&quot;Uint(&quot;</span> &lt;&lt; u &lt;&lt; <span class="stringliteral">&quot;)&quot;</span> &lt;&lt; endl; <span class="keywordflow">return</span> <span class="keyword">true</span>; }</div>
<div class="line">    <span class="keywordtype">bool</span> Int64(int64_t i) { cout &lt;&lt; <span class="stringliteral">&quot;Int64(&quot;</span> &lt;&lt; i &lt;&lt; <span class="stringliteral">&quot;)&quot;</span> &lt;&lt; endl; <span class="keywordflow">return</span> <span class="keyword">true</span>; }</div>
<div class="line">    <span class="keywordtype">bool</span> Uint64(uint64_t u) { cout &lt;&lt; <span class="stringliteral">&quot;Uint64(&quot;</span> &lt;&lt; u &lt;&lt; <span class="stringliteral">&quot;)&quot;</span> &lt;&lt; endl; <span class="keywordflow">return</span> <span class="keyword">true</span>; }</div>
<div class="line">    <span class="keywordtype">bool</span> Double(<span class="keywordtype">double</span> d) { cout &lt;&lt; <span class="stringliteral">&quot;Double(&quot;</span> &lt;&lt; d &lt;&lt; <span class="stringliteral">&quot;)&quot;</span> &lt;&lt; endl; <span class="keywordflow">return</span> <span class="keyword">true</span>; }</div>
<div class="line">    <span class="keywordtype">bool</span> String(<span class="keyword">const</span> <span class="keywordtype">char</span>* str, <a class="code" href="namespacerapidjson.html#a44eb33eaa523e36d466b1ced64b85c84">SizeType</a> length, <span class="keywordtype">bool</span> copy) { </div>
<div class="line">        cout &lt;&lt; <span class="stringliteral">&quot;String(&quot;</span> &lt;&lt; str &lt;&lt; <span class="stringliteral">&quot;, &quot;</span> &lt;&lt; length &lt;&lt; <span class="stringliteral">&quot;, &quot;</span> &lt;&lt; boolalpha &lt;&lt; copy &lt;&lt; <span class="stringliteral">&quot;)&quot;</span> &lt;&lt; endl;</div>
<div class="line">        <span class="keywordflow">return</span> <span class="keyword">true</span>;</div>
<div class="line">    }</div>
<div class="line">    <span class="keywordtype">bool</span> StartObject() { cout &lt;&lt; <span class="stringliteral">&quot;StartObject()&quot;</span> &lt;&lt; endl; <span class="keywordflow">return</span> <span class="keyword">true</span>; }</div>
<div class="line">    <span class="keywordtype">bool</span> Key(<span class="keyword">const</span> <span class="keywordtype">char</span>* str, <a class="code" href="namespacerapidjson.html#a44eb33eaa523e36d466b1ced64b85c84">SizeType</a> length, <span class="keywordtype">bool</span> copy) { </div>
<div class="line">        cout &lt;&lt; <span class="stringliteral">&quot;Key(&quot;</span> &lt;&lt; str &lt;&lt; <span class="stringliteral">&quot;, &quot;</span> &lt;&lt; length &lt;&lt; <span class="stringliteral">&quot;, &quot;</span> &lt;&lt; boolalpha &lt;&lt; copy &lt;&lt; <span class="stringliteral">&quot;)&quot;</span> &lt;&lt; endl;</div>
<div class="line">        <span class="keywordflow">return</span> <span class="keyword">true</span>;</div>
<div class="line">    }</div>
<div class="line">    <span class="keywordtype">bool</span> EndObject(<a class="code" href="namespacerapidjson.html#a44eb33eaa523e36d466b1ced64b85c84">SizeType</a> memberCount) { cout &lt;&lt; <span class="stringliteral">&quot;EndObject(&quot;</span> &lt;&lt; memberCount &lt;&lt; <span class="stringliteral">&quot;)&quot;</span> &lt;&lt; endl; <span class="keywordflow">return</span> <span class="keyword">true</span>; }</div>
<div class="line">    <span class="keywordtype">bool</span> StartArray() { cout &lt;&lt; <span class="stringliteral">&quot;StartArray()&quot;</span> &lt;&lt; endl; <span class="keywordflow">return</span> <span class="keyword">true</span>; }</div>
<div class="line">    <span class="keywordtype">bool</span> EndArray(<a class="code" href="namespacerapidjson.html#a44eb33eaa523e36d466b1ced64b85c84">SizeType</a> elementCount) { cout &lt;&lt; <span class="stringliteral">&quot;EndArray(&quot;</span> &lt;&lt; elementCount &lt;&lt; <span class="stringliteral">&quot;)&quot;</span> &lt;&lt; endl; <span class="keywordflow">return</span> <span class="keyword">true</span>; }</div>
<div class="line">};</div>
<div class="line"></div>
<div class="line"><span class="keywordtype">void</span> main() {</div>
<div class="line">    <span class="keyword">const</span> <span class="keywordtype">char</span> json[] = <span class="stringliteral">&quot; { \&quot;hello\&quot; : \&quot;world\&quot;, \&quot;t\&quot; : true , \&quot;f\&quot; : false, \&quot;n\&quot;: null, \&quot;i\&quot;:123, \&quot;pi\&quot;: 3.1416, \&quot;a\&quot;:[1, 2, 3, 4] } &quot;</span>;</div>
<div class="line"></div>
<div class="line">    MyHandler handler;</div>
<div class="line">    <a class="code" href="classrapidjson_1_1_generic_reader.html">Reader</a> reader;</div>
<div class="line">    <a class="code" href="structrapidjson_1_1_generic_string_stream.html">StringStream</a> ss(json);</div>
<div class="line">    reader.<a class="code" href="classrapidjson_1_1_generic_reader.html#ac9c540b77de19661f6f45e04b9b0937b">Parse</a>(ss, handler);</div>
<div class="line">}</div>
</div><!-- fragment --><p>注意RapidJSON使用模板去静态挷定<code>Reader</code>类型及处理器的类形,而不是使用含虚函数的类。这个范式可以通过把函数内联而改善性能。</p>
<h2><a class="anchor" id="Handler"></a>
处理器</h2>
<p>如前例所示,使用者需要实现一个处理器(handler),用于处理来自<code>Reader</code>的事件(函数调用)。处理器必须包含以下的成员函数。</p>
<div class="fragment"><div class="line"><span class="keyword">class </span>Handler {</div>
<div class="line">    <span class="keywordtype">bool</span> Null();</div>
<div class="line">    <span class="keywordtype">bool</span> Bool(<span class="keywordtype">bool</span> b);</div>
<div class="line">    <span class="keywordtype">bool</span> Int(<span class="keywordtype">int</span> i);</div>
<div class="line">    <span class="keywordtype">bool</span> Uint(<span class="keywordtype">unsigned</span> i);</div>
<div class="line">    <span class="keywordtype">bool</span> Int64(int64_t i);</div>
<div class="line">    <span class="keywordtype">bool</span> Uint64(uint64_t i);</div>
<div class="line">    <span class="keywordtype">bool</span> Double(<span class="keywordtype">double</span> d);</div>
<div class="line">    <span class="keywordtype">bool</span> String(<span class="keyword">const</span> Ch* str, <a class="code" href="namespacerapidjson.html#a44eb33eaa523e36d466b1ced64b85c84">SizeType</a> length, <span class="keywordtype">bool</span> copy);</div>
<div class="line">    <span class="keywordtype">bool</span> StartObject();</div>
<div class="line">    <span class="keywordtype">bool</span> Key(<span class="keyword">const</span> Ch* str, <a class="code" href="namespacerapidjson.html#a44eb33eaa523e36d466b1ced64b85c84">SizeType</a> length, <span class="keywordtype">bool</span> copy);</div>
<div class="line">    <span class="keywordtype">bool</span> EndObject(<a class="code" href="namespacerapidjson.html#a44eb33eaa523e36d466b1ced64b85c84">SizeType</a> memberCount);</div>
<div class="line">    <span class="keywordtype">bool</span> StartArray();</div>
<div class="line">    <span class="keywordtype">bool</span> EndArray(<a class="code" href="namespacerapidjson.html#a44eb33eaa523e36d466b1ced64b85c84">SizeType</a> elementCount);</div>
<div class="line">};</div>
</div><!-- fragment --><p>当<code>Reader</code>遇到JSON null值时会调用<code>Null()</code>。</p>
<p>当<code>Reader</code>遇到JSON true或false值时会调用<code>Bool(bool)</code>。</p>
<p>当<code>Reader</code>遇到JSON number,它会选择一个合适的C++类型映射,然后调用<code>Int(int)</code>、<code>Uint(unsigned)</code>、<code>Int64(int64_t)</code>、<code>Uint64(uint64_t)</code>及<code>Double(double)</code>的*其中之一个*。</p>
<p>当<code>Reader</code>遇到JSON string,它会调用<code>String(const char* str, SizeType length, bool copy)</code>。第一个参数是字符串的指针。第二个参数是字符串的长度(不包含空终止符号)。注意RapidJSON支持字串中含有空字符`'\0'<code>。若出现这种情况,便会有</code>strlen(str) &lt; length<code>。最后的</code>copy<code>参数表示处理器是否需要复制该字符串。在正常解析时,</code>copy = true<code>。仅当使用原位解析时,</code>copy = false`。此外,还要注意字符的类型与目标编码相关,我们稍后会再谈这一点。</p>
<p>当<code>Reader</code>遇到JSON object的开始之时,它会调用<code>StartObject()</code>。JSON的object是一个键值对(成员)的集合。若object包含成员,它会先为成员的名字调用<code>Key()</code>,然后再按值的类型调用函数。它不断调用这些键值对,直至最终调用<code>EndObject(SizeType memberCount)</code>。注意<code>memberCount</code>参数对处理器来说只是协助性质,使用者可能不需要此参数。</p>
<p>JSON array与object相似,但更简单。在array开始时,<code>Reader</code>会调用<code>BeginArary()</code>。若array含有元素,它会按元素的类型来读用函数。相似地,最后它会调用<code>EndArray(SizeType elementCount)</code>,其中<code>elementCount</code>参数对处理器来说只是协助性质。</p>
<p>每个处理器函数都返回一个<code>bool</code>。正常它们应返回<code>true</code>。若处理器遇到错误,它可以返回<code>false</code>去通知事件发送方停止继续处理。</p>
<p>例如,当我们用<code>Reader</code>解析一个JSON时,处理器检测到该JSON并不符合所需的schema,那么处理器可以返回<code>false</code>,令<code>Reader</code>停止之后的解析工作。而<code>Reader</code>会进入一个错误状态,并以<code>kParseErrorTermination</code>错误码标识。</p>
<h2><a class="anchor" id="GenericReader"></a>
GenericReader</h2>
<p>前面提及,<code>Reader</code>是<code>GenericReader</code>模板类的typedef:</p>
<div class="fragment"><div class="line"><span class="keyword">namespace </span>rapidjson {</div>
<div class="line"></div>
<div class="line"><span class="keyword">template</span> &lt;<span class="keyword">typename</span> SourceEncoding, <span class="keyword">typename</span> TargetEncoding, <span class="keyword">typename</span> Allocator = MemoryPoolAllocator&lt;&gt; &gt;</div>
<div class="line"><span class="keyword">class </span>GenericReader {</div>
<div class="line">    <span class="comment">// ...</span></div>
<div class="line">};</div>
<div class="line"></div>
<div class="line"><span class="keyword">typedef</span> GenericReader&lt;UTF8&lt;&gt;, UTF8&lt;&gt; &gt; <a class="code" href="namespacerapidjson.html#a4eaef42a208413d1f2c8d4655ecec52d">Reader</a>;</div>
<div class="line"></div>
<div class="line">} <span class="comment">// namespace rapidjson</span></div>
</div><!-- fragment --><p><code>Reader</code>使用UTF-8作为来源及目标编码。来源编码是指JSON流的编码。目标编码是指<code>String()</code>的<code>str</code>参数所用的编码。例如,要解析一个UTF-8流并输出至UTF-16 string事件,你需要这么定义一个reader:</p>
<div class="fragment"><div class="line">GenericReader&lt;UTF8&lt;&gt;, UTF16&lt;&gt; &gt; reader;</div>
</div><!-- fragment --><p>注意到<code>UTF16</code>的缺省类型是<code>wchar_t</code>。因此这个<code>reader</code>需要调用处理器的<code>String(const wchar_t*, SizeType, bool)</code>。</p>
<p>第三个模板参数<code>Allocator</code>是内部数据结构(实际上是一个堆栈)的分配器类型。</p>
<h2><a class="anchor" id="Parsing"></a>
解析</h2>
<p><code>Reader</code>的唯一功能就是解析JSON。</p>
<div class="fragment"><div class="line"><span class="keyword">template</span> &lt;<span class="keywordtype">unsigned</span> parseFlags, <span class="keyword">typename</span> InputStream, <span class="keyword">typename</span> Handler&gt;</div>
<div class="line"><span class="keywordtype">bool</span> Parse(InputStream&amp; is, Handler&amp; handler);</div>
<div class="line"></div>
<div class="line"><span class="comment">// 使用 parseFlags = kDefaultParseFlags</span></div>
<div class="line"><span class="keyword">template</span> &lt;<span class="keyword">typename</span> InputStream, <span class="keyword">typename</span> Handler&gt;</div>
<div class="line"><span class="keywordtype">bool</span> Parse(InputStream&amp; is, Handler&amp; handler);</div>
</div><!-- fragment --><p>若在解析中出现错误,它会返回<code>false</code>。使用者可调用<code>bool HasParseEror()</code>, <code>ParseErrorCode GetParseErrorCode()</code>及<code>size_t GetErrorOffset()</code>获取错误状态。实际上<code>Document</code>使用这些<code>Reader</code>函数去获取解析错误。请参考DOM去了解有关解析错误的细节。</p>
<h1><a class="anchor" id="Writer"></a>
Writer</h1>
<p><code>Reader</code>把JSON转换(解析)成为事件。<code>Writer</code>做完全相反的事情。它把事件转换成JSON。</p>
<p><code>Writer</code>是非常容易使用的。若你的应用程序只需把一些数据转换成JSON,可能直接使用<code>Writer</code>,会比建立一个<code>Document</code>然后用<code>Writer</code>把它转换成JSON更加方便。</p>
<p>在<code>simplewriter</code>例子里,我们做<code>simplereader</code>完全相反的事情。</p>
<div class="fragment"><div class="line"><span class="preprocessor">#include &quot;rapidjson/writer.h&quot;</span></div>
<div class="line"><span class="preprocessor">#include &quot;rapidjson/stringbuffer.h&quot;</span></div>
<div class="line"><span class="preprocessor">#include &lt;iostream&gt;</span></div>
<div class="line"></div>
<div class="line"><span class="keyword">using namespace </span>rapidjson;</div>
<div class="line"><span class="keyword">using namespace </span>std;</div>
<div class="line"></div>
<div class="line"><span class="keywordtype">void</span> main() {</div>
<div class="line">    <a class="code" href="classrapidjson_1_1_generic_string_buffer.html">StringBuffer</a> s;</div>
<div class="line">    <a class="code" href="classrapidjson_1_1_writer.html">Writer&lt;StringBuffer&gt;</a> writer(s);</div>
<div class="line"></div>
<div class="line">    writer.StartObject();</div>
<div class="line">    writer.Key(<span class="stringliteral">&quot;hello&quot;</span>);</div>
<div class="line">    writer.String(<span class="stringliteral">&quot;world&quot;</span>);</div>
<div class="line">    writer.Key(<span class="stringliteral">&quot;t&quot;</span>);</div>
<div class="line">    writer.Bool(<span class="keyword">true</span>);</div>
<div class="line">    writer.Key(<span class="stringliteral">&quot;f&quot;</span>);</div>
<div class="line">    writer.Bool(<span class="keyword">false</span>);</div>
<div class="line">    writer.Key(<span class="stringliteral">&quot;n&quot;</span>);</div>
<div class="line">    writer.Null();</div>
<div class="line">    writer.Key(<span class="stringliteral">&quot;i&quot;</span>);</div>
<div class="line">    writer.Uint(123);</div>
<div class="line">    writer.Key(<span class="stringliteral">&quot;pi&quot;</span>);</div>
<div class="line">    writer.<a class="code" href="classrapidjson_1_1_writer.html#ad5f042d9c1a8ce5be2d52e18255b4390">Double</a>(3.1416);</div>
<div class="line">    writer.Key(<span class="stringliteral">&quot;a&quot;</span>);</div>
<div class="line">    writer.StartArray();</div>
<div class="line">    <span class="keywordflow">for</span> (<span class="keywordtype">unsigned</span> i = 0; i &lt; 4; i++)</div>
<div class="line">        writer.Uint(i);</div>
<div class="line">    writer.EndArray();</div>
<div class="line">    writer.EndObject();</div>
<div class="line"></div>
<div class="line">    cout &lt;&lt; s.GetString() &lt;&lt; endl;</div>
<div class="line">}</div>
</div><!-- fragment --><div class="fragment"><div class="line">{<span class="stringliteral">&quot;hello&quot;</span>:<span class="stringliteral">&quot;world&quot;</span>,<span class="stringliteral">&quot;t&quot;</span>:<span class="keyword">true</span>,<span class="stringliteral">&quot;f&quot;</span>:<span class="keyword">false</span>,<span class="stringliteral">&quot;n&quot;</span>:null,<span class="stringliteral">&quot;i&quot;</span>:123,<span class="stringliteral">&quot;pi&quot;</span>:3.1416,<span class="stringliteral">&quot;a&quot;</span>:[0,1,2,3]}</div>
</div><!-- fragment --><p><code>String()</code>及<code>Key()</code>各有两个重载。一个是如处理器concept般,有3个参数。它能处理含空字符的字符串。另一个是如上中使用的较简单版本。</p>
<p>注意到,例子代码中的<code>EndArray()</code>及<code>EndObject()</code>并没有参数。可以传递一个<code>SizeType</code>的参数,但它会被<code>Writer</code>忽略。</p>
<p>你可能会怀疑,为什么不使用<code>sprintf()</code>或<code>std::stringstream</code>去建立一个JSON?</p>
<p>这有几个原因:</p><ol type="1">
<li><code>Writer</code>必然会输出一个结构良好(well-formed)的JSON。若然有错误的事件次序(如<code>Int()</code>紧随<code>StartObject()</code>出现),它会在调试模式中产生断言失败。</li>
<li><code>Writer::String()</code>可处理字符串转义(如把码点<code>U+000A</code>转换成<code>\n</code>)及进行Unicode转码。</li>
<li><code>Writer</code>一致地处理number的输出。</li>
<li><code>Writer</code>实现了事件处理器concept。可用于处理来自<code>Reader</code>、<code>Document</code>或其他事件发生器。</li>
<li><code>Writer</code>可对不同平台进行优化。</li>
</ol>
<p>无论如何,使用<code>Writer</code> API去生成JSON甚至乎比这些临时方法更简单。</p>
<h2><a class="anchor" id=""></a>
</h2>
<p><code>Writer</code>与<code>Reader</code>有少许设计区别。<code>Writer</code>是一个模板类,而不是一个typedef。 并没有<code>GenericWriter</code>。以下是<code>Writer</code>的声明。</p>
<div class="fragment"><div class="line"><span class="keyword">namespace </span>rapidjson {</div>
<div class="line"></div>
<div class="line"><span class="keyword">template</span>&lt;<span class="keyword">typename</span> OutputStream, <span class="keyword">typename</span> SourceEncoding = UTF8&lt;&gt;, <span class="keyword">typename</span> TargetEncoding = UTF8&lt;&gt;, <span class="keyword">typename</span> Allocator = CrtAllocator&lt;&gt; &gt;</div>
<div class="line"><span class="keyword">class </span>Writer {</div>
<div class="line"><span class="keyword">public</span>:</div>
<div class="line">    <a class="code" href="classrapidjson_1_1_writer.html#ac592904fad01d9d0f29bb0585fb02aa7">Writer</a>(OutputStream&amp; os, Allocator* allocator = 0, <span class="keywordtype">size_t</span> levelDepth = kDefaultLevelDepth)</div>
<div class="line"><span class="comment">// ...</span></div>
<div class="line">};</div>
<div class="line"></div>
<div class="line">} <span class="comment">// namespace rapidjson</span></div>
</div><!-- fragment --><p><code>OutputStream</code>模板参数是输出流的类型。它的类型不可以被自动推断,必须由使用者提供。</p>
<p><code>SourceEncoding</code>模板参数指定了<code>String(const Ch*, ...)</code>的编码。</p>
<p><code>TargetEncoding</code>模板参数指定输出流的编码。</p>
<p>最后一个<code>Allocator</code>是分配器的类型,用于分配内部数据结构(一个堆栈)。</p>
<p>此外,<code>Writer</code>的构造函数有一<code>levelDepth</code>参数。存储每层阶信息的初始内存分配量受此参数影响。</p>
<h2><a class="anchor" id="PrettyWriter"></a>
PrettyWriter</h2>
<p><code>Writer</code>所输出的是没有空格字符的最紧凑JSON,适合网络传输或储存,但不适合人类阅读。</p>
<p>因此,RapidJSON提供了一个<code>PrettyWriter</code>,它在输出中加入缩进及换行。</p>
<p><code>PrettyWriter</code>的用法与<code>Writer</code>几乎一样,不同之处是<code>PrettyWriter</code>提供了一个<code>SetIndent(Ch indentChar, unsigned indentCharCount)</code>函数。缺省的缩进是4个空格。</p>
<h2><a class="anchor" id="CompletenessReset"></a>
完整性及重置</h2>
<p>一个<code>Writer</code>只可输出单个JSON,其根节点可以是任何JSON类型。当处理完单个根节点事件(如<code>String()</code>),或匹配的最后<code>EndObject()</code>或<code>EndArray()</code>事件,输出的JSON是结构完整(well-formed)及完整的。使用者可调用<code>Writer::IsComplete()</code>去检测完整性。</p>
<p>当JSON完整时,<code>Writer</code>不能再接受新的事件。不然其输出便会是不合法的(例如有超过一个根节点)。为了重新利用<code>Writer</code>对象,使用者可调用<code>Writer::Reset(OutputStream&amp; os)</code>去重置其所有内部状态及设置新的输出流。</p>
<h1><a class="anchor" id="Techniques"></a>
技巧</h1>
<h2><a class="anchor" id="CustomDataStructure"></a>
解析JSON至自定义结构</h2>
<p><code>Document</code>的解析功能完全依靠<code>Reader</code>。实际上<code>Document</code>是一个处理器,在解析JSON时接收事件去建立一个DOM。</p>
<p>使用者可以直接使用<code>Reader</code>去建立其他数据结构。这消除了建立DOM的步骤,从而减少了内存开销并改善性能。</p>
<p>在以下的<code>messagereader</code>例子中,<code>ParseMessages()</code>解析一个JSON,该JSON应该是一个含键值对的object。</p>
<div class="fragment"><div class="line"><span class="preprocessor">#include &quot;<a class="code" href="reader_8h.html">rapidjson/reader.h</a>&quot;</span></div>
<div class="line"><span class="preprocessor">#include &quot;rapidjson/error/en.h&quot;</span></div>
<div class="line"><span class="preprocessor">#include &lt;iostream&gt;</span></div>
<div class="line"><span class="preprocessor">#include &lt;string&gt;</span></div>
<div class="line"><span class="preprocessor">#include &lt;map&gt;</span></div>
<div class="line"></div>
<div class="line"><span class="keyword">using namespace </span>std;</div>
<div class="line"><span class="keyword">using namespace </span>rapidjson;</div>
<div class="line"></div>
<div class="line"><span class="keyword">typedef</span> map&lt;string, string&gt; MessageMap;</div>
<div class="line"></div>
<div class="line"><span class="keyword">struct </span>MessageHandler</div>
<div class="line">    : <span class="keyword">public</span> <a class="code" href="structrapidjson_1_1_base_reader_handler.html">BaseReaderHandler</a>&lt;UTF8&lt;&gt;, MessageHandler&gt; {</div>
<div class="line">    MessageHandler() : state_(kExpectObjectStart) {</div>
<div class="line">    }</div>
<div class="line"></div>
<div class="line">    <span class="keywordtype">bool</span> StartObject() {</div>
<div class="line">        <span class="keywordflow">switch</span> (state_) {</div>
<div class="line">        <span class="keywordflow">case</span> kExpectObjectStart:</div>
<div class="line">            state_ = kExpectNameOrObjectEnd;</div>
<div class="line">            <span class="keywordflow">return</span> <span class="keyword">true</span>;</div>
<div class="line">        <span class="keywordflow">default</span>:</div>
<div class="line">            <span class="keywordflow">return</span> <span class="keyword">false</span>;</div>
<div class="line">        }</div>
<div class="line">    }</div>
<div class="line"></div>
<div class="line">    <span class="keywordtype">bool</span> String(<span class="keyword">const</span> <span class="keywordtype">char</span>* str, <a class="code" href="namespacerapidjson.html#a44eb33eaa523e36d466b1ced64b85c84">SizeType</a> length, <span class="keywordtype">bool</span>) {</div>
<div class="line">        <span class="keywordflow">switch</span> (state_) {</div>
<div class="line">        <span class="keywordflow">case</span> kExpectNameOrObjectEnd:</div>
<div class="line">            name_ = string(str, length);</div>
<div class="line">            state_ = kExpectValue;</div>
<div class="line">            <span class="keywordflow">return</span> <span class="keyword">true</span>;</div>
<div class="line">        <span class="keywordflow">case</span> kExpectValue:</div>
<div class="line">            messages_.insert(MessageMap::value_type(name_, <span class="keywordtype">string</span>(str, length)));</div>
<div class="line">            state_ = kExpectNameOrObjectEnd;</div>
<div class="line">            <span class="keywordflow">return</span> <span class="keyword">true</span>;</div>
<div class="line">        <span class="keywordflow">default</span>:</div>
<div class="line">            <span class="keywordflow">return</span> <span class="keyword">false</span>;</div>
<div class="line">        }</div>
<div class="line">    }</div>
<div class="line"></div>
<div class="line">    <span class="keywordtype">bool</span> EndObject(<a class="code" href="namespacerapidjson.html#a44eb33eaa523e36d466b1ced64b85c84">SizeType</a>) { <span class="keywordflow">return</span> state_ == kExpectNameOrObjectEnd; }</div>
<div class="line"></div>
<div class="line">    <span class="keywordtype">bool</span> Default() { <span class="keywordflow">return</span> <span class="keyword">false</span>; } <span class="comment">// All other events are invalid.</span></div>
<div class="line"></div>
<div class="line">    MessageMap messages_;</div>
<div class="line">    <span class="keyword">enum</span> State {</div>
<div class="line">        kExpectObjectStart,</div>
<div class="line">        kExpectNameOrObjectEnd,</div>
<div class="line">        kExpectValue,</div>
<div class="line">    }state_;</div>
<div class="line">    std::string name_;</div>
<div class="line">};</div>
<div class="line"></div>
<div class="line"><span class="keywordtype">void</span> ParseMessages(<span class="keyword">const</span> <span class="keywordtype">char</span>* json, MessageMap&amp; messages) {</div>
<div class="line">    <a class="code" href="classrapidjson_1_1_generic_reader.html">Reader</a> reader;</div>
<div class="line">    MessageHandler handler;</div>
<div class="line">    <a class="code" href="structrapidjson_1_1_generic_string_stream.html">StringStream</a> ss(json);</div>
<div class="line">    <span class="keywordflow">if</span> (reader.<a class="code" href="classrapidjson_1_1_generic_reader.html#ac9c540b77de19661f6f45e04b9b0937b">Parse</a>(ss, handler))</div>
<div class="line">        messages.swap(handler.messages_);   <span class="comment">// Only change it if success.</span></div>
<div class="line">    <span class="keywordflow">else</span> {</div>
<div class="line">        <a class="code" href="group___r_a_p_i_d_j_s_o_n___e_r_r_o_r_s.html#ga7d3acf640886b1f2552dc8c4cd6dea60">ParseErrorCode</a> e = reader.<a class="code" href="classrapidjson_1_1_generic_reader.html#a40fd326bad7d7033f096b549cbf159db">GetParseErrorCode</a>();</div>
<div class="line">        <span class="keywordtype">size_t</span> o = reader.<a class="code" href="classrapidjson_1_1_generic_reader.html#ab907a36c410e96154c99797a6a0ce16d">GetErrorOffset</a>();</div>
<div class="line">        cout &lt;&lt; <span class="stringliteral">&quot;Error: &quot;</span> &lt;&lt; <a class="code" href="group___r_a_p_i_d_j_s_o_n___e_r_r_o_r_s.html#gabdaf1a7a4db30fb0e3d927fdf0fabe79">GetParseError_En</a>(e) &lt;&lt; endl;;</div>
<div class="line">        cout &lt;&lt; <span class="stringliteral">&quot; at offset &quot;</span> &lt;&lt; o &lt;&lt; <span class="stringliteral">&quot; near &#39;&quot;</span> &lt;&lt; string(json).substr(o, 10) &lt;&lt; <span class="stringliteral">&quot;...&#39;&quot;</span> &lt;&lt; endl;</div>
<div class="line">    }</div>
<div class="line">}</div>
<div class="line"></div>
<div class="line"><span class="keywordtype">int</span> main() {</div>
<div class="line">    MessageMap messages;</div>
<div class="line"></div>
<div class="line">    <span class="keyword">const</span> <span class="keywordtype">char</span>* json1 = <span class="stringliteral">&quot;{ \&quot;greeting\&quot; : \&quot;Hello!\&quot;, \&quot;farewell\&quot; : \&quot;bye-bye!\&quot; }&quot;</span>;</div>
<div class="line">    cout &lt;&lt; json1 &lt;&lt; endl;</div>
<div class="line">    ParseMessages(json1, messages);</div>
<div class="line"></div>
<div class="line">    <span class="keywordflow">for</span> (MessageMap::const_iterator itr = messages.begin(); itr != messages.end(); ++itr)</div>
<div class="line">        cout &lt;&lt; itr-&gt;first &lt;&lt; <span class="stringliteral">&quot;: &quot;</span> &lt;&lt; itr-&gt;second &lt;&lt; endl;</div>
<div class="line"></div>
<div class="line">    cout &lt;&lt; endl &lt;&lt; <span class="stringliteral">&quot;Parse a JSON with invalid schema.&quot;</span> &lt;&lt; endl;</div>
<div class="line">    <span class="keyword">const</span> <span class="keywordtype">char</span>* json2 = <span class="stringliteral">&quot;{ \&quot;greeting\&quot; : \&quot;Hello!\&quot;, \&quot;farewell\&quot; : \&quot;bye-bye!\&quot;, \&quot;foo\&quot; : {} }&quot;</span>;</div>
<div class="line">    cout &lt;&lt; json2 &lt;&lt; endl;</div>
<div class="line">    ParseMessages(json2, messages);</div>
<div class="line"></div>
<div class="line">    <span class="keywordflow">return</span> 0;</div>
<div class="line">}</div>
</div><!-- fragment --><div class="fragment"><div class="line">{ <span class="stringliteral">&quot;greeting&quot;</span> : <span class="stringliteral">&quot;Hello!&quot;</span>, <span class="stringliteral">&quot;farewell&quot;</span> : <span class="stringliteral">&quot;bye-bye!&quot;</span> }</div>
<div class="line">farewell: bye-bye!</div>
<div class="line">greeting: Hello!</div>
<div class="line"></div>
<div class="line">Parse a JSON with invalid schema.</div>
<div class="line">{ <span class="stringliteral">&quot;greeting&quot;</span> : <span class="stringliteral">&quot;Hello!&quot;</span>, <span class="stringliteral">&quot;farewell&quot;</span> : <span class="stringliteral">&quot;bye-bye!&quot;</span>, <span class="stringliteral">&quot;foo&quot;</span> : {} }</div>
<div class="line">Error: Terminate parsing due to Handler error.</div>
<div class="line"> at offset 59 near <span class="stringliteral">&#39;} }...&#39;</span></div>
</div><!-- fragment --><p>第一个JSON(<code>json1</code>)被成功地解析至<code>MessageMap</code>。由于<code>MessageMap</code>是一个<code>std::map</code>,打印次序按键值排序。此次序与JSON中的次序不同。</p>
<p>在第二个JSON(<code>json2</code>)中,<code>foo</code>的值是一个空object。由于它是一个object,<code>MessageHandler::StartObject()</code>会被调用。然而,在<code>state_ = kExpectValue</code>的情况下,该函数会返回<code>false</code>,并导致解析过程终止。错误代码是<code>kParseErrorTermination</code>。</p>
<h2><a class="anchor" id="Filtering"></a>
过滤JSON</h2>
<p>如前面提及过,<code>Writer</code>可处理<code>Reader</code>发出的事件。<code>example/condense/condense.cpp</code>例子简单地设置<code>Writer</code>作为一个<code>Reader</code>的处理器,因此它能移除JSON中的所有空白字符。<code>example/pretty/pretty.cpp</code>例子使用同样的关系,只是以<code>PrettyWriter</code>取代<code>Writer</code>。因此<code>pretty</code>能够重新格式化JSON,加入缩进及换行。</p>
<p>实际上,我们可以使用SAX风格API去加入(多个)中间层去过滤JSON的内容。例如<code>capitalize</code>例子可以把所有JSON string改为大写。</p>
<div class="fragment"><div class="line"><span class="preprocessor">#include &quot;<a class="code" href="reader_8h.html">rapidjson/reader.h</a>&quot;</span></div>
<div class="line"><span class="preprocessor">#include &quot;rapidjson/writer.h&quot;</span></div>
<div class="line"><span class="preprocessor">#include &quot;rapidjson/filereadstream.h&quot;</span></div>
<div class="line"><span class="preprocessor">#include &quot;rapidjson/filewritestream.h&quot;</span></div>
<div class="line"><span class="preprocessor">#include &quot;rapidjson/error/en.h&quot;</span></div>
<div class="line"><span class="preprocessor">#include &lt;vector&gt;</span></div>
<div class="line"><span class="preprocessor">#include &lt;cctype&gt;</span></div>
<div class="line"></div>
<div class="line"><span class="keyword">using namespace </span>rapidjson;</div>
<div class="line"></div>
<div class="line"><span class="keyword">template</span>&lt;<span class="keyword">typename</span> OutputHandler&gt;</div>
<div class="line"><span class="keyword">struct </span>CapitalizeFilter {</div>
<div class="line">    CapitalizeFilter(OutputHandler&amp; out) : out_(out), buffer_() {</div>
<div class="line">    }</div>
<div class="line"></div>
<div class="line">    <span class="keywordtype">bool</span> Null() { <span class="keywordflow">return</span> out_.Null(); }</div>
<div class="line">    <span class="keywordtype">bool</span> Bool(<span class="keywordtype">bool</span> b) { <span class="keywordflow">return</span> out_.Bool(b); }</div>
<div class="line">    <span class="keywordtype">bool</span> Int(<span class="keywordtype">int</span> i) { <span class="keywordflow">return</span> out_.Int(i); }</div>
<div class="line">    <span class="keywordtype">bool</span> Uint(<span class="keywordtype">unsigned</span> u) { <span class="keywordflow">return</span> out_.Uint(u); }</div>
<div class="line">    <span class="keywordtype">bool</span> Int64(int64_t i) { <span class="keywordflow">return</span> out_.Int64(i); }</div>
<div class="line">    <span class="keywordtype">bool</span> Uint64(uint64_t u) { <span class="keywordflow">return</span> out_.Uint64(u); }</div>
<div class="line">    <span class="keywordtype">bool</span> Double(<span class="keywordtype">double</span> d) { <span class="keywordflow">return</span> out_.Double(d); }</div>
<div class="line">    <span class="keywordtype">bool</span> String(<span class="keyword">const</span> <span class="keywordtype">char</span>* str, <a class="code" href="namespacerapidjson.html#a44eb33eaa523e36d466b1ced64b85c84">SizeType</a> length, <span class="keywordtype">bool</span>) { </div>
<div class="line">        buffer_.clear();</div>
<div class="line">        <span class="keywordflow">for</span> (<a class="code" href="namespacerapidjson.html#a44eb33eaa523e36d466b1ced64b85c84">SizeType</a> i = 0; i &lt; length; i++)</div>
<div class="line">            buffer_.push_back(std::toupper(str[i]));</div>
<div class="line">        <span class="keywordflow">return</span> out_.String(&amp;buffer_.front(), length, <span class="keyword">true</span>); <span class="comment">// true = output handler need to copy the string</span></div>
<div class="line">    }</div>
<div class="line">    <span class="keywordtype">bool</span> StartObject() { <span class="keywordflow">return</span> out_.StartObject(); }</div>
<div class="line">    <span class="keywordtype">bool</span> Key(<span class="keyword">const</span> <span class="keywordtype">char</span>* str, <a class="code" href="namespacerapidjson.html#a44eb33eaa523e36d466b1ced64b85c84">SizeType</a> length, <span class="keywordtype">bool</span> copy) { <span class="keywordflow">return</span> String(str, length, copy); }</div>
<div class="line">    <span class="keywordtype">bool</span> EndObject(<a class="code" href="namespacerapidjson.html#a44eb33eaa523e36d466b1ced64b85c84">SizeType</a> memberCount) { <span class="keywordflow">return</span> out_.EndObject(memberCount); }</div>
<div class="line">    <span class="keywordtype">bool</span> StartArray() { <span class="keywordflow">return</span> out_.StartArray(); }</div>
<div class="line">    <span class="keywordtype">bool</span> EndArray(<a class="code" href="namespacerapidjson.html#a44eb33eaa523e36d466b1ced64b85c84">SizeType</a> elementCount) { <span class="keywordflow">return</span> out_.EndArray(elementCount); }</div>
<div class="line"></div>
<div class="line">    OutputHandler&amp; out_;</div>
<div class="line">    std::vector&lt;char&gt; buffer_;</div>
<div class="line">};</div>
<div class="line"></div>
<div class="line"><span class="keywordtype">int</span> main(<span class="keywordtype">int</span>, <span class="keywordtype">char</span>*[]) {</div>
<div class="line">    <span class="comment">// Prepare JSON reader and input stream.</span></div>
<div class="line">    <a class="code" href="classrapidjson_1_1_generic_reader.html">Reader</a> reader;</div>
<div class="line">    <span class="keywordtype">char</span> readBuffer[65536];</div>
<div class="line">    <a class="code" href="classrapidjson_1_1_file_read_stream.html">FileReadStream</a> is(stdin, readBuffer, <span class="keyword">sizeof</span>(readBuffer));</div>
<div class="line"></div>
<div class="line">    <span class="comment">// Prepare JSON writer and output stream.</span></div>
<div class="line">    <span class="keywordtype">char</span> writeBuffer[65536];</div>
<div class="line">    <a class="code" href="classrapidjson_1_1_file_write_stream.html">FileWriteStream</a> os(stdout, writeBuffer, <span class="keyword">sizeof</span>(writeBuffer));</div>
<div class="line">    <a class="code" href="classrapidjson_1_1_writer.html">Writer&lt;FileWriteStream&gt;</a> writer(os);</div>
<div class="line"></div>
<div class="line">    <span class="comment">// JSON reader parse from the input stream and let writer generate the output.</span></div>
<div class="line">    CapitalizeFilter&lt;Writer&lt;FileWriteStream&gt; &gt; filter(writer);</div>
<div class="line">    <span class="keywordflow">if</span> (!reader.<a class="code" href="classrapidjson_1_1_generic_reader.html#ac9c540b77de19661f6f45e04b9b0937b">Parse</a>(is, filter)) {</div>
<div class="line">        fprintf(stderr, <span class="stringliteral">&quot;\nError(%u): %s\n&quot;</span>, (<span class="keywordtype">unsigned</span>)reader.<a class="code" href="classrapidjson_1_1_generic_reader.html#ab907a36c410e96154c99797a6a0ce16d">GetErrorOffset</a>(), <a class="code" href="group___r_a_p_i_d_j_s_o_n___e_r_r_o_r_s.html#gabdaf1a7a4db30fb0e3d927fdf0fabe79">GetParseError_En</a>(reader.<a class="code" href="classrapidjson_1_1_generic_reader.html#a40fd326bad7d7033f096b549cbf159db">GetParseErrorCode</a>()));</div>
<div class="line">        <span class="keywordflow">return</span> 1;</div>
<div class="line">    }</div>
<div class="line"></div>
<div class="line">    <span class="keywordflow">return</span> 0;</div>
<div class="line">}</div>
</div><!-- fragment --><p>注意到,不可简单地把JSON当作字符串去改为大写。例如: </p><div class="fragment"><div class="line">[<span class="stringliteral">&quot;Hello\nWorld&quot;</span>]</div>
</div><!-- fragment --><p>简单地把整个JSON转为大写的话会产生错误的转义符: </p><div class="fragment"><div class="line">[<span class="stringliteral">&quot;HELLO\NWORLD&quot;</span>]</div>
</div><!-- fragment --><p>而<code>capitalize</code>就会产生正确的结果: </p><div class="fragment"><div class="line">[<span class="stringliteral">&quot;HELLO\nWORLD&quot;</span>]</div>
</div><!-- fragment --><p>我们还可以开发更复杂的过滤器。然而,由于SAX风格API在某一时间点只能提供单一事件的信息,使用者需要自行记录一些上下文信息(例如从根节点起的路径、储存其他相关值)。对于处理某些情况,用DOM会比SAX更容易实现。 </p>
</div></div><!-- contents -->
</div><!-- doc-content -->
<!-- HTML footer for doxygen 1.8.7-->
<!-- start footer part -->
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
  <ul>
  </ul>
</div>
<script type="text/javascript">
    /* * * CONFIGURATION VARIABLES * * */
    var disqus_shortname = 'rapidjson-doc';
    /* * * DON'T EDIT BELOW THIS LINE * * */
    (function() {
	    var dt = document.createElement('div');
	    dt.id = "disqus_thread";
	    (document.getElementsByClassName('contents')[0]).appendChild(dt);
        var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
        dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
        (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
    })();
</script>
</body>
</html>