C语言中解析JSON字符串的实用指南**
在C语言中处理JSON字符串是一个常见的需求,尤其是在与Web服务交互、配置文件解析或数据交换等场景,C语言本身并没有内置对JSON格式的原生支持,因此我们需要借助第三方库来轻松解析JSON字符串,本文将介绍几种流行的C语言JSON库,并以其中两个为例,展示如何解析JSON字符串。
为什么在C中解析JSON需要库?
JSON是一种轻量级的数据交换格式,它易于人阅读和编写,也易于机器解析和生成,其结构包括对象(用花括号表示)、数组(用方括号[]
表示)、字符串、数字、布尔值和null,C语言是过程式的,没有直接对应JSON对象和数组的数据结构(如Python的字典或列表),手动解析需要处理字符串分割、类型转换、内存管理等诸多细节,既繁琐又容易出错,使用成熟的JSON库是明智之举。
流行的C语言JSON库
- cJSON:一个轻量量级的、单文件的C语言JSON解析器,它易于集成,API简单直观,非常适合嵌入式系统或对内存占用有要求的项目。
- Jansson:一个功能丰富、纯C的JSON库,提供了类型安全的API,错误处理机制较好,性能也不错。
- ujson (Ultra JSON):以高性能著称,适合需要快速解析大量JSON数据的场景。
- json-c:另一个广泛使用的开源库,提供了一系列函数来创建、解析和操作JSON数据。
本文将重点介绍cJSON和Jansson的使用方法,因为它们对于初学者来说相对友好且文档齐全。
使用cJSON库解析JSON字符串
cJSON的核心思想是将JSON字符串解析成一个cJSON对象树,你可以遍历这棵树来获取所需的数据。
步骤1:获取并集成cJSON
- 从cJSON的GitHub仓库(https://github.com/DaveGamble/cJSON)下载源代码。
- 将
cJSON.h
和cJSON.c
文件添加到你的项目中。 - 编译时链接
cJSON.c
。
步骤2:解析JSON字符串并获取数据
假设我们有以下JSON字符串:
{ "name": "John Doe", "age": 30, "isStudent": false, "courses": ["Math", "Science", "History"], "address": { "street": "123 Main St", "city": "New York" } }
示例代码:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include "cJSON.h" int main() { const char *json_string = "{" "\"name\": \"John Doe\"," "\"age\": 30," "\"isStudent\": false," "\"courses\": [\"Math\", \"Science\", \"History\"]," "\"address\": {" "\"street\": \"123 Main St\"," "\"city\": \"New York\"" "}" "}"; // 1. 解析JSON字符串 cJSON *root = cJSON_Parse(json_string); if (root == NULL) { const char *error_ptr = cJSON_GetErrorPtr(); if (error_ptr != NULL) { fprintf(stderr, "Error before: %s\n", error_ptr); } return 1; } // 2. 获取字符串值 cJSON *name = cJSON_GetObjectItemCaseSensitive(root, "name"); if (cJSON_IsString(name) && (name->valuestring != NULL)) { printf("Name: %s\n", name->valuestring); } // 3. 获取数值 cJSON *age = cJSON_GetObjectItemCaseSensitive(root, "age"); if (cJSON_IsNumber(age)) { printf("Age: %d\n", age->valueint); } // 4. 获取布尔值 cJSON *isStudent = cJSON_GetObjectItemCaseSensitive(root, "isStudent"); if (cJSON_IsBool(isStudent)) { printf("Is Student: %s\n", cJSON_IsTrue(isStudent) ? "true" : "false"); } // 5. 获取数组 cJSON *courses = cJSON_GetObjectItemCaseSensitive(root, "courses"); if (cJSON_IsArray(courses)) { int course_count = cJSON_GetArraySize(courses); printf("Courses (%d):\n", course_count); for (int i = 0; i < course_count; i++) { cJSON *course = cJSON_GetArrayItem(courses, i); if (cJSON_IsString(course) && (course->valuestring != NULL)) { printf(" - %s\n", course->valuestring); } } } // 6. 获取嵌套对象 cJSON *address = cJSON_GetObjectItemCaseSensitive(root, "address"); if (cJSON_IsObject(address)) { cJSON *street = cJSON_GetObjectItemCaseSensitive(address, "street"); cJSON *city = cJSON_GetObjectItemCaseSensitive(address, "city"); if (cJSON_IsString(street) && (street->valuestring != NULL) && cJSON_IsString(city) && (city->valuestring != NULL)) { printf("Address: %s, %s\n", street->valuestring, city->valuestring); } } // 7. 释放内存 cJSON_Delete(root); return 0; }
cJSON关键点:
cJSON_Parse()
:解析JSON字符串,返回cJSON对象指针。cJSON_GetObjectItemCaseSensitive()
:根据键名获取对象中的项(区分大小写)。cJSON_IsString()
,cJSON_IsNumber()
,cJSON_IsBool()
,cJSON_IsArray()
,cJSON_IsObject()
:类型检查宏。valuestring
,valueint
,valuedouble
:获取对应类型的值。cJSON_GetArraySize()
:获取数组大小。cJSON_GetArrayItem()
:获取数组中的指定项。cJSON_Delete()
:释放解析后的cJSON对象树及其所有子项,防止内存泄漏。
使用Jansson库解析JSON字符串
Jansson提供了更类型化的API,错误处理也更为完善。
步骤1:获取并集成Jansson
- 从Jansson的官方网站(https://github.com/akheron/jansson)下载源代码并编译安装,或使用包管理器(如
apt-get install libjansson-dev
)。 - 在编译时链接Jansson库(
gcc your_program.c -ljansson
)。
步骤2:解析JSON字符串并获取数据
使用相同的JSON字符串示例:
示例代码:
#include <stdio.h> #include <jansson.h> int main() { const char *json_string = "{" "\"name\": \"John Doe\"," "\"age\": 30," "\"isStudent\": false," "\"courses\": [\"Math\", \"Science\", \"History\"]," "\"address\": {" "\"street\": \"123 Main St\"," "\"city\": \"New York\"" "}" "}"; json_error_t error; // 1. 解析JSON字符串 json_t *root = json_loads(json_string, 0, &error); if (!root) { fprintf(stderr, "Error on line %d: %s\n", error.line, error.text); return 1; } // 2. 获取字符串值 json_t *name = json_object_get(root, "name"); if (json_is_string(name)) { printf("Name: %s\n", json_string_value(name)); } // 3. 获取数值 json_t *age = json_object_get(root, "age"); if (json_is_integer(age)) { printf("Age: %d\n", json_integer_value(age)); } // 4. 获取布尔值 json_t *isStudent = json_object_get(root, "isStudent"); if (json_is_boolean(isStudent)) { printf("Is Student: %s\n", json_boolean_value(isStudent) ? "true" : "false"); } // 5. 获取数组 json_t *courses = json_object_get(root, "courses"); if (json_is_array(courses)) { size_t course_count = json_array_size(courses); printf("Courses (%zu):\n", course_count); for (size_t i = 0; i < course_count; i++) { json_t *course = json_array_get(courses, i); if (json_is_string(course)) { printf(" - %s\n", json_string_value(course)); } } } // 6. 获取嵌套对象 json_t *address = json_object_get(root, "address"); if (json_is_object(address)) { json_t *street = json_object_get(address, "street"); json_t *city =
还没有评论,来说两句吧...