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 =


还没有评论,来说两句吧...