2013-06-03 12 views
10

Ja próbuje użyć biblioteki cJSON, napisany przez Dave Gamble, aby odczytać w następujący JSON tablicy:Korzystanie cJSON czytać w tablicy JSON

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

Od czytania jego documentation, znalazłem sposoby odczytu w poszczególnych obiektach, ale nic w odniesieniu do tablic, a ja nie byłem w stanie domyślić się, jak to zrobić z podanych przykładów.

Oto co usiłuję:

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

wiem, że to jest złe, i nie tylko dlatego, że nie działa, ale nie mogę dowiedzieć się, jak to zrobić dobrze.

Oczywiście będę musiał zapętlić proces odczytu we wszystkich pozycjach dla każdego indeksu tablicy. Nie mam pojęcia, jak mam to zrobić, ponieważ nie wiem, gdzie powinienem używać indeksów w tym kodzie, lub jeśli jest to nawet właściwy początek. Istnieje cJSON_GetArrayItem(), ale pobiera on tylko liczbę (prawdopodobnie indeks) i brak łańcucha, aby wskazać, które pole chce.

+0

Jeżeli wartość „pozycji” jest tablicą, wydaje mi się, powinno być indeksowania tablicy gdzieś tam. Wtedy da ci z powrotem "obiekt", który możesz następnie wyszukać za pomocą klucza. –

+0

(Zwróć uwagę, że pomyłkowo pominąłeś otaczający '{}', gdy cytowałeś JSON. '{}' Oznacza "obiekt", a bez niego powyższy tekst jest nieprawidłowy JSON.) –

+0

To nie było tak, jak zostało zdefiniowane. w kompilatorze, po prostu pokazano go jako przykład – Nealon

Odpowiedz

19

Dokument wspomina o parse_object().

Myślę, że to jest to, co musisz zrobić.

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

wywołać tę funkcję jako

request_json = cJSON_Parse(request_body); 
parse_object(request_json); 
+0

BOCZNA UWAGA: Przechowywanie wartości w strukturze działa najlepiej dla mnie. – Nealon

1

mylę (nie przeczytawszy spec, a będąc nieco zardzewiały z 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 
} 
+0

Napisałem kod bardzo podobnie za pomocą cJSON wczoraj, z podobnie strukturalnymi danymi wejściowymi. Jedyną znaczącą różnicą była moja pętla: for (int i = 0 ;; i ++) i złamałem pętlę, gdy element wrócił NULL. Zauważ, że pętli nad tablicami cJSON w ten sposób jest O (n^2), ponieważ cJSON_GetArrayItem jest O (n). – Spike0xff

3

IMHO, jest to jeden z przykładów przypadek, w którym należy zamknąć enkapsulację biblioteki i pracować bezpośrednio ze strukturą danych obiektu. cJSON.h określa obiekt rdzenia jak następującej 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; 

(.. Można spierać się z niektórymi z wyborów nazewnictwa autor wykonane, oczywiście, ale dobre nazewnictwa jest ciężko)

kluczową sprawą należy zauważyć, że zarówno JSON Objects, jak i JSON Arrays mają niezerowe pole child, które wskazuje na podwójnie połączoną listę swoich dzieci. Obiekty podrzędne obiektów JSON mają również niezerowe pola string, które zawierają nazwę pola powiązaną z tym dzieckiem.

Tak więc, aby rodzajowo iteracyjne nad tablicy JSON ja w O (n) czasie wywołania funkcji dla każdego elementu, piszesz coś takiego:

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; 
    } 
} 

Ponieważ obiektów i Tablice różnią się tylko wewnętrznie w obecność nazw dla każdego elementu podrzędnego, funkcja ta będzie również iterować pola obiektu. Oddzwanianie może powiedzieć, ponieważ ja->type będzie albo cJSON_Array lub cJSON_Object, a jchild->string będzie również wartością inną niż null dla obiektów.

Wykonanie tej samej iteracji przez wywołanie cJSON_GetArraySize() i użycie cJSON_GetArrayItem() spowoduje zamówienie O (n^2), ponieważ musi za każdym razem przechodzić przez połączoną listę, aby zlokalizować n-ty element.

Możliwe, że cJSON powinien zawierać pewne ogólne funkcje ForEach, ale może to oznaczać początek znacznej odległości od rzeczywistego celu, jakim jest "najgłupszy możliwy parser, z którym można wykonać swoją pracę" .

3

Jeśli chcesz uruchomić nieco szybciej, to co kod wygląda następująco:

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; 
    } 
} 

Eliminuje to O (n^2) koszty, które RBerteig słusznie zauważa.

Połącz z:

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