http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/fd280b5c/thirdparty/rapidjson-1.1.0/doc/pointer.zh-cn.md
----------------------------------------------------------------------
diff --git a/thirdparty/rapidjson-1.1.0/doc/pointer.zh-cn.md 
b/thirdparty/rapidjson-1.1.0/doc/pointer.zh-cn.md
new file mode 100644
index 0000000..f58f55f
--- /dev/null
+++ b/thirdparty/rapidjson-1.1.0/doc/pointer.zh-cn.md
@@ -0,0 +1,234 @@
+# Pointer
+
+(本功能于 v1.1.0 发布)
+
+JSON Pointer 是一个标准化([RFC6901])的方式去选取一个 JSON 
Document(DOM)中的值。这类似于 XML 的 XPath。然而,JSON Pointer 
简单得多,而且每个 JSON Pointer 仅指向单个值。
+
+使用 RapidJSON 的 JSON Pointer 实现能简化一些 DOM 的操作。
+
+[TOC]
+
+# JSON Pointer {#JsonPointer}
+
+一个 JSON Pointer 由一串(零至多个)token 所组成,每个 token 
都有 `/` 前缀。每个 token 
可以是一个字符串或数字。例如,给定一个 JSON:
+~~~javascript
+{
+    "foo" : ["bar", "baz"],
+    "pi" : 3.1416
+}
+~~~
+
+以下的 JSON Pointer 解析为:
+
+1. `"/foo"` → `[ "bar", "baz" ]`
+2. `"/foo/0"` → `"bar"`
+3. `"/foo/1"` → `"baz"`
+4. `"/pi"` → `3.1416`
+
+要注意,一个空 JSON Pointer `""` (零个 token)解析为整个 
JSON。
+
+# 基本使用方法 {#BasicUsage}
+
+以下的代码范例不解自明。
+
+~~~cpp
+#include "rapidjson/pointer.h"
+
+// ...
+Document d;
+
+// 使用 Set() 创建 DOM
+Pointer("/project").Set(d, "RapidJSON");
+Pointer("/stars").Set(d, 10);
+
+// { "project" : "RapidJSON", "stars" : 10 }
+
+// 使用 Get() 访问 DOM。若该值不存在则返回 nullptr。
+if (Value* stars = Pointer("/stars").Get(d))
+    stars->SetInt(stars->GetInt() + 1);
+
+// { "project" : "RapidJSON", "stars" : 11 }
+
+// Set() 和 Create() 自动生成父值(如果它们不存在)。
+Pointer("/a/b/0").Create(d);
+
+// { "project" : "RapidJSON", "stars" : 11, "a" : { "b" : [ null ] } }
+
+// GetWithDefault() 
返回引用。若该值不存在则会深拷贝缺省值。
+Value& hello = Pointer("/hello").GetWithDefault(d, "world");
+
+// { "project" : "RapidJSON", "stars" : 11, "a" : { "b" : [ null ] }, "hello" 
: "world" }
+
+// Swap() 和 Set() 相似
+Value x("C++");
+Pointer("/hello").Swap(d, x);
+
+// { "project" : "RapidJSON", "stars" : 11, "a" : { "b" : [ null ] }, "hello" 
: "C++" }
+// x 变成 "world"
+
+// 删去一个成员或元素,若值存在返回 true
+bool success = Pointer("/a").Erase(d);
+assert(success);
+
+// { "project" : "RapidJSON", "stars" : 10 }
+~~~
+
+# 辅助函数 {#HelperFunctions}
+
+由于面向对象的调用习惯可能不符直觉,RapidJSON 
也提供了一些辅助函数,它们把成员函数包装成自由函数。
+
+以下的例子与上面例子所做的事情完全相同。
+
+~~~cpp
+Document d;
+
+SetValueByPointer(d, "/project", "RapidJSON");
+SetValueByPointer(d, "/stars", 10);
+
+if (Value* stars = GetValueByPointer(d, "/stars"))
+    stars->SetInt(stars->GetInt() + 1);
+
+CreateValueByPointer(d, "/a/b/0");
+
+Value& hello = GetValueByPointerWithDefault(d, "/hello", "world");
+
+Value x("C++");
+SwapValueByPointer(d, "/hello", x);
+
+bool success = EraseValueByPointer(d, "/a");
+assert(success);
+~~~
+
+以下对比 3 种调用方式:
+
+1. `Pointer(source).<Method>(root, ...)`
+2. `<Method>ValueByPointer(root, Pointer(source), ...)`
+3. `<Method>ValueByPointer(root, source, ...)`
+
+# 解析 Pointer {#ResolvingPointer}
+
+`Pointer::Get()` 或 `GetValueByPointer()` 函数并不修改 DOM。若那些 
token 不能匹配 DOM 里的值,这些函数便返回 `nullptr`。使用者
可利用这个方法来检查一个值是否存在。
+
+注意,数值 token 
可表示数组索引或成员名字。解析过程中会按值的类型来匹é…
ã€‚
+
+~~~javascript
+{
+    "0" : 123,
+    "1" : [456]
+}
+~~~
+
+1. `"/0"` → `123`
+2. `"/1/0"` → `456`
+
+Token `"0"` 在第一个 pointer 中被当作成员名字。它在第二个 
pointer 中被当作成数组索引。
+
+其他函数会改变 DOM,包括 
`Create()`、`GetWithDefault()`、`Set()`、`Swap()`。这些函数总是成功的。若一些父值不存在,就会创建它们。若父值类型不匹é
… token,也会强行改变其类型。改变类型也意味着完全移除å…
¶ DOM 子树的内容。
+
+例如,把上面的 JSON 解译至 `d` 之后,
+
+~~~cpp
+SetValueByPointer(d, "1/a", 789); // { "0" : 123, "1" : { "a" : 789 } }
+~~~
+
+## 解析负号 token
+
+另外,[RFC6901] 定义了一个特殊 token `-` 
(单个负号),用于表示数组最后元素的下一个元素。 
`Get()` 只会把此 token 当作成员名字 '"-"'。而å…
¶ä»–函数则会以此解析数组,等同于对数组调用 
`Value::PushBack()` 。
+
+~~~cpp
+Document d;
+d.Parse("{\"foo\":[123]}");
+SetValueByPointer(d, "/foo/-", 456); // { "foo" : [123, 456] }
+SetValueByPointer(d, "/-", 789);    // { "foo" : [123, 456], "-" : 789 }
+~~~
+
+## 解析 Document 及 Value
+
+当使用 `p.Get(root)` 或 `GetValueByPointer(root, p)`,`root` 
是一个(常数) `Value&`。这意味着,它也可以是 DOM 
里的一个子树。
+
+其他函数有两组签名。一组使用 `Document& document` 
作为参数,另一组使用 `Value& root`。第一组使用 
`document.GetAllocator()` 去创建值,而第二组则需要使用者
提供一个 allocator,如同 DOM 里的函数。
+
+以上例子都不需要 allocator 参数,因为它的第一个参数是 
`Document&`。但如果你需要对一个子æ 
‘进行解析,就需要如下面的例子般提供 allocator:
+
+~~~cpp
+class Person {
+public:
+    Person() {
+        document_ = new Document();
+        // CreateValueByPointer() here no need allocator
+        SetLocation(CreateValueByPointer(*document_, "/residence"), ...);
+        SetLocation(CreateValueByPointer(*document_, "/office"), ...);
+    };
+
+private:
+    void SetLocation(Value& location, const char* country, const char* 
addresses[2]) {
+        Value::Allocator& a = document_->GetAllocator();
+        // SetValueByPointer() here need allocator
+        SetValueByPointer(location, "/country", country, a);
+        SetValueByPointer(location, "/address/0", address[0], a);
+        SetValueByPointer(location, "/address/1", address[1], a);
+    }
+
+    // ...
+
+    Document* document_;
+};
+~~~
+
+`Erase()` 或 `EraseValueByPointer()` 不需要 
allocator。而且它们成功删除值之后会返回 `true`。
+
+# 错误处理 {#ErrorHandling}
+
+`Pointer` 在å…
¶å»ºæž„函数里会解译源字符串。若有解析错误,`Pointer::IsValid()`
 返回 `false`。你可使用 `Pointer::GetParseErrorCode()` 和 
