mirror of
https://github.com/kgabis/parson.git
synced 2025-07-14 16:02:09 +00:00
Add query support
This commit is contained in:
parent
642f0cb4f5
commit
477c23e557
44
README.md
44
README.md
@ -75,6 +75,50 @@ Date SHA Author
|
|||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
###Query
|
||||||
|
When you simply read JSON and get values without modifying it, you can use '.' and '[]' to traverse object and array hierarchy.
|
||||||
|
```c
|
||||||
|
void query_example(void) {
|
||||||
|
JSON_Value *root_value;
|
||||||
|
char *json_string;
|
||||||
|
|
||||||
|
/* json string to parse */
|
||||||
|
json_string = "{"
|
||||||
|
"\"list\":["
|
||||||
|
"{"
|
||||||
|
"\"index\":0,"
|
||||||
|
"\"data\":{"
|
||||||
|
"\"prop\":\"value\""
|
||||||
|
"}"
|
||||||
|
"},"
|
||||||
|
"{"
|
||||||
|
"\"index\":1,"
|
||||||
|
"\"data\":{"
|
||||||
|
"\"prop\":null"
|
||||||
|
"}"
|
||||||
|
"},"
|
||||||
|
"{"
|
||||||
|
"\"index\":2,"
|
||||||
|
"\"data\":{"
|
||||||
|
"\"prop\":123"
|
||||||
|
"}"
|
||||||
|
"}"
|
||||||
|
"]"
|
||||||
|
"}";
|
||||||
|
|
||||||
|
/* parsing json string */
|
||||||
|
root_value = json_parse_string(json_string);
|
||||||
|
|
||||||
|
if (JSONObject == json_type(root_value)) {
|
||||||
|
printf("Query: \"%s\", Result: \"%s\"\n", ".list[0].data.prop", json_value_query_string(root_value, ".list[0].data.prop"));
|
||||||
|
printf("Query: \"%s\", Result: \"%d\"\n", ".list[2].data.prop", (int)json_value_query_number(root_value, ".list[2].data.prop"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cleanup code */
|
||||||
|
json_value_free(root_value);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
###Persistence
|
###Persistence
|
||||||
In this example I'm using parson to save user information to a file and then load it and validate later.
|
In this example I'm using parson to save user information to a file and then load it and validate later.
|
||||||
```c
|
```c
|
||||||
|
116
parson.c
116
parson.c
@ -1929,3 +1929,119 @@ void json_set_allocation_functions(JSON_Malloc_Function malloc_fun, JSON_Free_Fu
|
|||||||
parson_malloc = malloc_fun;
|
parson_malloc = malloc_fun;
|
||||||
parson_free = free_fun;
|
parson_free = free_fun;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JSON_Value * json_value_query_value(JSON_Value *value, const char *query) {
|
||||||
|
const char *query_start = query, *field_start = query, *field_end = NULL;
|
||||||
|
char *name = NULL;
|
||||||
|
JSON_Value *return_value = NULL;
|
||||||
|
int in_bracket = 0, is_digit = 1;
|
||||||
|
while (query != NULL && *query != '\0') {
|
||||||
|
switch (*query) {
|
||||||
|
case '[':
|
||||||
|
if (in_bracket) {
|
||||||
|
// Ignore
|
||||||
|
} else if (field_start == query) {
|
||||||
|
field_start = query + 1;
|
||||||
|
in_bracket = 1;
|
||||||
|
} else if (field_start < query) {
|
||||||
|
field_end = query;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ']':
|
||||||
|
if (in_bracket) {
|
||||||
|
field_end = query;
|
||||||
|
query++;
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '.':
|
||||||
|
if (in_bracket) {
|
||||||
|
// Ignore
|
||||||
|
} else if (field_start == query) {
|
||||||
|
if (query_start == query) {
|
||||||
|
field_start = query + 1;
|
||||||
|
} else {
|
||||||
|
// Query ".."
|
||||||
|
field_end = query;
|
||||||
|
}
|
||||||
|
} else if (field_start < query) {
|
||||||
|
field_end = query;
|
||||||
|
query++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '0': case '1': case '2': case '3': case '4':
|
||||||
|
case '5': case '6': case '7': case '8': case '9':
|
||||||
|
// Keep is_digit = 1
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
is_digit = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (field_end != NULL) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
query++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (query != NULL && query_start < query && !in_bracket && field_end == NULL) {
|
||||||
|
field_end = query;
|
||||||
|
}
|
||||||
|
if (field_end == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
name = parson_strndup(field_start, field_end - field_start);
|
||||||
|
if (name == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (0 < strlen(name)) {
|
||||||
|
switch (json_type(value)) {
|
||||||
|
case JSONObject:
|
||||||
|
if (is_digit) {
|
||||||
|
return_value = json_object_get_value_at(json_value_get_object(value), atol(name));
|
||||||
|
} else {
|
||||||
|
return_value = json_object_get_value(json_value_get_object(value), name);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case JSONArray:
|
||||||
|
if (!is_digit) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return_value = json_array_get_value(json_value_get_array(value), atol(name));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return_value = value;
|
||||||
|
}
|
||||||
|
parson_free(name);
|
||||||
|
if (*query != '\0' && return_value != NULL) {
|
||||||
|
return_value = json_value_query_value(return_value, query);
|
||||||
|
}
|
||||||
|
return return_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char * json_value_query_string(JSON_Value *value, const char *query) {
|
||||||
|
return json_value_get_string(json_value_query_value(value, query));
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON_Object * json_value_query_object(JSON_Value *value, const char *query) {
|
||||||
|
return json_value_get_object(json_value_query_value(value, query));
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON_Array * json_value_query_array(JSON_Value *value, const char *query) {
|
||||||
|
return json_value_get_array(json_value_query_value(value, query));
|
||||||
|
}
|
||||||
|
|
||||||
|
double json_value_query_number(JSON_Value *value, const char *query) {
|
||||||
|
return json_value_get_number(json_value_query_value(value, query));
|
||||||
|
}
|
||||||
|
|
||||||
|
int json_value_query_boolean(JSON_Value *value, const char *query) {
|
||||||
|
return json_value_get_boolean(json_value_query_value(value, query));
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON_Value * json_query(JSON_Value *value, const char *query) {
|
||||||
|
return json_value_query_value(value, query);
|
||||||
|
}
|
||||||
|
9
parson.h
9
parson.h
@ -224,6 +224,15 @@ const char * json_string (const JSON_Value *value);
|
|||||||
double json_number (const JSON_Value *value);
|
double json_number (const JSON_Value *value);
|
||||||
int json_boolean(const JSON_Value *value);
|
int json_boolean(const JSON_Value *value);
|
||||||
|
|
||||||
|
/* Query */
|
||||||
|
JSON_Value * json_value_query_value (JSON_Value *value, const char *query);
|
||||||
|
const char * json_value_query_string (JSON_Value *value, const char *query);
|
||||||
|
JSON_Object * json_value_query_object (JSON_Value *value, const char *query);
|
||||||
|
JSON_Array * json_value_query_array (JSON_Value *value, const char *query);
|
||||||
|
double json_value_query_number (JSON_Value *value, const char *query); /* returns 0 on fail */
|
||||||
|
int json_value_query_boolean(JSON_Value *value, const char *query); /* returns -1 on fail */
|
||||||
|
JSON_Value * json_query (JSON_Value *value, const char *query); /* shorter version of json_value_query_value */
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
30
tests.c
30
tests.c
@ -208,6 +208,36 @@ void test_suite_2(JSON_Value *root_value) {
|
|||||||
TEST(json_object_get_object(root_object, "empty object") != NULL);
|
TEST(json_object_get_object(root_object, "empty object") != NULL);
|
||||||
TEST(json_object_get_array(root_object, "empty array") != NULL);
|
TEST(json_object_get_array(root_object, "empty array") != NULL);
|
||||||
|
|
||||||
|
TEST((json_value_query_value(root_value, ".") == root_value));
|
||||||
|
TEST((json_value_query_value(root_value, "..") == root_value));
|
||||||
|
TEST((json_value_query_value(root_value, "...") == root_value));
|
||||||
|
TEST((json_value_query_value(root_value, "[]") == root_value));
|
||||||
|
TEST((json_value_query_value(root_value, NULL) == NULL));
|
||||||
|
TEST((json_value_query_value(root_value, "") == NULL));
|
||||||
|
TEST((json_value_query_value(root_value, "noexist") == NULL));
|
||||||
|
TEST((json_value_query_value(root_value, ".noexist") == NULL));
|
||||||
|
TEST((json_value_query_value(root_value, "..noexist") == NULL));
|
||||||
|
TEST((json_value_query_value(root_value, "noexist.prop") == NULL));
|
||||||
|
TEST((json_value_query_value(root_value, ".noexist.prop") == NULL));
|
||||||
|
TEST((json_value_query_value(root_value, "..noexist.prop") == NULL));
|
||||||
|
TEST((json_value_query_value(root_value, ".[.no[[exist].prop") == NULL));
|
||||||
|
TEST((json_value_query_value(root_value, ".object].nested true") == NULL));
|
||||||
|
TEST(STREQ(json_value_query_string(root_value, "[0]"), "lorem ipsum"));
|
||||||
|
TEST(STREQ(json_value_query_string(root_value, "object.nested object.lorem"), "ipsum"));
|
||||||
|
TEST(STREQ(json_value_query_string(root_value, "object.nested object[0]"), "ipsum"));
|
||||||
|
TEST(STREQ(json_value_query_string(root_value, "object.nested array[0]"), "lorem"));
|
||||||
|
TEST(STREQ(json_value_query_string(root_value, ".object[nested array][1]"), "ipsum"));
|
||||||
|
TEST((json_value_query_number(root_value, ".object[nested number]") == 123));
|
||||||
|
TEST((json_value_query_boolean(root_value, ".object[nested true]") == 1));
|
||||||
|
|
||||||
|
array = json_value_query_array(root_value, ".object[nested array][]");
|
||||||
|
TEST(array != NULL);
|
||||||
|
TEST(json_array_get_count(array) == 2);
|
||||||
|
|
||||||
|
array = json_value_query_array(root_value, ".[x^2 array][]");
|
||||||
|
TEST(array != NULL);
|
||||||
|
TEST(json_array_get_count(array) == 11);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_suite_2_no_comments(void) {
|
void test_suite_2_no_comments(void) {
|
||||||
|
Loading…
Reference in New Issue
Block a user