#ifndef _GP_JSON_H
#define _GP_JSON_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cjson/cJSON.h>
/// @brief read json text format file, transfer the content to a cJSON object.
/// @param filename json text file path.
/// @return cJSON object
cJSON *json_read_text_file(const char *filename);
/// @brief get a leaf object's string content from a json text file
/// @param filename json text file.
/// @param path from root to leaf, split with "\\", for example "person\\address"
/// @return const char *, no need to free, It storaged in a local buff.
const char *GetJsonStringItem(const char *filename, const char *path);
/// @brief get a leaf object from a json root object
/// @param root Json's root object
/// @param path a string splited with "\\", from root's first childlayer to the remote branch, for example: "provice\\henan\\zhengzhou"
/// @return a cJSON* object, when used yet, should call cJSON_Delete() to release it.
cJSON* getJsonElement(cJSON* root, const char* path);
/// @brief get a leaf object form a json file.
/// @param filename json filename.
/// @param path a string splited with "\\", from root's first childlayer to the remote branch, for example: "provice\\henan\\zhengzhou"
/// @return a cJSON* object, when used yet, should call cJSON_Delete() to release it.
cJSON *GetJsonCommonItem(const char *filename, const char *path);
#endif
上面是用来读取json对象,或者json文件的一组辅助函数接口。它可以仅仅通过指定json文件名,和json层级结构相关的路径信息,来返回json文件中的某一个叶子节点;甚至可以直接返回字符串信息。
- 接口考虑了相关返回值的析构问题,明确标出的注意事项。
- 接口注释使用oxygen语法,现代编译环境(比如VsCode)可以直接在编写代码时,显示函数说明和参数说明。
- 实体函数中包含一个未在头文件中给出的测试函数入口。改为main,搭配.json文件可以直接编译测试。
- 编译参数也已给出。
/*
* cJson read helper functions.
* first version: Sep13,2023 by fengxh @zz.
* write in linux c99 format.
* main_read_json_text_file() used for test itself.
*
* ver0.1.20230914 by fengxh @zz.
* + created and tested yet.
* helped by ChatGPT3.5.
* build cmd line : gcc gpjson.c -lcjson
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cjson/cJSON.h>
#include "gpjson.h"
cJSON *json_read_text_file(const char *filename){
FILE *file = fopen(filename, "r");
if (file == NULL) {
printf("Failed to open the file.\n");
return NULL;
}
fseek(file, 0, SEEK_END);
long file_size = ftell(file);
fseek(file, 0, SEEK_SET);
char *file_content = (char *)malloc(file_size + 1);
fread(file_content, 1, file_size, file);
file_content[file_size] = '\0';
fclose(file);
cJSON *json = cJSON_Parse(file_content);
free(file_content);
if (json == NULL) {
printf("Failed to parse JSON.\n");
free(file_content);
return NULL;
}
return json;
}
cJSON* getJsonElement(cJSON* root, const char* path) {
cJSON* current = root;
char* path_copy = strdup(path); // 复制路径,以便分割
char* token = strtok(path_copy, "\\"); // 使用 "\" 分割路径
while (token != NULL) {
if (current != NULL && cJSON_IsObject(current)) {
current = cJSON_GetObjectItem(current, token);
} else {
current = NULL; // 节点不存在
break;
}
token = strtok(NULL, "\\");
}
free(path_copy);
return current;
}
cJSON *GetJsonCommonItem(const char *filename, const char *path)
{
cJSON *root = json_read_text_file(filename);
if(root == NULL) return NULL;
cJSON *ret = getJsonElement(root, path);
if(ret != NULL)
{
cJSON_Delete(root);
return cJSON_Duplicate(ret, 1);
}
cJSON_Delete(root);
return NULL;
}
const char *GetJsonStringItem(const char *filename, const char *path)
{
static char cache[1024*20];
cJSON *root = json_read_text_file(filename);
if(root == NULL) return NULL;
// 通过路径获取最终的cJSON元素
cJSON* element = getJsonElement(root, path);
if (element != NULL && element->type == cJSON_String) {
strncpy(cache, element->valuestring, 1024*20-1);
} else {
return NULL;
}
// 释放cJSON对象内存
cJSON_Delete(root);
return cache;
}
// 测试程序,可以查看效果。
int main_read_json_text_file(void){
cJSON *json = json_read_text_file("data.json");
printf("%s\n", cJSON_Print(json));
cJSON_Delete(json);
return 0;
}