13

I am attempting to use the cJSON library, written by Dave Gamble, to read in the following JSON array:

"items": 
[
    {
        "name": "command",
        "index": "X",
        "optional": "0"
    },
    {
        "name": "status",
        "index": "X",
        "optional": "0"
    }
]

From reading his documentation, I found ways to read in individual Objects, but nothing regarding Arrays, and I wasn't able to surmise how to do it from the examples given.

Here's what I'm trying:

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");

I know this is wrong, and not just because it's not working, but I can't figure out how to make it right.

Obviously I'm going to need to loop the process of reading in all of the entries for each index of the array. I have no idea how I'm going to do that though, because I don't know where I should be using the indexes in this code, or if it is even the right start. There is a cJSON_GetArrayItem(), but it takes only a number (presumably an index) and no string to indicate which field it wants.

4

4 回答 4

22

文档中提到了 parse_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"); 
  }
}

将此函数称为

request_json = cJSON_Parse(request_body);
parse_object(request_json);
于 2013-06-03T16:20:51.373 回答
5

如果你想跑得稍微快一点,代码如下所示:

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"));
于 2016-05-28T00:48:59.947 回答
4

恕我直言,这是您应该破坏库的封装并直接使用它的对象数据结构的一个示例。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 数组都有一个非空child字段,该字段指向其子项的双向链表。JSON 对象的子对象也有非空string字段,其中包含与该子对象关联的字段名称。

因此,要在 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_Arrayor cJSON_Object,并且jchild->string对于 Objects 也将是非空的。

通过调用cJSON_GetArraySize()和使用进行相同的迭代cJSON_GetArrayItem()将是 O(n^2) 的顺序,因为它每次都必须遍历链表才能找到第 n 个项目。

可以说,cJSON 应该包含一些通用ForEach函数,但这可能代表着大量范围蔓延的开始,远离它声称的“最愚蠢的解析器,你可以完成你的工作”的最初目标。

于 2014-08-06T22:42:18.293 回答
1

我的猜测(没有阅读规范,并且对 C 有点生疏):

request_json = cJSON_Parse(request_body);

items = cJSON_GetObjectItem(request_json, "items");
for (int i = 0; i < max; i++) {  // Presumably "max" can be derived from "items" somehow

    cJSON* item = cJSON_GetArrayItem(items, i);

    name = cJSON_GetObjectItem(item, "name");
    index = cJSON_GetObjectItem(item, "index");
    optional = cJSON_GetObjectItem(item, "optional");

    // Stash above info somewhere
}
于 2013-06-03T16:27:01.050 回答