These events can be easily match up with the JSON, except some event parameters need further explanation. Let's see the simplereader example which produces exactly the same output as above:
These events can be easily match up 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"
...
...
@@ -170,8 +170,117 @@ If an error occurs during parsing, it will return `false`. User can also calls `
# 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 of using `Writer` directly, instead of building a `Document` and then stringifying it with a `Writer`.
In `simplewriter` example, we do exactly the reverse of `simplereader`.
There is two `String()` 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. For example, user can set precision for `Double()`.
3.`Writer` implements the event handler concept. It can be used to handle events from `Reader`, `Document` or other event publisher.
4.`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.
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 last one, `Allocator` is the type of allocator, which is used for allocating internal data structure (a stack).
Besides, the constructor of `Writer` has a `levelDepth` parameter. This parameter affects the initial memory allocated for storing information per hierarchy level.
## Precision (#WriterPrecision)
When using `Double()`, the precision of output can be specified, for example:
~~~~~~~~~~cpp
writer.SetDoublePrecision(4);
writer.StartArary();
writer.Double(3.14159265359);
writer.EndArray();
~~~~~~~~~~
~~~~~~~~~~
[3.1416]
~~~~~~~~~~
## 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.
# Techniques {#Techniques}
## Parsing JSON to Custom Data Structure {#CustomDataStructure}
...
...
@@ -180,52 +289,59 @@ If an error occurs during parsing, it will return `false`. User can also calls `
User may uses `Reader` to build other data structures directly. This eliminates building of DOM, thus reducing memory and improving performance.
Example:
In the following `messagereader` example, `ParseMessages()` parses a JSON which should be an object with key-string pairs.
~~~~~~~~~~cpp
// Note: Ad hoc, not yet tested.
#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 GenericBaseHandler<> {
MessageHandler() : mState(kExpectStart) {
}
bool Default() {
return false;
struct MessageHandler : public BaseReaderHandler<> {
The first JSON (`json1`) was successfully parsed into `MessageMap`. Since it is a `std::map`, the print out are sorted by the key, which 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
TODO
~~~~~~~~~~
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.