208 lines
5.9 KiB
C++
208 lines
5.9 KiB
C++
|
// JSON to JSONx conversion example, using SAX API.
|
||
|
// JSONx is an IBM standard format to represent JSON as XML.
|
||
|
// https://www-01.ibm.com/support/knowledgecenter/SS9H2Y_7.1.0/com.ibm.dp.doc/json_jsonx.html
|
||
|
// This example parses JSON text from stdin with validation,
|
||
|
// and convert to JSONx format to stdout.
|
||
|
// Need compile with -D__STDC_FORMAT_MACROS for defining PRId64 and PRIu64 macros.
|
||
|
|
||
|
#include "rapidjson/reader.h"
|
||
|
#include "rapidjson/stringbuffer.h"
|
||
|
#include "rapidjson/filereadstream.h"
|
||
|
#include "rapidjson/filewritestream.h"
|
||
|
#include "rapidjson/error/en.h"
|
||
|
#include <cstdio>
|
||
|
|
||
|
using namespace rapidjson;
|
||
|
|
||
|
// For simplicity, this example only read/write in UTF-8 encoding
|
||
|
template <typename OutputStream>
|
||
|
class JsonxWriter {
|
||
|
public:
|
||
|
JsonxWriter(OutputStream& os) : os_(os), name_(), level_(0), hasName_(false) {
|
||
|
}
|
||
|
|
||
|
bool Null() {
|
||
|
return WriteStartElement("null", true);
|
||
|
}
|
||
|
|
||
|
bool Bool(bool b) {
|
||
|
return
|
||
|
WriteStartElement("boolean") &&
|
||
|
WriteString(b ? "true" : "false") &&
|
||
|
WriteEndElement("boolean");
|
||
|
}
|
||
|
|
||
|
bool Int(int i) {
|
||
|
char buffer[12];
|
||
|
return WriteNumberElement(buffer, sprintf(buffer, "%d", i));
|
||
|
}
|
||
|
|
||
|
bool Uint(unsigned i) {
|
||
|
char buffer[11];
|
||
|
return WriteNumberElement(buffer, sprintf(buffer, "%u", i));
|
||
|
}
|
||
|
|
||
|
bool Int64(int64_t i) {
|
||
|
char buffer[21];
|
||
|
return WriteNumberElement(buffer, sprintf(buffer, "%" PRId64, i));
|
||
|
}
|
||
|
|
||
|
bool Uint64(uint64_t i) {
|
||
|
char buffer[21];
|
||
|
return WriteNumberElement(buffer, sprintf(buffer, "%" PRIu64, i));
|
||
|
}
|
||
|
|
||
|
bool Double(double d) {
|
||
|
char buffer[30];
|
||
|
return WriteNumberElement(buffer, sprintf(buffer, "%.17g", d));
|
||
|
}
|
||
|
|
||
|
bool RawNumber(const char* str, SizeType length, bool) {
|
||
|
return
|
||
|
WriteStartElement("number") &&
|
||
|
WriteEscapedText(str, length) &&
|
||
|
WriteEndElement("number");
|
||
|
}
|
||
|
|
||
|
bool String(const char* str, SizeType length, bool) {
|
||
|
return
|
||
|
WriteStartElement("string") &&
|
||
|
WriteEscapedText(str, length) &&
|
||
|
WriteEndElement("string");
|
||
|
}
|
||
|
|
||
|
bool StartObject() {
|
||
|
return WriteStartElement("object");
|
||
|
}
|
||
|
|
||
|
bool Key(const char* str, SizeType length, bool) {
|
||
|
// backup key to name_
|
||
|
name_.Clear();
|
||
|
for (SizeType i = 0; i < length; i++)
|
||
|
name_.Put(str[i]);
|
||
|
hasName_ = true;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool EndObject(SizeType) {
|
||
|
return WriteEndElement("object");
|
||
|
}
|
||
|
|
||
|
bool StartArray() {
|
||
|
return WriteStartElement("array");
|
||
|
}
|
||
|
|
||
|
bool EndArray(SizeType) {
|
||
|
return WriteEndElement("array");
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
bool WriteString(const char* s) {
|
||
|
while (*s)
|
||
|
os_.Put(*s++);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool WriteEscapedAttributeValue(const char* s, size_t length) {
|
||
|
for (size_t i = 0; i < length; i++) {
|
||
|
switch (s[i]) {
|
||
|
case '&': WriteString("&"); break;
|
||
|
case '<': WriteString("<"); break;
|
||
|
case '"': WriteString("""); break;
|
||
|
default: os_.Put(s[i]); break;
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool WriteEscapedText(const char* s, size_t length) {
|
||
|
for (size_t i = 0; i < length; i++) {
|
||
|
switch (s[i]) {
|
||
|
case '&': WriteString("&"); break;
|
||
|
case '<': WriteString("<"); break;
|
||
|
default: os_.Put(s[i]); break;
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool WriteStartElement(const char* type, bool emptyElement = false) {
|
||
|
if (level_ == 0)
|
||
|
if (!WriteString("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"))
|
||
|
return false;
|
||
|
|
||
|
if (!WriteString("<json:") || !WriteString(type))
|
||
|
return false;
|
||
|
|
||
|
// For root element, need to add declarations
|
||
|
if (level_ == 0) {
|
||
|
if (!WriteString(
|
||
|
" xsi:schemaLocation=\"http://www.datapower.com/schemas/json jsonx.xsd\""
|
||
|
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
|
||
|
" xmlns:json=\"http://www.ibm.com/xmlns/prod/2009/jsonx\""))
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (hasName_) {
|
||
|
hasName_ = false;
|
||
|
if (!WriteString(" name=\"") ||
|
||
|
!WriteEscapedAttributeValue(name_.GetString(), name_.GetSize()) ||
|
||
|
!WriteString("\""))
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (emptyElement)
|
||
|
return WriteString("/>");
|
||
|
else {
|
||
|
level_++;
|
||
|
return WriteString(">");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool WriteEndElement(const char* type) {
|
||
|
if (!WriteString("</json:") ||
|
||
|
!WriteString(type) ||
|
||
|
!WriteString(">"))
|
||
|
return false;
|
||
|
|
||
|
// For the last end tag, flush the output stream.
|
||
|
if (--level_ == 0)
|
||
|
os_.Flush();
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool WriteNumberElement(const char* buffer, int length) {
|
||
|
if (!WriteStartElement("number"))
|
||
|
return false;
|
||
|
for (int j = 0; j < length; j++)
|
||
|
os_.Put(buffer[j]);
|
||
|
return WriteEndElement("number");
|
||
|
}
|
||
|
|
||
|
OutputStream& os_;
|
||
|
StringBuffer name_;
|
||
|
unsigned level_;
|
||
|
bool hasName_;
|
||
|
};
|
||
|
|
||
|
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));
|
||
|
JsonxWriter<FileWriteStream> writer(os);
|
||
|
|
||
|
// JSON reader parse from the input stream and let writer generate the output.
|
||
|
if (!reader.Parse(is, writer)) {
|
||
|
fprintf(stderr, "\nError(%u): %s\n", static_cast<unsigned>(reader.GetErrorOffset()), GetParseError_En(reader.GetParseErrorCode()));
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|