遍历和修改C json字符串 [英] Traversing through and modifying a C json string

查看:91
本文介绍了遍历和修改C json字符串的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在C中遍历和修改JSON字符串的正确方法是什么?

What's the correct way to traverse and modify a JSON string in C?

具体来说,我有一个字符串,body_buf.打印时

Specifically, I have a string, body_buf. When printed out

print("length: %d\n%.*s\n", body_len, body_len, body_buf);

它看起来像这样:

length: 113
{"field1":"something","whatever":10,"description":"body","id":"random","__oh__":{"session":"12345678jhgfdrtyui"}}

另一个更复杂的body_buf可能看起来像这样:

Another more complicated body_buf may look like this:

{"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(它还可以删除敏感信息),仅修改值,而不修改任何键:

I want to simplify body_buf (which also doubles as removing sensitive information) according to the following rules, only modifying the values, not any of the keys:

  1. 字符串成为字符串的长度.
  2. 字符串数组变为[array_len,max_len,min_len].
  3. 数字数组变为[array_len,max,min].

我不熟悉在C语言中使用JSON字符串的方法.最好的方法是什么?

I'm not familiar with working with JSON strings in C. What's the best way to do this?

我可以将body_buf视作一个字符串并遍历它,修改在:"之后的内容,因为根据类型的不同,这些值必然是我可能要修改的值.对于数组,我需要跟踪夹在"[]"之间的任何内容.和]".这可能有效,但看起来并不简单.

I can treat body_buf as a string and traverse through it, modifying whatever comes after a ":", because those are bound to be the values I might modify, depending on the type. For arrays, I need to keep track of anything that are sandwiched between "[" and "]". This could work but doesn't seem very straightforward.

或者,将body_buf转换为JSON类型,然后遍历嵌套结构.但是然后我也必须对其进行修改.我尚未找到使用json-c或其他方式遍历和修改(或通过某种深层复制创建一个新的)JSON对象的C示例(这将有所帮助).

Alternatively, perhaps convert the body_buf to a JSON type and then traverse through the nested structure. But then I also have to modify it. I have yet to find a C example (which would be helpful) using json-c or otherwise that traverses and modifies (or create a new one via some kind of deep copy?) a JSON object.

除了细节(上面的规则1-3)之外,这应该是一个相对常见的操作-遍历和修改.因此,对于那些更熟悉C语言中json-c或JSON操作的复杂性和良好/标准做法的人,我正在寻找一些指针.

Details (rules above, 1-3) aside, this should be a relatively common operation -- to traverse and modify. So for those more attuned to the intricacies and good/standard practices of json-c or JSON manipulation in general in C, I'm looking for some pointers.

同样,我有json-c:

Again, I have json-c:

#include "cJSON.h"
#include "cJSON_Utils.h"
#include <libjson/json.h>
#include <libjson/json_tokener.h>

到目前为止,我查看的相关信息包括:

Relevant information I've looked at so far include the following:

https://gist.github.com/alan-mushi/19546a0e2c6bd4e059fd

如何在json_tokener_parse()之后获取json值?

使用json-c解析深度嵌套的JSON密钥

推荐答案

我不知道如何简化" json会很有用. 第一次在c中使用json可能会令人恐惧.

I don't know how "simplify" the json will be useful. Using json in c can be scary the first time.

我喜欢cJSON库,它轻便,可移植且稳定. 它具有良好的测试覆盖率,并且许可证是MIT.

I like cJSON library, it is light, portable and stable. It has a good test coverage, and the license is MIT.

我认为使用库cJSON的这段代码将满足您的要求:

I think this code using the library cJSON will do what you asked:

#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("%s\n", 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来替换节点.

In the example above I preferred don't alter the input JSON, if you don't care about this you can use the funcion cJSON_ReplaceItemInObject to substitute the node.

P.S .:我假设数组仅包含字符串和数字,并且不要混合使用,因为没有规则可以处理其他数组配置.

P.S.: I am assuming arrays contain only strings and numbers, and don't mix it, because there is no rule to handle other array configurations.

P.S.2:此代码使用的是Ubuntu 20.04中提供的库版本,如果您从GitHub下载库,则该版本将包含更多功能.

P.S.2: This code is using the version of the library present in Ubuntu 20.04, if you download the library from GitHub the version will contain more features.

这篇关于遍历和修改C json字符串的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