diff options
| author | Joey Adams | 2010-07-14 04:05:24 +0000 |
|---|---|---|
| committer | Joey Adams | 2010-07-14 04:05:24 +0000 |
| commit | 46d4111846c2fdd0a2790c25ba51c8998d8ab218 (patch) | |
| tree | 551e0be5d2569a248cf2ca95864d9bbd33fe5c74 /jsonpath.c | |
| parent | 442fe529e29fc5538dc4172246758f68a4156106 (diff) | |
Refactored jsonpath a bit by introducing JPRef.
JPRef is a structure representing an item matched by jp_match.
Before, plain old json_node was used, which couldn't distinguish between
mutable references (actual JSON nodes from the original input)
and immutable references (e.g. characters in a string).
Yes, characters in a string are regarded as immutable because:
* That's how it is in JavaScript.
* It's easier to implement.
Diffstat (limited to 'jsonpath.c')
| -rw-r--r-- | jsonpath.c | 152 |
1 files changed, 109 insertions, 43 deletions
@@ -96,6 +96,28 @@ static jp_element *mkKeySubscript(char *key, size_t length, bool rd) return elem; } +static JPRef *mkRef(JPRefType type) +{ + JPRef *ref = palloc0(sizeof(*ref)); + ref->type = type; + return ref; +} + +static JPRef *mkRefNode(json_node *node) +{ + JPRef *ref = mkRef(JP_REF_NODE); + ref->u.node = node; + return ref; +} + +static JPRef *mkRefChar(const char *bytes, size_t length) +{ + JPRef *ref = mkRef(JP_REF_CHAR); + ref->u.chr.bytes = bytes; + ref->u.chr.length = length; + return ref; +} + char *jp_show(JSONPath *jp) { StringInfoData string[1]; @@ -323,75 +345,104 @@ static json_node *json_head(json_node *parent) #define json_foreach(child, parent) \ for ((child) = json_head(parent); (child) != NULL; (child) = (child)->next) -static json_node *json_index_subscript(json_node *json, long index) +static JPRef *json_index_subscript(JPRef *ref, long index) { + json_node *json; + if (index < 0) return NULL; - switch (json->type) { - case JSON_STRING: { - const char *sub_start; - size_t sub_bytes; - size_t sub_length; - json_node *sub_json; - - sub_length = utf8_substring( - json->v.string.str, json->v.string.length, - index, 1, - &sub_start, &sub_bytes); - - if (sub_length != 1) - return NULL; + switch (ref->type) { + case JP_REF_NODE: + json = ref->u.node; - sub_json = json_mkstring(sub_start, sub_bytes); - sub_json->parent = json; - return sub_json; - } - case JSON_ARRAY: { - json_node *child; + switch (json->type) { + case JSON_STRING: { + const char *sub_start; + size_t sub_bytes; + size_t sub_length; - if ((size_t)index >= json->v.children.count) - return NULL; + sub_length = utf8_substring( + json->v.string.str, json->v.string.length, + index, 1, + &sub_start, &sub_bytes); - for (child = json->v.children.head; - index && child; - child = child->next, index--) {} + if (sub_length != 1) + return NULL; - if (index != 0 || child == NULL) { - Assert(false); - return NULL; + return mkRefChar(sub_start, sub_bytes); + } + case JSON_ARRAY: { + json_node *child; + + if ((size_t)index >= json->v.children.count) + return NULL; + + for (child = json->v.children.head; + index && child; + child = child->next, index--) {} + + if (index != 0 || child == NULL) { + Assert(false); + return NULL; + } + + return mkRefNode(child); + } + default: + return NULL; } + break; + + case JP_REF_CHAR: + if (index != 0) + return NULL; + return ref; - return child; - } default: + Assert(false); return NULL; } } -static void match_recurse(List **results, ListCell *path, json_node *json) +/* +Currently, a lot of JPRef nodes are allocated just to pass json_node pointers +to match_recurse. If this becomes a memory/performance issue in the future, +JPRef could merged with json_node by adding JPRef's specialty types to the +json_type enum and json_node union. JPRef is currently not merged with +json_node in an attempt to keep the codebase tidy and easier to extend. +*/ +static void match_recurse(List **results, ListCell *path, JPRef *ref) { jp_element *elem; - json_node *child; + JPRef *child_ref; + json_node *json, *child; if (path == NULL) { /* The end of the JSONPath list is the "accept" state. */ - *results = lappend(*results, json); + *results = lappend(*results, ref); return; } elem = lfirst(path); + if (ref->type == JP_REF_NODE) + json = ref->u.node; + else + json = NULL; + switch (elem->type) { case JP_WILDCARD: - json_foreach(child, json) - match_recurse(results, lnext(path), child); + if (json) { + json_foreach(child, json) + match_recurse(results, lnext(path), mkRefNode(child)); + } break; case JP_INDEX_SUBSCRIPT: - child = json_index_subscript(json, elem->data.index); - if (child != NULL) - match_recurse(results, lnext(path), child); + child_ref = json_index_subscript(ref, elem->data.index); + if (child_ref != NULL) + match_recurse(results, lnext(path), child_ref); break; case JP_KEY_SUBSCRIPT: @@ -400,7 +451,7 @@ static void match_recurse(List **results, ListCell *path, json_node *json) child->key_length == elem->data.key.length && !memcmp(child->key, elem->data.key.ptr, child->key_length)) { - match_recurse(results, lnext(path), child); + match_recurse(results, lnext(path), mkRefNode(child)); } } break; @@ -408,9 +459,9 @@ static void match_recurse(List **results, ListCell *path, json_node *json) default:; } - if (elem->recursive_descent) { + if (elem->recursive_descent && json) { json_foreach(child, json) - match_recurse(results, path, child); + match_recurse(results, path, mkRefNode(child)); } } @@ -419,7 +470,22 @@ List *jp_match(JSONPath *jp, json_node *json) ListCell *lc = jp_head(jp); List *results = NIL; - match_recurse(&results, lc, json); + match_recurse(&results, lc, mkRefNode(json)); return results; } + +char *jpref_encode(JPRef *ref) +{ + switch (ref->type) { + case JP_REF_NODE: + return json_encode(ref->u.node, JSONOPT_USE_ORIG); + + case JP_REF_CHAR: + return json_encode_string(ref->u.chr.bytes, ref->u.chr.length, '"', false); + + default: + Assert(false); + return NULL; + } +} |
