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

md_doc_dom_8zh-cn.html « zh-cn - github.com/miloyip/rapidjson.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: a6eb9ce100a7e4d6bdb40c39259b40372617c288 (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
<!-- 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: DOM</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_dom_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">DOM </div>  </div>
</div><!--header-->
<div class="contents">
<div class="toc"><h3>目录</h3>
<ul><li class="level1"><a href="#Template">模板</a><ul><li class="level2"><a href="#Encoding">编码</a></li>
</ul>
</li>
<li class="level1"><a href="#Allocator">Allocator</a></li>
<li class="level1"><a href="#Parsing">解析</a><ul><li class="level2"><a href="#ParseError">解析错误</a></li>
<li class="level2"><a href="#InSituParsing">原位解析</a></li>
<li class="level2"><a href="#TranscodingAndValidation">转码与校验</a></li>
</ul>
</li>
<li class="level1"><a href="#Techniques">技巧</a></li>
</ul>
</div>
<div class="textblock"><p>文档对象模型(Document Object Model, DOM)是一种罝于内存中的JSON表示方式,以供查询及操作。我们己于教程中介绍了DOM的基本用法,本节将讲述一些细节及高级用法。</p>
<h1><a class="anchor" id="Template"></a>
模板</h1>
<p>教程中使用了<code>Value</code>和<code>Document</code>类型。与<code>std::string</code>相似,这些类型其实是两个模板类的<code>typedef</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> Encoding, <span class="keyword">typename</span> Allocator = MemoryPoolAllocator&lt;&gt; &gt;</div>
<div class="line"><span class="keyword">class </span>GenericValue {</div>
<div class="line">    <span class="comment">// ...</span></div>
<div class="line">};</div>
<div class="line"></div>
<div class="line"><span class="keyword">template</span> &lt;<span class="keyword">typename</span> Encoding, <span class="keyword">typename</span> Allocator = MemoryPoolAllocator&lt;&gt; &gt;</div>
<div class="line"><span class="keyword">class </span>GenericDocument : <span class="keyword">public</span> GenericValue&lt;Encoding, Allocator&gt; {</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> GenericValue&lt;UTF8&lt;&gt; &gt; <a class="code" href="namespacerapidjson.html#aa65fc9fb381b2cbc54f98673eadd6505">Value</a>;</div>
<div class="line"><span class="keyword">typedef</span> GenericDocument&lt;UTF8&lt;&gt; &gt; <a class="code" href="namespacerapidjson.html#ace11b5b575baf1cccd5ba5f8586dcdc8">Document</a>;</div>
<div class="line"></div>
<div class="line">} <span class="comment">// namespace rapidjson</span></div>
</div><!-- fragment --><p>使用者可以自定义这些模板参数。</p>
<h2><a class="anchor" id="Encoding"></a>
编码</h2>
<p><code>Encoding</code>参数指明在内存中的JSON String使用哪种编码。可行的选项有<code>UTF8</code>、<code>UTF16</code>、<code>UTF32</code>。要注意这3个类型其实也是模板类。<code>UTF8&lt;&gt;</code>等同<code>UTF8&lt;char&gt;</code>,这代表它使用<code>char</code>来存储字符串。更多细节可以参考编码。</p>
<p>这里是一个例子。假设一个Windows应用软件希望查询存储于JSON中的本地化字符串。Windows中含Unicode的函数使用UTF-16(宽字符)编码。无论JSON文件使用哪种编码,我们都可以把字符串以UTF-16形式存储在内存。</p>
<div class="fragment"><div class="line"><span class="keyword">using namespace </span>rapidjson;</div>
<div class="line"></div>
<div class="line"><span class="keyword">typedef</span> <a class="code" href="classrapidjson_1_1_generic_document.html">GenericDocument&lt;UTF16&lt;&gt;</a> &gt; WDocument;</div>
<div class="line"><span class="keyword">typedef</span> <a class="code" href="classrapidjson_1_1_generic_value.html">GenericValue&lt;UTF16&lt;&gt;</a> &gt; WValue;</div>
<div class="line"></div>
<div class="line">FILE* fp = fopen(<span class="stringliteral">&quot;localization.json&quot;</span>, <span class="stringliteral">&quot;rb&quot;</span>); <span class="comment">// 非Windows平台使用&quot;r&quot;</span></div>
<div class="line"></div>
<div class="line"><span class="keywordtype">char</span> readBuffer[256];</div>
<div class="line"><a class="code" href="classrapidjson_1_1_file_read_stream.html">FileReadStream</a> bis(fp, readBuffer, <span class="keyword">sizeof</span>(readBuffer));</div>
<div class="line"></div>
<div class="line"><a class="code" href="classrapidjson_1_1_auto_u_t_f_input_stream.html">AutoUTFInputStream&lt;unsigned, FileReadStream&gt;</a> eis(bis);  <span class="comment">// 包装bis成eis</span></div>
<div class="line"></div>
<div class="line">WDocument d;</div>
<div class="line">d.ParseStream&lt;0, <a class="code" href="structrapidjson_1_1_auto_u_t_f.html">AutoUTF&lt;unsigned&gt;</a> &gt;(eis);</div>
<div class="line"></div>
<div class="line"><span class="keyword">const</span> WValue locale(L<span class="stringliteral">&quot;ja&quot;</span>); <span class="comment">// Japanese</span></div>
<div class="line"></div>
<div class="line">MessageBoxW(hWnd, d[locale].GetString(), L<span class="stringliteral">&quot;Test&quot;</span>, MB_OK);</div>
</div><!-- fragment --><h2><a class="anchor" id="Allocator"></a>
Allocator</h2>
<p><code>Allocator</code>定义当<code>Document</code>/<code>Value</code>分配或释放内存时使用那个分配类。<code>Document</code>拥有或引用到一个<code>Allocator</code>实例。而为了节省内存,<code>Value</code>没有这么做。</p>
<p><code>GenericDocument</code>的缺省分配器是<code>MemoryPoolAllocator</code>。此分配器实际上会顺序地分配内存,并且不能逐一释放。当要解析一个JSON并生成DOM,这种分配器是非常合适的。</p>
<p>RapidJSON还提供另一个分配器<code>CrtAllocator</code>,当中CRT是C运行库(C RunTime library)的缩写。此分配器简单地读用标准的<code>malloc()</code>/<code>realloc()</code>/<code>free()</code>。当我们需要许多增减操作,这种分配器会更为适合。然而这种分配器远远比<code>MemoryPoolAllocator</code>低效。</p>
<h1><a class="anchor" id="Parsing"></a>
解析</h1>
<p><code>Document</code>提供几个解析函数。以下的(1)是根本的函数,其他都是调用(1)的协助函数。</p>
<div class="fragment"><div class="line"><span class="keyword">using namespace </span>rapidjson;</div>
<div class="line"></div>
<div class="line"><span class="comment">// (1) 根本</span></div>
<div class="line"><span class="keyword">template</span> &lt;<span class="keywordtype">unsigned</span> parseFlags, <span class="keyword">typename</span> SourceEncoding, <span class="keyword">typename</span> InputStream&gt;</div>
<div class="line"><a class="code" href="classrapidjson_1_1_generic_document.html">GenericDocument</a>&amp; <a class="code" href="classrapidjson_1_1_generic_document.html#a3ae97682cf04685c7db9d89ebc399b85">GenericDocument::ParseStream</a>(InputStream&amp; is);</div>
<div class="line"></div>
<div class="line"><span class="comment">// (2) 使用流的编码</span></div>
<div class="line"><span class="keyword">template</span> &lt;<span class="keywordtype">unsigned</span> parseFlags, <span class="keyword">typename</span> InputStream&gt;</div>
<div class="line"><a class="code" href="classrapidjson_1_1_generic_document.html">GenericDocument</a>&amp; <a class="code" href="classrapidjson_1_1_generic_document.html#a3ae97682cf04685c7db9d89ebc399b85">GenericDocument::ParseStream</a>(InputStream&amp; is);</div>
<div class="line"></div>
<div class="line"><span class="comment">// (3) 使用缺省标志</span></div>
<div class="line"><span class="keyword">template</span> &lt;<span class="keyword">typename</span> InputStream&gt;</div>
<div class="line"><a class="code" href="classrapidjson_1_1_generic_document.html">GenericDocument</a>&amp; <a class="code" href="classrapidjson_1_1_generic_document.html#a3ae97682cf04685c7db9d89ebc399b85">GenericDocument::ParseStream</a>(InputStream&amp; is);</div>
<div class="line"></div>
<div class="line"><span class="comment">// (4) 原位解析</span></div>
<div class="line"><span class="keyword">template</span> &lt;<span class="keywordtype">unsigned</span> parseFlags&gt;</div>
<div class="line"><a class="code" href="classrapidjson_1_1_generic_document.html">GenericDocument</a>&amp; <a class="code" href="classrapidjson_1_1_generic_document.html#a7ba626bf84eb45a9bca0b7723bf47f3f">GenericDocument::ParseInsitu</a>(Ch* str);</div>
<div class="line"></div>
<div class="line"><span class="comment">// (5) 原位解析,使用缺省标志</span></div>
<div class="line"><a class="code" href="classrapidjson_1_1_generic_document.html">GenericDocument</a>&amp; <a class="code" href="classrapidjson_1_1_generic_document.html#a7ba626bf84eb45a9bca0b7723bf47f3f">GenericDocument::ParseInsitu</a>(Ch* str);</div>
<div class="line"></div>
<div class="line"><span class="comment">// (6) 正常解析一个字符串</span></div>
<div class="line"><span class="keyword">template</span> &lt;<span class="keywordtype">unsigned</span> parseFlags, <span class="keyword">typename</span> SourceEncoding&gt;</div>
<div class="line"><a class="code" href="classrapidjson_1_1_generic_document.html">GenericDocument</a>&amp; <a class="code" href="classrapidjson_1_1_generic_document.html#aea842b533a858c9a3861451ad9e8642c">GenericDocument::Parse</a>(<span class="keyword">const</span> Ch* str);</div>
<div class="line"></div>
<div class="line"><span class="comment">// (7) 正常解析一个字符串,使用Document的编码</span></div>
<div class="line"><span class="keyword">template</span> &lt;<span class="keywordtype">unsigned</span> parseFlags&gt;</div>
<div class="line"><a class="code" href="classrapidjson_1_1_generic_document.html">GenericDocument</a>&amp; <a class="code" href="classrapidjson_1_1_generic_document.html#aea842b533a858c9a3861451ad9e8642c">GenericDocument::Parse</a>(<span class="keyword">const</span> Ch* str);</div>
<div class="line"></div>
<div class="line"><span class="comment">// (8) 正常解析一个字符串,使用缺省标志</span></div>
<div class="line"><a class="code" href="classrapidjson_1_1_generic_document.html">GenericDocument</a>&amp; <a class="code" href="classrapidjson_1_1_generic_document.html#aea842b533a858c9a3861451ad9e8642c">GenericDocument::Parse</a>(<span class="keyword">const</span> Ch* str);</div>
</div><!-- fragment --><p>教程中的例使用(8)去正常解析字符串。而流的例子使用前3个函数。我们将稍后介绍原位(*In situ*) 解析。</p>
<p><code>parseFlags</code>是以下位标置的组合:</p>
<table class="doxtable">
<tr>
<th>解析位标志 </th><th>意义  </th></tr>
<tr>
<td><code>kParseNoFlags</code> </td><td>没有任何标志。 </td></tr>
<tr>
<td><code>kParseDefaultFlags</code> </td><td>缺省的解析选项。它等于<code>RAPIDJSON_PARSE_DEFAULT_FLAGS</code>宏,此宏定义为<code>kParseNoFlags</code>。 </td></tr>
<tr>
<td><code>kParseInsituFlag</code> </td><td>原位(破坏性)解析。 </td></tr>
<tr>
<td><code>kParseValidateEncodingFlag</code> </td><td>校验JSON字符串的编码。 </td></tr>
<tr>
<td><code>kParseIterativeFlag</code> </td><td>迭代式(调用堆栈大小为常数复杂度)解析。 </td></tr>
<tr>
<td><code>kParseStopWhenDoneFlag</code> </td><td>当从流解析了一个完整的JSON根节点之后,停止继续处理余下的流。当使用了此标志,解析器便不会产生<code>kParseErrorDocumentRootNotSingular</code>错误。可使用本标志去解析同一个流里的多个JSON。 </td></tr>
<tr>
<td><code>kParseFullPrecisionFlag</code> </td><td>使用完整的精确度去解析数字(较慢)。如不设置此标节,则会使用正常的精确度(较快)。正常精确度会有最多3个<a href="http://en.wikipedia.org/wiki/Unit_in_the_last_place">ULP</a>的误差。 </td></tr>
<tr>
<td><code>kParseCommentsFlag</code> </td><td>容许单行 <code>// ...</code> 及多行 <code>/* ... */</code> 注释(放宽的JSON语法)。 </td></tr>
</table>
<p>由于使用了非类型模板参数,而不是函数参数,C++编译器能为个别组合生成代码,以改善性能及减少代码尺寸(当只用单种特化)。缺点是需要在编译期决定标志。</p>
<p><code>SourceEncoding</code>参数定义流使用了什么编码。这与<code>Document</code>的<code>Encoding</code>不相同。细节可参考<a href="#TranscodingAndValidation">转码和校验</a>一节。</p>
<p>此外<code>InputStream</code>是输入流的类型。</p>
<h2><a class="anchor" id="ParseError"></a>
解析错误</h2>
<p>当解析过程顺利完成,<code>Document</code>便会含有解析结果。当过程出现错误,原来的DOM会*维持不便*。可使用<code>bool HasParseError()</code>、<code>ParseErrorCode GetParseError()</code>及<code>size_t GetParseOffset()</code>获取解析的错误状态。</p>
<table class="doxtable">
<tr>
<th>解析错误代号 </th><th>描述  </th></tr>
<tr>
<td><code>kParseErrorNone</code> </td><td>无错误。 </td></tr>
<tr>
<td><code>kParseErrorDocumentEmpty</code> </td><td>文档是空的。 </td></tr>
<tr>
<td><code>kParseErrorDocumentRootNotSingular</code> </td><td>文档的根后面不能有其它值。 </td></tr>
<tr>
<td><code>kParseErrorValueInvalid</code> </td><td>不合法的值。 </td></tr>
<tr>
<td><code>kParseErrorObjectMissName</code> </td><td>Object成员缺少名字。 </td></tr>
<tr>
<td><code>kParseErrorObjectMissColon</code> </td><td>Object成员名字后缺少冒号。 </td></tr>
<tr>
<td><code>kParseErrorObjectMissCommaOrCurlyBracket</code> </td><td>Object成员后缺少逗号或<code>}</code>。 </td></tr>
<tr>
<td><code>kParseErrorArrayMissCommaOrSquareBracket</code> </td><td>Array元素后缺少逗号或<code>]</code> 。 </td></tr>
<tr>
<td><code>kParseErrorStringUnicodeEscapeInvalidHex</code> </td><td>String中的<code>\\u</code>转义符后含非十六进位数字。 </td></tr>
<tr>
<td><code>kParseErrorStringUnicodeSurrogateInvalid</code> </td><td>String中的代理对(surrogate pair)不合法。 </td></tr>
<tr>
<td><code>kParseErrorStringEscapeInvalid</code> </td><td>String含非法转义字符。 </td></tr>
<tr>
<td><code>kParseErrorStringMissQuotationMark</code> </td><td>String缺少关闭引号。 </td></tr>
<tr>
<td><code>kParseErrorStringInvalidEncoding</code> </td><td>String含非法编码。 </td></tr>
<tr>
<td><code>kParseErrorNumberTooBig</code> </td><td>Number的值太大,不能存储于<code>double</code>。 </td></tr>
<tr>
<td><code>kParseErrorNumberMissFraction</code> </td><td>Number缺少了小数部分。 </td></tr>
<tr>
<td><code>kParseErrorNumberMissExponent</code> </td><td>Number缺少了指数。 </td></tr>
</table>
<p>错误的偏移量定义为从流开始至错误处的字符数量。目前RapidJSON不记录错误行号。</p>
<p>要取得错误讯息,RapidJSON在<code><a class="el" href="en_8h_source.html">rapidjson/error/en.h</a></code>中提供了英文错误讯息。使用者可以修改它用于其他语言环境,或使用一个自定义的本地化系统。</p>
<p>以下是一个处理错误的例子。</p>
<div class="fragment"><div class="line"><span class="preprocessor">#include &quot;<a class="code" href="document_8h.html">rapidjson/document.h</a>&quot;</span></div>
<div class="line"><span class="preprocessor">#include &quot;rapidjson/error/en.h&quot;</span></div>
<div class="line"></div>
<div class="line"><span class="comment">// ...</span></div>
<div class="line"><a class="code" href="namespacerapidjson.html#ace11b5b575baf1cccd5ba5f8586dcdc8">Document</a> d;</div>
<div class="line"><span class="keywordflow">if</span> (d.Parse(json).HasParseError()) {</div>
<div class="line">    fprintf(stderr, <span class="stringliteral">&quot;\nError(offset %u): %s\n&quot;</span>, </div>
<div class="line">        (<span class="keywordtype">unsigned</span>)d.GetErrorOffset(),</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#gabdaf1a7a4db30fb0e3d927fdf0fabe79">GetParseError_En</a>(d.GetParseErrorCode()));</div>
<div class="line">    <span class="comment">// ...</span></div>
<div class="line">}</div>
</div><!-- fragment --><h2><a class="anchor" id="InSituParsing"></a>
原位解析</h2>
<p>根据<a href="http://en.wikipedia.org/wiki/In_situ">维基百科</a>:</p>
<blockquote class="doxtable">
<p><em>In situ</em> ... is a Latin phrase that translates literally to "on site" or "in position". It means "locally", "on site", "on the premises" or "in place" to describe an event where it takes place, and is used in many different contexts. ... (In computer science) An algorithm is said to be an in situ algorithm, or in-place algorithm, if the extra amount of memory required to execute the algorithm is O(1), that is, does not exceed a constant no matter how large the input. For example, heapsort is an in situ sorting algorithm. </p>
</blockquote>
<blockquote class="doxtable">
<p>翻译:*In situ*……是一个拉丁文片语,字面上的意思是指「现场」、「在位置」。在许多不同语境中,它描述一个事件发生的位置,意指「本地」、「现场」、「在处所」、「就位」。 …… (在计算机科学中)一个算法若称为原位算法,或在位算法,是指执行该算法所需的额外内存空间是O(1)的,换句话说,无论输入大小都只需要常数空间。例如,堆排序是一个原位排序算法。 </p>
</blockquote>
<p>在正常的解析过程中,对JSON string解码并复制至其他缓冲区是一个很大的开销。原位解析(*in situ* parsing)把这些JSON string直接解码于它原来存储的地方。由于解码后的string长度总是短于或等于原来储存于JSON的string,所以这是可行的。在这个语境下,对JSON string进行解码是指处理转义符,如<code>"\\n"</code>、<code>"\\u1234"</code>等,以及在string末端加入空终止符号(`'\0'`)。</p>
<p>以下的图比较正常及原位解析。JSON string值包含指向解码后的字符串。</p>
<div class="image">
<img src="normalparsing.png" alt="normalparsing.png"/>
<div class="caption">
正常解析</div></div>
<p> 在正常解析中,解码后的字符串被复制至全新分配的缓冲区中。<code>"\\\\n"</code>(2个字符)被解码成<code>"\\n"</code>(1个字符)。<code>"\\\\u0073"</code>(6个字符)被解码成<code>"s"</code>(1个字符)。</p>
<div class="image">
<img src="insituparsing.png" alt="insituparsing.png"/>
<div class="caption">
原位解析</div></div>
<p> 原位解析直接修改了原来的JSON。图中高亮了被更新的字符。若JSON string不含转义符,例如<code>"msg"</code>,那么解析过程仅仅是以空字符代替结束双引号。</p>
<p>由于原位解析修改了输入,其解析API需要<code>char*</code>而非<code>const char*</code>。</p>
<div class="fragment"><div class="line"><span class="comment">// 把整个文件读入buffer</span></div>
<div class="line">FILE* fp = fopen(<span class="stringliteral">&quot;test.json&quot;</span>, <span class="stringliteral">&quot;r&quot;</span>);</div>
<div class="line">fseek(fp, 0, SEEK_END);</div>
<div class="line"><span class="keywordtype">size_t</span> filesize = (size_t)ftell(fp);</div>
<div class="line">fseek(fp, 0, SEEK_SET);</div>
<div class="line"><span class="keywordtype">char</span>* buffer = (<span class="keywordtype">char</span>*)malloc(filesize + 1);</div>
<div class="line"><span class="keywordtype">size_t</span> readLength = fread(buffer, 1, filesize, fp);</div>
<div class="line">buffer[readLength] = <span class="charliteral">&#39;\0&#39;</span>;</div>
<div class="line">fclose(fp);</div>
<div class="line"></div>
<div class="line"><span class="comment">// 原位解析buffer至d,buffer内容会被修改。</span></div>
<div class="line"><a class="code" href="namespacerapidjson.html#ace11b5b575baf1cccd5ba5f8586dcdc8">Document</a> d;</div>
<div class="line">d.ParseInsitu(buffer);</div>
<div class="line"></div>
<div class="line"><span class="comment">// 在此查询、修改DOM……</span></div>
<div class="line"></div>
<div class="line">free(buffer);</div>
<div class="line"><span class="comment">// 注意:在这个位置,d可能含有指向已被释放的buffer的悬空指针</span></div>
</div><!-- fragment --><p>JSON string会被打上const-string的标志。但它们可能并非真正的「常数」。它的生命周期取决于存储JSON的缓冲区。</p>
<p>原位解析把分配开销及内存复制减至最小。通常这样做能改善缓存一致性,而这对现代计算机来说是一个重要的性能因素。</p>
<p>原位解析有以下限制:</p>
<ol type="1">
<li>整个JSON须存储在内存之中。</li>
<li>流的来源缓码与文档的目标编码必须相同。</li>
<li>需要保留缓冲区,直至文档不再被使用。</li>
<li>若DOM需要在解析后被长期使用,而DOM内只有很少JSON string,保留缓冲区可能造成内存浪费。</li>
</ol>
<p>原位解析最适合用于短期的、用完即弃的JSON。实际应用中,这些场合是非常普遍的,例如反序列化JSON至C++对象、处理以JSON表示的web请求等。</p>
<h2><a class="anchor" id="TranscodingAndValidation"></a>
转码与校验</h2>
<p>RapidJSON内部支持不同Unicode格式(正式的术语是UCS变换格式)间的转换。在DOM解析时,流的来源编码与DOM的编码可以不同。例如,来源流可能含有UTF-8的JSON,而DOM则使用UTF-16编码。在EncodedInputStream一节里有一个例子。</p>
<p>当从DOM输出一个JSON至输出流之时,也可以使用转码功能。在EncodedOutputStream一节里有一个例子。</p>
<p>在转码过程中,会把来源string解码成Unicode码点,然后把码点编码成目标格式。在解码时,它会校验来源string的字节序列是否合法。若遇上非合法序列,解析器会停止并返回<code>kParseErrorStringInvalidEncoding</code>错误。</p>
<p>当来源编码与DOM的编码相同,解析器缺省地*不会*校验序列。使用者可开启<code>kParseValidateEncodingFlag</code>去强制校验。</p>
<h1><a class="anchor" id="Techniques"></a>
技巧</h1>
<p>这里讨论一些DOM API的使用技巧。</p>
<h2>把DOM作为SAX事件发表者</h2>
<p>在RapidJSON中,利用<code>Writer</code>把DOM生成JSON的做法,看来有点奇怪。</p>
<div class="fragment"><div class="line"><span class="comment">// ...</span></div>
<div class="line">Writer&lt;StringBuffer&gt; writer(buffer);</div>
<div class="line">d.Accept(writer);</div>
</div><!-- fragment --><p>实际上,<code>Value::Accept()</code>是负责发布该值相关的SAX事件至处理器的。通过这个设计,<code>Value</code>及<code>Writer</code>解除了偶合。<code>Value</code>可生成SAX事件,而<code>Writer</code>则可以处理这些事件。</p>
<p>使用者可以创建自定义的处理器,去把DOM转换成其它格式。例如,一个把DOM转换成XML的处理器。</p>
<p>要知道更多关于SAX事件与处理器,可参阅SAX。</p>
<h2>使用者缓冲区{ #UserBuffer}</h2>
<p>许多应用软件可能需要尽量减少内存分配。</p>
<p><code>MemoryPoolAllocator</code>可以帮助这方面,它容许使用者提供一个缓冲区。该缓冲区可能置于程序堆栈,或是一个静态分配的「草稿缓冲区(scratch buffer)」(一个静态/全局的数组),用于储存临时数据。</p>
<p><code>MemoryPoolAllocator</code>会先用使用者缓冲区去解决分配请求。当使用者缓冲区用完,就会从基础分配器(缺省为<code>CrtAllocator</code>)分配一块内存。</p>
<p>以下是使用堆栈内存的例子,第一个分配器用于存储值,第二个用于解析时的临时缓冲。</p>
<div class="fragment"><div class="line"><span class="keyword">typedef</span> GenericDocument&lt;UTF8&lt;&gt;, MemoryPoolAllocator&lt;&gt;, MemoryPoolAllocator&lt;&gt;&gt; DocumentType;</div>
<div class="line"><span class="keywordtype">char</span> valueBuffer[4096];</div>
<div class="line"><span class="keywordtype">char</span> parseBuffer[1024];</div>
<div class="line">MemoryPoolAllocator&lt;&gt; valueAllocator(valueBuffer, <span class="keyword">sizeof</span>(valueBuffer));</div>
<div class="line">MemoryPoolAllocator&lt;&gt; parseAllocator(parseBuffer, <span class="keyword">sizeof</span>(parseBuffer));</div>
<div class="line">DocumentType d(&amp;valueAllocator, <span class="keyword">sizeof</span>(parseBuffer), &amp;parseAllocator);</div>
<div class="line">d.Parse(json);</div>
</div><!-- fragment --><p>若解析时分配总量少于4096+1024字节时,这段代码不会造成任何堆内存分配(经<code>new</code>或<code>malloc()</code>)。</p>
<p>使用者可以通过<code>MemoryPoolAllocator::Size()</code>查询当前已分的内存大小。那么使用者可以拟定使用者缓冲区的合适大小。 </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>