JsonCpp
维基教科书人认为此页面应该拆分成更小的页面,主题更窄。 您可以通过将此大页面拆分成更小的页面来帮助我们。请务必遵循命名规则。将书籍分成更小的部分可以提供更多的关注点,并允许每个部分都能很好地完成一项任务,这对每个人都有好处。 |
本书介绍了 JsonCpp 库(也称为 jsoncpp 和 json-cpp),JsonCpp 可能是 C++ 中使用最广泛的 JSON 数据库库。它可以解析和保存数据库,并提供一个广泛的库来访问和操作其成员。JsonCpp 可以与文件和字符串一起使用。
对于一个存在多年的库来说,JsonCpp 的文档化程度令人惊讶地差。您要么能找到一个非常简单的使用示例,要么能找到一个计算机生成的包含所有类和方法的列表。
我既不是该库的作者,也不是该库的贡献者。
JSON(JavaScript 对象表示法)是一种用于表示各种数据结构的 ASCII 格式。它非常独立于语言、机器、简单且易于人机阅读。
JSON 在json.org上进行了全面描述。
简而言之,JSON 值可以是以下之一(有关完整详细信息,请参阅json.org):
- null
- true 或 false
- 数字。
- 数字不能以 0(或 -0)开头,后跟另一个数字(例如,0 和 0.14 是有效的数字,而 03、012.34 和 -015 不是)。
- 如果数字包含小数点,则它也应该至少包含小数点前后的一个数字(例如,数字 15. 和 .15 是无效的)。
- 字符串。字符串用双引号括起来,可以包含以下转义序列
\" - quote \\ - backslash \/ - slash \n - newline \t - tabulation \r - carriage return \b - backspace \f - form feed \uxxxx , where x is a hexadecimal digit - any 2-byte symbol
- 数组。它用方括号中以逗号分隔的任何值列表表示。示例
[1, 2, 3, "Hello world\n", true]
- 对象,也称为关联数组、键值列表等。它用花括号中以逗号分隔的键值对列表表示。键值对的格式为
key : value
其中 key 是一个字符串,value 是任何 JSON 值。示例
{"foo":1, "bar":2, "baz":3.14, "hello world":[1,2,3]}
可以在任何标记之间插入空格。
数组元素通过其数字访问,而对象元素通过键访问。数组和对象可以为空。数组和对象可以递归地包含其他数组或对象。
虽然严格的 JSON 语法不允许任何注释,并且要求根值为数组或对象,但 JsonCpp 允许 C 样式和 C++ 样式的注释,并允许根值为任何类型。
截至 2016 年 2 月,共有数百种库用于解析和生成 62 种语言的 JSON,包括 22 种不同的 C++ 库。[1]
JsonCpp 可能是最流行的 C++ 库。另一个流行的库是rapidjson,它非常快。
从 Ubuntu 或 Debian Linux 的另一个版本使用它的最简单方法是,将其安装为
sudo apt-get install libjsoncpp-dev
(您可以使用 apt
代替 apt-get
。)
一个缺点是它不会安装最新版本。对于 Ubuntu 18.04.1,版本是 1.7.4,而截至 2018 年 8 月的最新版本是 1.8.4。对于 14.04,这个问题更严重,它安装了 0.6.0,而截至 2016 年 2 月的最新版本是 1.7.4。
要使用 JsonCpp,请包含
#include <jsoncpp/json/json.h>
要编译文件,请添加标志
-ljsoncpp
头文件将被安装到 /usr/include/jsoncpp/json。如果您好奇,库文件很可能被安装到 /usr/lib/x86_64-linux-gnu(但您几乎不需要知道它们的位置)。如果您想找到它,请尝试
ls /usr/lib/*/*jsoncpp* ls /usr/lib/*jsoncpp*
要使用合并后的源代码使用 JsonCpp,您无需下载或制作任何二进制文件。您将拥有一个 cpp 文件和两个 .h 文件,您应该将它们包含到您的项目中。这些文件将与系统无关。
- 从官方仓库下载并解压缩源代码。转到目录。
- 运行
python amalgamate.py
它将创建三个文件
dist/jsoncpp.cpp, the source file to be added to your project dist/json/json.h, the correspondent header file dist/json/json-forwards.h, which contains forward declarations of JSON types.
除了这三个文件,您不需要任何其他东西。
- 从官方仓库下载并解压缩源代码。转到目录。
- 安装 cmake。在 Ubuntu 或 Debian Linux 的另一个版本下
sudo apt-get install cmake
- 创建构建目录并进入它
mkdir -p build cd build
- 运行 cmake 命令
cmake -DCMAKE_BUILD_TYPE=release -DBUILD_STATIC_LIBS=ON -DBUILD_SHARED_LIBS=OFF -DARCHIVE_INSTALL_DIR=. -G "Unix Makefiles" ..
- 运行 make 命令
make
(您可以使用 -j
标志来并行构建,例如 make -j 4
。)
在 Unix 下,它将在您的构建目录中创建文件 src/lib_json/libjsoncpp.a。包含文件将在 ../include/json 中。安装文件(make install
可能会有帮助),并使用
#include <jsoncpp/json/json.h>
和
-ljsoncpp
- 从官方仓库下载并解压缩源代码。
- 在这个解压缩的源代码树中,在 makefiles/msvc2010(对于 MS Visual Studio 2010)或 vs71(MS Visual Studio 2003)下,您将找到一些 Visual Studio 项目文件,您可以对其进行升级和构建。
安装 JsonCpp。
创建一个包含以下内容的文件 alice.json
{
"book":"Alice in Wonderland",
"year":1865,
"characters":
[
{"name":"Jabberwock", "chapter":1},
{"name":"Cheshire Cat", "chapter":6},
{"name":"Mad Hatter", "chapter":7}
]
}
创建名为 alice.cpp 的文件,内容如下
#include <iostream>
#include <fstream>
#include <jsoncpp/json/json.h> // or jsoncpp/json.h , or json/json.h etc.
using namespace std;
int main() {
ifstream ifs("alice.json");
Json::Reader reader;
Json::Value obj;
reader.parse(ifs, obj); // reader can also read strings
cout << "Book: " << obj["book"].asString() << endl;
cout << "Year: " << obj["year"].asUInt() << endl;
const Json::Value& characters = obj["characters"]; // array of characters
for (int i = 0; i < characters.size(); i++){
cout << " name: " << characters[i]["name"].asString();
cout << " chapter: " << characters[i]["chapter"].asUInt();
cout << endl;
}
}
编译它
g++ -o alice alice.cpp -ljsoncpp
然后运行它
./alice
希望你会收到以下内容
Book: Alice in Wonderland
Year: 1865
name: Jabberwock chapter: 1
name: Cheshire Cat chapter: 6
name: Mad Hatter chapter: 7
所有内容都在 Json 命名空间中。
类和其他类型的名称使用大驼峰命名法(每个单词的首字母大写)。示例:Int
、ArrayIndex
、ValueType
。成员函数、字段和枚举值的名称使用小驼峰命名法(除了第一个单词外,每个单词的首字母大写)。示例:stringValue
、isInt
、size
。
JsonCpp 执行大量的有效性检查。如果操作无效,它将抛出 std::runtime_error
异常,并附带相关消息。
JsonCpp 将每个数字存储为 64 位整数(long long int
或 __int64
),或 64 位无符号整数(unsigned long long int
或 unsigned __int64
),或 double
。下面,我们将分别称它们为 int、uint 和 real。
数组或对象最多可以包含 个元素。字符串最多可以包含 个字符。对象键最多可以包含 个字符。
JsonCpp 提供了几个辅助类型。
以下类型在 config.h
中定义
- Int - 定义为
int
- UInt - 定义为
unsigned int
- Int64 - 64 位有符号整数,在 Microsoft Visual Studio 中定义为
__int64
,否则为long long int
- UInt64 - 64 位无符号整数,在 Microsoft Visual Studio 中定义为
unsigned __int64
,否则为unsigned long long int
- LargestInt - 最大的可能的有符号整数,定义为
Int64
- LargestUInt - 最大的可能的无符号整数,定义为
UInt64
ArrayIndex 是数组索引的类型。它被定义为 unsigned int
,这意味着数组或对象最多可以包含 个项目。
ValueType 是一个枚举,用于描述 JSON 值的类型。它被定义为
enum ValueType
{
nullValue = 0, ///< 'null' value
intValue, ///< signed integer value
uintValue, ///< unsigned integer value
realValue, ///< double value
stringValue, ///< UTF-8 string value
booleanValue, ///< bool value
arrayValue, ///< array value (ordered list)
objectValue ///< object value (collection of name/value pairs).
};
最简单的输入/输出方式是通过 operator<<
和 operator>>
。下面的程序从标准输入读取一个 JSON 值并将其写入标准输出。在发生语法错误的情况下,operator<<
将抛出 runtime_error
异常。
#include <iostream>
#include <jsoncpp/json/json.h> // or something
using namespace std;
int main() {
Json::Value val;
cin >> val;
cout << val;
}
例如
$ g++ -o copy-json copy-json.cpp -ljsoncpp
$ echo '{"a":[1,2],"b":[3,4]}' | ./copy-json
{
"a" : [ 1, 2 ],
"b" : [ 3, 4 ]
}
为了以这种方式从字符串中读取数据,或者写入字符串,可以使用 std::istringstream
和 std::ostringstream
,但还有其他方法可以做到这一点。
toStyledString 方法将任何值转换为格式化的字符串。它的声明如下
std::string toStyledString() const;
另一种更稳健的读取 JSON 值的方式是通过 Reader 类。它最实用的公共方法是(此处和以下,注释是我的,方法的顺序也是我的)
Reader(); // the default constructor
~Reader();
// Read a value from a JSON document and store it to root.
// If collectComments is true, comments are stored, otherwise they are ignored.
// In case of syntax error, it returns false, and the value of root may be arbitrary.
bool parse(const std::string& document, Value& root, bool collectComments = true); // from std::string
bool parse(const char *beginDoc, const char *endDoc, Value &root, bool collectComments=true); // from C-style string
bool parse(std::istream &is, Value &root, bool collectComments=true); // from input stream
// Returns a user friendly string that list errors in the parsed document.
std::string getFormattedErrorMessages() const;
示例
#include <iostream>
#include <jsoncpp/json/json.h> // or something
using namespace std;
int main() {
Json::Value val;
Json::Reader reader;
bool b = reader.parse(cin, val);
if (!b)
cout << "Error: " << reader.getFormattedErrorMessages();
else
cout << val;
}
与 Reader
不同,Writer 类是抽象类。有两个类实现了它
- FastWriter 生成未格式化的、非人类可读的文档。所有内容都将在一行中写入。
- StyledWriter 生成格式化的、人类可读的文档,类似于
operator<<
,但缩进更少,没有空行。
FastWriter
具有以下公共方法(默认构造函数和析构函数未显示)
// omit the word "null" when printing null values
// this contradicts the JSON standard, but accepted by JavaScript
// this function is not available in old versions
void dropNullPlaceholders();
// don't add newline as last character
// this function is not available in old versions
void omitEndingLineFeed();
// print space after ":" in objects
void enableYAMLCompatibility();
// write JSON object to a string
virtual std::string write(const Value &root);
StyledWriter
具有以下公共方法(默认构造函数和析构函数未显示)
virtual std::string write(const Value &root); // write JSON object to a string
最后,还有 StyledStreamWriter 类,用于写入流。它被 operator<<
直接调用。该类不是 Writer
或任何其他类的子类。它的公共方法如下
StyledStreamWriter(std::string indentation="\t");
~StyledStreamWriter();
void write(std::ostream &out, const Value &root);
StyledStreamWriter
并不是很有用,因为 operator<<
更方便。如果需要非标准缩进,可以考虑使用它。
示例
#include <iostream>
#include <jsoncpp/json/json.h> // or something
using namespace std;
int main() {
Json::Value val;
cin >> val;
Json::FastWriter fast;
Json::StyledWriter styled;
string sFast = fast.write(val);
string sStyled = styled.write(val);
cout << "Fast:\n" << sFast << "Styled:\n" << sStyled;
cout << "Styled stream:\n";
Json::StyledStreamWriter styledStream;
styledStream.write(cout, val);
}
Value 的以下方法返回有关它的某些信息
// get the type (intValue etc.)
ValueType type() const;
// get the number of elements in array or object (returns 0 for anything else, including string)
ArrayIndex size() const;
// returns true for empty array, empty object, or null
bool empty() const;
// returns true for null only
bool operator!() const;
// returns true for specific type only
bool isNull() const;
bool isBool() const;
bool isString() const;
bool isArray() const;
bool isObject() const;
// see explanations in text
bool isInt() const;
bool isInt64() const;
bool isUInt() const;
bool isUInt64() const;
bool isIntegral() const;
bool isDouble() const;
bool isNumeric() const;
isInt()
、isInt64()
、isUInt()
、isUInt64(
) 仅在满足以下所有条件时返回 true
- 类型为数字类型(int、uint 或 real)
- 如果类型为 real,则值应该没有小数部分
- 值应该在给定类型的范围内(分别为
Int
、Int64
、UInt
、UInt64
)
isDouble()
和 isNumeric()
当前在类型为 int、uint 或 real 时返回 true
。
isIntegral()
对于 int 或 uint 始终返回 true
。对于 real 值,如果该值没有小数部分,并且在 Int64
或 UInt64
的范围内,则返回 true
。对于所有其他类型,它返回 false
。
is... 函数不向后兼容。在 0.* 版本中,isInt()
和 isUInt()
仅检查类型,isInt64()
和 isUInt64()
不存在,isArray()
和 isObject()
也对 null 值返回 true,isIntegral
也对布尔值返回 true 等等。
示例
#include <iostream>
#include <jsoncpp/json/json.h> // or something
using namespace std;
int main() {
Json::Value val;
cin >> val;
switch (val.type()) {
case Json::nullValue: cout << "nullValue\n"; break;
case Json::intValue: cout << "intValue\n"; break;
case Json::uintValue: cout << "uintValue\n"; break;
case Json::realValue: cout << "realValue\n"; break;
case Json::stringValue: cout << "stringValue\n"; break;
case Json::booleanValue: cout << "booleanValue\n"; break;
case Json::arrayValue: cout << "arrayValue\n"; break;
case Json::objectValue: cout << "objectValue\n"; break;
default: cout << "wrong type\n"; break;
}
}
要获取数字、布尔值或字符串值本身,Value 类提供以下方法
const char* asCString() const;
std::string asString() const;
Int asInt() const;
UInt asUInt() const;
Int64 asInt64() const;
UInt64 asUInt64() const;
LargestInt asLargestInt() const;
LargestUInt asLargestUInt() const;
float asFloat() const;
double asDouble() const;
bool asBool() const;
其中一些方法可能会抛出 std::runtime_exception
。一个简单的规则:如果 isFoo()
返回 true,那么调用 asFoo()
是安全的,但反过来不一定为真。
另一个规则,调用以下方法始终是安全的
asString()
用于字符串asLargestInt()
用于 intasLargestUInt()
用于 uintasFloat()
或asDouble()
用于任何数字(int、uint 或 real)asBool()
用于布尔值
以下是详细信息。
asInt()
、asUInt
、asInt64()
、asUInt64(
)、asLargestInt()
、asLargestUInt()
方法执行以下操作
- 如果原始值为数字,则检查它是否在目标类型的范围内。如果不是,则抛出
std::runtime_error
。然后将该值强制转换为目标类型。强制转换是简单的,因此 real 值 3.9 发送到asInt()
后将变为 3。 - 如果原始值为布尔值或 null,则返回 1 表示 true,0 表示 false,0 表示 null。
- 对于字符串、数组和对象,将抛出
std::runtime_error
。
asFloat()
和 asDouble()
方法执行以下操作
- 如果原始值为数字,则将其强制转换为
float
或double
。 - 如果原始值为布尔值或 null,则返回 1.0 表示 true,0.0 表示 false,0.0 表示 null。
- 对于字符串、数组和对象,将抛出
std::runtime_error
。
asBool()
方法接受任何内容。
- false、null、0、0.0 或空字符串/数组/对象将被转换为
false
- true、非零数字或非空字符串/数组/对象将被转换为
true
asString()
方法健壮、速度慢,属于高级方法。它返回std::string
。它能正确处理零字符的字符串。它接受除数组和对象之外的所有类型。对于 null,该方法返回""
;对于布尔值,它返回"true"
或 "false"
;对于数字,它返回其字符串表示形式。对于数组和对象,它抛出std::runtime
异常。
asCString()
方法是快速、低级方法。它只接受字符串(否则会抛出std::runtime
异常),并直接返回内部存储的 C 风格字符串。该方法不会分配任何内容。不要对返回的指针调用free()
或 delete[]
!你需要记住两点
- 由于 C 风格字符串不能包含零字符,因此该方法只适合不包含零字符的字符串。
- 对于空字符串,它有时会返回 0。
如果你需要 C 风格字符串,但不想被零字符搞混,JsonCpp 的较新版本添加了以下方法
bool getString(char const** begin, char const** end) const;
该方法将第一个字符的指针存储到*begin
,将最后一个零字符的指针存储到*end
,并返回true
。对于非字符串以及有时对于空字符串,它返回false
。
示例
#include <iostream>
#include <jsoncpp/json/json.h> // or something
using namespace std;
int main() {
Json::Value val;
cin >> val;
switch (val.type()) {
case Json::nullValue: cout << "null\n"; break;
case Json::intValue: cout << "int " << val.asLargestInt() << "\n"; break;
case Json::uintValue: cout << "uint " << val.asLargestUInt() << "\n"; break;
case Json::realValue: cout << "real " << val.asDouble() << "\n"; break;
case Json::stringValue: cout << "string " << val.asString() << "\n"; break;
/*
-or-
case Json::stringValue: {
const char *begin;
const char *end;
val.getString(&begin, &end);
cout << "string of length " << end - begin << "\n";
}
break;
*/
case Json::booleanValue: cout << "boolean " << val.asBool() << "\n"; break;
case Json::arrayValue: cout << "array of length " << val.size() << "\n"; break;
case Json::objectValue: cout << "object of length " << val.size() << "\n"; break;
default: cout << "wrong type\n"; break;
}
}
Json::Value 类提供了以下构造函数
Value(ValueType type = nullValue);
Value(Int value);
Value(UInt value);
Value(Int64 value);
Value(UInt64 value);
Value(double value);
Value(const char *value);
Value(const char *beginValue, const char *endValue);
Value(const std::string &value);
Value(bool value);
Value(const Value &other);
第一个构造函数创建 null、false、0、0.0 或空字符串/数组/对象。其他构造函数不言自明。
还提供了赋值、交换和所有比较运算符(作为方法)。
Value &operator=(const Value &other);
void swap(Value &other);
bool operator<(const Value &other) const;
bool operator<=(const Value &other) const;
bool operator>=(const Value &other) const;
bool operator>(const Value &other) const;
bool operator==(const Value &other) const;
bool operator!=(const Value &other) const;
int compare(const Value &other) const;
数组有自己的方法。这些方法也适用于 null。
其中一些类似于 C++ STL 的向量
ArrayIndex size() const;
bool empty() const;
void clear();
void resize(ArrayIndex size);
Value& operator[](ArrayIndex index);
Value& operator[](int index);
const Value& operator[](const ArrayIndex index) const;
const Value& operator[](const int index) const;
请注意,ArrayIndex 被定义为无符号整数。
resize()
通过删除最后一个值或追加 null 值来更改数组大小。
如果operator[]
接收负索引,它会抛出std::runtime_error
异常。如果它接收等于或大于当前大小的index
,
- 非常量
operator[]
会追加index-size()+1
个 null 值,然后返回最后一个值 - 常量
operator[]
返回 null 值
要追加值,请使用append
Value &append(const Value &value);
这类似于 C++ 方法vector::push_back()
。换句话说,foo.append(bar)
等同于foo[foo.size()]=bar
。
get 方法返回第index
个元素,如果index
大于或等于大小,则返回defaultValue
Value get(ArrayIndex index, const Value &defaultValue) const;
请注意,它返回的值不是引用,因此调用该方法可能非常昂贵。
要检查索引的有效性,你可能需要使用isValidIndex
bool isValidIndex(ArrayIndex index) const;
这不太有用,因为value.isValidIndex(index)
等同于index < value.size()
。
你也可以使用removeIndex 删除一个值
bool removeIndex(ArrayIndex i, Value* removed);
没有奇迹,该方法需要线性时间。如果i
大于或等于大小,它返回false
。
如果foo
为 null,上面的方法将把它视为一个空数组
foo.empty()
返回true
foo.size()
返回 0foo.clear()
不做任何事foo.resize(0)
不做任何事- 对于正数大小,
foo.resize(size)
将foo
转换为包含size
个 null 的数组。 foo[i]
(非常量)将foo
转换为包含i+1
个 null 的数组,然后返回最后一个值foo[i]
(常量)返回 null 值foo.isValidIndex(i)
始终返回false
foo.get(index, defaultValue)
始终返回defaultValue
foo.append(bar)
使foo
成为一个包含一个元素的数组,该元素等于bar
foo.removeIndex
始终返回 false
clear()
、empty()
和size()
方法也适用于对象。
除此之外,为既不是数组也不是 null 的值调用以上任何方法都毫无用处。它们要么返回一些琐碎的值,要么抛出std::runtime_error
异常
foo.empty()
返回false
,除非foo
是一个空对象foo.size()
返回 0,除非foo
是一个对象foo.clear()
抛出std::runtime_error
异常,除非foo
是一个对象resize
、append
、get
、operator[]
抛出std::runtime_error
异常isValidIndex
始终返回false
removeIndex
始终返回false
对象有自己的方法。这些方法也适用于 null。
其中一些类似于 C++ STL 的映射
ArrayIndex size() const;
bool empty() const;
void clear();
Value& operator[](const char* key);
const Value& operator[](const char* key) const;
Value& operator[](const std::string& key);
const Value& operator[](const std::string& key) const;
这些不言自明。对于operator[]
,如果键不存在,非常量operator[]
会插入(键,null)对并返回该 null 的引用,而常量operator[]
只是返回某个 null 的引用。
以下方法将键作为 C++ 字符串、C 字符串或指定字符串开头和结尾的指针对来接收。最后一种形式在旧版本的 JsonCpp 中不存在。例如,如果字符串包含零字符,它很有用。
isMember 方法检查是否存在具有给定键的成员
bool isMember(const char* key) const;
bool isMember(const std::string& key) const;
bool isMember(const char* begin, const char* end) const; // only in newer versions
removeMember 方法删除一个元素。前两种形式返回被删除的值而不是引用,这可能非常昂贵。
Value removeMember(const char* key); // deprecated in versions 1.*
Value removeMember(const std::string& key); // deprecated in versions 1.*
bool removeMember(const char* key, Value* removed); // only since versions 1.*
bool removeMember(std::string const& key, Value* removed); // only since versions 1.*
bool removeMember(const char* begin, const char* end, Value* removed); // only since versions 1.*
要遍历对象的成员,你需要它们的键的完整列表。这是通过getMemberNames 完成的
Value::Members Value::getMemberNames() const;
Value::Members 被定义为
typedef std::vector<std::string> Members;
get 方法返回给定键的值,或者,如果不存在,则返回defaultValue
。就像数组一样,它返回的值不是引用,因此调用该方法可能非常昂贵。
Value get(const char* key, const Value& defaultValue) const;
Value get(const char* begin, const char* end, const Value& defaultValue) const;
Value get(const std::string& key, const Value& defaultValue) const; // only in newer versions
find 方法只存在于较新版本中。它以(begin,end)形式接收键并返回指向找到的值的指针。如果未找到,它返回NULL
指针。
const Value* find(const char* begin, const char* end) const; // only in newer versions
上面的方法将 null 值视为一个空对象
clear()
不做任何事size()
返回 0empty()
返回 true- 非常量
operator[]
将值转换为一个元素对象,具有给定的键和 null 值 - 常量
operator[]
返回 null removeMember()
返回 null(已弃用变体)或false
(新变体)。getMemberNames()
返回空的字符串向量get()
返回defaultValue
find()
返回NULL
clear()
、size()
、empty()
方法也适用于数组。除此之外,对于既不是 null 也不是对象的值,上面的方法会返回琐碎的值或抛出std::runtime_error
异常。
创建复杂结构
#include <iostream>
#include <jsoncpp/json/json.h> // or something
using namespace std;
int main() {
// create the characters array
Json::Value ch;
ch[0]["name"] = "Jabberwock";
ch[0]["chapter"] = 1;
ch[1]["name"] = "Cheshire Cat";
ch[1]["chapter"] = 6;
ch[2]["name"] = "Mad Hatter";
ch[2]["chapter"] = 7;
// create the main object
Json::Value val;
val["book"] = "Alice in Wonderland";
val["year"] = 1865;
val["characters"] = ch;
cout << val << '\n';
}
用于打印任何值的递归函数(当然,它已经存在,但我们从头开始实现它)
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <jsoncpp/json/json.h> // or something
using namespace std;
void Indent(ostream& ofs, int indent) {
for (int i=0; i<indent; i++)
ofs << ' ';
}
void MyPrint(ostream& ofs, const Json::Value& val, int indent=0) {
switch (val.type()) {
case Json::nullValue: ofs << "null"; break;
case Json::booleanValue: ofs << (val.asBool() ? "true" : "false"); break;
case Json::intValue: ofs << val.asLargestInt(); break;
case Json::uintValue: ofs << val.asLargestUInt(); break;
case Json::realValue: ofs << val.asDouble(); break;
case Json::stringValue: ofs << '"' << val.asString() << '"'; break;
case Json::arrayValue: {
Json::ArrayIndex size = val.size();
if (size == 0)
ofs << "[]";
else {
ofs << "[\n";
int newIndent = indent + 4;
for (Json::ArrayIndex i=0; i<size; i++) {
Indent(ofs, newIndent);
MyPrint(ofs, val[i], newIndent);
ofs << (i + 1 == size ? "\n" : ",\n");
}
Indent(ofs, indent);
ofs << ']';
}
break;
}
case Json::objectValue: {
if (val.empty())
ofs << "{}";
else {
ofs << "{\n";
int newIndent = indent + 4;
vector<string> keys = val.getMemberNames();
for (size_t i=0; i<keys.size(); i++) {
Indent(ofs, newIndent);
const string& key = keys[i];
ofs << '"' << key << '"' << " : ";
MyPrint(ofs, val[key], newIndent);
ofs << (i + 1 == keys.size() ? "\n" : ",\n");
}
Indent(ofs, indent);
ofs << '}';
}
break;
}
default :
cerr << "Wrong type!" << endl;
exit(0);
}
}
int main() {
ifstream ifs("alice.json");
Json::Value val;
ifs >> val;
MyPrint(cout, val);
cout << '\n';
}
迭代器类型为Json::Value::iterator 和Json::Value::const_iterator。它们是双向的,但不是随机的。Json::Value 的方法是
const_iterator begin() const;
const_iterator end() const;
iterator begin();
iterator end();
只有数组和对象具有非平凡的迭代器。如果foo
既不是数组也不是对象,则foo.begin()
等于foo.end()
。
迭代器具有完整的一组运算符:递增和递减(后缀和前缀++
和--
)、等于和不等于比较、赋值、默认构造函数和复制构造函数。迭代器不是随机的,因此无法将整数添加到迭代器。从另一个迭代器减去迭代器是可能的,但需要线性时间。
如果foo
是指向数组的迭代器,则*foo
是对相应数组元素的引用。如果foo
是指向对象的迭代器,则*foo
不是对(键,值)对的引用。它是对值的本身的引用。
operator->
从版本 1.* 开始可用。
示例
#include <iostream>
#include <fstream>
#include <jsoncpp/json/json.h> // or something
using namespace std;
int main() {
Json::Reader reader;
Json::Value val;
reader.parse("{\"one\":1,\"two\":2,\"three\":3}", val);
for(Json::Value::const_iterator it=val.begin(); it!=val.end(); ++it)
cout << it->asInt() << '\n';
}
将打印
1
3
2
要接收键(对于指向对象的迭代器)或索引(对于指向数组的迭代器),Json::Value::iterator
和Json::Value::const_iterator
提供了三种方法
// For iterator to array, returns the index
// For iterator to object, returs the key.
Value key() const;
// Return the index, or -1 if it is not an array iterator
UInt index() const;
// Return the key, or "" if it is not an object iterator.
const char *memberName() const;
如注释中所解释,key()
返回对象元素的键或数组元素的索引;index()
返回数组元素的索引,否则返回UInt(-1)
;memberName()
返回对象元素的键,否则返回空字符串 (""
)。
示例
这仅适用于较新版本。
#include <iostream>
#include <fstream>
#include <jsoncpp/json/json.h> // or something
using namespace std;
int main() {
Json::Reader reader;
Json::Value val;
reader.parse("{\"one\":1,\"two\":2,\"three\":3}", val);
for (Json::Value::const_iterator it=val.begin(); it!=val.end(); ++it)
cout << it.key().asString() << ':' << it->asInt() << '\n';
}
这将打印
one:1
three:3
two:2
对于旧版本,我们无法将 Json::Value::const_iterator 初始化为 Json::Value::iterator,并且没有 operator->。
在 0.* 版本中,从 const_iterator
到 iterator 的转换是不可能的,而相应的赋值是可能的。例如,如果 val
不是常量,我们无法编写
Json::Value::const_iterator it = val.begin();
相反,我们应该使用 Json::Value::iterator
。此外,没有 operator->
。
因此,我们应该用以下代码替换上面的代码
#include <iostream>
#include <fstream>
#include <jsoncpp/json/json.h> // or something
using namespace std;
int main() {
Json::Reader reader;
Json::Value val;
reader.parse("{\"one\":1,\"two\":2,\"three\":3}", val);
// We cannot declare "it" as a const_iterator, because begin() and end()
// return iterator, and there is no casting from iterator to const_iterator
for (Json::Value::iterator it=val.begin(); it!=val.end(); ++it)
cout << it.key().asString() << ':' << (*it).asInt() << '\n'; // no operator-> in this version
}