JSON 格式回顧
- 對象:
{ "key": value, ... } 無序鍵值對
- 陣列:
[ value, ... ] 有序列表
- 值類型:字符串、數字、對象、陣列、布爾、null
JSON-GLib 定位
- 基於 GLib/GObject 實現的完整 JSON 解析器/生成器
- 提供 DOM 樹 API (
JsonParser, JsonNode, JsonObject, JsonArray)
- 支持 GObject 序列化/反序列化 (自動映射屬性)
- 輕量、無外部依賴、跨平台
核心類別體系
| 類別 | 角色 | 關鍵方法 |
JsonParser | 解析入口 | json_parser_load_from_file(), json_parser_load_from_data(), json_parser_get_root() |
JsonNode | 通用節點 (封裝值+類型) | json_node_get_value_type(), json_node_get_object(), json_node_get_array(), json_node_get_string(), json_node_get_int(), json_node_get_double(), json_node_get_boolean() |
JsonObject | JSON 對象 | json_object_get_member(), json_object_get_members(), json_object_set_member() |
JsonArray | JSON 陣列 | json_array_get_length(), json_array_get_element(), json_array_add_element() |
JsonGenerator | 生成器 | json_generator_set_root(), json_generator_to_data(), json_generator_to_file() |
解析示例:讀取人員信息
JSON 數據 (person.json)
{
"firstName": "John",
"lastName": "Smith",
"male": true,
"age": 25,
"address": {
"streetAddress": "21 2nd Street",
"city": "New York",
"state": "NY",
"postalCode": "10021"
},
"phoneNumber": [
{ "type": "home", "number": "212 555-1234" },
{ "type": "fax", "number": "646 555-4567" }
]
}
C 代碼
#include
#include
int main(int argc, char *argv[]) {
if (argc < 2) {
g_print("Usage: %s \n", argv[0]);
return 1;
}
GError *error = NULL;
JsonParser *parser = json_parser_new();
if (!json_parser_load_from_file(parser, argv[1], &error)) {
g_print("Parse failed: %s\n", error->message);
g_error_free(error);
g_object_unref(parser);
return 1;
}
JsonNode *root = json_parser_get_root(parser);
JsonObject *obj = json_node_get_object(root);
// 讀取基本字段
const gchar *first = json_object_get_string_member(obj, "firstName");
const gchar *last = json_object_get_string_member(obj, "lastName");
gboolean male = json_object_get_boolean_member(obj, "male");
gint age = json_object_get_int_member(obj, "age");
g_print("Name: %s %s, Male: %s, Age: %d\n",
first, last, male ? "yes" : "no", age);
// 讀取嵌套對象
JsonNode *addr_node = json_object_get_member(obj, "address");
JsonObject *addr = json_node_get_object(addr_node);
const gchar *city = json_object_get_string_member(addr, "city");
g_print("City: %s\n", city);
// 讀取陣列
JsonNode *phones_node = json_object_get_member(obj, "phoneNumber");
JsonArray *phones = json_node_get_array(phones_node);
for (guint i = 0; i < json_array_get_length(phones); ++i) {
JsonNode *ph_node = json_array_get_element(phones, i);
JsonObject *ph = json_node_get_object(ph_node);
const gchar *type = json_object_get_string_member(ph, "type");
const gchar *num = json_object_get_string_member(ph, "number");
g_print("Phone[%d]: %s - %s\n", i, type, num);
}
g_object_unref(parser);
return 0;
}
編譯鏈接
gcc `pkg-config --cflags --libs json-glib-1.0` parse.c -o parse
./parse person.json
生成 JSON
JsonBuilder *builder = json_builder_new();
json_builder_begin_object(builder);
json_builder_set_member_name(builder, "name");
json_builder_add_string_value(builder, "Test");
json_builder_set_member_name(builder, "values");
json_builder_begin_array(builder);
json_builder_add_int_value(builder, 1);
json_builder_add_int_value(builder, 2);
json_builder_end_array(builder);
json_builder_end_object(builder);
JsonGenerator *gen = json_generator_new();
json_generator_set_root(gen, json_builder_get_root(builder));
gchar *str = json_generator_to_data(gen, NULL);
g_print("%s\n", str); // {"name":"Test","values":[1,2]}
g_free(str);
g_object_unref(gen);
g_object_unref(builder);
GObject 序列化
定義 GObject 子類,屬性標註 G_PARAM_READWRITE,即可自動雙向轉換:
// 類定義
typedef struct { GObject parent; gchar *name; gint age; } Person;
G_DEFINE_TYPE(Person, person, G_TYPE_OBJECT)
// 序列化
Person *p = g_object_new(PERSON_TYPE, "name", "Alice", "age", 30, NULL);
JsonNode *node = json_gobject_serialize(p); // 自動生成 JSON
// 反序列化
Person *p2 = g_object_new(PERSON_TYPE, NULL);
json_gobject_deserialize(p2, node); // 自動填充屬性
安裝與依賴
- Linux:
sudo apt-get install libjson-glib-dev
- FreeBSD:
cd /usr/ports/devel/json-glib && make install clean
- 依賴: GLib ≥ 2.32, GObject
對比其他 C JSON 庫
| 庫 | 特點 | 適用場景 |
| JSON-GLib | GLib 整合、DOM、GObject 序列化、完整規格 | GTK/GNOME 應用、需 GObject 映射 |
| cJSON | 單文件、輕量、無依賴、SAX+DOM | 嵌入式、簡單解析、無 GLib 環境 |
| Jansson | 高性能、線程安全、簡潔 API | 高併發服務、通用 C 項目 |
| RapidJSON | C++、SAX/DOM、極快、header-only | C++ 項目、性能敏感 |
總結
JSON-GLib 是 GLib 生態系統中處理 JSON 的標準選擇,DOM API 直觀易用,GObject 序列化極大簡化模型層代碼。若項目已依賴 GLib,首選之;否則按依賴體量選擇 cJSON/Jansson。
- 上一篇文章: 龐果網排列搜索問題:C語言全排列實現與性能優化探討
- 下一篇文章: Objective-C 參考計數與物件所有權核心觀念詳解
Copyright ©
程式碼之家 All Rights Reserved