summaryrefslogtreecommitdiff
path: root/jsonpath.c
diff options
context:
space:
mode:
Diffstat (limited to 'jsonpath.c')
-rw-r--r--jsonpath.c88
1 files changed, 60 insertions, 28 deletions
diff --git a/jsonpath.c b/jsonpath.c
index 253f2cb..edfa6e8 100644
--- a/jsonpath.c
+++ b/jsonpath.c
@@ -158,6 +158,11 @@ mkRefChar(const char *bytes, size_t length)
return ref;
}
+/*
+ * jp_show
+ * Unparse a JSONPath expression. This is used by parse_json_path
+ * to stringify successfully parsed JSONPaths.
+ */
char *
jp_show(JSONPath * jp)
{
@@ -201,6 +206,12 @@ jp_show(JSONPath * jp)
return string->data;
}
+/*
+ * Parse a long starting at *s .
+ *
+ * On success, return true and update *s to point to the end of the number.
+ * On failure, return false and leave *s untouched.
+ */
static bool
parse_long(const char **s, long *out)
{
@@ -215,6 +226,13 @@ parse_long(const char **s, long *out)
return true;
}
+/*
+ * jp_parse
+ * Parse a JSONPath expression (into a List of jp_element items).
+ *
+ * TODO: Get rid of all those gotos. The parser uses constant space,
+ * so there's no chance of a stack overflow anyway.
+ */
JSONPath *
jp_parse(const char *pattern)
{
@@ -232,7 +250,7 @@ jp_parse(const char *pattern)
skip_spaces(&s);
/* pattern may not be empty */
- if (!*s)
+ if (*s == '\0')
return NULL;
jp = lappend(jp, mkRoot());
@@ -346,7 +364,7 @@ identifier:
if (*s == '(')
{
- if (end - start == 4 && !memcmp(start, "char", 4))
+ if (end - start == 4 && memcmp(start, "char", 4) == 0)
{
s++;
skip_spaces(&s);
@@ -364,7 +382,7 @@ identifier:
string:
key = json_decode_string(&s, &key_length, false);
- if (!key)
+ if (key == NULL)
goto failed;
jp = lappend(jp, mkKeySubscript(key, key_length, recursive_descent));
@@ -420,7 +438,7 @@ static void match_recurse(void on_match(void *ctx, JPRef * ref), void *ctx,
switch (elem->type)
{
case JP_WILDCARD:
- if (json)
+ if (json != NULL)
{
json_foreach(child, json)
match_recurse(on_match, ctx, lnext(path), mkRefNode(child));
@@ -428,43 +446,36 @@ static void match_recurse(void on_match(void *ctx, JPRef * ref), void *ctx,
break;
case JP_INDEX_SUBSCRIPT:
- if (json && json->type == JSON_ARRAY)
+ if (json != NULL && json->type == JSON_ARRAY &&
+ elem->data.index >= 0 &&
+ (size_t) elem->data.index < json->v.children.count)
{
size_t i;
- size_t index = elem->data.index;
- /*
- * Note: elem->data.index is signed (long), while index is
- * unsigned (size_t).
- */
-
- if (elem->data.index >= 0 && index < json->v.children.count)
+ for (child = json->v.children.head, i = 0;
+ child != NULL && i < (size_t) elem->data.index;
+ child = child->next, i++)
{
- for (child = json->v.children.head, i = 0;
- child != NULL && i < index;
- child = child->next, i++)
- {
- }
+ }
- /*
- * If this fails, it means json->v.children.count was
- * greater than the actual number of children.
- */
- Assert(i == index && child != NULL);
+ /*
+ * If this fails, it means json->v.children.count was greater
+ * than the actual number of children.
+ */
+ Assert(i == elem->data.index && child != NULL);
- match_recurse(on_match, ctx, lnext(path), mkRefNode(child));
- }
+ match_recurse(on_match, ctx, lnext(path), mkRefNode(child));
}
break;
case JP_KEY_SUBSCRIPT:
- if (json && json->type == JSON_OBJECT)
+ if (json != NULL && json->type == JSON_OBJECT)
{
json_foreach(child, json)
{
if (child->key != NULL &&
child->key_length == elem->data.key.length &&
- !memcmp(child->key, elem->data.key.ptr, child->key_length))
+ memcmp(child->key, elem->data.key.ptr, child->key_length) == 0)
{
match_recurse(on_match, ctx, lnext(path), mkRefNode(child));
}
@@ -473,7 +484,8 @@ static void match_recurse(void on_match(void *ctx, JPRef * ref), void *ctx,
break;
case JP_CALL_CHAR:
- if (json && json->type == JSON_STRING && elem->data.index >= 0)
+ if (json != NULL && json->type == JSON_STRING &&
+ elem->data.index >= 0)
{
const char *sub_start;
size_t sub_bytes;
@@ -497,7 +509,7 @@ static void match_recurse(void on_match(void *ctx, JPRef * ref), void *ctx,
default:;
}
- if (elem->recursive_descent && json)
+ if (elem->recursive_descent && json != NULL)
{
json_foreach(child, json)
{
@@ -513,6 +525,13 @@ jp_match_callback(List **results, JPRef * ref)
*results = lappend(*results, ref);
}
+/*
+ * jp_match
+ * Match a parsed JSONPath expression against a JSON tree,
+ * yielding a List of JPRef* items.
+ *
+ * To convert the JPRef* items to JSON-formatted strings, use jpref_encode.
+ */
List *
jp_match(JSONPath * jp, JSON * json)
{
@@ -538,6 +557,15 @@ jp_set_callback(JSON * value, JPRef * ref)
}
}
+/*
+ * jp_set
+ * Set all elements that match a parsed JSONPath expression
+ * in a JSON tree to a new value.
+ *
+ * Note that jp_set uses json_replace_value so it doesn't have to deep-copy
+ * on every assignment if @value is a tree. This means that parent pointers
+ * of the resulting tree will not be trustworthy.
+ */
void
jp_set(JSONPath * jp, JSON * json, JSON * value)
{
@@ -546,6 +574,10 @@ jp_set(JSONPath * jp, JSON * json, JSON * value)
match_recurse((void *) jp_set_callback, value, lc, mkRefNode(json));
}
+/*
+ * jpref_encode
+ * Convert a JPRef to a JSON-formatted string.
+ */
char *
jpref_encode(JPRef * ref)
{