我试图使用由Dave Gamble编写的cJSON库来读取以下JSON数组:
"items":
[
{
"name": "command",
"index": "X",
"optional": "0"
},
{
"name": "status",
"index": "X",
"optional": "0"
}
]
Run Code Online (Sandbox Code Playgroud)
通过阅读他的文档,我找到了阅读单个对象的方法,但没有关于数组的内容,我无法从给出的示例中推测如何做到这一点.
这是我正在尝试的:
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");
Run Code Online (Sandbox Code Playgroud)
我知道这是错的,不仅因为它不起作用,而且我无法弄清楚如何使它正确.
显然,我需要循环读取数组中每个索引的所有条目的过程.我不知道我将如何做到这一点,因为我不知道我应该在这个代码中使用索引,或者它是否是正确的开始.有一个cJSON_GetArrayItem()
,但它只需要一个数字(可能是一个索引)而没有字符串来表示它想要的字段.
Den*_*hew 19
文档提到了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");
}
}
Run Code Online (Sandbox Code Playgroud)
将此功能称为
request_json = cJSON_Parse(request_body);
parse_object(request_json);
Run Code Online (Sandbox Code Playgroud)
恕我直言,这是一个例子,您应该打破库的封装并直接使用它的对象数据结构。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;
Run Code Online (Sandbox Code Playgroud)
(当然,人们可能会对作者做出的一些命名选择提出异议。但好的命名很难。)
需要注意的关键是 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;
}
}
Run Code Online (Sandbox Code Playgroud)
由于对象和数组仅在每个子项的名称存在方面存在内部差异,因此该函数还将迭代对象的字段。回调可以判断,因为ja->type
将是cJSON_Array
或cJSON_Object
,并且jchild->string
对于对象来说也将是非空的。
cJSON_GetArraySize()
通过调用和使用进行相同的迭代cJSON_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;
}
}
Run Code Online (Sandbox Code Playgroud)
这避免了 RBERTEIG 正确指出的 O(n^2) 成本。
致电:
parse_array(cJSON_GetObjectItem(cJSON_Parse(request_body),"items"));
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
34810 次 |
最近记录: |