在C中遍历和修改JSON字符串的正确方法是什么?
具体来说,我有一个字符串body_buf。当打印出来
print("length: %dn%.*sn", body_len, body_len, body_buf);
它看起来像这样:
length: 113
{"field1":"something","whatever":10,"description":"body","id":"random","__oh__":{"session":"12345678jhgfdrtyui"}}
另一个更复杂的body_buf可能看起来像这样:
{"status":1,"query":{},"proc":{"memory":{"total":17177939968,"cmax":18363625472,"amax":20000000000},"cpu":{"cores":[0.788,0.132,0.319,2.951,10.111,3.309,1.43,0.8,2.705,4.203,2.32,2,0.019,0.172,0.247,3.888,0.282,0.423,5.254,0.258,0.009,0.369,3.277,0.048,0.283,7.574,3.086,1.592,0.191,0.166,4.348,0.391,0.085,0.25,7.12,4.927,3.671,1.147,3.216,4.628,0.131,0.995,0.744,4.252,4.022,3.505,3.758,3.491],"total":108.886,"limit":800},"disk":{"used":20170,"limit":50000,"io_limit":500}}}
我想根据以下规则简化body_buf(它也兼任删除敏感信息),只修改值,不修改任何键:
- 字符串变成字符串的长度
- 字符串数组变为[array_len, max_len, min_len].
- 数字数组变为[array_len, max, min].
我不熟悉在c中使用JSON字符串,最好的方法是什么?
我可以将body_buf视为字符串并遍历它,修改":"后面的内容,因为根据类型,这些必然是我要修改的值。对于数组,我需要跟踪夹在"["one_answers"]"。这可以工作,但似乎不是很简单。
或者,可以将body_buf转换为JSON类型,然后遍历嵌套结构。然后我还要修改它。我还没有找到一个C的例子(这将是有帮助的)使用JSON - C或其他方式遍历和修改(或通过某种深度复制创建一个新的?)JSON对象。
除了细节(上面的规则,1-3)之外,这应该是一个相对常见的操作——遍历和修改。因此,对于那些更熟悉JSON - C或JSON操作的复杂性和良好/标准实践的人,我正在寻找一些指针。
我有json-c:
#include "cJSON.h"
#include "cJSON_Utils.h"
#include <libjson/json.h>
#include <libjson/json_tokener.h>
到目前为止,我看到的相关信息包括:
https://gist.github.com/alan-mushi/19546a0e2c6bd4e059fd
如何获得json值后json_tokener_parse()?
使用JSON -c解析深度嵌套JSON键
我不知道如何"简化";json将是有用的。第一次在c中使用json可能会很吓人。
我喜欢cJSON
库,它轻便、便携、稳定。它有很好的测试覆盖率,许可证是MIT。
我认为这段代码使用库cJSON
会做你问的:
#include <cjson/cJSON.h>
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include <limits.h>
#include <float.h>
const char json1[] = "{"field1":"something","whatever":10,"description":"body","id":"random","__oh__":{"session":"12345678jhgfdrtyui"}}";
const char json2[] = "{"status":1,"query":{},"proc":{"memory":{"total":17177939968,"cmax":18363625472,"amax":20000000000},"cpu":{"cores":[0.788,0.132,0.319,2.951,10.111,3.309,1.43,0.8,2.705,4.203,2.32,2,0.019,0.172,0.247,3.888,0.282,0.423,5.254,0.258,0.009,0.369,3.277,0.048,0.283,7.574,3.086,1.592,0.191,0.166,4.348,0.391,0.085,0.25,7.12,4.927,3.671,1.147,3.216,4.628,0.131,0.995,0.744,4.252,4.022,3.505,3.758,3.491],"total":108.886,"limit":800},"disk":{"used":20170,"limit":50000,"io_limit":500}}}";
const char json3[] = "{"Name":"Tom","Age":18,"Address":"California","arr":[1,2,3,4,5]}";
static void simplifyArray(cJSON *input, cJSON *output)
{
cJSON *item;
size_t noElems = 0;
if (cJSON_IsString(cJSON_GetArrayItem(input, 0))) {
size_t max, min;
max = 0;
min = UINT_MAX;
cJSON_ArrayForEach(item, input) {
noElems++;
size_t len = strlen(cJSON_GetStringValue(item));
if (len > max) max = len;
if (len < min) min = len;
}
cJSON *newArray = cJSON_AddArrayToObject(output, input->string);
cJSON_AddItemToArray(newArray, cJSON_CreateNumber(noElems));
cJSON_AddItemToArray(newArray, cJSON_CreateNumber(max));
cJSON_AddItemToArray(newArray, cJSON_CreateNumber(min));
} else if (cJSON_IsNumber(cJSON_GetArrayItem(input, 0))) {
double max, min;
max = -DBL_MAX;
min = DBL_MAX;
cJSON_ArrayForEach(item, input) {
noElems++;
double value = item->valuedouble;
if (value > max) max = value;
if (value < min) min = value;
}
cJSON *newArray = cJSON_AddArrayToObject(output, input->string);
cJSON_AddItemToArray(newArray, cJSON_CreateNumber(noElems));
cJSON_AddItemToArray(newArray, cJSON_CreateNumber(max));
cJSON_AddItemToArray(newArray, cJSON_CreateNumber(min));
}
}
static void simplify(cJSON *input, cJSON *output)
{
cJSON *elem;
for (elem = input; elem != NULL; elem = elem->next) {
if (cJSON_IsString(elem)) {
cJSON_AddNumberToObject(output, elem->string, strlen(cJSON_GetStringValue(elem)));
} else if (cJSON_IsArray(elem)) {
simplifyArray(elem, output);
} else if (cJSON_IsObject(elem)) {
cJSON *newOutput = cJSON_AddObjectToObject(output, elem->string);
simplify(elem->child, newOutput);
} else {
cJSON *dup = cJSON_Duplicate(elem, true);
cJSON_AddItemToObject(output, elem->string, dup);
}
}
}
static void simplifyAndPrint(const char *json)
{
cJSON *input = cJSON_Parse(json);
cJSON *output = cJSON_CreateObject();
simplify(input->child, output);
printf("%sn", cJSON_PrintUnformatted(output));
cJSON_Delete(input);
cJSON_Delete(output);
}
int main()
{
simplifyAndPrint(json1);
simplifyAndPrint(json2);
simplifyAndPrint(json3);
return 0;
}
输出:
{"field1":9,"whatever":10,"description":4,"id":6,"__oh__":{"session":18}}
{"status":1,"query":{},"proc":{"memory":{"total":17177939968,"cmax":18363625472,"amax":20000000000},"cpu":{"cores":[48,10.111,0.009],"total":108.886,"limit":800},"disk":{"used":20170,"limit":50000,"io_limit":500}}}
{"Name":3,"Age":18,"Address":10,"arr":[5,5,1]}
在上面的例子中,我倾向于不改变输入JSON,如果你不关心这个,你可以使用函数cJSON_ReplaceItemInObject
来替换节点。
注::我假设数组只包含字符串和数字,不要混合,因为没有规则来处理其他数组配置。
注:2:这段代码使用的是Ubuntu 20.04版本的库,如果你从GitHub上下载这个库,这个版本将包含更多的功能。