Tijson
An easy-to-use json parser/generator written in modern cpp
Table of Contents
About Tijson
Tijson is a standard recursive descent JSON parser / generator written based on C++ 17.Cross platform (Windows / Linux / OS X) and cross compiler (GCC / Clang). It only supports UTF-8 text, aims to be simple ,lightweight and easy to use, and supports a variety of error handling methods.
Getting Started
Tijson is a header-only library, you only need to copy the tijson.h
in the include
folder in this repository to your project directory and include it as a header file to use it.
#include "tijson.h"
Example
#include "tijson.h"
#include <iostream>
int main() {
auto root = tijson::Parse(R"({"repo":"Tijson", "author":"Meow-2", "star":0})");
root["author"].SetString(root["author"].GetString().substr(0, 4));
root["star"] = root["star"].GetNumber()+1;
std::cout << root.Stringify()<<'\n';
//{ "star":1, "author":"Meow", "repo":"Tijson" }
return 0;
}
Parse
// two methods
auto json_val0 = tijson::Parse(R"({"Meow-2":"Tijson"})");
auto json_val1 = tijson::Parser::Parse(R"({"Meow-2":"Tijson"})");
// auto is tijson::Value, json_val0 is the same as json_val1
The difference between the above two methods is that in the first method, when the parsing fails, the error code will be written into the Value, and the program continues to execute, while the second method directly throws an exception and the program terminates.
Example of Error Code
auto json_val = tijson::Parse(R"({"Meow-2":"Tijson"})");
if (json_val)
std::cout << json_val.Stringify() << '\n'; //{ "Meow-2":"Tijson" }
else
tijson::PARSE_ERROR err = json_val.GetParseErrorCode();
The Definition of Parse Error Code
enum class PARSE_ERROR : size_t
{
NO_ERROR = 0,
EXPECT_VALUE,
INVALID_VALUE,
ROOT_NOT_SINGULAR,
NUMBER_TOO_BIG,
MISS_QUOTATION_MARK,
INVALID_STRING_ESCAPE,
INVALID_STRING_CHAR,
INVALID_UNICODE_HEX,
INVALID_UNICODE_SURROGATE,
MISS_COMMA_OR_SQUARE_BRACKET,
MISS_KEY,
MISS_COLON,
MISS_COMMA_OR_CURLY_BRACKET
};
Example of Exception
try{
auto json_val = tijson::Parse(R"({"Meow-2":"Tijson"})");
std::cout << json_val.Stringify() << '\n'; //{ "Meow-2":"Tijson" }
}catch(tijson::ParseException e){
std::cout<<e.what();
}
When an exception is thrown, the information carried by the exception is the string corresponding to the error code, which has the same meaning as the error code. Unlike the error code, if it is not caught, the program will be terminated.
Access
tijson::Value json_val = tijson::Parse(R"(
{
"Null" : null,
"True" : true,
"False" : false,
"Number" : 314159E-5,
"String" : "tijson",
"Array" : [ ["Hello\nWorld"]],
"Object": {
"TIJSON":[123, "Tijson"]
}
}
)");
Example of Get/Set
tijson::Value json_val = tijson::Parse(R"(
{
"Null" : null,
"True" : true,
"False" : false,
"Number" : 314159E-5,
"String" : "tijson",
"Array" : [ "Meow-2", ["Hello\tWorld"]],
"Object": {
"TIJSON":[123, "Tijson"]
}
}
)");
auto& obj = json_val.GetObject();
std::cout << obj["Null"].IsNull() << '\n'; // 1
std::cout << obj["True"].GetBool() << '\n'; // 1
std::cout << obj["False"].GetBool() << '\n'; // 0
std::cout << obj["Number"].GetNumber() << '\n'; // 3.14159
std::cout << obj["String"].GetString() << '\n'; // tijson
auto& arr = obj["Array"].GetArray();
std::cout << arr[0].GetString() << '\n'; // Meow-2
std::cout << arr[1].GetArray()[0].GetString() << '\n'; // Hello World
auto& objj = obj["Object"].GetObject();
auto& objj_tijson = objj["TIJSON"].GetArray();
std::cout << objj_tijson[0].GetNumber() << '\n'; // 123
std::cout << objj_tijson[1].GetString() << '\n'; // Tijson
The json value parsed from the json text is stored in the tijson::Value
object.You need to use Get
of the corresponding type to get its value, but you need to pay attention to the following three points:
The json value of null
type can only be checked by IsNull()
, but cannot be gotten. Similarly, each json type value has its corresponding Is
methods
Array
andObject
are actuallystd::vector<tijson::Value>
andstd::unordermap<std::string, tijson::Value>
Get
with the wrong type will throw anAccessException
exception
For any kind of tijson::Value
, you can use Set
to set it to any type of json
value, such as freely modifying the above obj["Null"]
.
obj["Null"].SetString("NULL");
std::cout << obj["Null"].GetString() << '\n'; // NULL
obj["Null"].SetBool(true);
std::cout << obj["Null"].GetBool() << '\n'; // 1
obj["Null"].SetNumber(123);
std::cout << obj["Null"].GetNumber() << '\n'; // 123
obj["Null"].SetArray({"Meow-2", {"Hello\tWorld"}});
auto& a = obj["Null"].GetArray();
std::cout << a[0].GetString() << '\n'; // Meow-2
std::cout << a[1].GetArray()[0].GetString() << '\n'; // Hello World
obj["Null"].SetObject({
{"TIJSON", {123, "Tijson"}}
});
auto& o = obj["Null"].GetObject();
auto& o_tijson = o["TIJSON"].GetArray();
std::cout << o_tijson[0].GetNumber() << '\n'; // 123
std::cout << o_tijson[1].GetString() << '\n'; // Tijson
For SetArray()
, you can use std::initializer_list
method and it supports nesting of std::initializer_list
.
For SetObject()
, you can also use the std::initializer_list
method, the nesting of std::initializer_list
is not supported (it will be regarded as Array
).
If you want to implement Oject
nesting, you need to explicitly specify it as tijson::Object
, such as:
obj["Null"].SetObject({
{ "TIJSON", tijson::Object({ {"Meow-2", "Tijson"} }) }
});
Example of Assignment Operator
Get/Set directly accesses/modifies inside tojson::Value
, and can also use assignment instead of Set, but there will be overhead of implicit construction and movement.
obj["Null"] = "NULL";
std::cout << obj["Null"].GetString() << '\n'; // NULL
obj["Null"] = true;
std::cout << obj["Null"].GetBool() << '\n'; // 1
obj["Null"] = 123;
std::cout << obj["Null"].GetNumber() << '\n'; // 123
obj["Null"] = {"Meow-2", {"Hello\tWorld"}};
auto& a = obj["Null"].GetArray();
std::cout << a[0].GetString() << '\n'; // Meow-2
std::cout << a[1].GetArray()[0].GetString() << '\n'; // Hello World
obj["Null"] = tijson::Object({
{"TIJSON", {123, "Tijson"}} // Explicit Initialize Object
});
auto& o = obj["Null"].GetObject();
auto& o_tijson = o["TIJSON"].GetArray();
std::cout << o_tijson[0].GetNumber() << '\n'; // 123
std::cout << o_tijson[1].GetString() << '\n'; // Tijson
When use assignment operator to assignment tijson::Object
, std::initializer_list
is not supported, because it will be regarded as Array
.
Serialization
The Stringify()
member function can be used to generate compact strings for any type of json value.
tijson::Value me(tijson::Object{});
me["name"] = "Meow-2";
me["age"] = 24;
me["interest"] = {"Animation", "Coding", "Open Source"};
me["learning"] = {"C++", "Linux", "Vim"};
me[""] = Value(); //default initialize as `null`
me["this repo"] = tijson::Object({
{"name", "Tijson"},
{"star", 0},
{"url", "https://github.com/Meow-2/Tijson"},
});
std::cout << me.Stringify() << '\n';
// { "this repo":{ "url":"https:\/\/github.com\/Meow-2\/Tijson", "star":0, "name":"Tijson" }, "remark":null, "learning":[ "C++", "Lin
// ux", "Vim" ], "interest":[ "Animation", "Coding", "Open Source" ], "age":24, "name":"Meow-2" }
Compare
The json::Value
type only supports the same type of comparison (==, !=), when both represent the same json value, they are considered to be the same.
At the same time, tijson::Value
supports automatic conversion to bool
, and it is false only when tijson::Value::type_
is tijson::Value::TYPE::INVALID
, so it can be used to check json Whether the parsing was successful.
auto json_val = tijson::Parse(R"({"Meow-2":"Tijson"})");
if (json_val){
// parse succeeds
}
if (!json_val){
// parse fails
}
Prerequisites
Tojson does not depend on third-party libraries, only the standard library and C++17 support are required.
If you want to run the test cases in the test
folder, you need to have:
- magic_enum
- gtest
This project supports vcpkg Manifest
, if you want to install the above dependencies automatically, just clone this project and then:
git submodule update --init \
&& ./vcpkg/bootstrap-vcpkg.sh \
&& cmake -B build \
&& cmake --build build \
or run build_test.sh
directly.
./build_test.sh
TODO
- Optimize Get/Set return type
- Provide parsing error codes as error handling methods other than exceptions
- Provide more convenient access (Get/Set) syntactic sugar
- Added GetIf as an exception-free Get
- Support C++20 Module
- Use C++20 std::format to format strings
- Generator generated format beautification
- Added nativejson-benchmark test and optimized performance
- ...
参考
License
MIT License