跳转到内容

JsonCpp

100% developed
来自 维基教科书,开放的世界,开放的书籍

本书介绍了 JsonCpp 库(也称为 jsoncpp 和 json-cpp),JsonCpp 可能是 C++ 中使用最广泛的 JSON 数据库库。它可以解析和保存数据库,并提供一个广泛的库来访问和操作其成员。JsonCpp 可以与文件和字符串一起使用。

对于一个存在多年的库来说,JsonCpp 的文档化程度令人惊讶地差。您要么能找到一个非常简单的使用示例,要么能找到一个计算机生成的包含所有类和方法的列表。

我既不是该库的作者,也不是该库的贡献者。

JSON(JavaScript 对象表示法)是一种用于表示各种数据结构的 ASCII 格式。它非常独立于语言、机器、简单且易于人机阅读。

JSON 在json.org上进行了全面描述。

简而言之,JSON 值可以是以下之一(有关完整详细信息,请参阅json.org):

  • null
  • truefalse
  • 数字
    • 数字不能以 0(或 -0)开头,后跟另一个数字(例如,00.14 是有效的数字,而 03012.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,它非常快。

安装和运行

[编辑 | 编辑源代码]

使用 apt 或 apt-get

[编辑 | 编辑源代码]

从 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

[编辑 | 编辑源代码]
  • 官方仓库下载并解压缩源代码。转到目录。
  • 安装 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

使用 MS Visual Studio

[编辑 | 编辑源代码]
  • 官方仓库下载并解压缩源代码。
  • 在这个解压缩的源代码树中,在 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

JsonCpp 的约定和限制

[编辑 | 编辑源代码]

所有内容都在 Json 命名空间中。

类和其他类型的名称使用大驼峰命名法(每个单词的首字母大写)。示例:IntArrayIndexValueType。成员函数、字段和枚举值的名称使用小驼峰命名法(除了第一个单词外,每个单词的首字母大写)。示例:stringValueisIntsize

JsonCpp 执行大量的有效性检查。如果操作无效,它将抛出 std::runtime_error 异常,并附带相关消息。

JsonCpp 将每个数字存储为 64 位整数(long long int__int64),或 64 位无符号整数(unsigned long long intunsigned __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::istringstreamstd::ostringstream,但还有其他方法可以做到这一点。

toStyledString()

[编辑 | 编辑源代码]

toStyledString 方法将任何值转换为格式化的字符串。它的声明如下

std::string toStyledString() const;

Json::Reader

[编辑 | 编辑源代码]

另一种更稳健的读取 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;
}

Json::Writer

[编辑 | 编辑源代码]

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

[编辑 | 编辑源代码]

最后,还有 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,则值应该没有小数部分
  • 值应该在给定类型的范围内(分别为 IntInt64UIntUInt64

isDouble()isNumeric() 当前在类型为 int、uint 或 real 时返回 true

isIntegral() 对于 int 或 uint 始终返回 true。对于 real 值,如果该值没有小数部分,并且在 Int64UInt64 的范围内,则返回 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() 用于 int
  • asLargestUInt() 用于 uint
  • asFloat()asDouble() 用于任何数字(int、uint 或 real)
  • asBool() 用于布尔值

以下是详细信息。

asInt()asUIntasInt64()asUInt64()、asLargestInt()asLargestUInt() 方法执行以下操作

  • 如果原始值为数字,则检查它是否在目标类型的范围内。如果不是,则抛出 std::runtime_error。然后将该值强制转换为目标类型。强制转换是简单的,因此 real 值 3.9 发送到 asInt() 后将变为 3。
  • 如果原始值为布尔值或 null,则返回 1 表示 true,0 表示 false,0 表示 null。
  • 对于字符串、数组和对象,将抛出 std::runtime_error

asFloat()asDouble() 方法执行以下操作

  • 如果原始值为数字,则将其强制转换为 floatdouble
  • 如果原始值为布尔值或 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

为 null 值调用数组方法

[编辑 | 编辑源代码]

如果foo 为 null,上面的方法将把它视为一个空数组

  • foo.empty() 返回true
  • foo.size() 返回 0
  • foo.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 是一个对象
  • resizeappendgetoperator[] 抛出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 值调用对象方法

[编辑 | 编辑源代码]

上面的方法将 null 值视为一个空对象

  • clear() 不做任何事
  • size() 返回 0
  • empty() 返回 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::iteratorJson::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::iteratorJson::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
}
华夏公益教科书