Let’s talk about the jsoncons C++ library, a treasure trove for developers, and write an easy-to-understand article with code examples.
A New Choice for JSON Processing: Making JSON Operations in C++ as Easy as Breathing with jsoncons
In modern C++ development, JSON (JavaScript Object Notation) is ubiquitous. Whether for configuration files, network API communication, or data persistence, JSON is the preferred lightweight data exchange format.
However, native C++ does not have built-in support for JSON. Developers often need to look for third-party libraries to handle JSON. Well-known libraries such as nlohmann/json and RapidJSON are available, but today we will introduce another powerful, efficient, and elegantly designed option: jsoncons.
What is jsoncons?
jsoncons is an open-source C++ library designed for processing JSON (as well as binary formats like BSON, CBOR, MessagePack, and UBJSON). Its name comes from “JSON Cons” (JSON construction), and its core philosophy is to provide a type-safe, easy-to-use, high-performance interface for parsing, generating, and manipulating JSON data.
Why choose jsoncons?
- Single Header File Library: In most cases, you only need to include one header file
jsoncons/json.hpp, without complex compilation and linking processes, making integration extremely simple. - STL Style Interface: It heavily utilizes patterns from the C++ Standard Template Library (STL), such as iterators and container-style access, making it very easy to learn for C++ developers familiar with STL.
- Type Safety: It provides a
jsoncons::jsontype that can be manipulated likestd::maporstd::vector, allowing many errors to be caught at compile time. - High Performance: Designed with performance in mind, it offers fast parsing and serialization speeds.
- Rich Features: Supports advanced features such as JSON Schema validation, JSON Patch, JSON Pointer, and streaming parsing/generation.
- Cross-Platform: Supports C++11 and above, usable on various platforms and compilers.
Quick Start: Installation and Inclusion
jsoncons is a header-only library, making installation very simple:
- Download: Visit its GitHub repository (https://github.com/danielaparker/jsoncons) to download the source code.
- Include: Add the downloaded
includedirectory to your compiler’s include path. - Include the header file in your code:
#include <jsoncons/json.hpp> // Use namespace to simplify code (optional) using namespace jsoncons;
Practical Exercise: Code Examples
Let’s explore the charm of jsoncons through several common scenarios.
Scenario 1: Creating and Modifying JSON
Imagine we want to build a JSON object representing user information.
#include <iostream>
#include <jsoncons/json.hpp>
using namespace jsoncons;
int main() {
// Create an empty JSON object
json user;
// Add key-value pairs like a map
user["name"] = "Zhang San";
user["age"] = 30;
user["email"] = "[email protected]";
user["is_active"] = true;
// Create a JSON array
json hobbies;
hobbies.push_back("Reading");
hobbies.push_back("Swimming");
hobbies.push_back("Programming");
// Set the array as a property of the object
user["hobbies"] = hobbies;
// Output JSON string (default formatting)
std::cout << "(1) Constructed JSON:\n" << pretty_print(user) << "\n\n";
return 0;
}
Output:
(1) Constructed JSON:
{
"age": 30,
"email": "[email protected]",
"hobbies": ["Reading", "Swimming", "Programming"],
"is_active": true,
"name": "Zhang San"
}
See, it’s very similar to manipulating std::map<std::string, std::any> or std::unordered_map!
Scenario 2: Parsing a JSON String
Now, we have a JSON string that we need to parse and read data from.
#include <iostream>
#include <jsoncons/json.hpp>
using namespace jsoncons;
int main() {
// JSON string to be parsed
std::string json_str = R"(
{
"product": "Laptop",
"price": 5999.99,
"in_stock": true,
"tags": ["Electronics", "Office", "High Performance"],
"dimensions": {
"width": 35.6,
"height": 2.1,
"depth": 24.3
}
}
)";
try {
// Parse JSON string
json product = json::parse(json_str);
// Read basic types
std::string name = product["product"].as<std::string>();
double price = product["price"].as<double>();
bool inStock = product["in_stock"].as<bool>();
std::cout << "(2) Product Information:\n";
std::cout << " Name: " << name << "\n";
std::cout << " Price: ¥" << price << "\n";
std::cout << " In Stock: " << (inStock ? "Yes" : "No") << "\n\n";
// Iterate over array
std::cout << " Tags: ";
for (const auto& tag : product["tags"].array_range()) {
std::cout << tag.as<std::string>() << " ";
}
std::cout << "\n\n";
// Access nested object
const json& dims = product["dimensions"];
std::cout << " Dimensions (cm): Width " << dims["width"].as<double>()
<< ", Height " << dims["height"].as<double>()
<< ", Depth " << dims["depth"].as<double>() << "\n";
} catch (const std::exception& e) {
std::cerr << "Error parsing JSON: " << e.what() << std::endl;
}
return 0;
}
Output:
(2) Product Information:
Name: Laptop
Price: ¥5999.99
In Stock: Yes
Tags: Electronics Office High Performance
Dimensions (cm): Width 35.6, Height 2.1, Depth 24.3
Note the as<T>() method, which provides type-safe conversion. If the types do not match, it will throw an exception.
Scenario 3: Reading and Writing JSON from Files
In practical applications, JSON data is often stored in files.
#include <iostream>
#include <fstream>
#include <jsoncons/json.hpp>
using namespace jsoncons;
int main() {
// Read JSON from file (assuming the filename is data.json)
std::ifstream input_file("data.json");
if (!input_file) {
std::cerr << "Cannot open file data.json\n";
return 1;
}
json config;
try {
// Parse from file stream
input_file >> config;
input_file.close();
std::cout << "(3) Configuration read from file:\n";
std::cout << pretty_print(config) << "\n\n";
// Modify configuration
config["database"]["port"] = 5432;
config["logging"]["level"] = "DEBUG";
// Write back to file
std::ofstream output_file("updated_config.json");
if (!output_file) {
std::cerr << "Cannot create file updated_config.json\n";
return 1;
}
// Use pretty_print for formatted output
output_file << pretty_print(config);
output_file.close();
std::cout << "Configuration updated and saved to updated_config.json\n";
} catch (const std::exception& e) {
std::cerr << "Error processing JSON file: " << e.what() << std::endl;
}
return 0;
}
Scenario 4: Using JSON Pointer and Patch (Advanced Features)
jsoncons supports JSON Pointer (like XPath for XML) to locate specific nodes in JSON, as well as JSON Patch to describe changes to JSON documents.
#include <iostream>
#include <jsoncons/json.hpp>
#include <jsoncons_ext/jsonpointer/jsonpointer.hpp>
#include <jsoncons_ext/jsonpatch/jsonpatch.hpp>
using namespace jsoncons;
using namespace jsoncons::jsonpointer;
using namespace jsoncons::jsonpatch;
int main() {
json doc = json::parse(R"(
{
"store": {
"book": [
{"title": "First Book", "price": 8.95},
{"title": "Second Book", "price": 12.50}
],
"bicycle": {"color": "Red", "price": 19.95}
}
})");
// Use JSON Pointer to get nested value
json* price_ptr = jsonpointer::get(doc, "/store/book/0/price");
if (price_ptr) {
std::cout << "(4) Price of the first book: " << price_ptr->as<double>() << "\n";
}
// Create a JSON Patch to modify the document
json patch = json::parse(R"([
{"op": "replace", "path": "/store/book/0/title", "value": "Updated First Book"},
{"op": "add", "path": "/store/book/-", "value": {"title": "Third Book", "price": 15.00}}
])");
// Apply Patch
jsonpatch::apply_patch(doc, patch);
std::cout << "Document after applying Patch:\n" << pretty_print(doc) << "\n";
return 0;
}
Conclusion
jsoncons is a powerful and well-designed C++ JSON library. It greatly simplifies JSON processing in C++ by providing an intuitive, STL-like interface. Whether for simple configuration reading and writing or complex API data exchanges, jsoncons can handle it all.
Review of Advantages:
- Easy to Use: Header-only library, just include it.
- Type Safety: The
as<T>()method avoids runtime type errors. - Excellent Performance: Fast parsing and serialization speeds.
- Comprehensive Features: Supports various data formats and advanced features.
If you are looking for a reliable and efficient C++ JSON library, jsoncons is definitely worth trying! Check out its GitHub repository for more detailed documentation and rich examples.