hjiang / jsonxx Goto Github PK
View Code? Open in Web Editor NEWA JSON parser in C++
License: MIT License
A JSON parser in C++
License: MIT License
Sweeping through the .cc file, I didn't see anything that warranted the separate source file. Easy integration for a library is a very attractive feature, and you can't be easier to integrate than with a single header, the best libraries out there are header-only. Hiding the implementation details can be accomplished with anonymous namespaces.
This would make writing JSON so much easy. Or even something like object.add( "key", "value")
so we dont have to use object << "key" << "value"
all the time
jsonxx is not able to parse a boolean values if the stream is set to throw exceptions.
settings.json
{
"flag" : true
}
main.cpp
#include "jsonxx.h"
#include <fstream>
using namespace std;
int main(int argc, char* argv[]) {
ifstream file;
// let file throw exceptions
file.exceptions(
ifstream::failbit // Logical error on i/o operation
| ifstream::badbit); // Read/writing error on i/o operation
try {
file.open("settings.json");
jsonxx::Object settings;
const bool success = settings.parse(file);
if (!success) {
throw ifstream::failure("JSON syntax error");
}
file.close();
cout << "success" << endl;
}
catch (ifstream::failure e) {
cout << "Unable to load settings: " << e.what() << endl;
}
cin.ignore();
return 0;
}
error
iostream stream error
fault location
The failure occurs when jsonxx tries to parse the boolean value as number:
bool parse_number(std::istream& input, Number& value) {
input >> std::ws;
std::streampos rollback = input.tellg();
input >> value; // <--- iostream stream error
if (input.fail()) {
input.clear();
input.seekg(rollback);
return false;
}
return true;
}
possible fix
bool parse_number(std::istream& input, Number& value) {
input >> std::ws;
std::streampos rollback = input.tellg();
bool failed = true;
try {
input >> value;
if (!input.fail()) {
failed = false;
}
} catch (std::ios::failure& e) {
if (!input.fail()) {
throw;
}
}
if (failed) {
input.clear();
input.seekg(rollback);
return false;
}
return true;
}
I think it might be worth using std::string_view as a view into one large std::string that contains the whole document when parsing. This way there will only be 1 memory allocation.
Only trouble is that string_view is still experimental so would probably have to wait for it to appear in the next standard.
It looks like there is an issue when using this under Windows and there are unicode characters. The code in parse_string does not appear to work. It might be due to the implementation of stringstream.
In the code for parse_string, there is the following code:
case 'u':
int i;
std::stringstream ss;
for( i = 0; (!input.eof() && input.good()) && i < 4; ++i ) {
input.get(ch);
ss << ch;
}
if( input.good() && (ss >> i) )
value.push_back(i);
Using Visual Studio 2013, ss >> i, on the stream "000d" makes i == 0, which means that there are embedded nuls. I'm not even sure what (ss >> i) is supposed to return when cast to a bool.
Why I get this error? What does it mean?
[JSONXX] expression 'has<T>(key)' failed at ../includes/jsonxx/jsonxx.h:367 -> program_app ../includes/jsonxx/jsonxx.cc:29: void jsonxx::assertion(const char*, int, const char*, bool): Assertion `0' failed.
How can I iterate an array or object?
like STL:
iterator::it
Would like to be able to accept both quoted and unquoted keys.
{ item1: 'value1',
"item2": "value2"
}
With UnquotedKeys enabled, only item1 loads, when UnquotedKeys is disabled, this example fails to parse.
Hi, I'm the maintainer of the jsonxx
package for build2
(see https://cppget.org/jsonxx?q=jsonxx and https://github.com/build2-packaging/jsonxx). (I had to package it because it was used in a project at work which buildsystem we changed to build2
recently).
I prepared the v1.0.1
package but we realized the header doesn't expose the right version number there: https://github.com/hjiang/jsonxx/blob/master/jsonxx.h#L22
This is valid json data. But how can I get "var1" or "var2"?
std::string json_str(
"[ "
" \"var1\", "
" { \"id\" : \"1234\" }, "
" \"var2\", "
" \"var3\" "
"] "
);
I'm trying to parse an array of json objects that have that structure:
[
{
"foo": "var",
"foo2": "var2"
},
{
"foo": "var3",
"foo2": "var4"
}
]
It seems to be a valid JSON for JSONLint but I'm not able to access to the array JSON objects, Is there an easy way to accomplish that?
Seems like \u values are still not parsed correctly.
Ex : \u00e7 (can be found in https://open.tan.fr/ewp/tempsattente.json/COMB2)
I'm not entirely confortable with specs, but it seems that a big part of it is not supported. For example, the current code doesn't support surrogate pair.
We can also compare with what other json parser are doing and it is quite different :
https://github.com/miloyip/rapidjson/blob/master/include/rapidjson/reader.h#L696
https://github.com/open-source-parsers/jsoncpp/blob/master/src/lib_json/json_reader.cpp#L682
First observed using the xtensa (Espressif) compiler. Same result using GCC on Ubuntu 64.
$ gcc --version
gcc (Ubuntu 6.3.0-12ubuntu2) 6.3.0 20170406
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#include <stdio.h>
#include <jsonxx.hpp>
using namespace jsonxx;
int main (int argc, char**argv) {
const char * test = "abcmango";
Object obj;
obj << "test_1" << Value(test);
obj << "test_2" << test;
obj << "test_3" << String(test);
obj << "test_4" << Value("defbanana");
obj << "test_5" << "defbanana";
obj << "test_6" << String("defbanana");
printf("%s\n", obj.json().c_str());
}
Observed output:
{
"test_1": null,
"test_2": null,
"test_3": "abcmango",
"test_4": "defbanana",
"test_5": "defbanana",
"test_6": "defbanana"
}
Expected output:
{
"test_1": "abcmango",
"test_2": "abcmango",
"test_3": "abcmango",
"test_4": "defbanana",
"test_5": "defbanana",
"test_6": "defbanana"
}
Right now the jsonxx::Number encompass both the floating point and integer values. This causes problems when I want to put that number as string. Specifically, I would want to avoid the trailing zeros.
I'm open on doing a pull request, but this seems like a API decision that has been made a while ago. Any reason for that?
desktop% g++ -v
Using built-in specs.
Target: x86_64-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-libgcj-multifile --enable-languages=c,c++,objc,obj-c++,java,fortran,ada --enable-java-awt=gtk --disable-dssi --disable-plugin --with-java-home=/usr/lib/jvm/java-1.4.2-gcj-1.4.2.0/jre --with-cpu=generic --host=x86_64-redhat-linux
Thread model: posix
gcc version 4.1.2 20080704 (Red Hat 4.1.2-54)
desktop%
desktop% git clone https://github.com/hjiang/jsonxx.git
Cloning into 'jsonxx'...
remote: Counting objects: 463, done.
remote: Total 463 (delta 0), reused 0 (delta 0), pack-reused 463
Receiving objects: 100% (463/463), 116.83 KiB | 66.00 KiB/s, done.
Resolving deltas: 100% (236/236), done.
Checking connectivity... done.
desktop% cd jsonxx
desktop% make
g++ -Werror -Wall -g -c -o jsonxx.o jsonxx.cc
jsonxx.cc: In member function ‘std::string jsonxx::Object::xml(unsigned int, const std::string&, const std::string&) const’:
jsonxx.cc:848: error: reference to ‘xml’ is ambiguous
jsonxx.h:83: error: candidates are: std::string jsonxx::xml(std::istream&, unsigned int)
jsonxx.h:82: error: candidates are: std::string jsonxx::xml(const std::string&, unsigned int)
jsonxx.cc:609: error: namespace jsonxx::::xml { }
jsonxx.cc:848: error: ‘xml’ is not a namespace-name
jsonxx.cc:848: error: expected namespace-name before ‘;’ token
jsonxx.cc:855: error: ‘defrootattrib’ was not declared in this scope
jsonxx.cc:855: error: ‘tag’ was not declared in this scope
jsonxx.cc:858: error: ‘defheader’ was not declared in this scope
jsonxx.cc: In member function ‘std::string jsonxx::Array::xml(unsigned int, const std::string&, const std::string&) const’:
jsonxx.cc:875: error: reference to ‘xml’ is ambiguous
jsonxx.h:83: error: candidates are: std::string jsonxx::xml(std::istream&, unsigned int)
jsonxx.h:82: error: candidates are: std::string jsonxx::xml(const std::string&, unsigned int)
jsonxx.cc:609: error: namespace jsonxx::::xml { }
jsonxx.cc:875: error: ‘xml’ is not a namespace-name
jsonxx.cc:875: error: expected namespace-name before ‘;’ token
jsonxx.cc:882: error: ‘defrootattrib’ was not declared in this scope
jsonxx.cc:882: error: ‘tag’ was not declared in this scope
jsonxx.cc:885: error: ‘defheader’ was not declared in this scope
jsonxx.cc: In function ‘std::string jsonxx::xml(std::istream&, unsigned int)’:
jsonxx.cc:949: error: reference to ‘xml’ is ambiguous
jsonxx.cc:948: error: candidates are: std::string jsonxx::xml(std::istream&, unsigned int)
jsonxx.h:82: error: candidates are: std::string jsonxx::xml(const std::string&, unsigned int)
jsonxx.cc:609: error: namespace jsonxx::::xml { }
jsonxx.cc:949: error: ‘xml’ is not a namespace-name
jsonxx.cc:949: error: expected namespace-name before ‘;’ token
jsonxx.cc:972: error: ‘defheader’ was not declared in this scope
cc1plus: warnings being treated as errors
jsonxx.cc: At global scope:
jsonxx.cc:799: warning: ‘jsonxx::::xml::defheader’ defined but not used
jsonxx.cc:816: warning: ‘jsonxx::::xml::defrootattrib’ defined but not used
make: *** [jsonxx.o] Error 1
desktop%
When parsing an empty line the parser stops parsing. An empty line is defined as a line that has no white-space.
Simple test case:
{
string teststr("{\"name\": 10,\n\"file\":11}");
istringstream input(teststr);
Object o;
TEST(o.parse(input));
TEST(o.has<Number>("file")); // fails
}
Apple LLVM version 5.0 (clang-500.2.79) (based on LLVM 3.3svn)
Target: x86_64-apple-darwin13.0.2
[JSONXX] expression 'v.parse(input)' failed at jsonxx_test.cc:171 -> Assertion failed: (0), function assertion, file jsonxx.cc, line 29.
In file included from /Users/ambethia/Dropbox/Dev/CoderNight/BlueHawaii/ext/jsonxx/jsonxx.cc:8:
/Users/ambethia/Dropbox/Dev/CoderNight/BlueHawaii/ext/jsonxx/jsonxx.h:119:21: error:
copying a temporary object of incomplete type 'jsonxx::Value'
return *this << Value(value), *this;
^
/Users/ambethia/Dropbox/Dev/CoderNight/BlueHawaii/ext/jsonxx/jsonxx.h:65:7: note:
forward declaration of 'jsonxx::Value'
class Value;
^
1 error generated.
make[2]: *** [ext/CMakeFiles/jsonxx.dir/jsonxx/jsonxx.cc.o] Error 1
make[1]: *** [ext/CMakeFiles/jsonxx.dir/all] Error 2
make: *** [all] Error 2
I'm sorry I'm too inexperienced with c++ to work out the solution on my own.
Hello,
I'm getting a build error while compiling an application which makes use of jsonxx, basically compilation fails at a line containing
errorCode = obj.get("errorCode");
The error reported is:
Undefined symbols for architecture x86_64:
"long& jsonxx::Value::get()", referenced from:
long& jsonxx::Object::get(std::string const&) in ServerResponse.o
"bool jsonxx::Value::is() const", referenced from:
bool jsonxx::Object::has(std::string const&) const in ServerResponse.o
ld: symbol(s) not found for architecture x86_64
Looking at jsonxx.cc I can see there is no code at all for long& jsonxx::Object::get(std::string const&), I tried to update my tree and again jsonxx.cc fails to compile because the aforementioned method is inexistent.
This is inconsistent with the example in your Wiki, is there a reason why I can't retrieve a "long" value?
Hi!
My small test code don't work.
#include <iostream>
#include <jsonxx/jsonxx.h>
using namespace std;
using namespace jsonxx;
int main() {
std::string json_str;
json_str = "[ 'var1', { 'id': '1234' }, 'var2', 'var3' ]";
Object json;
json.parse(json_str);
return 0;
}
This error appear by invoking the linker:
Test.cpp:12: undefined reference to `jsonxx::Object::Object()'
Test.cpp:15: undefined reference to `jsonxx::Object::~Object()'
Any idea?
Hello,
what does line 375 in jsonxx.cc mean? Is it C++? I am trying to compile it with Visual Studio 2010 and it shows me the error.
For some reason false
gets parsed by double long istream <<
as fa
, but fails. Then when it gets passed on to check if its a boolean, the peek
and get
now return l
instead of f
. To fix this, I implemented an actual parser for numbers. I'm sure this isn't the best way to parse numbers, but I needed a fix asap:
bool parse_number(std::istream& input, Number& value) {
input >> std::ws;
char digits[10] = {'0','1','2','3','4','5','6','7','8','9'};
size_t bI = 0;
int left = 0;
int right = 0;
bool hasDecimal = false;
char ch;
while(input && !input.eof()){
ch = input.peek();
bool matchedDigit = false;
for(size_t i = 0; i < 10; i++){
if(ch == digits[i]){
if(hasDecimal){
right = (right * 10) + i;
}
else {
left = (left * 10) + i;
}
matchedDigit = true;
input.get();
bI++;
break;
}
}
if(matchedDigit)continue;
if(bI > 0 && ch == '.' && hasDecimal == false){
hasDecimal = true;
input.get();
bI++;
}
else {
break;
}
}
if(bI > 0){
value = left + right * pow(10.0,log10(right) + 1);
return true;
}
else {
return false;
}
}
I was wondering if you guys could publish a release (perhaps version 0.1.0
or something). This would make it easier to use with meson, since I would be able to link to the source tarballs to download automatically in my code.
It refuses to parse this file. JSON validator tells the file is valid.
t.tar.gz
Hi,
I have some changes that implements a tagged XML format.
I use this in several of my projects where I need to use both JSON and SOAP services.
If you would like to review and add my code, please drop me a line :)
The following example document is a sample of the JSON structure.
{
"name/surname":"John Smith",
"address": {
"streetAddress": "21 2nd Street",
"city": "New York",
"state": "NY",
"postal-code": 10021,
},
"IDs": [
"2-111",
"2-222"
],
"additionalInfo": null,
"remote": false,
"height": 62.4,
"ficoScore": "> 640"
}
The following output is the result of the transformed document to JSONTaggedXML.
<?xml version="1.0" encoding="UTF-8"?>
<JsonItem>
<name type="json:string" name="name">John Smith</name>
<address type="json:object" name="address">
<streetAddress type="json:string" name="streetAddress">21 2nd Street</streetAddress>
<city type="json:string" name="city">New York</city>
<state type="json:string" name="state">NY</state>
<postalCode type="json:number" name="postalCode">10021</postalCode>
</address>
<phoneNumbers type="json:array" name="phoneNumbers">
<JsonItem type="json:string">212 555-1111</JsonItem>
<JsonItem type="json:string">212 555-2222</JsonItem>
</phoneNumbers>
<additionalInfo type="json:null" name="additionalInfo" />
<remote type="json:boolean" name="remote">false</remote>
<height type="json:number" name="height">62.4</height>
<ficoScore type="json:string" name="ficoScore">> 640</ficoScore>
</JsonItem>
Regards,
TMB
I tried adding this myself, but encountered errors:
[ 1%] Linking CXX executable jsonxx
/data/data/com.termux/files/usr/bin/../lib/crtbegin_dynamic.o: In function `_start':
crtbegin.c:(.text+0x84): undefined reference to `main'
clang-5.0: error: linker command failed with exit code 1 (use -v to see invocation) make[2]: *** [lib/jsonxx/CMakeFiles/jsonxx.dir/build.make:95: lib/jsonxx/jsonxx] Error 1
make[1]: *** [CMakeFiles/Makefile2:86: lib/jsonxx/CMakeFiles/jsonxx.dir/all] Error 2
make: *** [Makefile:130: all] Error 2
Hi,
Following test case is failing. Was it working before?
Regards,
Prem
$:~/Code/jsonxx-master$ cat Makefile
CXXFLAGS=-W -Wall -g
jsonxx_test: jsonxx_test.cc jsonxx.o
jsonxx.o: jsonxx.h jsonxx.cc
test: jsonxx_test
./jsonxx_test
.PHONY: clean
clean:
rm -f jsonxx_test *.o *~
$:~/Code/jsonxx-master$ make
g++ -W -Wall -g -c -o jsonxx.o jsonxx.cc
g++ -W -Wall -g jsonxx_test.cc jsonxx.o -o jsonxx_test
jsonxx_test.cc: In function 'int main(int, const char**)':
jsonxx_test.cc:563:24: warning: passing NULL to non-pointer argument 1 of 'jsonxx::Object& jsonxx::Object::operator<<(const T&) [with T = long int]' [-Wconversion-null]
jsonxx_test.cc:563:24: warning: passing NULL to non-pointer argument 1 of 'jsonxx::Object& jsonxx::Object::operator<<(const T&) [with T = long int]' [-Wconversion-null]
$:~/Code/jsonxx-master$ ls
LICENSE README.textile jsonxx.h jsonxx_test
Makefile jsonxx.cc jsonxx.o jsonxx_test.cc
$:~/Code/jsonxx-master$ ./jsonxx_test
[JSONXX] expression 'value == "\b\f\n\r\t\xe\x2"' failed at jsonxx_test.cc:100 -> jsonxx_test: jsonxx.cc:29: void jsonxx::assertion(const char*, int, const char*, bool): Assertion `0' failed.
Aborted
$:~/Code/jsonxx-master$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.6/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.6.3-1ubuntu5' --with-bugurl=file:///usr/share/doc/gcc-4.6/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.6 --enable-shared --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.6 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --enable-plugin --enable-objc-gc --disable-werror --with-arch-32=i686 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5)
Hi,
Whenever there is an assertion failure in jsonxx code, the program aborts by jsonxx. I can't afford that in my production code.
Is it possible to disable the assertions?
[JSONXX] expression 'read.size()' failed at jsonxx_test.cc:619 -> jsonxx_test: jsonxx.cc:29: void jsonxx::assertion(const char *, int, const char *, bool): Assertion `0' failed.
My json is as following:
{
"string" : "lorem ipsum",
"utf string" : "\u006corem\u0020ipsum",
"utf-8 string": "あいうえお",
"surrogate string": "lorem\uD834\uDD1Eipsum\uD834\uDF67lorem",
"positive one" : 1,
"negative one" : -1,
"pi" : 3.14,
"hard to parse number" : -3.14e-4,
"big int": 2147483647,
"big uint": 4294967295,
"boolean true" : true,
"boolean false" : false,
"null" : null,
"string array" : ["lorem", "ipsum"],
"x^2 array" : [0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100],
"/" : null,
"object" : { "nested string" : "str",
"nested true" : true,
"nested false" : false,
"nested null" : null,
"nested number" : 123,
"nested array" : ["lorem", "ipsum"],
"nested object" : {"lorem": "ipsum"}
},
"/" : null,
"/**/" : "comment",
"//" : "comment",
"url" : "https://www.example.com/search?q=12345",
"escaped chars" : "" \ /",
"empty object" : {},
"empty array" : []
}
source json String is {"now":[{"action":6,}]},
but after parse,result is {"action":2.086006742350501e-309},
Hi, I'm currently attempting to use this library to parse the json output from the twitter API. So far this has been the easiest and cleanest json parser for C++ I've been able to find. After a while I found a huge problem though. When a 'tweet' contains geo information it partly failed to parse it. The place info in the raw json is listed below:
{"place":{"full_name":"Limburg, The Netherlands","attributes":{},"name":"Limburg","place_type":"admin","bounding_box":{"type":"Polygon","coordinates":[[[5.5661376,50.750449],[6.2268848,50.750449],[6.2268848,51.7784841],[5.5661376,51.7784841]]]},"url":"http://api.twitter.com/1/geo/id/4ef0c00cbdff9ac8.json","country_code":"NL","id":"4ef0c00cbdff9ac8","country":"The Netherlands"}/* Normal tweet information */}
I believe it mainly fails at the coordinates part. Now here is the even weirder part of it, listed below is a simple cout of the parsed object.
{"bounding_box": {"coordinates": [[[5.56614, 50.7504], [6.22688, 50.7504], [6.22688, 51.7785], [5.56614, 51.7785]]], "type": "Polygon"}, "country": "The Netherlands", "country_code": "NL", "favorited": false, "id": "4ef0c00cbdff9ac8", "name": "Limburg", "place": {"full_name": "Limburg, The Netherlands"}, "place_type": "admin", "url": "http://api.twitter.com/1/geo/id/4ef0c00cbdff9ac8.json"/* Normal tweet information */}
As you can see it doesn't have a place, it pretty much just put it's own info in the first level. Apart from this it's also just not parsing certain things in these situations. I'd highly appreciate it if this got fixed so I can happily use this json parser after all. Thanks in advance.
Ps. as you can see I took some stuff out of the raw json to save a lot of space, if you need a full example on what it failed at just let me know.
I fixed my version this way and it seems to work:
jsonxx.h, line 64:
typedef bool BooleanJS;
I quess Boolean is a reserved word from prefixed headers on iOS SDK.
Hi!
How can I parse values automatically? I use something like this:
json.has<jsonxx::Object>("data");
But key data
can have a value: Object, Array, Number, Boolean or String!?
So, is there a wildcard directive or something?
For example:
json.has<boost::any>("data");
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.