C语言 使用 cJSON 读取 JSON 数组
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16900874/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Using cJSON to read in a JSON array
提问by Nealon
I am attempting to use the cJSON library, written by Dave Gamble, to read in the following JSON array:
我正在尝试使用 Dave Gamble 编写的 cJSON 库来读取以下 JSON 数组:
"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.
显然,我将需要循环读取数组每个索引的所有条目的过程。我不知道我将如何做到这一点,因为我不知道我应该在哪里使用这段代码中的索引,或者它是否是正确的开始。有一个cJSON_GetArrayItem(),但它只需要一个数字(大概是一个索引)并且没有字符串来指示它想要哪个字段。
回答by Denny Mathew
Document mentions about parse_object().
文档中提到了 parse_object()。
I think this is what you need to do.
我认为这是你需要做的。
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");
}
}
Call this function as
将此函数称为
request_json = cJSON_Parse(request_body);
parse_object(request_json);
回答by Dave Gamble
If you want to run slightly faster, this is what the code looks like:
如果你想运行得稍微快一点,代码如下所示:
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;
}
}
This avoids the O(n^2) cost that RBerteig correctly points out.
这避免了 RBERTEIG 正确指出的 O(n^2) 成本。
Call with:
致电:
parse_array(cJSON_GetObjectItem(cJSON_Parse(request_body),"items"));
回答by RBerteig
IMHO, this is one example of a case where you should burst the library's encapsulation and work directly with it's object data structure. cJSON.hdefines the core object as the following struct:
恕我直言,这是您应该打破库的封装并直接使用它的对象数据结构的情况的一个示例。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;
(One could quibble with some of the naming choices the author made, of course. But good naming is hard.)
(当然,人们可以对作者所做的一些命名选择提出异议。但好的命名很难。)
The key thing to note is that both JSON Objects and JSON Arrays have a non-null childfield, which points to a doubly-linked list of their children. Children of JSON Objects also have non-null stringfields which contains the field name associated with that child.
需要注意的关键是 JSON 对象和 JSON 数组都有一个非空child字段,它指向它们子项的双向链表。JSON 对象的子对象也有string包含与该子对象关联的字段名称的非空字段。
So, to generically iterate over the JSON Array jain O(n) time, calling a function for each element, you write something like this:
因此,要ja在 O(n) 时间内对 JSON 数组进行一般迭代,为每个元素调用一个函数,您可以编写如下代码:
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;
}
}
Since Objects and Arrays only differ internally in the presence of names for each child item, that function will also iterate the fields of an object. The callback can tell because ja->typewill be either cJSON_Arrayor cJSON_Object, and jchild->stringwill be non-null for Objects as well.
由于对象和数组仅在每个子项的名称存在时内部不同,因此该函数还将迭代对象的字段。回调可以告诉因为ja->type将是cJSON_Array或cJSON_Object,并且jchild->string对于对象也将是非空的。
Doing the same iteration by calling cJSON_GetArraySize()and using cJSON_GetArrayItem()will be order O(n^2) because it has to traverse the linked list each time to locate the nth item.
通过调用cJSON_GetArraySize()和使用cJSON_GetArrayItem()进行相同的迭代将是 O(n^2) 的顺序,因为它每次都必须遍历链表以定位第 n 个项目。
Arguably, cJSON should include some generic ForEachfunctions, but that might represent the beginning of a significant amount of scope-creep away from it's professed original goal of being "the dumbest possible parser that you can get your job done with".
可以说,cJSON 应该包含一些通用ForEach函数,但这可能代表了大量范围蠕变的开始,它声称最初的目标是“可以完成工作的最愚蠢的解析器”。
回答by Hot Licks
My guess (not having read the spec, and being a bit rusty with C):
我的猜测(没有阅读规范,并且对 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
}

