// 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 class FilterKeyHandler { public: 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(); } private: FilterKeyHandler(const FilterKeyHandler&); FilterKeyHandler& operator=(const FilterKeyHandler&); 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), parseResult_() {} // SAX event flow: reader -> filter -> handler template bool operator()(Handler& handler) { FilterKeyHandler filter(handler, keyString_, keyLength_); Reader reader; parseResult_ = reader.Parse(is_, filter); return parseResult_; } const ParseResult& GetParseResult() const { return parseResult_; } private: FilterKeyReader(const FilterKeyReader&); FilterKeyReader& operator=(const FilterKeyReader&); 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; }