Add query support

pull/54/head
kulikala 8 years ago
parent 642f0cb4f5
commit 477c23e557
  1. 44
      README.md
  2. 116
      parson.c
  3. 9
      parson.h
  4. 30
      tests.c

@ -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

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

@ -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

@ -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…
Cancel
Save