`GetParseErrorOffset()` 去获取错信息。
+
+要注意的是,所有解析函数都假设 pointer 
是合法的。对一个非法 pointer 解析会做成断言失败。
+
+# URI 片段表示方式 {#URIFragment}
+
+除了我们一直在使用的字符串方式表示 JSON pointer,[RFC6901] 
也定义了一个 JSON Pointer 的 URI 片段(fragment)表示方式。URI 
片段是定义于 [RFC3986] "Uniform Resource Identifier (URI): Generic 
Syntax"。
+
+URI 片段的主要分别是必然以 `#` (pound 
sign)开头,而一些字符也会以百分比编码成 UTF-8 
序列。例如,以下的表展示了不同表示法下的 C/C++ 
字符串常数。
+
+字符串表示方式 | URI 片段表示方式 | Pointer Tokens (UTF-8)
+----------------------|-----------------------------|------------------------
+`"/foo/0"`            | `"#/foo/0"`                 | `{"foo", 0}`
+`"/a~1b"`             | `"#/a~1b"`                  | `{"a/b"}`
+`"/m~0n"`             | `"#/m~0n"`                  | `{"m~n"}`
+`"/ "`                | `"#/%20"`                   | `{" "}`
+`"/\0"`               | `"#/%00"`                   | `{"\0"}`
+`"/€"`                | `"#/%E2%82%AC"`             | `{"€"}`
+
+RapidJSON 完全支持 URI 片段表示方式。它在解译时会自动检测 
`#` 号。
+
+# 字符串化
+
+你也可以把一个 `Pointer` 字符串化,储存于字符串或å…
¶ä»–输出流。例如:
+
+~~~
+Pointer p(...);
+StringBuffer sb;
+p.Stringify(sb);
+std::cout << sb.GetString() << std::endl;
+~~~
+
+使用 `StringifyUriFragment()` 可以把 pointer 字符串化为 URI 
片段表示法。
+
+# 使用者提供的 tokens {#UserSuppliedTokens}
+
+若一个 pointer 
会用于多次解析,它应该只被创建一次,然后再施于不同的 
DOM ,或在不同时间做解析。这样可以避免多次创键 
`Pointer`,节省时间和内存分配。
+
+我们甚至可以再更进一步,完全消去解析过程及动态内
存分配。我们可以直接生成 token 数组:
+
+~~~cpp
+#define NAME(s) { s, sizeof(s) / sizeof(s[0]) - 1, kPointerInvalidIndex }
+#define INDEX(i) { #i, sizeof(#i) - 1, i }
+
+static const Pointer::Token kTokens[] = { NAME("foo"), INDEX(123) };
+static const Pointer p(kTokens, sizeof(kTokens) / sizeof(kTokens[0]));
+// Equivalent to static const Pointer p("/foo/123");
+~~~
+
+这种做法可能适合内存受限的系统。
+
+[RFC3986]: https://tools.ietf.org/html/rfc3986
+[RFC6901]: https://tools.ietf.org/html/rfc6901

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/fd280b5c/thirdparty/rapidjson-1.1.0/doc/sax.md
----------------------------------------------------------------------
diff --git a/thirdparty/rapidjson-1.1.0/doc/sax.md 
b/thirdparty/rapidjson-1.1.0/doc/sax.md
new file mode 100644
index 0000000..1d4fc2a
--- /dev/null
+++ b/thirdparty/rapidjson-1.1.0/doc/sax.md
@@ -0,0 +1,486 @@
+# SAX
+
+The term "SAX" originated from [Simple API for 
XML](http://en.wikipedia.org/wiki/Simple_API_for_XML). We borrowed this term 
for JSON parsing and generation.
+
+In RapidJSON, `Reader` (typedef of `GenericReader<...>`) is the SAX-style 
parser for JSON, and `Writer` (typedef of `GenericWriter<...>`) is the 
SAX-style generator for JSON.
+
+[TOC]
+
+# Reader {#Reader}
+
+`Reader` parses a JSON from a stream. While it reads characters from the 
stream, it analyze the characters according to the syntax of JSON, and publish 
events to a handler.
+
+For example, here is a JSON.
+
+~~~~~~~~~~js
+{
+    "hello": "world",
+    "t": true ,
+    "f": false,
+    "n": null,
+    "i": 123,
+    "pi": 3.1416,
+    "a": [1, 2, 3, 4]
+}
+~~~~~~~~~~
+
+While a `Reader` parses this JSON, it publishes the following events to the 
handler sequentially:
+
+~~~~~~~~~~
+StartObject()
+Key("hello", 5, true)
+String("world", 5, true)
+Key("t", 1, true)
+Bool(true)
+Key("f", 1, true)
+Bool(false)
+Key("n", 1, true)
+Null()
+Key("i")
+UInt(123)
+Key("pi")
+Double(3.1416)
+Key("a")
+StartArray()
+Uint(1)
+Uint(2)
+Uint(3)
+Uint(4)
+EndArray(4)
+EndObject(7)
+~~~~~~~~~~
+
+These events can be easily matched with the JSON, except some event parameters 
need further explanation. Let's see the `simplereader` example which produces 
exactly the same output as above:
+
+~~~~~~~~~~cpp
+#include "rapidjson/reader.h"
+#include <iostream>
+
+using namespace rapidjson;
+using namespace std;
+
+struct MyHandler : public BaseReaderHandler<UTF8<>, MyHandler> {
+    bool Null() { cout << "Null()" << endl; return true; }
+    bool Bool(bool b) { cout << "Bool(" << boolalpha << b << ")" << endl; 
return true; }
+    bool Int(int i) { cout << "Int(" << i << ")" << endl; return true; }
+    bool Uint(unsigned u) { cout << "Uint(" << u << ")" << endl; return true; }
+    bool Int64(int64_t i) { cout << "Int64(" << i << ")" << endl; return true; 
}
+    bool Uint64(uint64_t u) { cout << "Uint64(" << u << ")" << endl; return 
true; }
+    bool Double(double d) { cout << "Double(" << d << ")" << endl; return 
true; }
+    bool String(const char* str, SizeType length, bool copy) { 
+        cout << "String(" << str << ", " << length << ", " << boolalpha << 
copy << ")" << endl;
+        return true;
+    }
+    bool StartObject() { cout << "StartObject()" << endl; return true; }
+    bool Key(const char* str, SizeType length, bool copy) { 
+        cout << "Key(" << str << ", " << length << ", " << boolalpha << copy 
<< ")" << endl;
+        return true;
+    }
+    bool EndObject(SizeType memberCount) { cout << "EndObject(" << memberCount 
<< ")" << endl; return true; }
+    bool StartArray() { cout << "StartArray()" << endl; return true; }
+    bool EndArray(SizeType elementCount) { cout << "EndArray(" << elementCount 
<< ")" << endl; return true; }
+};
+
+void main() {
+    const char json[] = " { \"hello\" : \"world\", \"t\" : true , \"f\" : 
false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } ";
+
+    MyHandler handler;
+    Reader reader;
+    StringStream ss(json);
+    reader.Parse(ss, handler);
+}
+~~~~~~~~~~
+
+Note that, RapidJSON uses template to statically bind the `Reader` type and 
the handler type, instead of using class with virtual functions. This paradigm 
can improve the performance by inlining functions.
+
+## Handler {#Handler}
+
+As the previous example showed, user needs to implement a handler, which 
consumes the events (function calls) from `Reader`. The handler must contain 
the following member functions.
+
+~~~~~~~~~~cpp
+class Handler {
+    bool Null();
+    bool Bool(bool b);
+    bool Int(int i);
+    bool Uint(unsigned i);
+    bool Int64(int64_t i);
+    bool Uint64(uint64_t i);
+    bool Double(double d);
+    bool RawNumber(const Ch* str, SizeType length, bool copy);
+    bool String(const Ch* str, SizeType length, bool copy);
+    bool StartObject();
+    bool Key(const Ch* str, SizeType length, bool copy);
+    bool EndObject(SizeType memberCount);
+    bool StartArray();
+    bool EndArray(SizeType elementCount);
+};
+~~~~~~~~~~
+
+`Null()` is called when the `Reader` encounters a JSON null value.
+
+`Bool(bool)` is called when the `Reader` encounters a JSON true or false value.
+
+When the `Reader` encounters a JSON number, it chooses a suitable C++ type 
mapping. And then it calls *one* function out of `Int(int)`, `Uint(unsigned)`, 
`Int64(int64_t)`, `Uint64(uint64_t)` and `Double(double)`. If 
`kParseNumbersAsStrings` is enabled, `Reader` will always calls `RawNumber()` 
instead.
+
+`String(const char* str, SizeType length, bool copy)` is called when the 
`Reader` 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 `'\0'` inside a string. If such 
situation happens, `strlen(str) < length`. The last `copy` indicates whether 
the handler needs to make a copy of the string. For normal parsing, `copy = 
true`. Only when *insitu* parsing is used, `copy = false`. And beware that, the 
character type depends on the target encoding, which will be explained later.
+
+When the `Reader` encounters the beginning of an object, it calls 
`StartObject()`. An object in JSON is a set of name-value pairs. If the object 
contains members it first calls `Key()` for the name of member, and then calls 
functions depending on the type of the value. These calls of name-value pairs 
repeats until calling `EndObject(SizeType memberCount)`. Note that the 
`memberCount` parameter is just an aid for the handler, user may not need this 
parameter.
+
+Array is similar to object but simpler. At the beginning of an array, the 
`Reader` calls `BeginArary()`. If there is elements, it calls functions 
according to the types of element. Similarly, in the last call 
`EndArray(SizeType elementCount)`, the parameter `elementCount` is just an aid 
for the handler.
+
+Every handler functions returns a `bool`. Normally it should returns `true`. 
If the handler encounters an error, it can return `false` to notify event 
publisher to stop further processing.
+
+For example, when we parse a JSON with `Reader` and the handler detected that 
the JSON does not conform to the required schema, then the handler can return 
`false` and let the `Reader` stop further parsing. And the `Reader` will be in 
error state with error code `kParseErrorTermination`.
+
+## GenericReader {#GenericReader}
+
+As mentioned before, `Reader` is a typedef of a template class `GenericReader`:
+
+~~~~~~~~~~cpp
+namespace rapidjson {
+
+template <typename SourceEncoding, typename TargetEncoding, typename Allocator 
= MemoryPoolAllocator<> >
+class GenericReader {
+    // ...
+};
+
+typedef GenericReader<UTF8<>, UTF8<> > Reader;
+
+} // namespace rapidjson
+~~~~~~~~~~
+
+The `Reader` 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 `str` parameter in `String()` calls. For example, to parse a 
UTF-8 stream and outputs UTF-16 string events, you can define a reader by:
+
+~~~~~~~~~~cpp
+GenericReader<UTF8<>, UTF16<> > reader;
+~~~~~~~~~~
+
+Note that, the default character type of `UTF16` is `wchar_t`. So this 
`reader`needs to call `String(const wchar_t*, SizeType, bool)` of the handler.
+
+The third template parameter `Allocator` is the allocator type for internal 
data structure (actually a stack).
+
+## Parsing {#SaxParsing}
+
+The one and only one function of `Reader` is to parse JSON. 
+
+~~~~~~~~~~cpp
+template <unsigned parseFlags, typename InputStream, typename Handler>
+bool Parse(InputStream& is, Handler& handler);
+
+// with parseFlags = kDefaultParseFlags
+template <typename InputStream, typename Handler>
+bool Parse(InputStream& is, Handler& handler);
+~~~~~~~~~~
+
+If an error occurs during parsing, it will return `false`. User can also calls 
`bool HasParseEror()`, `ParseErrorCode GetParseErrorCode()` and `size_t 
GetErrorOffset()` to obtain the error states. Actually `Document` uses these 
`Reader` functions to obtain parse errors. Please refer to [DOM](doc/dom.md) 
for details about parse error.
+
+# Writer {#Writer}
+
+`Reader` converts (parses) JSON into events. `Writer` does exactly the 
opposite. It converts events into JSON. 
+
+`Writer` is very easy to use. If your application only need to converts some 
data into JSON, it may be a good choice to use `Writer` directly, instead of 
building a `Document` and then stringifying it with a `Writer`.
+
+In `simplewriter` example, we do exactly the reverse of `simplereader`.
+
+~~~~~~~~~~cpp
+#include "rapidjson/writer.h"
+#include "rapidjson/stringbuffer.h"
+#include <iostream>
+
+using namespace rapidjson;
+using namespace std;
+
+void main() {
+    StringBuffer s;
+    Writer<StringBuffer> writer(s);
+    
+    writer.StartObject();
+    writer.Key("hello");
+    writer.String("world");
+    writer.Key("t");
+    writer.Bool(true);
+    writer.Key("f");
+    writer.Bool(false);
+    writer.Key("n");
+    writer.Null();
+    writer.Key("i");
+    writer.Uint(123);
+    writer.Key("pi");
+    writer.Double(3.1416);
+    writer.Key("a");
+    writer.StartArray();
+    for (unsigned i = 0; i < 4; i++)
+        writer.Uint(i);
+    writer.EndArray();
+    writer.EndObject();
+
+    cout << s.GetString() << endl;
+}
+~~~~~~~~~~
+
+~~~~~~~~~~
+{"hello":"world","t":true,"f":false,"n":null,"i":123,"pi":3.1416,"a":[0,1,2,3]}
+~~~~~~~~~~
+
+There are two `String()` and `Key()` 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.
+
+Note that, the example code does not pass any parameters in `EndArray()` and 
`EndObject()`. An `SizeType` can be passed but it will be simply ignored by 
`Writer`.
+
+You may doubt that, why not just using `sprintf()` or `std::stringstream` to 
build a JSON?
+
+There are various reasons:
+1. `Writer` must output a well-formed JSON. If there is incorrect event 
sequence (e.g. `Int()` just after `StartObject()`), it generates assertion fail 
in debug mode.
+2. `Writer::String()` can handle string escaping (e.g. converting code point 
`U+000A` to `\n`) and Unicode transcoding.
+3. `Writer` handles number output consistently.
+4. `Writer` implements the event handler concept. It can be used to handle 
events from `Reader`, `Document` or other event publisher.
+5. `Writer` can be optimized for different platforms.
+
+Anyway, using `Writer` API is even simpler than generating a JSON by ad hoc 
methods.
+
+## Template {#WriterTemplate}
+
+`Writer` has a minor design difference to `Reader`. `Writer` is a template 
class, not a typedef. There is no `GenericWriter`. The following is the 
declaration.
+
+~~~~~~~~~~cpp
+namespace rapidjson {
+
+template<typename OutputStream, typename SourceEncoding = UTF8<>, typename 
TargetEncoding = UTF8<>, typename Allocator = CrtAllocator<>, unsigned 
writeFlags = kWriteDefaultFlags>
+class Writer {
+public:
+    Writer(OutputStream& os, Allocator* allocator = 0, size_t levelDepth = 
kDefaultLevelDepth)
+// ...
+};
+
+} // namespace rapidjson
+~~~~~~~~~~
+
+The `OutputStream` template parameter is the type of output stream. It cannot 
be deduced and must be specified by user.
+
+The `SourceEncoding` template parameter specifies the encoding to be used in 
`String(const Ch*, ...)`.
+
+The `TargetEncoding` template parameter specifies the encoding in the output 
stream.
+
+The `Allocator` is the type of allocator, which is used for allocating 
internal data structure (a stack).
+
+The `writeFlags` are combination of the following bit-flags:
+
+Parse flags                   | Meaning
+------------------------------|-----------------------------------
+`kWriteNoFlags`               | No flag is set.
+`kWriteDefaultFlags`          | Default write flags. It is equal to macro 
`RAPIDJSON_WRITE_DEFAULT_FLAGS`, which is defined as `kWriteNoFlags`.
+`kWriteValidateEncodingFlag`  | Validate encoding of JSON strings.
+`kWriteNanAndInfFlag`         | Allow writing of `Infinity`, `-Infinity` and 
`NaN`.
+
+Besides, the constructor of `Writer` has a `levelDepth` parameter. This 
parameter affects the initial memory allocated for storing information per 
hierarchy level.
+
+## PrettyWriter {#PrettyWriter}
+
+While the output of `Writer` is the most condensed JSON without white-spaces, 
suitable for network transfer or storage, it is not easily readable by human.
+
+Therefore, RapidJSON provides a `PrettyWriter`, which adds indentation and 
line feeds in the output.
+
+The usage of `PrettyWriter` is exactly the same as `Writer`, expect that 
`PrettyWriter` provides a `SetIndent(Ch indentChar, unsigned indentCharCount)` 
function. The default is 4 spaces.
+
+## Completeness and Reset {#CompletenessReset}
+
+A `Writer` can only output a single JSON, which can be any JSON type at the 
root. Once the singular event for root (e.g. `String()`), or the last matching 
`EndObject()` or `EndArray()` event, is handled, the output JSON is well-formed 
and complete. User can detect this state by calling `Writer::IsComplete()`.
+
+When a JSON is complete, the `Writer` cannot accept any new events. Otherwise 
the output will be invalid (i.e. having more than one root). To reuse the 
`Writer` object, user can call `Writer::Reset(OutputStream& os)` to reset all 
internal states of the `Writer` with a new output stream.
+
+# Techniques {#SaxTechniques}
+
+## Parsing JSON to Custom Data Structure {#CustomDataStructure}
+
+`Document`'s parsing capability is completely based on `Reader`. Actually 
`Document` is a handler which receives events from a reader to build a DOM 
during parsing.
+
+User may uses `Reader` to build other data structures directly. This 
eliminates building of DOM, thus reducing memory and improving performance.
+
+In the following `messagereader` example, `ParseMessages()` parses a JSON 
which should be an object with key-string pairs.
+
+~~~~~~~~~~cpp
+#include "rapidjson/reader.h"
+#include "rapidjson/error/en.h"
+#include <iostream>
+#include <string>
+#include <map>
+
+using namespace std;
+using namespace rapidjson;
+
+typedef map<string, string> MessageMap;
+
+struct MessageHandler
+    : public BaseReaderHandler<UTF8<>, MessageHandler> {
+    MessageHandler() : state_(kExpectObjectStart) {
+    }
+
+    bool StartObject() {
+        switch (state_) {
+        case kExpectObjectStart:
+            state_ = kExpectNameOrObjectEnd;
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    bool String(const char* str, SizeType length, bool) {
+        switch (state_) {
+        case kExpectNameOrObjectEnd:
+            name_ = string(str, length);
+            state_ = kExpectValue;
+            return true;
+        case kExpectValue:
+            messages_.insert(MessageMap::value_type(name_, string(str, 
length)));
+            state_ = kExpectNameOrObjectEnd;
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    bool EndObject(SizeType) { return state_ == kExpectNameOrObjectEnd; }
+
+    bool Default() { return false; } // All other events are invalid.
+
+    MessageMap messages_;
+    enum State {
+        kExpectObjectStart,
+        kExpectNameOrObjectEnd,
+        kExpectValue,
+    }state_;
+    std::string name_;
+};
+
+void ParseMessages(const char* json, MessageMap& messages) {
+    Reader reader;
+    MessageHandler handler;
+    StringStream ss(json);
+    if (reader.Parse(ss, handler))
+        messages.swap(handler.messages_);   // Only change it if success.
+    else {
+        ParseErrorCode e = reader.GetParseErrorCode();
+        size_t o = reader.GetErrorOffset();
+        cout << "Error: " << GetParseError_En(e) << endl;;
+        cout << " at offset " << o << " near '" << string(json).substr(o, 10) 
<< "...'" << endl;
+    }
+}
+
+int main() {
+    MessageMap messages;
+
+    const char* json1 = "{ \"greeting\" : \"Hello!\", \"farewell\" : 
\"bye-bye!\" }";
+    cout << json1 << endl;
+    ParseMessages(json1, messages);
+
+    for (MessageMap::const_iterator itr = messages.begin(); itr != 
messages.end(); ++itr)
+        cout << itr->first << ": " << itr->second << endl;
+
+    cout << endl << "Parse a JSON with invalid schema." << endl;
+    const char* json2 = "{ \"greeting\" : \"Hello!\", \"farewell\" : 
\"bye-bye!\", \"foo\" : {} }";
+    cout << json2 << endl;
+    ParseMessages(json2, messages);
+
+    return 0;
+}
+~~~~~~~~~~
+
+~~~~~~~~~~
+{ "greeting" : "Hello!", "farewell" : "bye-bye!" }
+farewell: bye-bye!
+greeting: Hello!
+
+Parse a JSON with invalid schema.
+{ "greeting" : "Hello!", "farewell" : "bye-bye!", "foo" : {} }
+Error: Terminate parsing due to Handler error.
+ at offset 59 near '} }...'
+~~~~~~~~~~
+
+The first JSON (`json1`) was successfully parsed into `MessageMap`. Since 
`MessageMap` is a `std::map`, the printing order are sorted by the key. This 
order is different from the JSON's order.
+
+In the second JSON (`json2`), `foo`'s value is an empty object. As it is an 
object, `MessageHandler::StartObject()` will be called. However, at that moment 
`state_ = kExpectValue`, so that function returns `false` and cause the parsing 
process be terminated. The error code is `kParseErrorTermination`.
+
+## Filtering of JSON {#Filtering}
+
+As mentioned earlier, `Writer` can handle the events published by `Reader`. 
`condense` example simply set a `Writer` as handler of a `Reader`, so it can 
remove all white-spaces in JSON. `pretty` example uses the same relationship, 
but replacing `Writer` by `PrettyWriter`. So `pretty` can be used to reformat a 
JSON with indentation and line feed.
+
+Actually, we can add intermediate layer(s) to filter the contents of JSON via 
these SAX-style API. For example, `capitalize` example capitalize all strings 
in a JSON.
+
+~~~~~~~~~~cpp
+#include "rapidjson/reader.h"
+#include "rapidjson/writer.h"
+#include "rapidjson/filereadstream.h"
+#include "rapidjson/filewritestream.h"
+#include "rapidjson/error/en.h"
+#include <vector>
+#include <cctype>
+
+using namespace rapidjson;
+
+template<typename OutputHandler>
+struct CapitalizeFilter {
+    CapitalizeFilter(OutputHandler& out) : out_(out), buffer_() {
+    }
+
+    bool Null() { return out_.Null(); }
+    bool Bool(bool b) { return out_.Bool(b); }
+    bool Int(int i) { return out_.Int(i); }
+    bool Uint(unsigned u) { return out_.Uint(u); }
+    bool Int64(int64_t i) { return out_.Int64(i); }
+    bool Uint64(uint64_t u) { return out_.Uint64(u); }
+    bool Double(double d) { return out_.Double(d); }
+    bool RawNumber(const char* str, SizeType length, bool copy) { return 
out_.RawNumber(str, length, copy); }
+    bool String(const char* str, SizeType length, bool) { 
+        buffer_.clear();
+        for (SizeType i = 0; i < length; i++)
+            buffer_.push_back(std::toupper(str[i]));
+        return out_.String(&buffer_.front(), length, true); // true = output 
handler need to copy the string
+    }
+    bool StartObject() { return out_.StartObject(); }
+    bool Key(const char* str, SizeType length, bool copy) { return String(str, 
length, copy); }
+    bool EndObject(SizeType memberCount) { return out_.EndObject(memberCount); 
}
+    bool StartArray() { return out_.StartArray(); }
+    bool EndArray(SizeType elementCount) { return out_.EndArray(elementCount); 
}
+
+    OutputHandler& out_;
+    std::vector<char> buffer_;
+};
+
+int main(int, char*[]) {
+    // Prepare JSON reader and input stream.
+    Reader reader;
+    char readBuffer[65536];
+    FileReadStream is(stdin, readBuffer, sizeof(readBuffer));
+
+    // Prepare JSON writer and output stream.
+    char writeBuffer[65536];
+    FileWriteStream os(stdout, writeBuffer, sizeof(writeBuffer));
+    Writer<FileWriteStream> writer(os);
+
+    // JSON reader parse from the input stream and let writer generate the 
output.
+    CapitalizeFilter<Writer<FileWriteStream> > filter(writer);
+    if (!reader.Parse(is, filter)) {
+        fprintf(stderr, "\nError(%u): %s\n", 
(unsigned)reader.GetErrorOffset(), 
GetParseError_En(reader.GetParseErrorCode()));
+        return 1;
+    }
+
+    return 0;
+}
+~~~~~~~~~~
+
+Note that, it is incorrect to simply capitalize the JSON as a string. For 
example:
+~~~~~~~~~~
+["Hello\nWorld"]
+~~~~~~~~~~
+
+Simply capitalizing the whole JSON would contain incorrect escape character:
+~~~~~~~~~~
+["HELLO\NWORLD"]
+~~~~~~~~~~
+
+The correct result by `capitalize`:
+~~~~~~~~~~
+["HELLO\nWORLD"]
+~~~~~~~~~~
+
+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.

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/fd280b5c/thirdparty/rapidjson-1.1.0/doc/sax.zh-cn.md
----------------------------------------------------------------------
diff --git a/thirdparty/rapidjson-1.1.0/doc/sax.zh-cn.md 
b/thirdparty/rapidjson-1.1.0/doc/sax.zh-cn.md
new file mode 100644
index 0000000..b20286d
--- /dev/null
+++ b/thirdparty/rapidjson-1.1.0/doc/sax.zh-cn.md
@@ -0,0 +1,487 @@
+# SAX
+
+"SAX" 此术语源于 [Simple API for 
XML](http://en.wikipedia.org/wiki/Simple_API_for_XML)。我们借了此术语去套用在
 JSON 的解析及生成。
+
+在 RapidJSON 中,`Reader`(`GenericReader<...>` 的 typedef)是 JSON 的 
SAX 风格解析器,而 `Writer`(`GenericWriter<...>` 的 typedef)则是 
JSON 的 SAX 风格生成器。
+
+[TOC]
+
+# Reader {#Reader}
+
+`Reader` 从输入流解析一个 
JSON。当它从流中读取字符时,它会基于 JSON 
的语法去分析字符,并向处理器发送事件。
+
+例如,以下是一个 JSON。
+
+~~~~~~~~~~js
+{
+    "hello": "world",
+    "t": true ,
+    "f": false,
+    "n": null,
+    "i": 123,
+    "pi": 3.1416,
+    "a": [1, 2, 3, 4]
+}
+~~~~~~~~~~
+
+当一个 `Reader` 解析此 JSON 
时,它会顺序地向处理器发送以下的事件:
+
+~~~~~~~~~~
+StartObject()
+Key("hello", 5, true)
+String("world", 5, true)
+Key("t", 1, true)
+Bool(true)
+Key("f", 1, true)
+Bool(false)
+Key("n", 1, true)
+Null()
+Key("i")
+UInt(123)
+Key("pi")
+Double(3.1416)
+Key("a")
+StartArray()
+Uint(1)
+Uint(2)
+Uint(3)
+Uint(4)
+EndArray(4)
+EndObject(7)
+~~~~~~~~~~
+
+除了一些事件参数需要再作解释,这些事件可以轻松地与 
JSON 对上。我们可以看看 `simplereader` 例子怎样产生和以上完å…
¨ç›¸åŒçš„结果:
+
+~~~~~~~~~~cpp
+#include "rapidjson/reader.h"
+#include <iostream>
+
+using namespace rapidjson;
+using namespace std;
+
+struct MyHandler : public BaseReaderHandler<UTF8<>, MyHandler> {
+    bool Null() { cout << "Null()" << endl; return true; }
+    bool Bool(bool b) { cout << "Bool(" << boolalpha << b << ")" << endl; 
return true; }
+    bool Int(int i) { cout << "Int(" << i << ")" << endl; return true; }
+    bool Uint(unsigned u) { cout << "Uint(" << u << ")" << endl; return true; }
+    bool Int64(int64_t i) { cout << "Int64(" << i << ")" << endl; return true; 
}
+    bool Uint64(uint64_t u) { cout << "Uint64(" << u << ")" << endl; return 
true; }
+    bool Double(double d) { cout << "Double(" << d << ")" << endl; return 
true; }
+    bool String(const char* str, SizeType length, bool copy) { 
+        cout << "String(" << str << ", " << length << ", " << boolalpha << 
copy << ")" << endl;
+        return true;
+    }
+    bool StartObject() { cout << "StartObject()" << endl; return true; }
+    bool Key(const char* str, SizeType length, bool copy) { 
+        cout << "Key(" << str << ", " << length << ", " << boolalpha << copy 
<< ")" << endl;
+        return true;
+    }
+    bool EndObject(SizeType memberCount) { cout << "EndObject(" << memberCount 
<< ")" << endl; return true; }
+    bool StartArray() { cout << "StartArray()" << endl; return true; }
+    bool EndArray(SizeType elementCount) { cout << "EndArray(" << elementCount 
<< ")" << endl; return true; }
+};
+
+void main() {
+    const char json[] = " { \"hello\" : \"world\", \"t\" : true , \"f\" : 
false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } ";
+
+    MyHandler handler;
+    Reader reader;
+    StringStream ss(json);
+    reader.Parse(ss, handler);
+}
+~~~~~~~~~~
+
+注意 RapidJSON 使用模板去静态挷定 `Reader` 
类型及处理器的类形,而不是使用含虚函数的类。这个范式可以通过把函数å†
…联而改善性能。
+
+## 处理器 {#Handler}
+
+如前例所示,使用者
需要实现一个处理器(handler),用于处理来自 `Reader` 
的事件(函数调用)。处理器必须包含以下的成员函数。
+
+~~~~~~~~~~cpp
+class Handler {
+    bool Null();
+    bool Bool(bool b);
+    bool Int(int i);
+    bool Uint(unsigned i);
+    bool Int64(int64_t i);
+    bool Uint64(uint64_t i);
+    bool Double(double d);
+    bool RawNumber(const Ch* str, SizeType length, bool copy);
+    bool String(const Ch* str, SizeType length, bool copy);
+    bool StartObject();
+    bool Key(const Ch* str, SizeType length, bool copy);
+    bool EndObject(SizeType memberCount);
+    bool StartArray();
+    bool EndArray(SizeType elementCount);
+};
+~~~~~~~~~~
+
+当 `Reader` 遇到 JSON null 值时会调用 `Null()`。
+
+当 `Reader` 遇到 JSON true 或 false 值时会调用 `Bool(bool)`。
+
+当 `Reader` 遇到 JSON number,它会选择一个合适的 C++ 类型映
射,然后调用 
`Int(int)`、`Uint(unsigned)`、`Int64(int64_t)`、`Uint64(uint64_t)` 及 
`Double(double)` 的 * 其中之一个 *。 若开启了 
`kParseNumbersAsStrings` 选项,`Reader` 便会改为调用 `RawNumber()`。
+
+当 `Reader` 遇到 JSON string,它会调用 `String(const char* str, 
SizeType length, bool 
copy)`。第一个参数是字符串的指针。第二个参数是字符串的长度(不åŒ
…含空终止符号)。注意 RapidJSON 支持字串中含有空字符 
`'\0'`。若出现这种情况,便会有 `strlen(str) < length`。最后的 
`copy` 
参数表示处理器是否需要复制该字符串。在正常解析时,`copy
 = true`。仅当使用原位解析时,`copy = 
false`。此外,还要注意字符的类型与目标编码相å…
³ï¼Œæˆ‘们稍后会再谈这一点。
+
+当 `Reader` 遇到 JSON object 的开始之时,它会调用 
`StartObject()`。JSON 的 object 是一个键值对(成员)的集合。若 
object 包含成员,它会先为成员的名字调用 
`Key()`,然后再按值的类型调用函数。它不断调用这些键值对,直至最终调用
 `EndObject(SizeType memberCount)`。注意 `memberCount` 
参数对处理器来说只是协助性质,使用者
可能不需要此参数。
+
+JSON array 与 object 相似,但更简单。在 array 开始时,`Reader` 
会调用 `BeginArary()`。若 array 含有元素,它会按元素
的类型来读用函数。相似地,最后它会调用 `EndArray(SizeType 
elementCount)`,其中 `elementCount` 
参数对处理器来说只是协助性质。
+
+每个处理器函数都返回一个 `bool`。正常它们应返回 
`true`。若处理器遇到错误,它可以返回 `false` 
去通知事件发送方停止继续处理。
+
+例如,当我们用 `Reader` 解析一个 JSON 时,处理器检测到该 
JSON 并不符合所需的 schema,那么处理器可以返回 `false`,令 
`Reader` 停止之后的解析工作。而 `Reader` 会进å…
¥ä¸€ä¸ªé”™è¯¯çŠ¶æ€ï¼Œå¹¶ä»¥ `kParseErrorTermination` 错误码标识。
+
+## GenericReader {#GenericReader}
+
+前面提及,`Reader` 是 `GenericReader` 模板类的 typedef:
+
+~~~~~~~~~~cpp
+namespace rapidjson {
+
+template <typename SourceEncoding, typename TargetEncoding, typename Allocator 
= MemoryPoolAllocator<> >
+class GenericReader {
+    // ...
+};
+
+typedef GenericReader<UTF8<>, UTF8<> > Reader;
+
+} // namespace rapidjson
+~~~~~~~~~~
+
+`Reader` 使用 UTF-8 作为来源及目标编码。来源编码是指 JSON 
流的编码。目标编码是指 `String()` 的 `str` 参数所用的编ç 
ã€‚例如,要解析一个 UTF-8 流并输出至 UTF-16 string 事件,你
需要这么定义一个 reader:
+
+~~~~~~~~~~cpp
+GenericReader<UTF8<>, UTF16<> > reader;
+~~~~~~~~~~
+
+注意到 `UTF16` 的缺省类型是 `wchar_t`。因此这个 `reader` 
需要调用处理器的 `String(const wchar_t*, SizeType, bool)`。
+
+第三个模板参数 `Allocator` 是内部数据结构(实际上是一个å 
†æ ˆï¼‰çš„分配器类型。
+
+## 解析 {#SaxParsing}
+
+`Reader` 的唯一功能就是解析 JSON。 
+
+~~~~~~~~~~cpp
+template <unsigned parseFlags, typename InputStream, typename Handler>
+bool Parse(InputStream& is, Handler& handler);
+
+// 使用 parseFlags = kDefaultParseFlags
+template <typename InputStream, typename Handler>
+bool Parse(InputStream& is, Handler& handler);
+~~~~~~~~~~
+
+若在解析中出现错误,它会返回 `false`。使用者可调用 `bool 
HasParseEror()`, `ParseErrorCode GetParseErrorCode()` 及 `size_t 
GetErrorOffset()` 获取错误状态。实际上 `Document` 使用这些 
`Reader` 函数去获取解析错误。请参考 [DOM](doc/dom.zh-cn.md) 
去了解有关解析错误的细节。
+
+# Writer {#Writer}
+
+`Reader` 把 JSON 转换(解析)成为事件。`Writer` 做完å…
¨ç›¸åçš„事情。它把事件转换成 JSON。
+
+`Writer` 是非常容易使用的。若你
的应用程序只需把一些数据转换成 JSON,可能直接使用 
`Writer`,会比建立一个 `Document` 然后用 `Writer` 把它转换成 
JSON 更加方便。
+
+在 `simplewriter` 例子里,我们做 `simplereader` 完全相反的事情
。
+
+~~~~~~~~~~cpp
+#include "rapidjson/writer.h"
+#include "rapidjson/stringbuffer.h"
+#include <iostream>
+
+using namespace rapidjson;
+using namespace std;
+
+void main() {
+    StringBuffer s;
+    Writer<StringBuffer> writer(s);
+    
+    writer.StartObject();
+    writer.Key("hello");
+    writer.String("world");
+    writer.Key("t");
+    writer.Bool(true);
+    writer.Key("f");
+    writer.Bool(false);
+    writer.Key("n");
+    writer.Null();
+    writer.Key("i");
+    writer.Uint(123);
+    writer.Key("pi");
+    writer.Double(3.1416);
+    writer.Key("a");
+    writer.StartArray();
+    for (unsigned i = 0; i < 4; i++)
+        writer.Uint(i);
+    writer.EndArray();
+    writer.EndObject();
+
+    cout << s.GetString() << endl;
+}
+~~~~~~~~~~
+
+~~~~~~~~~~
+{"hello":"world","t":true,"f":false,"n":null,"i":123,"pi":3.1416,"a":[0,1,2,3]}
+~~~~~~~~~~
+
+`String()` 及 `Key()` 各有两个重载。一个是如处理器 concept 
般,有 3 
个参数。它能处理含空字符的字符串。另一个是如上中使用的较简单版本。
+
+注意到,例子代码中的 `EndArray()` 及 `EndObject()` 
并没有参数。可以传递一个 `SizeType` 的参数,但它会被 
`Writer` 忽略。
+
+你可能会怀疑,为什么不使用 `sprintf()` 或 `std::stringstream` 
去建立一个 JSON?
+
+这有几个原因:
+1. `Writer` 必然会输出一个结构良好(well-formed)的 
JSON。若然有错误的事件次序(如 `Int()` 紧随 `StartObject()` 
出现),它会在调试模式中产生断言失败。
+2. `Writer::String()` 可处理字符串转义(如把码点 `U+000A` 
转换成 `\n`)及进行 Unicode 转码。
+3. `Writer` 一致地处理 number 的输出。
+4. `Writer` 实现了事件处理器 concept。可用于处理来自 
`Reader`、`Document` 或其他事件发生器。
+5. `Writer` 可对不同平台进行优化。
+
+无论如何,使用 `Writer` API 去生成 JSON 
甚至乎比这些临时方法更简单。
+
+## 模板 {#WriterTemplate}
+
+`Writer` 与 `Reader` 有少许设计区别。`Writer` 
是一个模板类,而不是一个 typedef。 并没有 
`GenericWriter`。以下是 `Writer` 的声明。
+
+~~~~~~~~~~cpp
+namespace rapidjson {
+
+template<typename OutputStream, typename SourceEncoding = UTF8<>, typename 
TargetEncoding = UTF8<>, typename Allocator = CrtAllocator<> >
+class Writer {
+public:
+    Writer(OutputStream& os, Allocator* allocator = 0, size_t levelDepth = 
kDefaultLevelDepth)
+// ...
+};
+
+} // namespace rapidjson
+~~~~~~~~~~
+
+`OutputStream` 
模板参数是输出流的类型。它的类型不可以被自动推断,必
须由使用者提供。
+
+`SourceEncoding` 模板参数指定了 `String(const Ch*, ...)` 的编码。
+
+`TargetEncoding` 模板参数指定输出流的编码。
+
+`Allocator` 是分配器的类型,用于分配内部数据结构(一个å 
†æ ˆï¼‰ã€‚
+
+`writeFlags` 是以下位标志的组合:
+
+写入位标志                     | 意义
+------------------------------|-----------------------------------
+`kWriteNoFlags`               | 没有任何标志。
+`kWriteDefaultFlags`          | 缺省的解析选项。它等于 
`RAPIDJSON_WRITE_DEFAULT_FLAGS` 宏,此宏定义为  `kWriteNoFlags`。
+`kWriteValidateEncodingFlag`  | 校验 JSON 字符串的编码。
+`kWriteNanAndInfFlag`         | 容许写入 `Infinity`, `-Infinity` 及 
`NaN`。
+
+此外,`Writer` 的构造函数有一 `levelDepth` 
参数。存储每层阶信息的初始内存分配量受此参数影响。
+
+## PrettyWriter {#PrettyWriter}
+
+`Writer` 所输出的是没有空格字符的最紧凑 JSON,适合网络传
输或储存,但不适合人类阅读。
+
+因此,RapidJSON 提供了一个 `PrettyWriter`,它在输出中加å…
¥ç¼©è¿›åŠæ¢è¡Œã€‚
+
+`PrettyWriter` 的用法与 `Writer` 几乎一样,不同之处是 
`PrettyWriter` 提供了一个 `SetIndent(Ch indentChar, unsigned 
indentCharCount)` 函数。缺省的缩进是 4 个空格。
+
+## 完整性及重置 {#CompletenessReset}
+
+一个 `Writer` 只可输出单个 JSON,其根节点可以是任何 JSON 
类型。当处理完单个根节点事件(如 `String()`),或匹é…
çš„最后 `EndObject()` 或 `EndArray()` 事件,输出的 JSON 
是结构完整(well-formed)及完整的。使用者可调用 
`Writer::IsComplete()` 去检测完整性。
+
+当 JSON 完整时,`Writer` 不能再接受新的事件。不然å…
¶è¾“出便会是不合法的(例如有超过一个æ 
¹èŠ‚点)。为了重新利用 `Writer` 对象,使用者可调用 
`Writer::Reset(OutputStream& os)` 去重置其所有内
部状态及设置新的输出流。
+
+# 技巧 {#SaxTechniques}
+
+## 解析 JSON 至自定义结构 {#CustomDataStructure}
+
+`Document` 的解析功能完全依靠 `Reader`。实际上 `Document` 
是一个处理器,在解析 JSON 时接收事件去建立一个 DOM。
+
+使用者可以直接使用 `Reader` 去建立å…
¶ä»–数据结构。这消除了建立 DOM 的步骤,从而减少了内
存开销并改善性能。
+
+在以下的 `messagereader` 例子中,`ParseMessages()` 解析一个 
JSON,该 JSON 应该是一个含键值对的 object。
+
+~~~~~~~~~~cpp
+#include "rapidjson/reader.h"
+#include "rapidjson/error/en.h"
+#include <iostream>
+#include <string>
+#include <map>
+
+using namespace std;
+using namespace rapidjson;
+
+typedef map<string, string> MessageMap;
+
+struct MessageHandler
+    : public BaseReaderHandler<UTF8<>, MessageHandler> {
+    MessageHandler() : state_(kExpectObjectStart) {
+    }
+
+    bool StartObject() {
+        switch (state_) {
+        case kExpectObjectStart:
+            state_ = kExpectNameOrObjectEnd;
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    bool String(const char* str, SizeType length, bool) {
+        switch (state_) {
+        case kExpectNameOrObjectEnd:
+            name_ = string(str, length);
+            state_ = kExpectValue;
+            return true;
+        case kExpectValue:
+            messages_.insert(MessageMap::value_type(name_, string(str, 
length)));
+            state_ = kExpectNameOrObjectEnd;
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    bool EndObject(SizeType) { return state_ == kExpectNameOrObjectEnd; }
+
+    bool Default() { return false; } // All other events are invalid.
+
+    MessageMap messages_;
+    enum State {
+        kExpectObjectStart,
+        kExpectNameOrObjectEnd,
+        kExpectValue,
+    }state_;
+    std::string name_;
+};
+
+void ParseMessages(const char* json, MessageMap& messages) {
+    Reader reader;
+    MessageHandler handler;
+    StringStream ss(json);
+    if (reader.Parse(ss, handler))
+        messages.swap(handler.messages_);   // Only change it if success.
+    else {
+        ParseErrorCode e = reader.GetParseErrorCode();
+        size_t o = reader.GetErrorOffset();
+        cout << "Error: " << GetParseError_En(e) << endl;;
+        cout << " at offset " << o << " near '" << string(json).substr(o, 10) 
<< "...'" << endl;
+    }
+}
+
+int main() {
+    MessageMap messages;
+
+    const char* json1 = "{ \"greeting\" : \"Hello!\", \"farewell\" : 
\"bye-bye!\" }";
+    cout << json1 << endl;
+    ParseMessages(json1, messages);
+
+    for (MessageMap::const_iterator itr = messages.begin(); itr != 
messages.end(); ++itr)
+        cout << itr->first << ": " << itr->second << endl;
+
+    cout << endl << "Parse a JSON with invalid schema." << endl;
+    const char* json2 = "{ \"greeting\" : \"Hello!\", \"farewell\" : 
\"bye-bye!\", \"foo\" : {} }";
+    cout << json2 << endl;
+    ParseMessages(json2, messages);
+
+    return 0;
+}
+~~~~~~~~~~
+
+~~~~~~~~~~
+{ "greeting" : "Hello!", "farewell" : "bye-bye!" }
+farewell: bye-bye!
+greeting: Hello!
+
+Parse a JSON with invalid schema.
+{ "greeting" : "Hello!", "farewell" : "bye-bye!", "foo" : {} }
+Error: Terminate parsing due to Handler error.
+ at offset 59 near '} }...'
+~~~~~~~~~~
+
+第一个 JSON(`json1`)被成功地解析至 `MessageMap`。由于 
`MessageMap` 是一个 `std::map`,打印次序按键值排序。此次序与 
JSON 中的次序不同。
+
+在第二个 JSON(`json2`)中,`foo` 的值是一个空 
object。由于它是一个 object,`MessageHandler::StartObject()` 
会被调用。然而,在 `state_ = kExpectValue` 的情
况下,该函数会返回 `false`,并导致解析过程终止。错误代ç 
æ˜¯ `kParseErrorTermination`。
+
+## 过滤 JSON {#Filtering}
+
+如前面提及过,`Writer` 可处理 `Reader` 
发出的事件。`example/condense/condense.cpp` 例子简单地设置 
`Writer` 作为一个 `Reader` 的处理器,因此它能移除 JSON 
中的所有空白字符。`example/pretty/pretty.cpp` 例子使用同样的å…
³ç³»ï¼Œåªæ˜¯ä»¥ `PrettyWriter` 取代 `Writer`。因此 `pretty` 能够重新æ 
¼å¼åŒ– JSON,加入缩进及换行。
+
+实际上,我们可以使用 SAX 风格 API 去加å…
¥ï¼ˆå¤šä¸ªï¼‰ä¸­é—´å±‚去过滤 JSON 的内容。例如 `capitalize` 
例子可以把所有 JSON string 改为大写。
+
+~~~~~~~~~~cpp
+#include "rapidjson/reader.h"
+#include "rapidjson/writer.h"
+#include "rapidjson/filereadstream.h"
+#include "rapidjson/filewritestream.h"
+#include "rapidjson/error/en.h"
+#include <vector>
+#include <cctype>
+
+using namespace rapidjson;
+
+template<typename OutputHandler>
+struct CapitalizeFilter {
+    CapitalizeFilter(OutputHandler& out) : out_(out), buffer_() {
+    }
+
+    bool Null() { return out_.Null(); }
+    bool Bool(bool b) { return out_.Bool(b); }
+    bool Int(int i) { return out_.Int(i); }
+    bool Uint(unsigned u) { return out_.Uint(u); }
+    bool Int64(int64_t i) { return out_.Int64(i); }
+    bool Uint64(uint64_t u) { return out_.Uint64(u); }
+    bool Double(double d) { return out_.Double(d); }
+    bool RawNumber(const char* str, SizeType length, bool copy) { return 
out_.RawNumber(str, length, copy); }
+    bool String(const char* str, SizeType length, bool) { 
+        buffer_.clear();
+        for (SizeType i = 0; i < length; i++)
+            buffer_.push_back(std::toupper(str[i]));
+        return out_.String(&buffer_.front(), length, true); // true = output 
handler need to copy the string
+    }
+    bool StartObject() { return out_.StartObject(); }
+    bool Key(const char* str, SizeType length, bool copy) { return String(str, 
length, copy); }
+    bool EndObject(SizeType memberCount) { return out_.EndObject(memberCount); 
}
+    bool StartArray() { return out_.StartArray(); }
+    bool EndArray(SizeType elementCount) { return out_.EndArray(elementCount); 
}
+
+    OutputHandler& out_;
+    std::vector<char> buffer_;
+};
+
+int main(int, char*[]) {
+    // Prepare JSON reader and input stream.
+    Reader reader;
+    char readBuffer[65536];
+    FileReadStream is(stdin, readBuffer, sizeof(readBuffer));
+
+    // Prepare JSON writer and output stream.
+    char writeBuffer[65536];
+    FileWriteStream os(stdout, writeBuffer, sizeof(writeBuffer));
+    Writer<FileWriteStream> writer(os);
+
+    // JSON reader parse from the input stream and let writer generate the 
output.
+    CapitalizeFilter<Writer<FileWriteStream> > filter(writer);
+    if (!reader.Parse(is, filter)) {
+        fprintf(stderr, "\nError(%u): %s\n", 
(unsigned)reader.GetErrorOffset(), 
GetParseError_En(reader.GetParseErrorCode()));
+        return 1;
+    }
+
+    return 0;
+}
+~~~~~~~~~~
+
+注意到,不可简单地把 JSON 当作字符串去改为大写。例如:
+~~~~~~~~~~
+["Hello\nWorld"]
+~~~~~~~~~~
+
+简单地把整个 JSON 转为大写的话会产生错误的转义符:
+~~~~~~~~~~
+["HELLO\NWORLD"]
+~~~~~~~~~~
+
+而 `capitalize` 就会产生正确的结果:
+~~~~~~~~~~
+["HELLO\nWORLD"]
+~~~~~~~~~~
+
+我们还可以开发更复杂的过滤器。然而,由于 SAX 风格 API 
在某一时间点只能提供单一事件的信息,使用者
需要自行记录一些上下文信息(例如从æ 
¹èŠ‚点起的路径、储存其他相关值)。对于处理某些情况,用 
DOM 会比 SAX 更容易实现。
+

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/fd280b5c/thirdparty/rapidjson-1.1.0/doc/schema.md
----------------------------------------------------------------------
diff --git a/thirdparty/rapidjson-1.1.0/doc/schema.md 
b/thirdparty/rapidjson-1.1.0/doc/schema.md
new file mode 100644
index 0000000..a83cebc
--- /dev/null
+++ b/thirdparty/rapidjson-1.1.0/doc/schema.md
@@ -0,0 +1,237 @@
+# Schema
+
+(This feature was released in v1.1.0)
+
+JSON Schema is a draft standard for describing the format of JSON data. The 
schema itself is also JSON data. By validating a JSON structure with JSON 
Schema, your code can safely access the DOM without manually checking types, or 
whether a key exists, etc. It can also ensure that the serialized JSON conform 
to a specified schema.
+
+RapidJSON implemented a JSON Schema validator for [JSON Schema Draft 
v4](http://json-schema.org/documentation.html). If you are not familiar with 
JSON Schema, you may refer to [Understanding JSON 
Schema](http://spacetelescope.github.io/understanding-json-schema/).
+
+[TOC]
+
+## Basic Usage
+
+First of all, you need to parse a JSON Schema into `Document`, and then 
compile the `Document` into a `SchemaDocument`.
+
+Secondly, construct a `SchemaValidator` with the `SchemaDocument`. It is 
similar to a `Writer` in the sense of handling SAX events. So, you can use 
`document.Accept(validator)` to validate a document, and then check the 
validity.
+
+~~~cpp
+#include "rapidjson/schema.h"
+
+// ...
+
+Document sd;
+if (!sd.Parse(schemaJson).HasParseError()) {
+    // the schema is not a valid JSON.
+    // ...       
+}
+SchemaDocument schema(sd); // Compile a Document to SchemaDocument
+// sd is no longer needed here.
+
+Document d;
+if (!d.Parse(inputJson).HasParseError()) {
+    // the input is not a valid JSON.
+    // ...       
+}
+
+SchemaValidator validator(schema);
+if (!d.Accept(validator)) {
+    // Input JSON is invalid according to the schema
+    // Output diagnostic information
+    StringBuffer sb;
+    validator.GetInvalidSchemaPointer().StringifyUriFragment(sb);
+    printf("Invalid schema: %s\n", sb.GetString());
+    printf("Invalid keyword: %s\n", validator.GetInvalidSchemaKeyword());
+    sb.Clear();
+    validator.GetInvalidDocumentPointer().StringifyUriFragment(sb);
+    printf("Invalid document: %s\n", sb.GetString());
+}
+~~~
+
+Some notes:
+
+* One `SchemaDocment` can be referenced by multiple `SchemaValidator`s. It 
will not be modified by `SchemaValidator`s.
+* A `SchemaValidator` may be reused to validate multiple documents. To run it 
for other documents, call `validator.Reset()` first.
+
+## Validation during parsing/serialization
+
+Unlike most JSON Schema validator implementations, RapidJSON provides a 
SAX-based schema validator. Therefore, you can parse a JSON from a stream while 
validating it on the fly. If the validator encounters a JSON value that 
invalidates the supplied schema, the parsing will be terminated immediately. 
This design is especially useful for parsing large JSON files.
+
+### DOM parsing
+
+For using DOM in parsing, `Document` needs some preparation and finalizing 
tasks, in addition to receiving SAX events, thus it needs some work to route 
the reader, validator and the document. `SchemaValidatingReader` is a helper 
class that doing such work.
+
+~~~cpp
+#include "rapidjson/filereadstream.h"
+
+// ...
+SchemaDocument schema(sd); // Compile a Document to SchemaDocument
+
+// Use reader to parse the JSON
+FILE* fp = fopen("big.json", "r");
+FileReadStream is(fp, buffer, sizeof(buffer));
+
+// Parse JSON from reader, validate the SAX events, and store in d.
+Document d;
+SchemaValidatingReader<kParseDefaultFlags, FileReadStream, UTF8<> > reader(is, 
schema);
+d.Populate(reader);
+
+if (!reader.GetParseResult()) {
+    // Not a valid JSON
+    // When reader.GetParseResult().Code() == kParseErrorTermination,
+    // it may be terminated by:
+    // (1) the validator found that the JSON is invalid according to schema; or
+    // (2) the input stream has I/O error.
+
+    // Check the validation result
+    if (!reader.IsValid()) {
+        // Input JSON is invalid according to the schema
+        // Output diagnostic information
+        StringBuffer sb;
+        reader.GetInvalidSchemaPointer().StringifyUriFragment(sb);
+        printf("Invalid schema: %s\n", sb.GetString());
+        printf("Invalid keyword: %s\n", reader.GetInvalidSchemaKeyword());
+        sb.Clear();
+        reader.GetInvalidDocumentPointer().StringifyUriFragment(sb);
+        printf("Invalid document: %s\n", sb.GetString());
+    }
+}
+~~~
+
+### SAX parsing
+
+For using SAX in parsing, it is much simpler. If it only need to validate the 
JSON without further processing, it is simply:
+
+~~~
+SchemaValidator validator(schema);
+Reader reader;
+if (!reader.Parse(stream, validator)) {
+    if (!validator.IsValid()) {
+        // ...    
+    }
+}
+~~~
+
+This is exactly the method used in the 
[schemavalidator](example/schemavalidator/schemavalidator.cpp) example. The 
distinct advantage is low memory usage, no matter how big the JSON was (the 
memory usage depends on the complexity of the schema).
+
+If you need to handle the SAX events further, then you need to use the 
template class `GenericSchemaValidator` to set the output handler of the 
validator:
+
+~~~
+MyHandler handler;
+GenericSchemaValidator<SchemaDocument, MyHandler> validator(schema, handler);
+Reader reader;
+if (!reader.Parse(ss, validator)) {
+    if (!validator.IsValid()) {
+        // ...    
+    }
+}
+~~~
+
+### Serialization
+
+It is also possible to do validation during serializing. This can ensure the 
result JSON is valid according to the JSON schema.
+
+~~~
+StringBuffer sb;
+Writer<StringBuffer> writer(sb);
+GenericSchemaValidator<SchemaDocument, Writer<StringBuffer> > validator(s, 
writer);
+if (!d.Accept(validator)) {
+    // Some problem during Accept(), it may be validation or encoding issues.
+    if (!validator.IsValid()) {
+        // ...
+    }
+}
+~~~
+
+Of course, if your application only needs SAX-style serialization, it can 
simply send SAX events to `SchemaValidator` instead of `Writer`.
+
+## Remote Schema
+
+JSON Schema supports [`$ref` 
keyword](http://spacetelescope.github.io/understanding-json-schema/structuring.html),
 which is a [JSON pointer](doc/pointer.md) referencing to a local or remote 
schema. Local pointer is prefixed with `#`, while remote pointer is an relative 
or absolute URI. For example:
+
+~~~js
+{ "$ref": "definitions.json#/address" }
+~~~
+
+As `SchemaDocument` does not know how to resolve such URI, it needs a 
user-provided `IRemoteSchemaDocumentProvider` instance to do so.
+
+~~~
+class MyRemoteSchemaDocumentProvider : public IRemoteSchemaDocumentProvider {
+public:
+    virtual const SchemaDocument* GetRemoteDocument(const char* uri, SizeTyp 
length) {
+        // Resolve the uri and returns a pointer to that schema.
+    }
+};
+
+// ...
+
+MyRemoteSchemaDocumentProvider provider;
+SchemaDocument schema(sd, &provider);
+~~~
+
+## Conformance
+
+RapidJSON passed 262 out of 263 tests in [JSON Schema Test 
Suite](https://github.com/json-schema/JSON-Schema-Test-Suite) (Json Schema 
draft 4).
+
+The failed test is "changed scope ref invalid" of "change resolution scope" in 
`refRemote.json`. It is due to that `id` schema keyword and URI combining 
function are not implemented.
+
+Besides, the `format` schema keyword for string values is ignored, since it is 
not required by the specification.
+
+### Regular Expression
+
+The schema keyword `pattern` and `patternProperties` uses regular expression 
to match the required pattern.
+
+RapidJSON implemented a simple NFA regular expression engine, which is used by 
default. It supports the following syntax.
+
+|Syntax|Description|
+|------|-----------|
+|`ab`    | Concatenation |
+|`a|b`   | Alternation |
+|`a?`    | Zero or one |
+|`a*`    | Zero or more |
+|`a+`    | One or more |
+|`a{3}`  | Exactly 3 times |
+|`a{3,}` | At least 3 times |
+|`a{3,5}`| 3 to 5 times |
+|`(ab)`  | Grouping |
+|`^a`    | At the beginning |
+|`a$`    | At the end |
+|`.`     | Any character |
+|`[abc]` | Character classes |
+|`[a-c]` | Character class range |
+|`[a-z0-9_]` | Character class combination |
+|`[^abc]` | Negated character classes |
+|`[^a-c]` | Negated character class range |
+|`[\b]`   | Backspace (U+0008) |
+|`\|`, `\\`, ...  | Escape characters |
+|`\f` | Form feed (U+000C) |
+|`\n` | Line feed (U+000A) |
+|`\r` | Carriage return (U+000D) |
+|`\t` | Tab (U+0009) |
+|`\v` | Vertical tab (U+000B) |
+
+For C++11 compiler, it is also possible to use the `std::regex` by defining 
`RAPIDJSON_SCHEMA_USE_INTERNALREGEX=0` and `RAPIDJSON_SCHEMA_USE_STDREGEX=1`. 
If your schemas do not need `pattern` and `patternProperties`, you can set both 
macros to zero to disable this feature, which will reduce some code size.
+
+## Performance
+
+Most C++ JSON libraries do not yet support JSON Schema. So we tried to 
evaluate the performance of RapidJSON's JSON Schema validator according to 
[json-schema-benchmark](https://github.com/ebdrup/json-schema-benchmark), which 
tests 11 JavaScript libraries running on Node.js.
+
+That benchmark runs validations on [JSON Schema Test 
Suite](https://github.com/json-schema/JSON-Schema-Test-Suite), in which some 
test suites and tests are excluded. We made the same benchmarking procedure in 
[`schematest.cpp`](test/perftest/schematest.cpp).
+
+On a Mac Book Pro (2.8 GHz Intel Core i7), the following results are collected.
+
+|Validator|Relative speed|Number of test runs per second|
+|---------|:------------:|:----------------------------:|
+|RapidJSON|155%|30682|
+|[`ajv`](https://github.com/epoberezkin/ajv)|100%|19770 (± 1.31%)|
+|[`is-my-json-valid`](https://github.com/mafintosh/is-my-json-valid)|70%|13835 
(± 2.84%)|
+|[`jsen`](https://github.com/bugventure/jsen)|57.7%|11411 (± 1.27%)|
+|[`schemasaurus`](https://github.com/AlexeyGrishin/schemasaurus)|26%|5145 (± 
1.62%)|
+|[`themis`](https://github.com/playlyfe/themis)|19.9%|3935 (± 2.69%)|
+|[`z-schema`](https://github.com/zaggino/z-schema)|7%|1388 (± 0.84%)|
+|[`jsck`](https://github.com/pandastrike/jsck#readme)|3.1%|606 (± 2.84%)|
+|[`jsonschema`](https://github.com/tdegrunt/jsonschema#readme)|0.9%|185 (± 
1.01%)|
+|[`skeemas`](https://github.com/Prestaul/skeemas#readme)|0.8%|154 (± 0.79%)|
+|tv4|0.5%|93 (± 0.94%)|
+|[`jayschema`](https://github.com/natesilva/jayschema)|0.1%|21 (± 1.14%)|
+
+That is, RapidJSON is about 1.5x faster than the fastest JavaScript library 
(ajv). And 1400x faster than the slowest one.

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/fd280b5c/thirdparty/rapidjson-1.1.0/doc/schema.zh-cn.md
----------------------------------------------------------------------
diff --git a/thirdparty/rapidjson-1.1.0/doc/schema.zh-cn.md 
b/thirdparty/rapidjson-1.1.0/doc/schema.zh-cn.md
new file mode 100644
index 0000000..a01c1b1
--- /dev/null
+++ b/thirdparty/rapidjson-1.1.0/doc/schema.zh-cn.md
@@ -0,0 +1,237 @@
+# Schema
+
+(本功能于 v1.1.0 发布)
+
+JSON Schema 是描述 JSON 格式的一个标准草案。一个 schema 
本身也是一个 JSON。使用 JSON Schema 去校验 JSON,可以让你
的代码安全地访问 DOM,而无
须检查类型或键值是否存在等。这也能确保输出的 JSON 
是符合指定的 schema。
+
+RapidJSON 实现了一个 [JSON Schema Draft 
v4](http://json-schema.org/documentation.html) 的校验器。若你不熟悉 
JSON Schema,可以参考 [Understanding JSON 
Schema](http://spacetelescope.github.io/understanding-json-schema/)。
+
+[TOC]
+
+## 基本用法
+
+首先,你要把 JSON Schema 解析成 `Document`,再把它编译成一个 
`SchemaDocument`。
+
+然后,利用该 `SchemaDocument` 创建一个 `SchemaValidator`。它与 
`Writer` 相似,都是能够处理 SAX 事件的。因此,你可以用 
`document.Accept(validator)` 去校验一个 JSON,然后再获取æ 
¡éªŒç»“果。
+
+~~~cpp
+#include "rapidjson/schema.h"
+
+// ...
+
+Document sd;
+if (!sd.Parse(schemaJson).HasParseError()) {
+    // 此 schema 不是合法的 JSON
+    // ...       
+}
+SchemaDocument schema(sd); // 把一个 Document 编译至 SchemaDocument
+// 之后不再需要 sd
+
+Document d;
+if (!d.Parse(inputJson).HasParseError()) {
+    // 输入不是一个合法的 JSON
+    // ...       
+}
+
+SchemaValidator validator(schema);
+if (!d.Accept(validator)) {
+    // 输入的 JSON 不合乎 schema
+    // 打印诊断信息
+    StringBuffer sb;
+    validator.GetInvalidSchemaPointer().StringifyUriFragment(sb);
+    printf("Invalid schema: %s\n", sb.GetString());
+    printf("Invalid keyword: %s\n", validator.GetInvalidSchemaKeyword());
+    sb.Clear();
+    validator.GetInvalidDocumentPointer().StringifyUriFragment(sb);
+    printf("Invalid document: %s\n", sb.GetString());
+}
+~~~
+
+一些注意点:
+
+* 一个 `SchemaDocment` 能被多个 `SchemaValidator` 引用。它不会被 
`SchemaValidator` 修改。
+* 可以重复使用一个 `SchemaValidator` 来校验多个文件。在æ 
¡éªŒå…¶ä»–文件前,须先调用 `validator.Reset()`。
+
+## 在解析/生成时进行校验
+
+与大部分 JSON Schema 校验器有所不同,RapidJSON 
提供了一个基于 SAX 的 schema 校验器实现。因此,你
可以在输入流解析 JSON 的同时进行校验。若æ 
¡éªŒå™¨é‡åˆ°ä¸€ä¸ªä¸Ž schema 
不符的值,就会立即终止解析。这设计对于解析大型 JSON 
文件时特别有用。
+
+### DOM 解析
+
+在使用 DOM 进行解析时,`Document` 除了接收 SAX 
事件外,还需做一些准备及结束工作,因此,为了连接 
`Reader`、`SchemaValidator` 和 `Document` 要做多一点事情
。`SchemaValidatingReader` 是一个辅助类去做那些工作。
+
+~~~cpp
+#include "rapidjson/filereadstream.h"
+
+// ...
+SchemaDocument schema(sd); // 把一个 Document 编译至 SchemaDocument
+
+// 使用 reader 解析 JSON
+FILE* fp = fopen("big.json", "r");
+FileReadStream is(fp, buffer, sizeof(buffer));
+
+// 用 reader 解析 JSON,校验它的 SAX 事件,并存储至 d
+Document d;
+SchemaValidatingReader<kParseDefaultFlags, FileReadStream, UTF8<> > reader(is, 
schema);
+d.Populate(reader);
+
+if (!reader.GetParseResult()) {
+    // 不是一个合法的 JSON
+    // 当 reader.GetParseResult().Code() == kParseErrorTermination,
+    // 它可能是被以下原因中止:
+    // (1) 校验器发现 JSON 不合乎 schema;或
+    // (2) 输入流有 I/O 错误。
+
+    // 检查校验结果
+    if (!reader.IsValid()) {
+        // 输入的 JSON 不合乎 schema
+        // 打印诊断信息
+        StringBuffer sb;
+        reader.GetInvalidSchemaPointer().StringifyUriFragment(sb);
+        printf("Invalid schema: %s\n", sb.GetString());
+        printf("Invalid keyword: %s\n", reader.GetInvalidSchemaKeyword());
+        sb.Clear();
+        reader.GetInvalidDocumentPointer().StringifyUriFragment(sb);
+        printf("Invalid document: %s\n", sb.GetString());
+    }
+}
+~~~
+
+### SAX 解析
+
+使用 SAX 解析时,情况就简单得多。若只需要校验 JSON 而无
需进一步处理,那么仅需要:
+
+~~~
+SchemaValidator validator(schema);
+Reader reader;
+if (!reader.Parse(stream, validator)) {
+    if (!validator.IsValid()) {
+        // ...    
+    }
+}
+~~~
+
+这种方式和 [schemavalidator](example/schemavalidator/schemavalidator.cpp) 
例子完全相同。这带来的独特优势是,无论 JSON 
多巨大,永远维持低内存用量(内存用量只与 Schema 
的复杂度相关)。
+
+若你需要进一步处理 SAX 事件,便可使用模板类 
`GenericSchemaValidator` 去设置校验器的输出 `Handler`:
+
+~~~
+MyHandler handler;
+GenericSchemaValidator<SchemaDocument, MyHandler> validator(schema, handler);
+Reader reader;
+if (!reader.Parse(ss, validator)) {
+    if (!validator.IsValid()) {
+        // ...    
+    }
+}
+~~~
+
+### 生成
+
+我们也可以在生成(serialization)的时候进行æ 
¡éªŒã€‚这能确保输出的 JSON 符合一个 JSON Schema。
+
+~~~
+StringBuffer sb;
+Writer<StringBuffer> writer(sb);
+GenericSchemaValidator<SchemaDocument, Writer<StringBuffer> > validator(s, 
writer);
+if (!d.Accept(validator)) {
+    // Some problem during Accept(), it may be validation or encoding issues.
+    if (!validator.IsValid()) {
+        // ...
+    }
+}
+~~~
+
+当然,如果你的应用仅需要 SAX 风格的生成,那么只需要把 
SAX 事件由原来发送到 `Writer`,改为发送到 `SchemaValidator`。
+
+## 远程 Schema
+
+JSON Schema 支持 [`$ref` å…
³é”®å­—](http://spacetelescope.github.io/understanding-json-schema/structuring.html),它是一个
 [JSON pointer](doc/pointer.zh-cn.md) 
引用至一个本地(local)或远程(remote) 
schema。本地指针的首字符是 
`#`,而远程指针是一个相对或绝对 URI。例如:
+
+~~~js
+{ "$ref": "definitions.json#/address" }
+~~~
+
+由于 `SchemaDocument` 并不知道如何处理那些 URI,它需要使用者
提供一个 `IRemoteSchemaDocumentProvider` 的实例去处理。
+
+~~~
+class MyRemoteSchemaDocumentProvider : public IRemoteSchemaDocumentProvider {
+public:
+    virtual const SchemaDocument* GetRemoteDocument(const char* uri, SizeTyp 
length) {
+        // Resolve the uri and returns a pointer to that schema.
+    }
+};
+
+// ...
+
+MyRemoteSchemaDocumentProvider provider;
+SchemaDocument schema(sd, &provider);
+~~~
+
+## 标准的符合程度
+
+RapidJSON 通过了 [JSON Schema Test 
Suite](https://github.com/json-schema/JSON-Schema-Test-Suite) (Json Schema 
draft 4) 中 263 个测试的 262 个。
+
+没通过的测试是 `refRemote.json` 中的 "change resolution scope" - 
"changed scope ref invalid"。这是由于未实现 `id` schema 关键字及 
URI 合并功能。
+
+除此以外,关于字符串类型的 `format` schema å…
³é”®å­—也会被忽略,因为标准中并没需求必须实现。
+
+### 正则表达式
+
+`pattern` 及 `patternProperties` 这两个 schema å…
³é”®å­—使用了正则表达式去匹配所需的模式。
+
+RapidJSON 实现了一个简单的 NFA 
正则表达式引擎,并预设使用。它支持以下语法。
+
+|语法|描述|
+|------|-----------|
+|`ab`    | 串联 |
+|`a|b`   | 交替 |
+|`a?`    | 零或一次 |
+|`a*`    | 零或多次 |
+|`a+`    | 一或多次 |
+|`a{3}`  | 刚好 3 次 |
+|`a{3,}` | 至少 3 次 |
+|`a{3,5}`| 3 至 5 次 |
+|`(ab)`  | 分组 |
+|`^a`    | 在开始处 |
+|`a$`    | 在结束处 |
+|`.`     | 任何字符 |
+|`[abc]` | 字符组 |
+|`[a-c]` | 字符组范围 |
+|`[a-z0-9_]` | 字符组组合 |
+|`[^abc]` | 字符组取反 |
+|`[^a-c]` | 字符组范围取反 |
+|`[\b]`   | 退格符 (U+0008) |
+|`\|`, `\\`, ...  | 转义字符 |
+|`\f` | 馈页 (U+000C) |
+|`\n` | 馈行 (U+000A) |
+|`\r` | 回车 (U+000D) |
+|`\t` | 制表 (U+0009) |
+|`\v` | 垂直制表 (U+000B) |
+
+对于使用 C++11 编译器的使用者,也可使用 
`std::regex`,只需定义 `RAPIDJSON_SCHEMA_USE_INTERNALREGEX=0` 及 
`RAPIDJSON_SCHEMA_USE_STDREGEX=1`。若你的 schema 无需使用 `pattern` 或 
`patternProperties`,可以把两个宏都设为零,以禁用此功能,这æ
 ·åšå¯èŠ‚省一些代码体积。
+
+## 性能
+
+大部分 C++ JSON 库都未支持 JSON Schema。因此我们尝试按照 
[json-schema-benchmark](https://github.com/ebdrup/json-schema-benchmark) 
去评估 RapidJSON 的 JSON Schema 校验器。该评测测试了 11 
个运行在 node.js 上的 JavaScript 库。
+
+该评测校验 [JSON Schema Test 
Suite](https://github.com/json-schema/JSON-Schema-Test-Suite) 
中的测试,当中排除了一些测试套件及个别测试。我们在 
[`schematest.cpp`](test/perftest/schematest.cpp) 实现了相同的评测。
+
+在 MacBook Pro (2.8 GHz Intel Core i7) 上收集到以下结果。
+
+|校验器|相对速度|每秒执行的测试数目|
+|---------|:------------:|:----------------------------:|
+|RapidJSON|155%|30682|
+|[`ajv`](https://github.com/epoberezkin/ajv)|100%|19770 (± 1.31%)|
+|[`is-my-json-valid`](https://github.com/mafintosh/is-my-json-valid)|70%|13835 
(± 2.84%)|
+|[`jsen`](https://github.com/bugventure/jsen)|57.7%|11411 (± 1.27%)|
+|[`schemasaurus`](https://github.com/AlexeyGrishin/schemasaurus)|26%|5145 (± 
1.62%)|
+|[`themis`](https://github.com/playlyfe/themis)|19.9%|3935 (± 2.69%)|
+|[`z-schema`](https://github.com/zaggino/z-schema)|7%|1388 (± 0.84%)|
+|[`jsck`](https://github.com/pandastrike/jsck#readme)|3.1%|606 (± 2.84%)|
+|[`jsonschema`](https://github.com/tdegrunt/jsonschema#readme)|0.9%|185 (± 
1.01%)|
+|[`skeemas`](https://github.com/Prestaul/skeemas#readme)|0.8%|154 (± 0.79%)|
+|tv4|0.5%|93 (± 0.94%)|
+|[`jayschema`](https://github.com/natesilva/jayschema)|0.1%|21 (± 1.14%)|
+
+换言之,RapidJSON 比最快的 JavaScript 库(ajv)快约 
1.5x。比最慢的快 1400x。

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/fd280b5c/thirdparty/rapidjson-1.1.0/doc/stream.md
----------------------------------------------------------------------
diff --git a/thirdparty/rapidjson-1.1.0/doc/stream.md 
b/thirdparty/rapidjson-1.1.0/doc/stream.md
new file mode 100644
index 0000000..b79ce53
--- /dev/null
+++ b/thirdparty/rapidjson-1.1.0/doc/stream.md
@@ -0,0 +1,426 @@
+# Stream
+
+In RapidJSON, `rapidjson::Stream` is a concept for reading/writing JSON. Here 
we first show how to use streams provided. And then see how to create a custom 
stream.
+
+[TOC]
+
+# Memory Streams {#MemoryStreams}
+
+Memory streams store JSON in memory.
+
+## StringStream (Input) {#StringStream}
+
+`StringStream` is the most basic input stream. It represents a complete, 
read-only JSON stored in memory. It is defined in `rapidjson/rapidjson.h`.
+
+~~~~~~~~~~cpp
+#include "rapidjson/document.h" // will include "rapidjson/rapidjson.h"
+
+using namespace rapidjson;
+
+// ...
+const char json[] = "[1, 2, 3, 4]";
+StringStream s(json);
+
+Document d;
+d.ParseStream(s);
+~~~~~~~~~~
+
+Since this is very common usage, `Document::Parse(const char*)` is provided to 
do exactly the same as above:
+
+~~~~~~~~~~cpp
+// ...
+const char json[] = "[1, 2, 3, 4]";
+Document d;
+d.Parse(json);
+~~~~~~~~~~
+
+Note that, `StringStream` is a typedef of `GenericStringStream<UTF8<> >`, user 
may use another encodings to represent the character set of the stream.
+
+## StringBuffer (Output) {#StringBuffer}
+
+`StringBuffer` is a simple output stream. It allocates a memory buffer for 
writing the whole JSON. Use `GetString()` to obtain the buffer.
+
+~~~~~~~~~~cpp
+#include "rapidjson/stringbuffer.h"
+
+StringBuffer buffer;
+Writer<StringBuffer> writer(buffer);
+d.Accept(writer);
+
+const char* output = buffer.GetString();
+~~~~~~~~~~
+
+When the buffer is full, it will increases the capacity automatically. The 
default capacity is 256 characters (256 bytes for UTF8, 512 bytes for UTF16, 
etc.). User can provide an allocator and a initial capacity.
+
+~~~~~~~~~~cpp
+StringBuffer buffer1(0, 1024); // Use its allocator, initial size = 1024
+StringBuffer buffer2(allocator, 1024);
+~~~~~~~~~~
+
+By default, `StringBuffer` will instantiate an internal allocator.
+
+Similarly, `StringBuffer` is a typedef of `GenericStringBuffer<UTF8<> >`.
+
+# File Streams {#FileStreams}
+
+When parsing a JSON from file, you may read the whole JSON into memory and use 
``StringStream`` above.
+
+However, if the JSON is big, or memory is limited, you can use 
`FileReadStream`. It only read a part of JSON from file into buffer, and then 
let the part be parsed. If it runs out of characters in the buffer, it will 
read the next part from file.
+
+## FileReadStream (Input) {#FileReadStream}
+
+`FileReadStream` reads the file via a `FILE` pointer. And user need to provide 
a buffer.
+
+~~~~~~~~~~cpp
+#include "rapidjson/filereadstream.h"
+#include <cstdio>
+
+using namespace rapidjson;
+
+FILE* fp = fopen("big.json", "rb"); // non-Windows use "r"
+
+char readBuffer[65536];
+FileReadStream is(fp, readBuffer, sizeof(readBuffer));
+
+Document d;
+d.ParseStream(is);
+
+fclose(fp);
+~~~~~~~~~~
+
+Different from string streams, `FileReadStream` is byte stream. It does not 
handle encodings. If the file is not UTF-8, the byte stream can be wrapped in a 
`EncodedInputStream`. It will be discussed very soon.
+
+Apart from reading file, user can also use `FileReadStream` to read `stdin`.
+
+## FileWriteStream (Output) {#FileWriteStream}
+
+`FileWriteStream` is buffered output stream. Its usage is very similar to 
`FileReadStream`.
+
+~~~~~~~~~~cpp
+#include "rapidjson/filewritestream.h"
+#include <cstdio>
+
+using namespace rapidjson;
+
+Document d;
+d.Parse(json);
+// ...
+
+FILE* fp = fopen("output.json", "wb"); // non-Windows use "w"
+
+char writeBuffer[65536];
+FileWriteStream os(fp, writeBuffer, sizeof(writeBuffer));
+
+Writer<FileWriteStream> writer(os);
+d.Accept(writer);
+
+fclose(fp);
+~~~~~~~~~~
+
+It can also directs the output to `stdout`.
+
+# iostream Wrapper {#iostreamWrapper}
+
+Due to users' requests, RapidJSON provided official wrappers for 
`std::basic_istream` and `std::basic_ostream`. However, please note that the 
performance will be much lower than the other streams above.
+
+## IStreamWrapper {#IStreamWrapper}
+
+`IStreamWrapper` wraps any class drived from `std::istream`, such as 
`std::istringstream`, `std::stringstream`, `std::ifstream`, `std::fstream`, 
into RapidJSON's input stream.
+
+~~~cpp
+#include <rapidjson/document.h>
+#include <rapidjson/istreamwrapper.h>
+#include <fstream>
+
+using namespace rapidjson;
+using namespace std;
+
+ifstream ifs("test.json");
+IStreamWrapper isw(ifs);
+
+Document d;
+d.ParseStream(isw);
+~~~
+
+For classes derived from `std::wistream`, use `WIStreamWrapper`.
+
+## OStreamWrapper {#OStreamWrapper}
+
+Similarly, `OStreamWrapper` wraps any class derived from `std::ostream`, such 
as `std::ostringstream`, `std::stringstream`, `std::ofstream`, `std::fstream`, 
into RapidJSON's input stream.
+
+~~~cpp
+#include <rapidjson/document.h>
+#include <rapidjson/ostreamwrapper.h>
+#include <rapidjson/writer.h>
+#include <fstream>
+
+using namespace rapidjson;
+using namespace std;
+
+Document d;
+d.Parse(json);
+
+// ...
+
+ofstream ofs("output.json");
+OStreamWrapper osw(ofs);
+
+Writer<OStreamWrapper> writer(osw);
+d.Accept(writer);
+~~~
+
+For classes derived from `std::wostream`, use `WOStreamWrapper`.
+
+# Encoded Streams {#EncodedStreams}
+
+Encoded streams do not contain JSON itself, but they wrap byte streams to 
provide basic encoding/decoding function.
+
+As mentioned above, UTF-8 byte streams can be read directly. However, UTF-16 
and UTF-32 have endian issue. To handle endian correctly, it needs to convert 
bytes into characters (e.g. `wchar_t` for UTF-16) while reading, and characters 
into bytes while writing.
+
+Besides, it also need to handle [byte order mark 
(BOM)](http://en.wikipedia.org/wiki/Byte_order_mark). When reading from a byte 
stream, it is needed to detect or just consume the BOM if exists. When writing 
to a byte stream, it can optionally write BOM.
+
+If the encoding of stream is known in compile-time, you may use 
`EncodedInputStream` and `EncodedOutputStream`. If the stream can be UTF-8, 
UTF-16LE, UTF-16BE, UTF-32LE, UTF-32BE JSON, and it is only known in runtime, 
you may use `AutoUTFInputStream` and `AutoUTFOutputStream`. These streams are 
defined in `rapidjson/encodedstream.h`.
+
+Note that, these encoded streams can be applied to streams other than file. 
For example, you may have a file in memory, or a custom byte stream, be wrapped 
in encoded streams.
+
+## EncodedInputStream {#EncodedInputStream}
+
+`EncodedInputStream` has two template parameters. The first one is a 
`Encoding` class, such as `UTF8`, `UTF16LE`, defined in 
`rapidjson/encodings.h`. The second one is the class of stream to be wrapped.
+
+~~~~~~~~~~cpp
+#include "rapidjson/document.h"
+#include "rapidjson/filereadstream.h"   // FileReadStream
+#include "rapidjson/encodedstream.h"    // EncodedInputStream
+#include <cstdio>
+
+using namespace rapidjson;
+
+FILE* fp = fopen("utf16le.json", "rb"); // non-Windows use "r"
+
+char readBuffer[256];
+FileReadStream bis(fp, readBuffer, sizeof(readBuffer));
+
+EncodedInputStream<UTF16LE<>, FileReadStream> eis(bis);  // wraps bis into eis
+
+Document d; // Document is GenericDocument<UTF8<> > 
+d.ParseStream<0, UTF16LE<> >(eis);  // Parses UTF-16LE file into UTF-8 in 
memory
+
+fclose(fp);
+~~~~~~~~~~
+
+## EncodedOutputStream {#EncodedOutputStream}
+
+`EncodedOutputStream` is similar but it has a `bool putBOM` parameter in the 
constructor, controlling whether to write BOM into output byte stream.
+
+~~~~~~~~~~cpp
+#include "rapidjson/filewritestream.h"  // FileWriteStream
+#include "rapidjson/encodedstream.h"    // EncodedOutputStream
+#include <cstdio>
+
+Document d;         // Document is GenericDocument<UTF8<> > 
+// ...
+
+FILE* fp = fopen("output_utf32le.json", "wb"); // non-Windows use "w"
+
+char writeBuffer[256];
+FileWriteStream bos(fp, writeBuffer, sizeof(writeBuffer));
+
+typedef EncodedOutputStream<UTF32LE<>, FileWriteStream> OutputStream;
+OutputStream eos(bos, true);   // Write BOM
+
+Writer<OutputStream, UTF32LE<>, UTF8<>> writer(eos);
+d.Accept(writer);   // This generates UTF32-LE file from UTF-8 in memory
+
+fclose(fp);
+~~~~~~~~~~
+
+## AutoUTFInputStream {#AutoUTFInputStream}
+
+Sometimes an application may want to handle all supported JSON encoding. 
`AutoUTFInputStream` will detection encoding by BOM first. If BOM is 
unavailable, it will use  characteristics of valid JSON to make detection. If 
neither method success, it falls back to the UTF type provided in constructor.
+
+Since the characters (code units) may be 8-bit, 16-bit or 32-bit. 
`AutoUTFInputStream` requires a character type which can hold at least 32-bit. 
We may use `unsigned`, as in the template parameter:
+
+~~~~~~~~~~cpp
+#include "rapidjson/document.h"
+#include "rapidjson/filereadstream.h"   // FileReadStream
+#include "rapidjson/encodedstream.h"    // AutoUTFInputStream
+#include <cstdio>
+
+using namespace rapidjson;
+
+FILE* fp = fopen("any.json", "rb"); // non-Windows use "r"
+
+char readBuffer[256];
+FileReadStream bis(fp, readBuffer, sizeof(readBuffer));
+
+AutoUTFInputStream<unsigned, FileReadStream> eis(bis);  // wraps bis into eis
+
+Document d;         // Document is GenericDocument<UTF8<> > 
+d.ParseStream<0, AutoUTF<unsigned> >(eis); // This parses any UTF file into 
UTF-8 in memory
+
+fclose(fp);
+~~~~~~~~~~
+
+When specifying the encoding of stream, uses `AutoUTF<CharType>` as in 
`ParseStream()` above.
+
+You can obtain the type of UTF via `UTFType GetType()`. And check whether a 
BOM is found by `HasBOM()`
+
+## AutoUTFOutputStream {#AutoUTFOutputStream}
+
+Similarly, to choose encoding for output during runtime, we can use 
`AutoUTFOutputStream`. This class is not automatic *per se*. You need to 
specify the UTF type and whether to write BOM in runtime.
+
+~~~~~~~~~~cpp
+using namespace rapidjson;
+
+void WriteJSONFile(FILE* fp, UTFType type, bool putBOM, const Document& d) {
+    char writeBuffer[256];
+    FileWriteStream bos(fp, writeBuffer, sizeof(writeBuffer));
+
+    typedef AutoUTFOutputStream<unsigned, FileWriteStream> OutputStream;
+    OutputStream eos(bos, type, putBOM);
+    
+    Writer<OutputStream, UTF8<>, AutoUTF<> > writer;
+    d.Accept(writer);
+}
+~~~~~~~~~~
+
+`AutoUTFInputStream` and `AutoUTFOutputStream` is more convenient than 
`EncodedInputStream` and `EncodedOutputStream`. They just incur a little bit 
runtime overheads.
+
+# Custom Stream {#CustomStream}
+
+In addition to memory/file streams, user can create their own stream classes 
which fits RapidJSON's API. For example, you may create network stream, stream 
from compressed file, etc.
+
+RapidJSON combines different types using templates. A class containing all 
required interface can be a stream. The Stream interface is defined in comments 
of `rapidjson/rapidjson.h`:
+
+~~~~~~~~~~cpp
+concept Stream {
+    typename Ch;    //!< Character type of the stream.
+
+    //! Read the current character from stream without moving the read cursor.
+    Ch Peek() const;
+
+    //! Read the current character from stream and moving the read cursor to 
next character.
+    Ch Take();
+
+    //! Get the current read cursor.
+    //! \return Number of characters read from start.
+    size_t Tell();
+
+    //! Begin writing operation at the current read pointer.
+    //! \return The begin writer pointer.
+    Ch* PutBegin();
+
+    //! Write a character.
+    void Put(Ch c);
+
+    //! Flush the buffer.
+    void Flush();
+
+    //! End the writing operation.
+    //! \param begin The begin write pointer returned by PutBegin().
+    //! \return Number of characters written.
+    size_t PutEnd(Ch* begin);
+}
+~~~~~~~~~~
+
+For input stream, they must implement `Peek()`, `Take()` and `Tell()`.
+For output stream, they must implement `Put()` and `Flush()`. 
+There are two special interface, `PutBegin()` and `PutEnd()`, which are only 
for *in situ* parsing. Normal streams do not implement them. However, if the 
interface is not needed for a particular stream, it is still need to a dummy 
implementation, otherwise will generate compilation error.
+
+## Example: istream wrapper {#ExampleIStreamWrapper}
+
+The following example is a simple wrapper of `std::istream`, which only 
implements 3 functions.
+
+~~~~~~~~~~cpp
+class MyIStreamWrapper {
+public:
+    typedef char Ch;
+
+    MyIStreamWrapper(std::istream& is) : is_(is) {
+    }
+
+    Ch Peek() const { // 1
+        int c = is_.peek();
+        return c == std::char_traits<char>::eof() ? '\0' : (Ch)c;
+    }
+
+    Ch Take() { // 2
+        int c = is_.get();
+        return c == std::char_traits<char>::eof() ? '\0' : (Ch)c;
+    }
+
+    size_t Tell() const { return (size_t)is_.tellg(); } // 3
+
+    Ch* PutBegin() { assert(false); return 0; }
+    void Put(Ch) { assert(false); }
+    void Flush() { assert(false); }
+    size_t PutEnd(Ch*) { assert(false); return 0; }
+
+private:
+    MyIStreamWrapper(const MyIStreamWrapper&);
+    MyIStreamWrapper& operator=(const MyIStreamWrapper&);
+
+    std::istream& is_;
+};
+~~~~~~~~~~
+
+User can use it to wrap instances of `std::stringstream`, `std::ifstream`.
+
+~~~~~~~~~~cpp
+const char* json = "[1,2,3,4]";
+std::stringstream ss(json);
+MyIStreamWrapper is(ss);
+
+Document d;
+d.ParseStream(is);
+~~~~~~~~~~
+
+Note that, this implementation may not be as efficient as RapidJSON's memory 
or file streams, due to internal overheads of the standard library.
+
+## Example: ostream wrapper {#ExampleOStreamWrapper}
+
+The following example is a simple wrapper of `std::istream`, which only 
implements 2 functions.
+
+~~~~~~~~~~cpp
+class MyOStreamWrapper {
+public:
+    typedef char Ch;
+
+    MyOStreamWrapper(std::ostream& os) : os_(os) {
+    }
+
+    Ch Peek() const { assert(false); return '\0'; }
+    Ch Take() { assert(false); return '\0'; }
+    size_t Tell() const {  }
+
+    Ch* PutBegin() { assert(false); return 0; }
+    void Put(Ch c) { os_.put(c); }                  // 1
+    void Flush() { os_.flush(); }                   // 2
+    size_t PutEnd(Ch*) { assert(false); return 0; }
+
+private:
+    MyOStreamWrapper(const MyOStreamWrapper&);
+    MyOStreamWrapper& operator=(const MyOStreamWrapper&);
+
+    std::ostream& os_;
+};
+~~~~~~~~~~
+
+User can use it to wrap instances of `std::stringstream`, `std::ofstream`.
+
+~~~~~~~~~~cpp
+Document d;
+// ...
+
+std::stringstream ss;
+MyOStreamWrapper os(ss);
+
+Writer<MyOStreamWrapper> writer(os);
+d.Accept(writer);
+~~~~~~~~~~
+
+Note that, this implementation may not be as efficient as RapidJSON's memory 
or file streams, due to internal overheads of the standard library.
+
+# Summary {#Summary}
+
+This section describes stream classes available in RapidJSON. Memory streams 
are simple. File stream can reduce the memory required during JSON parsing and 
generation, if the JSON is stored in file system. Encoded streams converts 
between byte streams and character streams. Finally, user may create custom 
streams using a simple interface.

Reply via email to