跳轉到內容

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
}
華夏公益教科書