JIOS : JSON Input Output Streams
Similar to C++ streams, but the stream elements are structured JSON data rather than characters.
Contents
- Features
- [Parsing Examples](#Parsing Examples)
- [Printing Examples](#Printing Examples)
- Dependencies
- [Other Libraries](#Other Libraries)
Features
Incremental Streamed Parsing
Not all parsing of JSON has to happen at once, but rather parsing can be streamed before all JSON is available. This is similar to many SAX parsers, but with jios
client code still calls jios
and "pulls" data rather than being called like a SAX parser would.
Document Object Model (DOM) friendliness
JSON objects and arrays are represented by distinct C++ types and can be "walked" and iterated in for loops like a DOM interface.
Non-blocking Parsing of Asynchronous Data Sources
jios
can be called assuming all data is available or the expecting
method can be called to check whether jios
is still expecting more data. This can be used in asynchronous code to determine parsing should performed later when more data is available.
Parse Directly Into Strongly-types Data Structures
Source back-end do not have to construct entire json objects in memory and instead data can read data incrementally into custom strongly types C++ objects.
A template library (express.hpp
) is included which makes it easy to declare the JSON object members to bind to C++ class members so that such C++ classes can immediately be read and written as JSON.
Interoperable with standard C++ streams
Three ways jios
interoperates with C++ streams:
- included back-end source and sink and read and write with C++ streams.
- C++ types and have insertion (<<) and extraction (>>) defined for C++ streams automatically work with
jios
. This mechanism can be overloaded when C++ types should be represented as structures JSON rather than JSON strings. - The
jios
front-end provides syntactic sugar and semantics that are like C++ streams.
Separate Independent Back-ends
Streams are backed by source and sink back-ends which do not have to operate on textual JSON.
Interoperability with Google Protocol Buffers
C++ classes generated by Google Protocol Buffers are automatically readable and writable to any jios
sources and sinks.
Parsing Examples
istringstream ss("1 \"two\" 3");
int i, j;
string s;
json_in(ss) >> i >> s >> j;
Use any type with the istream >> (extraction) operator defined
using namespace boost::posix_time;
istringstream ss("[\"00:01:03\", \"00:00:12\"]");
time_duration t1, t2;
ijarray ija = json_in(ss).get().array();
ija >> t1 >> t2;
cout << boolalpha << bool(t1 == seconds(63)) << ' '
<< bool(t2 == seconds(12)) << endl;
outputs
true true
Parse JSON arrays into standard containers
istringstream ss("[1, 2, 3]"); list<int> many; json_in(ss) >> many; list<int> expect = {1, 2, 3}; cout << boolalpha << bool(many == expect) << endl; outputs
true
### Iterate on JSON streams and arrays
```cpp
istringstream ss("1 2 3 4 5");
int sum = 0;
for (ijvalue & v : json_in(ss)) {
int i;
if (v.read(i)) {
sum += i;
}
}
cout << sum << endl;
outputs
15
JSON arrays are parsed as a stream and accessible incrementally
stringstream ss;
int i = 0;
ss << "[";
ijarray ija = json_in(ss).get().array();
ss << "1 ";
ija >> i;
cout << i << endl;
ss << ", 2 ";
ija >> i;
cout << i << endl;
ss << "]";
if (ija.at_end()) { cout << "Done!" << endl; }
outputs
1
2
Done!
Iterate by name value pair on JSON objects
stringstream ss;
ss << R"( { "a":1, "b":2, "c":3 } )";
int sum = 0;
for (ijpair & nv : json_in(ss).get().object()) {
int i;
if (nv.read(i)) {
sum += i;
}
}
cout << sum << endl;
outputs
6
Parse JSON object as stream of name value pairs
stringstream ss;
ss << R"( { "Joe":35, "Jane":33 } )";
string name1, name2;
int age1, age2;
ijobject ijo = json_in(ss).get().object();
ijo >> tie(name1, age1) >> tie(name2, age2);
cout << name1 << " is " << age1 - age2 << " years older than "
<< name2 << endl;
outputs
Joe is 2 years older than Jane
Printing Examples
jios::json_out(std::cout, '\n') << 1 << 2 << "three";
outputs
1
2
"three"
In the rest of the examples assume
using namespace std;
using namespace jios;
ojstream jout = json_out(cout);
JSON Arrays
ojarray oja = jout.put().array();
for (int i = 0; i < 3; ++i) {
oja << i;
}
oja << endj;
outputs
[0, 1, 2]
JSON Objects
string b = "BEE";
jout.put().object() << make_pair("one", 1) << tie("two", b) << endj;
outputs
{"one":1, "two":"BEE"}
Use any type with the ostream << (insertion) operator defined
using namespace boost::posix_time;
jout.put().array() << seconds(3) << seconds(2) << seconds(1) << endj;
outputs
["00:00:03", "00:00:02", "00:00:01"]
Even use such types as JSON object keys.
using namespace boost::posix_time;
jout.put().object() << make_pair(seconds(3), "launch")
<< make_pair(seconds(7), "explode") << endj;
outputs
{"00:00:03":"launch", "00:00:07":"explode"}
Dependencies
Other Libraries
There are many C/C++ JSON libraries. www.json.org has a long list of such C and C++ libraries.
A few worth mentioning are
- JSON-C : the C library currently used by jios
- JsonCpp : a C++ library I have used in the past
- https://github.com/Loki-Astari/ThorsSerializer
- https://github.com/rsms/jsont