使用cJSON读取JSON数组

使用cJSON读取JSON数组,c,json,cjson,C,Json,Cjson,我试图使用Dave Gamble编写的cJSON库来读取以下JSON数组: "items": [ { "name": "command", "index": "X", "optional": "0" }, { "name": "status", "index": "X", "optional": "0" } ] 通过阅读他的文章,我找到了读取单个对象的方法,但没有关

我试图使用Dave Gamble编写的cJSON库来读取以下JSON数组:

"items": 
[
    {
        "name": "command",
        "index": "X",
        "optional": "0"
    },
    {
        "name": "status",
        "index": "X",
        "optional": "0"
    }
]
通过阅读他的文章,我找到了读取单个对象的方法,但没有关于数组的内容,我也无法从给出的示例中推测如何进行读取

以下是我正在尝试的:

cJSON* request_json = NULL;
cJSON* items = cJSON_CreateArray();
cJSON* name = NULL;
cJSON* index = NULL;
cJSON* optional = NULL;

request_json = cJSON_Parse(request_body);

items = cJSON_GetObjectItem(request_json, "items");

name = cJSON_GetObjectItem(items, "name");
index = cJSON_GetObjectItem(items, "index");
optional = cJSON_GetObjectItem(items, "optional");
我知道这是错误的,不仅仅是因为它不起作用,而是我不知道如何使它正确


显然,我需要循环读取数组每个索引的所有条目的过程。我不知道我将如何做到这一点,因为我不知道我应该在代码中的何处使用索引,或者它是否是正确的开始。有一个
cJSON\u GetArrayItem()
,但它只需要一个数字(可能是一个索引)而不需要字符串来指示它需要哪个字段。

文档提到了parse\u object()

我想这就是你需要做的

void parse_object(cJSON *root)
{
  cJSON* name = NULL;
  cJSON* index = NULL;
  cJSON* optional = NULL;

  int i;

  cJSON *item = cJSON_GetObjectItem(items,"items");
  for (i = 0 ; i < cJSON_GetArraySize(item) ; i++)
  {
     cJSON * subitem = cJSON_GetArrayItem(item, i);
     name = cJSON_GetObjectItem(subitem, "name");
     index = cJSON_GetObjectItem(subitem, "index");
     optional = cJSON_GetObjectItem(subitem, "optional"); 
  }
}
我猜(没有读过规范,对C有点生疏):

request\u json=cJSON\u Parse(请求体);
items=cJSON_GetObjectItem(请求“items”);
对于(inti=0;i
IMHO,这是一个例子,您应该突破库的封装,直接使用它的对象数据结构
cJSON.h
将核心对象定义为以下
struct

/* The cJSON structure: */
typedef struct cJSON {
    struct cJSON *next,*prev;   /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
    struct cJSON *child;        /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */

    int type;                   /* The type of the item, as above. */

    char *valuestring;          /* The item's string, if type==cJSON_String */
    int valueint;               /* The item's number, if type==cJSON_Number */
    double valuedouble;         /* The item's number, if type==cJSON_Number */

    char *string;               /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
} cJSON;
(当然,人们可能会对作者的一些命名选择产生质疑。但好的命名是很难的。)

需要注意的关键是,JSON对象和JSON数组都有一个非空的
子字段
字段,该字段指向其子对象的双链接列表。JSON对象的子对象还具有非空的
字符串
字段,其中包含与该子对象关联的字段名

因此,要在O(n)时间内对JSON数组
ja
进行一般性迭代,为每个元素调用一个函数,可以编写如下代码:

cJSON_ForEachItem(cJSON *ja, int (*f)(cJSON *ja, int i, cJSON *jchild)) 
{
    cJSON *jchild;
    int i;
    for (jchild=ja->child, i=0; jchild; jchild=jchild->next, ++i) {
        // do something here with the ith child...
        if (f(ja, i, jchild))
            break;
    }
}
由于对象和数组只在每个子项的名称上存在内部差异,因此该函数还将迭代对象的字段。回调可以判断,因为
ja->type
将是
cJSON_数组
cJSON_对象
,并且对象的
jchild->string
也将是非空的

通过调用
cJSON\u GetArraySize()
并使用
cJSON\u GetArrayItem()
执行相同的迭代将是顺序O(n^2),因为它每次都必须遍历链表才能找到第n个项目


可以说,cJSON应该包含一些通用的
ForEach
函数,但这可能意味着大量范围开始从它宣称的最初目标——成为“可以完成工作的最愚蠢的解析器”——开始慢慢扩展,这是代码的样子:

void parse_array(cJSON *array)
{
  cJSON *item = array ? array->child : 0;
  while (item)
  {
     cJSON *name = cJSON_GetObjectItem(item, "name");
     cJSON *index = cJSON_GetObjectItem(item, "index");
     cJSON *optional = cJSON_GetObjectItem(item, "optional"); 

     item=item->next;
  }
}
这避免了RBerteig正确指出的O(n^2)代价

致电:

parse_array(cJSON_GetObjectItem(cJSON_Parse(request_body),"items"));

如果“items”的值是一个数组,那么在我看来,您应该在其中的某个位置索引一个数组。然后,这将返回一个“对象”,您可以通过键进行搜索。(注意,在引用JSON时,您错误地忽略了周围的
{}
{}
表示一个“对象”,没有它,上面的文本是无效的JSON。)编译器中不是这样定义的,仅将其作为示例展示理解JSON的语法很重要。这是阅读的关键。是的,我明白了,再次,我只是引用文本,让阅读的人理解itI。我昨天使用cJSON编写了非常类似的代码,具有类似的结构输入。唯一显著的区别是我的循环是:for(inti=0;;i++),当项目返回NULL时,我中断了循环。请注意,以这种方式在cJSON阵列上循环是O(n^2),因为cJSON_GetArrayItem是O(n)。
void parse_array(cJSON *array)
{
  cJSON *item = array ? array->child : 0;
  while (item)
  {
     cJSON *name = cJSON_GetObjectItem(item, "name");
     cJSON *index = cJSON_GetObjectItem(item, "index");
     cJSON *optional = cJSON_GetObjectItem(item, "optional"); 

     item=item->next;
  }
}
parse_array(cJSON_GetObjectItem(cJSON_Parse(request_body),"items"));