| <!-- 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.16"/> |
| <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="navtreedata.js"></script> |
| <script type="text/javascript" src="navtree.js"></script> |
| <script type="text/javascript"> |
| /* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */ |
| $(document).ready(initResizable); |
| /* @license-end */</script> |
| <link href="search/search.css" rel="stylesheet" type="text/css"/> |
| <script type="text/javascript" src="search/searchdata.js"></script> |
| <script type="text/javascript" src="search/search.js"></script> |
| <script type="text/javascript"> |
| /* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */ |
| $(document).ready(function() { init_search(); }); |
| /* @license-end */ |
| </script> |
| <link href="doxygen.css" rel="stylesheet" type="text/css" /> |
| <link href="doxygenextra.css" rel="stylesheet" type="text/css"/> |
| </head> |
| <body> |
| <div id="top"><!-- do not remove this div, it is closed by doxygen! --> |
| <div id="topbanner"><a href="https://github.com/Tencent/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="Search" 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 --> |
| <!-- Generated by Doxygen 1.8.16 --> |
| <script type="text/javascript"> |
| /* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */ |
| var searchBox = new SearchBox("searchBox", "search",false,'Search'); |
| /* @license-end */ |
| </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"> |
| /* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */ |
| $(document).ready(function(){initNavTree('md_doc_sax.html','');}); |
| /* @license-end */ |
| </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)"> |
| </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="PageDoc"><div class="header"> |
| <div class="headertitle"> |
| <div class="title">SAX </div> </div> |
| </div><!--header--> |
| <div class="contents"> |
| <div class="toc"><h3>Table of Contents</h3> |
| <ul><li class="level1"><a href="#Reader">Reader</a><ul><li class="level2"><a href="#Handler">Handler</a></li> |
| <li class="level2"><a href="#GenericReader">GenericReader</a></li> |
| <li class="level2"><a href="#SaxParsing">Parsing</a></li> |
| <li class="level2"><a href="#TokenByTokenParsing">Token-by-Token Parsing</a></li> |
| </ul> |
| </li> |
| <li class="level1"><a href="#Writer">Writer</a><ul><li class="level2"><a href="#WriterTemplate">Template</a></li> |
| <li class="level2"><a href="#PrettyWriter">PrettyWriter</a></li> |
| <li class="level2"><a href="#CompletenessReset">Completeness and Reset</a></li> |
| </ul> |
| </li> |
| <li class="level1"><a href="#SaxTechniques">Techniques</a><ul><li class="level2"><a href="#CustomDataStructure">Parsing JSON to Custom Data Structure</a></li> |
| <li class="level2"><a href="#Filtering">Filtering of JSON</a></li> |
| </ul> |
| </li> |
| </ul> |
| </div> |
| <div class="textblock"><p>The term "SAX" originated from <a href="http://en.wikipedia.org/wiki/Simple_API_for_XML">Simple API for XML</a>. We borrowed this term for JSON parsing and generation.</p> |
| <p>In RapidJSON, <code>Reader</code> (typedef of <code>GenericReader<...></code>) is the SAX-style parser for JSON, and <code>Writer</code> (typedef of <code>GenericWriter<...></code>) is the SAX-style generator for JSON.</p> |
| <h1><a class="anchor" id="Reader"></a> |
| Reader</h1> |
| <p><code>Reader</code> parses a JSON from a stream. While it reads characters from the stream, it analyzes the characters according to the syntax of JSON, and publishes events to a handler.</p> |
| <p>For example, here is a JSON.</p> |
| <div class="fragment"><div class="line">{</div> |
| <div class="line"> "hello": "world",</div> |
| <div class="line"> "t": true ,</div> |
| <div class="line"> "f": false,</div> |
| <div class="line"> "n": null,</div> |
| <div class="line"> "i": 123,</div> |
| <div class="line"> "pi": 3.1416,</div> |
| <div class="line"> "a": [1, 2, 3, 4]</div> |
| <div class="line">}</div> |
| </div><!-- fragment --><p>When a <code>Reader</code> parses this JSON, it publishes the following events to the handler sequentially:</p> |
| <div class="fragment"><div class="line">StartObject()</div> |
| <div class="line">Key("hello", 5, true)</div> |
| <div class="line">String("world", 5, true)</div> |
| <div class="line">Key("t", 1, true)</div> |
| <div class="line">Bool(true)</div> |
| <div class="line">Key("f", 1, true)</div> |
| <div class="line">Bool(false)</div> |
| <div class="line">Key("n", 1, true)</div> |
| <div class="line">Null()</div> |
| <div class="line">Key("i")</div> |
| <div class="line">Uint(123)</div> |
| <div class="line">Key("pi")</div> |
| <div class="line">Double(3.1416)</div> |
| <div class="line">Key("a")</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>These events can be easily matched with the JSON, but some event parameters need further explanation. Let's see the <code>simplereader</code> example which produces exactly the same output as above:</p> |
| <div class="fragment"><div class="line"><span class="preprocessor">#include "<a class="code" href="reader_8h.html">rapidjson/reader.h</a>"</span></div> |
| <div class="line"><span class="preprocessor">#include <iostream></span></div> |
| <div class="line"> </div> |
| <div class="line"><span class="keyword">using namespace </span><a class="code" href="namespacerapidjson.html">rapidjson</a>;</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 : <span class="keyword">public</span> <a class="code" href="structrapidjson_1_1_base_reader_handler.html">BaseReaderHandler</a><UTF8<>, MyHandler> {</div> |
| <div class="line"> <span class="keywordtype">bool</span> Null() { cout << <span class="stringliteral">"Null()"</span> << 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 << <span class="stringliteral">"Bool("</span> << boolalpha << b << <span class="stringliteral">")"</span> << 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 << <span class="stringliteral">"Int("</span> << i << <span class="stringliteral">")"</span> << 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 << <span class="stringliteral">"Uint("</span> << u << <span class="stringliteral">")"</span> << 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 << <span class="stringliteral">"Int64("</span> << i << <span class="stringliteral">")"</span> << 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 << <span class="stringliteral">"Uint64("</span> << u << <span class="stringliteral">")"</span> << 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 << <span class="stringliteral">"Double("</span> << d << <span class="stringliteral">")"</span> << 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 << <span class="stringliteral">"String("</span> << str << <span class="stringliteral">", "</span> << length << <span class="stringliteral">", "</span> << boolalpha << copy << <span class="stringliteral">")"</span> << 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 << <span class="stringliteral">"StartObject()"</span> << 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 << <span class="stringliteral">"Key("</span> << str << <span class="stringliteral">", "</span> << length << <span class="stringliteral">", "</span> << boolalpha << copy << <span class="stringliteral">")"</span> << 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 << <span class="stringliteral">"EndObject("</span> << memberCount << <span class="stringliteral">")"</span> << endl; <span class="keywordflow">return</span> <span class="keyword">true</span>; }</div> |
| <div class="line"> <span class="keywordtype">bool</span> StartArray() { cout << <span class="stringliteral">"StartArray()"</span> << 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 << <span class="stringliteral">"EndArray("</span> << elementCount << <span class="stringliteral">")"</span> << 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">" { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } "</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>Note that RapidJSON uses templates to statically bind the <code>Reader</code> type and the handler type, instead of using classes with virtual functions. This paradigm can improve performance by inlining functions.</p> |
| <h2><a class="anchor" id="Handler"></a> |
| Handler</h2> |
| <p>As shown in the previous example, the user needs to implement a handler which consumes the events (via function calls) from the <code>Reader</code>. The handler must contain the following member functions.</p> |
| <div class="fragment"><div class="line"><span class="keyword">class </span><a class="code" href="classrapidjson_1_1_handler.html">Handler</a> {</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> RawNumber(<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> 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>Null()</code> is called when the <code>Reader</code> encounters a JSON null value.</p> |
| <p><code>Bool(bool)</code> is called when the <code>Reader</code> encounters a JSON true or false value.</p> |
| <p>When the <code>Reader</code> encounters a JSON number, it chooses a suitable C++ type mapping. And then it calls <em>one</em> function out of <code>Int(int)</code>, <code>Uint(unsigned)</code>, <code>Int64(int64_t)</code>, <code>Uint64(uint64_t)</code> and <code>Double(double)</code>. If <code>kParseNumbersAsStrings</code> is enabled, <code>Reader</code> will always calls <code>RawNumber()</code> instead.</p> |
| <p><code>String(const char* str, SizeType length, bool copy)</code> is called when the <code>Reader</code> encounters a string. The first parameter is pointer to the string. The second parameter is the length of the string (excluding the null terminator). Note that RapidJSON supports null character <code>\0</code> inside a string. If such situation happens, <code>strlen(str) < length</code>. The last <code>copy</code> indicates whether the handler needs to make a copy of the string. For normal parsing, <code>copy = true</code>. Only when <em>insitu</em> parsing is used, <code>copy = false</code>. And be aware that the character type depends on the target encoding, which will be explained later.</p> |
| <p>When the <code>Reader</code> encounters the beginning of an object, it calls <code>StartObject()</code>. An object in JSON is a set of name-value pairs. If the object contains members it first calls <code>Key()</code> for the name of member, and then calls functions depending on the type of the value. These calls of name-value pairs repeat until calling <code>EndObject(SizeType memberCount)</code>. Note that the <code>memberCount</code> parameter is just an aid for the handler; users who do not need this parameter may ignore it.</p> |
| <p>Arrays are similar to objects, but simpler. At the beginning of an array, the <code>Reader</code> calls <code>BeginArray()</code>. If there is elements, it calls functions according to the types of element. Similarly, in the last call <code>EndArray(SizeType elementCount)</code>, the parameter <code>elementCount</code> is just an aid for the handler.</p> |
| <p>Every handler function returns a <code>bool</code>. Normally it should return <code>true</code>. If the handler encounters an error, it can return <code>false</code> to notify the event publisher to stop further processing.</p> |
| <p>For example, when we parse a JSON with <code>Reader</code> and the handler detects that the JSON does not conform to the required schema, the handler can return <code>false</code> and let the <code>Reader</code> stop further parsing. This will place the <code>Reader</code> in an error state, with error code <code>kParseErrorTermination</code>.</p> |
| <h2><a class="anchor" id="GenericReader"></a> |
| GenericReader</h2> |
| <p>As mentioned before, <code>Reader</code> is a typedef of a template class <code>GenericReader</code>:</p> |
| <div class="fragment"><div class="line"><span class="keyword">namespace </span><a class="code" href="namespacerapidjson.html">rapidjson</a> {</div> |
| <div class="line"> </div> |
| <div class="line"><span class="keyword">template</span> <<span class="keyword">typename</span> SourceEncoding, <span class="keyword">typename</span> TargetEncoding, <span class="keyword">typename</span> Allocator = MemoryPoolAllocator<> ></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<UTF8<>, UTF8<> > <a class="code" href="namespacerapidjson.html#ad5310edd1226f5b3ea82dc0d4d3740c6">Reader</a>;</div> |
| <div class="line"> </div> |
| <div class="line">} <span class="comment">// namespace rapidjson</span></div> |
| </div><!-- fragment --><p>The <code>Reader</code> uses UTF-8 as both source and target encoding. The source encoding means the encoding in the JSON stream. The target encoding means the encoding of the <code>str</code> parameter in <code>String()</code> calls. For example, to parse a UTF-8 stream and output UTF-16 string events, you can define a reader by:</p> |
| <div class="fragment"><div class="line">GenericReader<UTF8<>, UTF16<> > reader;</div> |
| </div><!-- fragment --><p>Note that, the default character type of <code>UTF16</code> is <code>wchar_t</code>. So this <code>reader</code> needs to call <code>String(const wchar_t*, SizeType, bool)</code> of the handler.</p> |
| <p>The third template parameter <code>Allocator</code> is the allocator type for internal data structure (actually a stack).</p> |
| <h2><a class="anchor" id="SaxParsing"></a> |
| Parsing</h2> |
| <p>The main function of <code>Reader</code> is used to parse JSON.</p> |
| <div class="fragment"><div class="line"><span class="keyword">template</span> <<span class="keywordtype">unsigned</span> parseFlags, <span class="keyword">typename</span> InputStream, <span class="keyword">typename</span> Handler></div> |
| <div class="line"><span class="keywordtype">bool</span> Parse(InputStream& is, <a class="code" href="classrapidjson_1_1_handler.html">Handler</a>& handler);</div> |
| <div class="line"> </div> |
| <div class="line"><span class="comment">// with parseFlags = kDefaultParseFlags</span></div> |
| <div class="line"><span class="keyword">template</span> <<span class="keyword">typename</span> InputStream, <span class="keyword">typename</span> Handler></div> |
| <div class="line"><span class="keywordtype">bool</span> Parse(InputStream& is, <a class="code" href="classrapidjson_1_1_handler.html">Handler</a>& handler);</div> |
| </div><!-- fragment --><p>If an error occurs during parsing, it will return <code>false</code>. User can also call <code>bool HasParseError()</code>, <code>ParseErrorCode GetParseErrorCode()</code> and <code>size_t GetErrorOffset()</code> to obtain the error states. In fact, <code>Document</code> uses these <code>Reader</code> functions to obtain parse errors. Please refer to <a class="el" href="md_doc_dom.html">DOM</a> for details about parse errors.</p> |
| <h2><a class="anchor" id="TokenByTokenParsing"></a> |
| Token-by-Token Parsing</h2> |
| <p>Some users may wish to parse a JSON input stream a single token at a time, instead of immediately parsing an entire document without stopping. To parse JSON this way, instead of calling <code>Parse</code>, you can use the <code>IterativeParse</code> set of functions:</p> |
| <div class="fragment"><div class="line"><span class="keywordtype">void</span> IterativeParseInit();</div> |
| <div class="line"> </div> |
| <div class="line"><span class="keyword">template</span> <<span class="keywordtype">unsigned</span> parseFlags, <span class="keyword">typename</span> InputStream, <span class="keyword">typename</span> Handler></div> |
| <div class="line"><span class="keywordtype">bool</span> IterativeParseNext(InputStream& is, <a class="code" href="classrapidjson_1_1_handler.html">Handler</a>& handler);</div> |
| <div class="line"> </div> |
| <div class="line"><span class="keywordtype">bool</span> IterativeParseComplete();</div> |
| </div><!-- fragment --><p>Here is an example of iteratively parsing JSON, token by token:</p> |
| <div class="fragment"><div class="line">reader.IterativeParseInit();</div> |
| <div class="line"><span class="keywordflow">while</span> (!reader.IterativeParseComplete()) {</div> |
| <div class="line"> reader.IterativeParseNext<<a class="code" href="namespacerapidjson.html#a81379eb4e94a0386d71d15fda882ebc9a5640cb00db7814b7f22be3683dda9835">kParseDefaultFlags</a>>(is, handler);</div> |
| <div class="line"> <span class="comment">// Your handler has been called once.</span></div> |
| <div class="line">}</div> |
| </div><!-- fragment --><h1><a class="anchor" id="Writer"></a> |
| Writer</h1> |
| <p><code>Reader</code> converts (parses) JSON into events. <code>Writer</code> does exactly the opposite. It converts events into JSON.</p> |
| <p><code>Writer</code> is very easy to use. If your application only need to converts some data into JSON, it may be a good choice to use <code>Writer</code> directly, instead of building a <code>Document</code> and then stringifying it with a <code>Writer</code>.</p> |
| <p>In <code>simplewriter</code> example, we do exactly the reverse of <code>simplereader</code>.</p> |
| <div class="fragment"><div class="line"><span class="preprocessor">#include "rapidjson/writer.h"</span></div> |
| <div class="line"><span class="preprocessor">#include "rapidjson/stringbuffer.h"</span></div> |
| <div class="line"><span class="preprocessor">#include <iostream></span></div> |
| <div class="line"> </div> |
| <div class="line"><span class="keyword">using namespace </span><a class="code" href="namespacerapidjson.html">rapidjson</a>;</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<StringBuffer></a> writer(s);</div> |
| <div class="line"> </div> |
| <div class="line"> writer.StartObject();</div> |
| <div class="line"> writer.Key(<span class="stringliteral">"hello"</span>);</div> |
| <div class="line"> writer.String(<span class="stringliteral">"world"</span>);</div> |
| <div class="line"> writer.Key(<span class="stringliteral">"t"</span>);</div> |
| <div class="line"> writer.Bool(<span class="keyword">true</span>);</div> |
| <div class="line"> writer.Key(<span class="stringliteral">"f"</span>);</div> |
| <div class="line"> writer.Bool(<span class="keyword">false</span>);</div> |
| <div class="line"> writer.Key(<span class="stringliteral">"n"</span>);</div> |
| <div class="line"> writer.Null();</div> |
| <div class="line"> writer.Key(<span class="stringliteral">"i"</span>);</div> |
| <div class="line"> writer.Uint(123);</div> |
| <div class="line"> writer.Key(<span class="stringliteral">"pi"</span>);</div> |
| <div class="line"> writer.Double(3.1416);</div> |
| <div class="line"> writer.Key(<span class="stringliteral">"a"</span>);</div> |
| <div class="line"> writer.StartArray();</div> |
| <div class="line"> <span class="keywordflow">for</span> (<span class="keywordtype">unsigned</span> i = 0; i < 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 << s.GetString() << endl;</div> |
| <div class="line">}</div> |
| </div><!-- fragment --><div class="fragment"><div class="line">{"hello":"world","t":true,"f":false,"n":null,"i":123,"pi":3.1416,"a":[0,1,2,3]}</div> |
| </div><!-- fragment --><p>There are two <code>String()</code> and <code>Key()</code> overloads. One is the same as defined in handler concept with 3 parameters. It can handle string with null characters. Another one is the simpler version used in the above example.</p> |
| <p>Note that, the example code does not pass any parameters in <code>EndArray()</code> and <code>EndObject()</code>. An <code>SizeType</code> can be passed but it will be simply ignored by <code>Writer</code>.</p> |
| <p>You may doubt that, why not just using <code>sprintf()</code> or <code>std::stringstream</code> to build a JSON?</p> |
| <p>There are various reasons:</p><ol type="1"> |
| <li><code>Writer</code> must output a well-formed JSON. If there is incorrect event sequence (e.g. <code>Int()</code> just after <code>StartObject()</code>), it generates assertion fail in debug mode.</li> |
| <li><code>Writer::String()</code> can handle string escaping (e.g. converting code point <code>U+000A</code> to <code>\n</code>) and Unicode transcoding.</li> |
| <li><code>Writer</code> handles number output consistently.</li> |
| <li><code>Writer</code> implements the event handler concept. It can be used to handle events from <code>Reader</code>, <code>Document</code> or other event publisher.</li> |
| <li><code>Writer</code> can be optimized for different platforms.</li> |
| </ol> |
| <p>Anyway, using <code>Writer</code> API is even simpler than generating a JSON by ad hoc methods.</p> |
| <h2><a class="anchor" id="WriterTemplate"></a> |
| Template</h2> |
| <p><code>Writer</code> has a minor design difference to <code>Reader</code>. <code>Writer</code> is a template class, not a typedef. There is no <code>GenericWriter</code>. The following is the declaration.</p> |
| <div class="fragment"><div class="line"><span class="keyword">namespace </span><a class="code" href="namespacerapidjson.html">rapidjson</a> {</div> |
| <div class="line"> </div> |
| <div class="line"><span class="keyword">template</span><<span class="keyword">typename</span> OutputStream, <span class="keyword">typename</span> SourceEncoding = UTF8<>, <span class="keyword">typename</span> TargetEncoding = UTF8<>, <span class="keyword">typename</span> Allocator = CrtAllocator<>, <span class="keywordtype">unsigned</span> writeFlags = kWriteDefaultFlags></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#a98a421c806b456688874511f64add1f2">Writer</a>(OutputStream& os, <a class="code" href="classrapidjson_1_1_allocator.html">Allocator</a>* 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>The <code>OutputStream</code> template parameter is the type of output stream. It cannot be deduced and must be specified by user.</p> |
| <p>The <code>SourceEncoding</code> template parameter specifies the encoding to be used in <code>String(const Ch*, ...)</code>.</p> |
| <p>The <code>TargetEncoding</code> template parameter specifies the encoding in the output stream.</p> |
| <p>The <code>Allocator</code> is the type of allocator, which is used for allocating internal data structure (a stack).</p> |
| <p>The <code>writeFlags</code> are combination of the following bit-flags:</p> |
| <table class="markdownTable"> |
| <tr class="markdownTableHead"> |
| <th class="markdownTableHeadNone">Parse flags </th><th class="markdownTableHeadNone">Meaning </th></tr> |
| <tr class="markdownTableRowOdd"> |
| <td class="markdownTableBodyNone"><code>kWriteNoFlags</code> </td><td class="markdownTableBodyNone">No flag is set. </td></tr> |
| <tr class="markdownTableRowEven"> |
| <td class="markdownTableBodyNone"><code>kWriteDefaultFlags</code> </td><td class="markdownTableBodyNone">Default write flags. It is equal to macro <code>RAPIDJSON_WRITE_DEFAULT_FLAGS</code>, which is defined as <code>kWriteNoFlags</code>. </td></tr> |
| <tr class="markdownTableRowOdd"> |
| <td class="markdownTableBodyNone"><code>kWriteValidateEncodingFlag</code> </td><td class="markdownTableBodyNone">Validate encoding of JSON strings. </td></tr> |
| <tr class="markdownTableRowEven"> |
| <td class="markdownTableBodyNone"><code>kWriteNanAndInfFlag</code> </td><td class="markdownTableBodyNone">Allow writing of <code>Infinity</code>, <code>-Infinity</code> and <code>NaN</code>. </td></tr> |
| </table> |
| <p>Besides, the constructor of <code>Writer</code> has a <code>levelDepth</code> parameter. This parameter affects the initial memory allocated for storing information per hierarchy level.</p> |
| <h2><a class="anchor" id="PrettyWriter"></a> |
| PrettyWriter</h2> |
| <p>While the output of <code>Writer</code> is the most condensed JSON without white-spaces, suitable for network transfer or storage, it is not easily readable by human.</p> |
| <p>Therefore, RapidJSON provides a <code>PrettyWriter</code>, which adds indentation and line feeds in the output.</p> |
| <p>The usage of <code>PrettyWriter</code> is exactly the same as <code>Writer</code>, expect that <code>PrettyWriter</code> provides a <code>SetIndent(Ch indentChar, unsigned indentCharCount)</code> function. The default is 4 spaces.</p> |
| <h2><a class="anchor" id="CompletenessReset"></a> |
| Completeness and Reset</h2> |
| <p>A <code>Writer</code> can only output a single JSON, which can be any JSON type at the root. Once the singular event for root (e.g. <code>String()</code>), or the last matching <code>EndObject()</code> or <code>EndArray()</code> event, is handled, the output JSON is well-formed and complete. User can detect this state by calling <code>Writer::IsComplete()</code>.</p> |
| <p>When a JSON is complete, the <code>Writer</code> cannot accept any new events. Otherwise the output will be invalid (i.e. having more than one root). To reuse the <code>Writer</code> object, user can call <code>Writer::Reset(OutputStream& os)</code> to reset all internal states of the <code>Writer</code> with a new output stream.</p> |
| <h1><a class="anchor" id="SaxTechniques"></a> |
| Techniques</h1> |
| <h2><a class="anchor" id="CustomDataStructure"></a> |
| Parsing JSON to Custom Data Structure</h2> |
| <p><code>Document</code>'s parsing capability is completely based on <code>Reader</code>. Actually <code>Document</code> is a handler which receives events from a reader to build a DOM during parsing.</p> |
| <p>User may uses <code>Reader</code> to build other data structures directly. This eliminates building of DOM, thus reducing memory and improving performance.</p> |
| <p>In the following <code>messagereader</code> example, <code>ParseMessages()</code> parses a JSON which should be an object with key-string pairs.</p> |
| <div class="fragment"><div class="line"><span class="preprocessor">#include "<a class="code" href="reader_8h.html">rapidjson/reader.h</a>"</span></div> |
| <div class="line"><span class="preprocessor">#include "rapidjson/error/en.h"</span></div> |
| <div class="line"><span class="preprocessor">#include <iostream></span></div> |
| <div class="line"><span class="preprocessor">#include <string></span></div> |
| <div class="line"><span class="preprocessor">#include <map></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><a class="code" href="namespacerapidjson.html">rapidjson</a>;</div> |
| <div class="line"> </div> |
| <div class="line"><span class="keyword">typedef</span> map<string, string> 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><UTF8<>, MessageHandler> {</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& 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#a042c621cf745c5ed3a6f5ff9418dd05e">GetParseErrorCode</a>();</div> |
| <div class="line"> <span class="keywordtype">size_t</span> o = reader.<a class="code" href="classrapidjson_1_1_generic_reader.html#ab50019e0a715320f83b7610b83dcef8f">GetErrorOffset</a>();</div> |
| <div class="line"> cout << <span class="stringliteral">"Error: "</span> << <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) << endl;;</div> |
| <div class="line"> cout << <span class="stringliteral">" at offset "</span> << o << <span class="stringliteral">" near '"</span> << string(json).substr(o, 10) << <span class="stringliteral">"...'"</span> << 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">"{ \"greeting\" : \"Hello!\", \"farewell\" : \"bye-bye!\" }"</span>;</div> |
| <div class="line"> cout << json1 << 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 << itr->first << <span class="stringliteral">": "</span> << itr->second << endl;</div> |
| <div class="line"> </div> |
| <div class="line"> cout << endl << <span class="stringliteral">"Parse a JSON with invalid schema."</span> << endl;</div> |
| <div class="line"> <span class="keyword">const</span> <span class="keywordtype">char</span>* json2 = <span class="stringliteral">"{ \"greeting\" : \"Hello!\", \"farewell\" : \"bye-bye!\", \"foo\" : {} }"</span>;</div> |
| <div class="line"> cout << json2 << 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">{ "greeting" : "Hello!", "farewell" : "bye-bye!" }</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">{ "greeting" : "Hello!", "farewell" : "bye-bye!", "foo" : {} }</div> |
| <div class="line">Error: Terminate parsing due to Handler error.</div> |
| <div class="line"> at offset 59 near '} }...'</div> |
| </div><!-- fragment --><p>The first JSON (<code>json1</code>) was successfully parsed into <code>MessageMap</code>. Since <code>MessageMap</code> is a <code>std::map</code>, the printing order are sorted by the key. This order is different from the JSON's order.</p> |
| <p>In the second JSON (<code>json2</code>), <code>foo</code>'s value is an empty object. As it is an object, <code>MessageHandler::StartObject()</code> will be called. However, at that moment <code>state_ = kExpectValue</code>, so that function returns <code>false</code> and cause the parsing process be terminated. The error code is <code>kParseErrorTermination</code>.</p> |
| <h2><a class="anchor" id="Filtering"></a> |
| Filtering of JSON</h2> |
| <p>As mentioned earlier, <code>Writer</code> can handle the events published by <code>Reader</code>. <code>condense</code> example simply set a <code>Writer</code> as handler of a <code>Reader</code>, so it can remove all white-spaces in JSON. <code>pretty</code> example uses the same relationship, but replacing <code>Writer</code> by <code>PrettyWriter</code>. So <code>pretty</code> can be used to reformat a JSON with indentation and line feed.</p> |
| <p>Actually, we can add intermediate layer(s) to filter the contents of JSON via these SAX-style API. For example, <code>capitalize</code> example capitalize all strings in a JSON.</p> |
| <div class="fragment"><div class="line"><span class="preprocessor">#include "<a class="code" href="reader_8h.html">rapidjson/reader.h</a>"</span></div> |
| <div class="line"><span class="preprocessor">#include "rapidjson/writer.h"</span></div> |
| <div class="line"><span class="preprocessor">#include "rapidjson/filereadstream.h"</span></div> |
| <div class="line"><span class="preprocessor">#include "rapidjson/filewritestream.h"</span></div> |
| <div class="line"><span class="preprocessor">#include "rapidjson/error/en.h"</span></div> |
| <div class="line"><span class="preprocessor">#include <vector></span></div> |
| <div class="line"><span class="preprocessor">#include <cctype></span></div> |
| <div class="line"> </div> |
| <div class="line"><span class="keyword">using namespace </span><a class="code" href="namespacerapidjson.html">rapidjson</a>;</div> |
| <div class="line"> </div> |
| <div class="line"><span class="keyword">template</span><<span class="keyword">typename</span> OutputHandler></div> |
| <div class="line"><span class="keyword">struct </span>CapitalizeFilter {</div> |
| <div class="line"> CapitalizeFilter(OutputHandler& 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> RawNumber(<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> out_.RawNumber(str, length, copy); }</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 < length; i++)</div> |
| <div class="line"> buffer_.push_back(std::toupper(str[i]));</div> |
| <div class="line"> <span class="keywordflow">return</span> out_.String(&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& out_;</div> |
| <div class="line"> std::vector<char> 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<FileWriteStream></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<Writer<FileWriteStream> > 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">"\nError(%u): %s\n"</span>, (<span class="keywordtype">unsigned</span>)reader.<a class="code" href="classrapidjson_1_1_generic_reader.html#ab50019e0a715320f83b7610b83dcef8f">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#a042c621cf745c5ed3a6f5ff9418dd05e">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>Note that, it is incorrect to simply capitalize the JSON as a string. For example: </p><div class="fragment"><div class="line">["Hello\nWorld"]</div> |
| </div><!-- fragment --><p>Simply capitalizing the whole JSON would contain incorrect escape character: </p><div class="fragment"><div class="line">["HELLO\NWORLD"]</div> |
| </div><!-- fragment --><p>The correct result by <code>capitalize</code>: </p><div class="fragment"><div class="line">["HELLO\nWORLD"]</div> |
| </div><!-- fragment --><p>More complicated filters can be developed. However, since SAX-style API can only provide information about a single event at a time, user may need to book-keeping the contextual information (e.g. the path from root value, storage of other related values). Some processing may be easier to be implemented in DOM than SAX. </p> |
| </div></div><!-- contents --> |
| </div><!-- PageDoc --> |
| </div><!-- doc-content --> |
| <div class="ttc" id="aclassrapidjson_1_1_allocator_html"><div class="ttname"><a href="classrapidjson_1_1_allocator.html">Allocator</a></div><div class="ttdoc">Concept for allocating, resizing and freeing memory block.</div></div> |
| <div class="ttc" id="aclassrapidjson_1_1_generic_string_buffer_html"><div class="ttname"><a href="classrapidjson_1_1_generic_string_buffer.html">rapidjson::GenericStringBuffer</a></div><div class="ttdoc">Represents an in-memory output stream.</div><div class="ttdef"><b>Definition:</b> fwd.h:59</div></div> |
| <div class="ttc" id="astructrapidjson_1_1_generic_string_stream_html"><div class="ttname"><a href="structrapidjson_1_1_generic_string_stream.html">rapidjson::GenericStringStream</a></div><div class="ttdoc">Read-only string stream.</div><div class="ttdef"><b>Definition:</b> fwd.h:47</div></div> |
| <div class="ttc" id="agroup___r_a_p_i_d_j_s_o_n___e_r_r_o_r_s_html_ga7d3acf640886b1f2552dc8c4cd6dea60"><div class="ttname"><a href="group___r_a_p_i_d_j_s_o_n___e_r_r_o_r_s.html#ga7d3acf640886b1f2552dc8c4cd6dea60">rapidjson::ParseErrorCode</a></div><div class="ttdeci">ParseErrorCode</div><div class="ttdoc">Error code of parsing.</div><div class="ttdef"><b>Definition:</b> error.h:64</div></div> |
| <div class="ttc" id="aclassrapidjson_1_1_file_write_stream_html"><div class="ttname"><a href="classrapidjson_1_1_file_write_stream.html">rapidjson::FileWriteStream</a></div><div class="ttdoc">Wrapper of C file stream for output using fwrite().</div><div class="ttdef"><b>Definition:</b> filewritestream.h:32</div></div> |
| <div class="ttc" id="aclassrapidjson_1_1_file_read_stream_html"><div class="ttname"><a href="classrapidjson_1_1_file_read_stream.html">rapidjson::FileReadStream</a></div><div class="ttdoc">File byte stream for input using fread().</div><div class="ttdef"><b>Definition:</b> filereadstream.h:34</div></div> |
| <div class="ttc" id="anamespacerapidjson_html_a44eb33eaa523e36d466b1ced64b85c84"><div class="ttname"><a href="namespacerapidjson.html#a44eb33eaa523e36d466b1ced64b85c84">rapidjson::SizeType</a></div><div class="ttdeci">unsigned SizeType</div><div class="ttdoc">Size type (for string lengths, array sizes, etc.)</div><div class="ttdef"><b>Definition:</b> rapidjson.h:415</div></div> |
| <div class="ttc" id="aclassrapidjson_1_1_generic_reader_html_ac9c540b77de19661f6f45e04b9b0937b"><div class="ttname"><a href="classrapidjson_1_1_generic_reader.html#ac9c540b77de19661f6f45e04b9b0937b">rapidjson::GenericReader::Parse</a></div><div class="ttdeci">ParseResult Parse(InputStream &is, Handler &handler)</div><div class="ttdoc">Parse JSON text.</div><div class="ttdef"><b>Definition:</b> reader.h:559</div></div> |
| <div class="ttc" id="aclassrapidjson_1_1_generic_reader_html"><div class="ttname"><a href="classrapidjson_1_1_generic_reader.html">rapidjson::GenericReader</a></div><div class="ttdoc">SAX-style JSON parser. Use Reader for UTF8 encoding and default allocator.</div><div class="ttdef"><b>Definition:</b> fwd.h:88</div></div> |
| <div class="ttc" id="aclassrapidjson_1_1_generic_reader_html_a042c621cf745c5ed3a6f5ff9418dd05e"><div class="ttname"><a href="classrapidjson_1_1_generic_reader.html#a042c621cf745c5ed3a6f5ff9418dd05e">rapidjson::GenericReader::GetParseErrorCode</a></div><div class="ttdeci">ParseErrorCode GetParseErrorCode() const</div><div class="ttdoc">Get the ParseErrorCode of last parsing.</div><div class="ttdef"><b>Definition:</b> reader.h:685</div></div> |
| <div class="ttc" id="areader_8h_html"><div class="ttname"><a href="reader_8h.html">reader.h</a></div></div> |
| <div class="ttc" id="aclassrapidjson_1_1_writer_html_a98a421c806b456688874511f64add1f2"><div class="ttname"><a href="classrapidjson_1_1_writer.html#a98a421c806b456688874511f64add1f2">rapidjson::Writer::Writer</a></div><div class="ttdeci">Writer(OutputStream &os, StackAllocator *stackAllocator=0, size_t levelDepth=kDefaultLevelDepth)</div><div class="ttdoc">Constructor.</div><div class="ttdef"><b>Definition:</b> writer.h:102</div></div> |
| <div class="ttc" id="anamespacerapidjson_html_a81379eb4e94a0386d71d15fda882ebc9a5640cb00db7814b7f22be3683dda9835"><div class="ttname"><a href="namespacerapidjson.html#a81379eb4e94a0386d71d15fda882ebc9a5640cb00db7814b7f22be3683dda9835">rapidjson::kParseDefaultFlags</a></div><div class="ttdoc">Default parse flags. Can be customized by defining RAPIDJSON_PARSE_DEFAULT_FLAGS.</div><div class="ttdef"><b>Definition:</b> reader.h:158</div></div> |
| <div class="ttc" id="astructrapidjson_1_1_base_reader_handler_html"><div class="ttname"><a href="structrapidjson_1_1_base_reader_handler.html">rapidjson::BaseReaderHandler</a></div><div class="ttdoc">Default implementation of Handler.</div><div class="ttdef"><b>Definition:</b> fwd.h:85</div></div> |
| <div class="ttc" id="aclassrapidjson_1_1_writer_html"><div class="ttname"><a href="classrapidjson_1_1_writer.html">rapidjson::Writer</a></div><div class="ttdoc">JSON writer.</div><div class="ttdef"><b>Definition:</b> fwd.h:95</div></div> |
| <div class="ttc" id="anamespacerapidjson_html"><div class="ttname"><a href="namespacerapidjson.html">rapidjson</a></div><div class="ttdoc">main RapidJSON namespace</div><div class="ttdef"><b>Definition:</b> rapidjson.h:409</div></div> |
| <div class="ttc" id="anamespacerapidjson_html_ad5310edd1226f5b3ea82dc0d4d3740c6"><div class="ttname"><a href="namespacerapidjson.html#ad5310edd1226f5b3ea82dc0d4d3740c6">rapidjson::Reader</a></div><div class="ttdeci">GenericReader< UTF8< char >, UTF8< char >, CrtAllocator > Reader</div><div class="ttdoc">Reader with UTF8 encoding and default allocator.</div><div class="ttdef"><b>Definition:</b> fwd.h:88</div></div> |
| <div class="ttc" id="agroup___r_a_p_i_d_j_s_o_n___e_r_r_o_r_s_html_gabdaf1a7a4db30fb0e3d927fdf0fabe79"><div class="ttname"><a href="group___r_a_p_i_d_j_s_o_n___e_r_r_o_r_s.html#gabdaf1a7a4db30fb0e3d927fdf0fabe79">rapidjson::GetParseError_En</a></div><div class="ttdeci">const RAPIDJSON_ERROR_CHARTYPE * GetParseError_En(ParseErrorCode parseErrorCode)</div><div class="ttdoc">Maps error code of parsing into error message.</div><div class="ttdef"><b>Definition:</b> en.h:36</div></div> |
| <div class="ttc" id="aclassrapidjson_1_1_generic_reader_html_ab50019e0a715320f83b7610b83dcef8f"><div class="ttname"><a href="classrapidjson_1_1_generic_reader.html#ab50019e0a715320f83b7610b83dcef8f">rapidjson::GenericReader::GetErrorOffset</a></div><div class="ttdeci">size_t GetErrorOffset() const</div><div class="ttdoc">Get the position of last parsing error in input, 0 otherwise.</div><div class="ttdef"><b>Definition:</b> reader.h:688</div></div> |
| <div class="ttc" id="aclassrapidjson_1_1_handler_html"><div class="ttname"><a href="classrapidjson_1_1_handler.html">Handler</a></div><div class="ttdoc">Concept for receiving events from GenericReader upon parsing. The functions return true if no error o...</div></div> |
| <!-- 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> |
| </body> |
| </html> |