The official repository is https://github.com/VA7ODR/json. This C++23 library provides value and document types for parsing, editing, and writing JSON. It is MIT licensed. Include json.hpp and link the library built from json.cpp.
json::valueandjson::documentare always available.- With
JSON_ORDERED=ON,ojson::valueandojson::documentare also built; object keys retain insertion order. - With
JSON_DATA_DOCUMENT=ON,data::documentis built as an XML-capable subclass ofjson::document. - With both options enabled,
odata::documentis the XML-capable ordered counterpart.
data::value and odata::value are forward declarations only; XML documents use the inherited json::value or ojson::value type. The accessor and container methods below apply to each concrete value/document pair.
cmake -S . -B build -DJSON_SAMPLES=ON -DJSON_TEST_EXAMPLE=ON
cmake --build build
cmake --install buildCMake options: JSON_ORDERED (default ON), JSON_DATA_DOCUMENT (default ON), JSON_SAMPLES (default OFF), JSON_TEST_EXAMPLE (default OFF), JSON_USE_TEMP_FILES, JSON_RESTORE_TEMP_FILES, and ADDRESSSANITIZER. The first two select the namespace variants above; JSON_SAMPLES builds conversion tools, JSON_TEST_EXAMPLE builds testbed, and the remaining options enable file protection or sanitizer flags. Run cmake --build build --target testbed && build/testbed for the manual checks.
There are two ways to parse and two ways to write JSON documents:
- parse(string) - pass a JSON string and it will parse it. This returns true if parsing was successful. parseResult() will contain error information if parsing failed.
- parseFile(string) - will parse a file with the name given. This returns true if parsing was successful. parseResult() will contain error information if parsing failed.
- write(pretty) - returns an sdstring containing the JSON document. Pass true for pretty if you want the JSON formatted with indentation and line feeds or omit pretty or pass false to have the JSON without tabs or line feeds.
- writeFile(string, pretty) - will write the JSON document to the file passed as string. Pretty works the same as above. Will return true if the file could be opened and saved or false if the file could not be written.
Here is an example of reading and updating a simple JSON file with json::document:
json::document jDoc;
if(jDoc.parseFile("sample.json")){
// read was successful
printf("bar = %s\n", jDoc["bar"].c_str());
} else {
printf("Error reading JSON file: %s\n", jDoc.parseResult().c_str());
}
jDoc["bar"] = "baz";
jDoc.writeFile("sample.json", true); // true is optional and tells the writer to output "pretty" JSON.
You can access arrays using a number as the index in the square brackets:
for(size_t i = 0; i < jDoc.size(); i++){
jDoc[i] = i * 2;
}
You can access objects using a string or char array as the index in the square brackets:
jDoc["foo"] = 8;
Any numeric value, boolean, char array / string, object, or array can be assigned to any JSON value:
jDoc["null"] = (char*)NULL;
jDoc["true"] = true;
jDoc["false"] = false;
jDoc["number"] = 1.234;
jDoc["string"] = "Hello, world!";
jDoc["object"] = jDoc["other_object"];
jDoc["array"] = jDoc["other_array"];
You can retrieve values from a json::document with several conversion functions:
- boolean() - returns a bool.
- number() - returns a double. (Converts from strings as appropriate.)
- integer() - returns a 64bit integer. (Converts from strings as appropriate.)
- c_str() - returns a const char *. Guaranteed to not be NULL. (Converts from numbers as appropriate)
- string() - returns a std::string & (converts from numbers as appropriate). Use _sdstring() for the project string type.
Here are some examples:
int i = (int)jDoc["integer"].integer();
double d = jDoc["double"].number();
std::string str = jDoc["string"].string();
const char * szChar = jDoc["char"].c_str();
You can get other information with the following functions:
- size() - returns the number of elements in arrays or objects. Numbers, strings, and booleans return 1, and nulls and non-existant values return 0.
- exists(string or number) - returns true if the object or array contains the index value. False otherwise.
- isA() - returns the type of value. Can be:
- json::JSON_VOID - value does not exist.
- json::JSON_NULL - value is NULL.
- json::JSON_BOOLEAN - value is a boolean.
- json::JSON_NUMBER - value is a number.
- json::JSON_STRING - value is a string.
- json::JSON_ARRAY - value is an array.
- json::JSON_OBJECT - value is an object.
- isA(json type) - returns true if the value's type is the same as that passed in the argument. The types are the same as those returned from the isA() function above.
- empty() - returns false if an object or an array has items in it or if the value is a string, number, or boolean. Returns true if the value doesn't exist, if it's a NULL, or if it is an empty object or array.
Some other functions for working with JSON are:
- emptyArray() - creates an empty array [] at the location specified.
- emptyObject() - creates an empty object {} at the location specified.
- push_back(value) - pushes the value to the end of an array. Creates the array if it doesn't exist.
- push_front(value) - pushes the value to the start of an array. Creates the array if it doesn't exist.
- pop_back() - returns a json value (json::value) that is the last item in an array and removes it from the array. Returns a value with an isA() type of json::JSON_VOID if the array is empty.
- pop_front() - returns a json value (json::value) that is the first item in an array and removes it from the array. Returns a value with an isA() type of json::JSON_VOID if the array is empty.
- insert(number, string, or iterators and a value) - will insert a new value into an existing array or object at the point indicated. This will invalidate any iterators referencing the array or object in question. For an object, this is the same as just adding the value the normal way.
Some Examples of these are:
jDoc["empty"].emptyArray();
jDoc["empty"].emptyObject();
jDoc["array"].push_back(6);
jDoc["array"].push_front("Test");
int i = (int)jDoc["array"].pop_back().integer();
std::string s = jDoc["array"].pop_front().string();
jDoc["array"].insert(0, "new value");
There are three functions for removing data from a json::document:
- clear() - this removes the contents of the value it is used on.
- erase(index, iterator, or 2 iterators) - this finds the specified value or range of values and removes it. The arguments can be either a number for removing an item from an array, a string for removing an item from an object, an iterator that will remove an item from an array or an object, or two iterators, one for the range start and one for the range end that will remove all items from an array or object that fall between the iterators. Any iterator for the array or object will be invalidated by erase.
- destroy() - similar to erase, but removes the item it is called from.
For example:
jDoc.clear(); // completely clears the json::document.
jDoc["array"].clear(); // empties the array "array" but leaves it in the document as [].
jDoc["array"].erase(6); // removes item 6 from "array".
jDoc.erase("array"); //removes "array" completely from the document.
jDoc["array"].destroy(); // the same as jDoc.erase("array");
json::document also has a full set of operators:
- +, - , *, /, %, +=, -=, *=, /=, %= work on numbers, some work on booleans and + and += append strings like in std::string.
- ==, !=, <, >, <=, >= work on all value types.
- ++, --, and - work on numbers and booleans only.
For example:
if(jDoc["number"] == 6){} // works
if(6 == jDoc["number"]) {} // INVALID! Use this instead:
if(6 == jDoc["number"].number()) {}
jDoc["string"] += ", world!";
jDoc["number"]++;
Although you can use size() and an index to iterate through a json::document array, it will not work for objects. For both, it is better to use iterators. Iterators are extremely fast. The functions for using them are the same as many of the standard container classes:
- begin() - returns an iterator pointing to the beginning of an array or object. If a value is not an array or object it will return end().
- end() - returns an iterator pointing to the end of the array or object (technically it represents one past the end.)
- rbegin() - returns a reverse iterator pointing to the last item in an array or object. If a value is not an array or object it will return rend().
- find(string or number index) - will return an iterator pointing to the given member of an array or object. Will return end() if it isn't found or the value is not an array or object.
- rfind(string or number index) - will return a reverse_iterator pointing to the given member of an array or object. Will return rend() if it isn't found or the value is not an array or object.
For normal iterators:
json::iterator itObject= jDoc["some_object"].find("some_sub_value");
for(json::iterator it = (*itObject).begin(); it != (*itObject).end(); ++it){
std::string sKey = it.key().string(); // this will work for arrays as well, but the key will always return 0.
// key() returns a JSON value (value).
std::cout << "key = " << sKey << ", value = " << (*it).number() << "\n";
}
For reverse_iterators:
json::iterator itObject= jDoc["some_object"].find("some_sub_value");
for(json::reverse_iterator rit = (*itObject).rbegin(); rit != (*itObject).rend(); ++rit){
std::string sKey = rit.key().string(); // this will work for arrays as well, but the key will always return 0.
// key() returns a JSON value (value).
std::cout << "key = " << sKey << ", value = " << (*rit).number() << "\n";
}
data::document and odata::document support the same inherited JSON accessors plus parseXML, parseXMLFile, writeXML, and writeXMLFile. XML attributes are represented with an @ prefix; character data for tagged values with attributes uses the #value key. rootTag(), standAlone(), forceXMLHeader(), and noXMLHeader() control XML output. The XML conversion uses the bundled tinyxml library.
The following program will open a JSON file and resave it in a "pretty" format with indentation and line feeds.
#include "json.hpp"
#include <iostream>
int main(int argc, char ** argv) {
for(int i = 1; i < argc; i++){
json::document jDoc;
if(jDoc.parseFile(argv[i])){
jDoc.writeFile(argv[i], true);
} else {
std::cout << "Failed to open file " << argv[i] << ": " << jDoc.parseResult() << "\n";
}
}
return 0;
}
Copyright (c) 2012-2026 James Baker
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
The official repository for this library is at https://github.com/VA7ODR/json