From 05b2ed7532bcaa17f0e2794a7fab67155d3e5cd3 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Sat, 23 Apr 2016 16:02:40 +0800 Subject: [PATCH] Add filterkey and filterkeydom examples --- example/CMakeLists.txt | 2 + example/filterkey/filterkey.cpp | 130 +++++++++++++++++++++ example/filterkeydom/filterkeydom.cpp | 161 ++++++++++++++++++++++++++ readme.md | 2 + readme.zh-cn.md | 2 + 5 files changed, 297 insertions(+) create mode 100644 example/filterkey/filterkey.cpp create mode 100644 example/filterkeydom/filterkeydom.cpp diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index fd0e6eb..4d448cc 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -7,6 +7,8 @@ endif() set(EXAMPLES capitalize condense + filterkey + filterkeydom jsonx messagereader parsebyparts diff --git a/example/filterkey/filterkey.cpp b/example/filterkey/filterkey.cpp new file mode 100644 index 0000000..1416362 --- /dev/null +++ b/example/filterkey/filterkey.cpp @@ -0,0 +1,130 @@ +// JSON filterkey example with SAX-style API. + +// This example parses JSON text from stdin with validation. +// During parsing, specified key will be filtered using a SAX handler. +// It re-output the JSON content to stdout without whitespace. + +#include "rapidjson/reader.h" +#include "rapidjson/writer.h" +#include "rapidjson/filereadstream.h" +#include "rapidjson/filewritestream.h" +#include "rapidjson/error/en.h" +#include + +using namespace rapidjson; + +// This handler forwards event into an output handler, with filtering the descendent events of specified key. +template +struct FilterKeyHandler { + typedef char Ch; + + FilterKeyHandler(OutputHandler& outputHandler, const Ch* keyString, SizeType keyLength) : + outputHandler_(outputHandler), keyString_(keyString), keyLength_(keyLength), filterValueDepth_(), filteredKeyCount_() + {} + + bool Null() { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.Null() && EndValue(); } + bool Bool(bool b) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.Bool(b) && EndValue(); } + bool Int(int i) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.Int(i) && EndValue(); } + bool Uint(unsigned u) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.Uint(u) && EndValue(); } + bool Int64(int64_t i) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.Int64(i) && EndValue(); } + bool Uint64(uint64_t u) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.Uint64(u) && EndValue(); } + bool Double(double d) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.Double(d) && EndValue(); } + bool RawNumber(const Ch* str, SizeType len, bool copy) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.RawNumber(str, len, copy) && EndValue(); } + bool String (const Ch* str, SizeType len, bool copy) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.String (str, len, copy) && EndValue(); } + + bool StartObject() { + if (filterValueDepth_ > 0) { + filterValueDepth_++; + return true; + } + else { + filteredKeyCount_.push(0); + return outputHandler_.StartObject(); + } + } + + bool Key(const Ch* str, SizeType len, bool copy) { + if (filterValueDepth_ > 0) + return true; + else if (len == keyLength_ && std::memcmp(str, keyString_, len) == 0) { + filterValueDepth_ = 1; + return true; + } + else { + ++filteredKeyCount_.top(); + return outputHandler_.Key(str, len, copy); + } + } + + bool EndObject(SizeType) { + if (filterValueDepth_ > 0) { + filterValueDepth_--; + return EndValue(); + } + else { + // Use our own filtered memberCount + SizeType memberCount = filteredKeyCount_.top(); + filteredKeyCount_.pop(); + return outputHandler_.EndObject(memberCount) && EndValue(); + } + } + + bool StartArray() { + if (filterValueDepth_ > 0) { + filterValueDepth_++; + return true; + } + else + return outputHandler_.StartArray(); + } + + bool EndArray(SizeType elementCount) { + if (filterValueDepth_ > 0) { + filterValueDepth_--; + return EndValue(); + } + else + return outputHandler_.EndArray(elementCount) && EndValue(); + } + + bool EndValue() { + if (filterValueDepth_ == 1) // Just at the end of value after filtered key + filterValueDepth_ = 0; + return true; + } + + OutputHandler& outputHandler_; + const char* keyString_; + const SizeType keyLength_; + unsigned filterValueDepth_; + std::stack filteredKeyCount_; +}; + +int main(int argc, char* argv[]) { + if (argc != 2) { + fprintf(stderr, "filterkey key < input.json > output.json\n"); + return 1; + } + + // 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 writer(os); + + // Prepare Filter + FilterKeyHandler > filter(writer, argv[1], static_cast(strlen(argv[1]))); + + // JSON reader parse from the input stream, filter handler filters the events, and forward to writer. + // i.e. the events flow is: reader -> filter -> writer + if (!reader.Parse(is, filter)) { + fprintf(stderr, "\nError(%u): %s\n", static_cast(reader.GetErrorOffset()), GetParseError_En(reader.GetParseErrorCode())); + return 1; + } + + return 0; +} diff --git a/example/filterkeydom/filterkeydom.cpp b/example/filterkeydom/filterkeydom.cpp new file mode 100644 index 0000000..aba50bd --- /dev/null +++ b/example/filterkeydom/filterkeydom.cpp @@ -0,0 +1,161 @@ +// JSON filterkey example which populates filtered SAX events into a Document. + +// This example parses JSON text from stdin with validation. +// During parsing, specified key will be filtered using a SAX handler. +// And finally the filtered events are used to populate a Document. +// As an example, the document is written to standard output. + +#include "rapidjson/document.h" +#include "rapidjson/writer.h" +#include "rapidjson/filereadstream.h" +#include "rapidjson/filewritestream.h" +#include "rapidjson/error/en.h" +#include + +using namespace rapidjson; + +// This handler forwards event into an output handler, with filtering the descendent events of specified key. +template +struct FilterKeyHandler { + typedef char Ch; + + FilterKeyHandler(OutputHandler& outputHandler, const Ch* keyString, SizeType keyLength) : + outputHandler_(outputHandler), keyString_(keyString), keyLength_(keyLength), filterValueDepth_(), filteredKeyCount_() + {} + + bool Null() { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.Null() && EndValue(); } + bool Bool(bool b) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.Bool(b) && EndValue(); } + bool Int(int i) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.Int(i) && EndValue(); } + bool Uint(unsigned u) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.Uint(u) && EndValue(); } + bool Int64(int64_t i) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.Int64(i) && EndValue(); } + bool Uint64(uint64_t u) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.Uint64(u) && EndValue(); } + bool Double(double d) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.Double(d) && EndValue(); } + bool RawNumber(const Ch* str, SizeType len, bool copy) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.RawNumber(str, len, copy) && EndValue(); } + bool String (const Ch* str, SizeType len, bool copy) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.String (str, len, copy) && EndValue(); } + + bool StartObject() { + if (filterValueDepth_ > 0) { + filterValueDepth_++; + return true; + } + else { + filteredKeyCount_.push(0); + return outputHandler_.StartObject(); + } + } + + bool Key(const Ch* str, SizeType len, bool copy) { + if (filterValueDepth_ > 0) + return true; + else if (len == keyLength_ && std::memcmp(str, keyString_, len) == 0) { + filterValueDepth_ = 1; + return true; + } + else { + ++filteredKeyCount_.top(); + return outputHandler_.Key(str, len, copy); + } + } + + bool EndObject(SizeType) { + if (filterValueDepth_ > 0) { + filterValueDepth_--; + return EndValue(); + } + else { + // Use our own filtered memberCount + SizeType memberCount = filteredKeyCount_.top(); + filteredKeyCount_.pop(); + return outputHandler_.EndObject(memberCount) && EndValue(); + } + } + + bool StartArray() { + if (filterValueDepth_ > 0) { + filterValueDepth_++; + return true; + } + else + return outputHandler_.StartArray(); + } + + bool EndArray(SizeType elementCount) { + if (filterValueDepth_ > 0) { + filterValueDepth_--; + return EndValue(); + } + else + return outputHandler_.EndArray(elementCount) && EndValue(); + } + + bool EndValue() { + if (filterValueDepth_ == 1) // Just at the end of value after filtered key + filterValueDepth_ = 0; + return true; + } + + OutputHandler& outputHandler_; + const char* keyString_; + const SizeType keyLength_; + unsigned filterValueDepth_; + std::stack filteredKeyCount_; +}; + +// Implements a generator for Document::Populate() +template +class FilterKeyReader { +public: + typedef char Ch; + + FilterKeyReader(InputStream& is, const Ch* keyString, SizeType keyLength) : + is_(is), keyString_(keyString), keyLength_(keyLength) + {} + + // SAX event flow: reader -> filter -> handler + template + bool operator()(Handler& handler) { + FilterKeyHandler filter(handler, keyString_, keyLength_); + Reader reader; + return parseResult_ = reader.Parse(is_, filter); + } + + const ParseResult& GetParseResult() const { return parseResult_; } + +private: + InputStream& is_; + const char* keyString_; + const SizeType keyLength_; + ParseResult parseResult_; +}; + +int main(int argc, char* argv[]) { + if (argc != 2) { + fprintf(stderr, "filterkeydom key < input.json > output.json\n"); + return 1; + } + + // Prepare input stream. + char readBuffer[65536]; + FileReadStream is(stdin, readBuffer, sizeof(readBuffer)); + + // Prepare Filter + FilterKeyReader reader(is, argv[1], static_cast(strlen(argv[1]))); + + // Populates the filtered events from reader + Document document; + document.Populate(reader); + ParseResult pr = reader.GetParseResult(); + if (!pr) { + fprintf(stderr, "\nError(%u): %s\n", static_cast(pr.Offset()), GetParseError_En(pr.Code())); + return 1; + } + + // Prepare JSON writer and output stream. + char writeBuffer[65536]; + FileWriteStream os(stdout, writeBuffer, sizeof(writeBuffer)); + Writer writer(os); + + // Write the document to standard output + document.Accept(writer); + return 0; +} diff --git a/readme.md b/readme.md index d7675bc..77c3b5b 100644 --- a/readme.md +++ b/readme.md @@ -146,3 +146,5 @@ More [examples](https://github.com/miloyip/rapidjson/tree/master/example) are av * Advanced * [prettyauto](https://github.com/miloyip/rapidjson/blob/master/example/prettyauto/prettyauto.cpp): A modified version of [pretty](https://github.com/miloyip/rapidjson/blob/master/example/pretty/pretty.cpp) to automatically handle JSON with any UTF encodings. * [parsebyparts](https://github.com/miloyip/rapidjson/blob/master/example/parsebyparts/parsebyparts.cpp): Implements an `AsyncDocumentParser` which can parse JSON in parts, using C++11 thread. + * [filterkey](https://github.com/miloyip/rapidjson/blob/master/example/filterkey/filterkey.cpp): A command line tool to remove all values with user-specified key. + * [filterkeydom](https://github.com/miloyip/rapidjson/blob/master/example/filterkey/filterkey.cpp): Same tool as above, but it demonstrates how to use a generator to populate a `Document`. diff --git a/readme.zh-cn.md b/readme.zh-cn.md index d7772c5..97101d1 100644 --- a/readme.zh-cn.md +++ b/readme.zh-cn.md @@ -138,3 +138,5 @@ int main() { * 进阶 * [prettyauto](https://github.com/miloyip/rapidjson/blob/master/example/prettyauto/prettyauto.cpp): [pretty](https://github.com/miloyip/rapidjson/blob/master/example/pretty/pretty.cpp) 的修改版本,可自动处理任何 UTF 编码的 JSON。 * [parsebyparts](https://github.com/miloyip/rapidjson/blob/master/example/parsebyparts/parsebyparts.cpp): 这例子中的 `AsyncDocumentParser` 类使用 C++ 线程来逐段解析 JSON。 + * [filterkey](https://github.com/miloyip/rapidjson/blob/master/example/filterkey/filterkey.cpp): 移取使用者指定的键值的命令行工具。 + * [filterkeydom](https://github.com/miloyip/rapidjson/blob/master/example/filterkey/filterkey.cpp): 如上的工具,但展示如何使用生成器(generator)去填充一个 `Document`。 \ No newline at end of file