Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/zabbix/zabbix.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/zbxjson/jsonpath.c')
-rw-r--r--src/libs/zbxjson/jsonpath.c1297
1 files changed, 889 insertions, 408 deletions
diff --git a/src/libs/zbxjson/jsonpath.c b/src/libs/zbxjson/jsonpath.c
index b57aff6f8d5..eec2ffc6935 100644
--- a/src/libs/zbxjson/jsonpath.c
+++ b/src/libs/zbxjson/jsonpath.c
@@ -18,7 +18,6 @@
**/
#include "jsonpath.h"
-#include "zbxjson.h"
#include "zbxregexp.h"
#include "zbxvariant.h"
@@ -26,21 +25,17 @@
#include "zbxexpr.h"
#include "json.h"
#include "json_parser.h"
+#include "jsonobj.h"
typedef struct
{
- char *name;
- const char *value;
+ zbx_jsonobj_t *root; /* the root object */
+ zbx_jsonpath_t *path;
+ unsigned char found; /* set to 1 when one object was matched and */
+ /* no more matches are required */
+ zbx_vector_jsonobj_ref_t objects; /* the matched objects */
}
-zbx_json_element_t;
-
-ZBX_VECTOR_DECL(json, zbx_json_element_t)
-ZBX_VECTOR_IMPL(json, zbx_json_element_t)
-
-static int jsonpath_query_object(const struct zbx_json_parse *jp_root, const struct zbx_json_parse *jp,
- const zbx_jsonpath_t *jsonpath, int path_depth, zbx_vector_json_t *objects);
-static int jsonpath_query_array(const struct zbx_json_parse *jp_root, const struct zbx_json_parse *jp,
- const zbx_jsonpath_t *jsonpath, int path_depth, zbx_vector_json_t *objects);
+zbx_jsonpath_context_t;
typedef struct
{
@@ -49,6 +44,10 @@ typedef struct
}
zbx_jsonpath_token_def_t;
+static int jsonpath_query_object(zbx_jsonpath_context_t *ctx, zbx_jsonobj_t *obj, int path_depth);
+static int jsonpath_query_array(zbx_jsonpath_context_t *ctx, zbx_jsonobj_t *array, int path_depth);
+static int jsonpath_str_copy_value(char **str, size_t *str_alloc, size_t *str_offset, zbx_jsonobj_t *obj);
+
/* define token groups and precedence */
static zbx_jsonpath_token_def_t jsonpath_tokens[] = {
{0, 0},
@@ -74,6 +73,7 @@ static zbx_jsonpath_token_def_t jsonpath_tokens[] = {
{ZBX_JSONPATH_TOKEN_GROUP_OPERATOR2, 7} /* ZBX_JSONPATH_TOKEN_OP_REGEXP */
};
+
static int jsonpath_token_precedence(int type)
{
return jsonpath_tokens[type].precedence;
@@ -84,31 +84,118 @@ static int jsonpath_token_group(int type)
return jsonpath_tokens[type].group;
}
-/* json element vector support */
-static void zbx_vector_json_add_element(zbx_vector_json_t *elements, const char *name, const char *value)
+/******************************************************************************
+ * *
+ * Purpose: add external json object reference to a vector *
+ * *
+ * Parameters: refs - [IN/OUT] the json object reference vector *
+ * name - [IN] the json object name or array index *
+ * value - [IN] the json object *
+ * *
+ ******************************************************************************/
+static void zbx_vector_jsonobj_ref_add_object(zbx_vector_jsonobj_ref_t *refs, const char *name,
+ zbx_jsonobj_t *value)
{
- zbx_json_element_t el;
+ zbx_jsonobj_ref_t ref;
- el.name = zbx_strdup(NULL, name);
- el.value = value;
- zbx_vector_json_append(elements, el);
+ ref.name = zbx_strdup(NULL, name);
+ ref.external = 1;
+
+ ref.value = value;
+ zbx_vector_jsonobj_ref_append(refs, ref);
+}
+
+/******************************************************************************
+ * *
+ * Purpose: add internal json object reference to a vector *
+ * *
+ * Parameters: refs - [IN/OUT] the json object reference vector *
+ * name - [IN] the json object name or array index *
+ * str - [IN] the string value of the object *
+ * *
+ * Comments: This function will create json object and add internal reference,*
+ * meaning the object will be destroyed together with its reference.*
+ * *
+ ******************************************************************************/
+static void zbx_vector_jsonobj_ref_add_string(zbx_vector_jsonobj_ref_t *refs, const char *name,
+ const char *str)
+{
+ zbx_jsonobj_ref_t ref;
+
+ ref.name = zbx_strdup(NULL, name);
+ ref.external = 0;
+
+ ref.value = (zbx_jsonobj_t *)zbx_malloc(NULL, sizeof(zbx_jsonobj_t));
+ jsonobj_init(ref.value, ZBX_JSON_TYPE_STRING);
+ jsonobj_set_string(ref.value, zbx_strdup(NULL, str));
+
+ zbx_vector_jsonobj_ref_append(refs, ref);
+}
+
+/******************************************************************************
+ * *
+ * Purpose: add a copy of json object reference to a vector *
+ * *
+ * Parameters: refs - [IN/OUT] the json object reference vector *
+ * ref - [IN] the json object reference *
+ * *
+ * Comments: For internal references a new internal json object will be *
+ * created. *
+ * *
+ ******************************************************************************/
+static void zbx_vector_jsonobj_ref_add(zbx_vector_jsonobj_ref_t *refs, zbx_jsonobj_ref_t *ref)
+{
+ if (0 != ref->external)
+ zbx_vector_jsonobj_ref_add_object(refs, ref->name, ref->value);
+ else
+ zbx_vector_jsonobj_ref_add_string(refs, ref->name, ref->value->data.string);
}
-static void zbx_vector_json_copy(zbx_vector_json_t *dst, const zbx_vector_json_t *src)
+/******************************************************************************
+ * *
+ * Purpose: copy json object references from one vector to other *
+ * *
+ * Parameters: dst - [IN/OUT] the destination json object reference vector *
+ * src - [IN] the source json object reference vector *
+ * *
+ * Comments: For internal references a new internal json object will be *
+ * created. *
+ * *
+ ******************************************************************************/
+static void zbx_vector_jsonobj_ref_copy(zbx_vector_jsonobj_ref_t *dst, const zbx_vector_jsonobj_ref_t *src)
{
int i;
for (i = 0; i < src->values_num; i++)
- zbx_vector_json_add_element(dst, src->values[i].name, src->values[i].value);
+ {
+ if (0 != src->values[i].external)
+ zbx_vector_jsonobj_ref_add_object(dst, src->values[i].name, src->values[i].value);
+ else
+ zbx_vector_jsonobj_ref_add_string(dst, src->values[i].name, src->values[i].value->data.string);
+ }
}
-static void zbx_vector_json_clear_ext(zbx_vector_json_t *elements)
+/******************************************************************************
+ * *
+ * Purpose: free resources allocated by json object reference *
+ * *
+ ******************************************************************************/
+static void zbx_vector_jsonobj_ref_clear_ext(zbx_vector_jsonobj_ref_t *refs)
{
int i;
- for (i = 0; i < elements->values_num; i++)
- zbx_free(elements->values[i].name);
- zbx_vector_json_clear(elements);
+ for (i = 0; i < refs->values_num; i++)
+ {
+ zbx_jsonobj_ref_t *ref = &refs->values[i];
+
+ zbx_free(ref->name);
+ if (0 == ref->external)
+ {
+ zbx_jsonobj_clear(ref->value);
+ zbx_free(ref->value);
+ }
+ }
+ zbx_vector_jsonobj_ref_clear(refs);
}
/******************************************************************************
@@ -215,16 +302,116 @@ static void jsonpath_list_free(zbx_jsonpath_list_node_t *list)
/******************************************************************************
* *
+ * Purpose: append array index to list *
+ * *
+ ******************************************************************************/
+static zbx_jsonpath_list_node_t *jsonpath_list_append_index(zbx_jsonpath_list_node_t *head, int index,
+ int check_duplicate)
+{
+ zbx_jsonpath_list_node_t *node;
+
+ if (0 != check_duplicate)
+ {
+ for (node = head; NULL != node; node = node->next)
+ {
+ int query_index;
+
+ memcpy(&query_index, node->data, sizeof(query_index));
+ if (query_index == index)
+ return head;
+ }
+ }
+
+ node = jsonpath_list_create_node(sizeof(int));
+ node->next = head;
+ memcpy(node->data, &index, sizeof(int));
+
+ return node;
+}
+
+/******************************************************************************
+ * *
+ * Purpose: append name to list *
+ * *
+ ******************************************************************************/
+static zbx_jsonpath_list_node_t *jsonpath_list_append_name(zbx_jsonpath_list_node_t *head, const char *name, size_t len)
+{
+ zbx_jsonpath_list_node_t *node, *new_node;
+
+ new_node = jsonpath_list_create_node(len + 1);
+ jsonpath_unquote(new_node->data, name, len + 1);
+
+ for (node = head; NULL != node; node = node->next)
+ {
+ if (0 == strcmp((char *)new_node->data, (char *)node->data))
+ {
+ zbx_free(new_node);
+ return head;
+ }
+ }
+
+ new_node->next = head;
+
+ return new_node;
+}
+
+/******************************************************************************
+ * *
+ * Purpose: create jsonpath structure and compile json path *
+ * *
+ ******************************************************************************/
+static zbx_jsonpath_t *jsonpath_create_token_jsonpath(const char *text, size_t len)
+{
+ zbx_jsonpath_t *path;
+ char *tmp_text;
+
+ tmp_text = jsonpath_strndup(text, len);
+
+ if ('@' == *tmp_text)
+ *tmp_text = '$';
+
+ path = (zbx_jsonpath_t *)zbx_malloc(NULL, sizeof(zbx_jsonpath_t));
+
+ if (FAIL == zbx_jsonpath_compile(tmp_text, path))
+ {
+ zbx_free(path);
+ goto out;
+ }
+
+ if (1 != path->definite)
+ {
+ zbx_set_json_strerror("only simple path are supported in jsonpath expression: \"%s\"", text);
+ zbx_jsonpath_clear(path);
+ zbx_free(path);
+ goto out;
+ }
+
+ if (ZBX_JSONPATH_SEGMENT_FUNCTION == path->segments[path->segments_num - 1].type)
+ {
+ zbx_set_json_strerror("functions are not supported in jsonpath expression: \"%s\"", text);
+ zbx_jsonpath_clear(path);
+ zbx_free(path);
+ }
+out:
+ zbx_free(tmp_text);
+
+ return path;
+}
+
+/******************************************************************************
+ * *
* Purpose: create jsonpath expression token *
* *
* Parameters: type - [IN] the token type *
* expression - [IN] the expression *
* loc - [IN] the token location in the expression *
* *
- * Return value: The created token (must be freed by the caller). *
+ * Return value: The created token (must be freed by the caller) or *
+ * NULL in the case of error. *
* *
******************************************************************************/
-static zbx_jsonpath_token_t *jsonpath_create_token(int type, const char *expression, const zbx_strloc_t *loc)
+static zbx_jsonpath_token_t *jsonpath_create_token(unsigned char type, const char *expression,
+ const zbx_strloc_t *loc)
{
zbx_jsonpath_token_t *token;
@@ -234,23 +421,46 @@ static zbx_jsonpath_token_t *jsonpath_create_token(int type, const char *express
switch (token->type)
{
case ZBX_JSONPATH_TOKEN_CONST_STR:
- token->data = jsonpath_unquote_dyn(expression + loc->l, loc->r - loc->l + 1);
+ token->text = jsonpath_unquote_dyn(expression + loc->l, loc->r - loc->l + 1);
+ token->path = NULL;
break;
case ZBX_JSONPATH_TOKEN_PATH_ABSOLUTE:
case ZBX_JSONPATH_TOKEN_PATH_RELATIVE:
+ if (NULL == (token->path = jsonpath_create_token_jsonpath(expression + loc->l,
+ loc->r - loc->l + 1)))
+ {
+ zbx_free(token);
+ }
+ else
+ token->text = jsonpath_strndup(expression + loc->l, loc->r - loc->l + 1);
+ break;
case ZBX_JSONPATH_TOKEN_CONST_NUM:
- token->data = jsonpath_strndup(expression + loc->l, loc->r - loc->l + 1);
+ token->text = jsonpath_strndup(expression + loc->l, loc->r - loc->l + 1);
+ token->path = NULL;
break;
default:
- token->data = NULL;
+ token->text = NULL;
+ token->path = NULL;
}
return token;
}
+/******************************************************************************
+ * *
+ * Purpose: free jsonpath expression token *
+ * *
+ ******************************************************************************/
static void jsonpath_token_free(zbx_jsonpath_token_t *token)
{
- zbx_free(token->data);
+ zbx_free(token->text);
+
+ if (NULL != token->path)
+ {
+ zbx_jsonpath_clear(token->path);
+ zbx_free(token->path);
+ }
+
zbx_free(token);
}
@@ -274,16 +484,21 @@ static void jsonpath_reserve(zbx_jsonpath_t *jsonpath, int num)
jsonpath->segments_alloc *= 2;
jsonpath->segments = (zbx_jsonpath_segment_t *)zbx_realloc(jsonpath->segments,
- sizeof(zbx_jsonpath_segment_t) * jsonpath->segments_alloc);
+ sizeof(zbx_jsonpath_segment_t) * (size_t)jsonpath->segments_alloc);
/* Initialize the memory allocated for new segments, as parser can set */
/* detached flag for the next segment, so the memory cannot be initialized */
/* when creating a segment. */
memset(jsonpath->segments + old_alloc, 0,
- (jsonpath->segments_alloc - old_alloc) * sizeof(zbx_jsonpath_segment_t));
+ (size_t)(jsonpath->segments_alloc - old_alloc) * sizeof(zbx_jsonpath_segment_t));
}
}
+/******************************************************************************
+ * *
+ * Purpose: free resource allocated by jsonpath segment *
+ * *
+ ******************************************************************************/
static void jsonpath_segment_clear(zbx_jsonpath_segment_t *segment)
{
switch (segment->type)
@@ -391,7 +606,7 @@ static int jsonpath_next(const char **pnext)
* FAIL - otherwise *
* *
******************************************************************************/
-static int jsonpath_parse_substring(const char *start, int *len)
+static int jsonpath_parse_substring(const char *start, size_t *len)
{
const char *ptr;
char quotes;
@@ -400,7 +615,7 @@ static int jsonpath_parse_substring(const char *start, int *len)
{
if (*ptr == quotes)
{
- *len = ptr - start + 1;
+ *len = (size_t)(ptr - start + 1);
return SUCCEED;
}
@@ -429,7 +644,7 @@ static int jsonpath_parse_substring(const char *start, int *len)
* jsonpath filter expressions. *
* *
******************************************************************************/
-static int jsonpath_parse_path(const char *start, int *len)
+static int jsonpath_parse_path(const char *start, size_t *len)
{
const char *ptr = start + 1;
@@ -439,7 +654,7 @@ static int jsonpath_parse_path(const char *start, int *len)
return FAIL;
}
- *len = ptr - start;
+ *len = (size_t)(ptr - start);
return SUCCEED;
}
@@ -454,7 +669,7 @@ static int jsonpath_parse_path(const char *start, int *len)
* FAIL - otherwise *
* *
******************************************************************************/
-static int jsonpath_parse_number(const char *start, int *len)
+static int jsonpath_parse_number(const char *start, size_t *len)
{
const char *ptr = start;
char *end;
@@ -474,7 +689,7 @@ static int jsonpath_parse_number(const char *start, int *len)
if (ptr != end || HUGE_VAL == tmp || -HUGE_VAL == tmp || EDOM == errno)
return FAIL;
- *len = (int)(ptr - start);
+ *len = (size_t)(ptr - start);
return SUCCEED;
}
@@ -494,14 +709,14 @@ static int jsonpath_parse_number(const char *start, int *len)
* FAIL - otherwise *
* *
******************************************************************************/
-static int jsonpath_expression_next_token(const char *expression, int pos, int prev_group,
+static int jsonpath_expression_next_token(const char *expression, size_t pos, int prev_group,
zbx_jsonpath_token_type_t *type, zbx_strloc_t *loc)
{
- int len;
+ size_t len;
const char *ptr = expression + pos;
SKIP_WHITESPACE(ptr);
- loc->l = ptr - expression;
+ loc->l = (size_t)(ptr - expression);
switch (*ptr)
{
@@ -633,6 +848,139 @@ out:
return zbx_jsonpath_error(ptr);
}
+/* value types on index stack */
+typedef enum
+{
+ ZBX_JSONPATH_CONST = 1, /* constant value - string or number */
+ ZBX_JSONPATH_VALUE, /* result of an operation after which cannot be used in index */
+ ZBX_JSONPATH_PATH, /* relative jsonpath - @.a.b.c */
+ ZBX_JSONPATH_PATH_OP /* result of an operation with jsonpath which still can be used in index */
+}
+zbx_jsonpath_index_value_type_t;
+
+typedef struct
+{
+ zbx_jsonpath_index_value_type_t type;
+ zbx_jsonpath_token_t *index_token;
+ zbx_jsonpath_token_t *value_token;
+}
+zbx_jsonpath_index_value_t;
+
+ZBX_VECTOR_DECL(jpi_value, zbx_jsonpath_index_value_t)
+ZBX_VECTOR_IMPL(jpi_value, zbx_jsonpath_index_value_t)
+
+/******************************************************************************
+ * *
+ * Purpose: analyze expression and set indexing fields if possible *
+ * *
+ * Comments: Expression can be indexed if it contains relative json path *
+ * comparison with constant that is used in and operations. *
+ * This is tested by doing a pseudo evaluation by operand types *
+ * and checking the result type. *
+ * *
+ * So expressions like ?(@.a.b == 1), ?(@.a == "A" and @.b == "B") *
+ * can be indexed (by @.a.b and by @.a) while expressions like *
+ * ?(@.a == @.b), ?(@.a == "A" or @.b == "B") cannot. *
+ * *
+ ******************************************************************************/
+static void jsonpath_expression_prepare_index(zbx_jsonpath_expression_t *exp)
+{
+ int i;
+ zbx_vector_jpi_value_t stack;
+ zbx_jsonpath_index_value_t *left, *right;
+
+ zbx_vector_jpi_value_create(&stack);
+
+ for (i = 0; i < exp->tokens.values_num; i++)
+ {
+ zbx_jsonpath_token_t *token = (zbx_jsonpath_token_t *)exp->tokens.values[i];
+ zbx_jsonpath_index_value_t jpi = {0};
+
+ switch (token->type)
+ {
+ case ZBX_JSONPATH_TOKEN_OP_NOT:
+ if (1 > stack.values_num)
+ goto out;
+ stack.values[stack.values_num - 1].type = ZBX_JSONPATH_VALUE;
+ stack.values[stack.values_num - 1].index_token = NULL;
+ stack.values[stack.values_num - 1].value_token = NULL;
+ continue;
+ case ZBX_JSONPATH_TOKEN_PATH_RELATIVE:
+ jpi.index_token = token;
+ jpi.type = ZBX_JSONPATH_PATH;
+ zbx_vector_jpi_value_append(&stack, jpi);
+ continue;
+ case ZBX_JSONPATH_TOKEN_PATH_ABSOLUTE:
+ jpi.type = ZBX_JSONPATH_VALUE;
+ zbx_vector_jpi_value_append(&stack, jpi);
+ continue;
+ case ZBX_JSONPATH_TOKEN_CONST_STR:
+ case ZBX_JSONPATH_TOKEN_CONST_NUM:
+ jpi.value_token = token;
+ jpi.type = ZBX_JSONPATH_CONST;
+ zbx_vector_jpi_value_append(&stack, jpi);
+ continue;
+ }
+
+ if (2 > stack.values_num)
+ goto out;
+
+ left = &stack.values[stack.values_num - 2];
+ right = &stack.values[stack.values_num - 1];
+ stack.values_num--;
+
+ switch (token->type)
+ {
+ case ZBX_JSONPATH_TOKEN_OP_EQ:
+ if ((ZBX_JSONPATH_PATH == left->type || ZBX_JSONPATH_PATH == right->type) &&
+ (ZBX_JSONPATH_CONST == left->type || ZBX_JSONPATH_CONST == right->type))
+ {
+ left->type = ZBX_JSONPATH_PATH_OP;
+
+ if (ZBX_JSONPATH_CONST == right->type)
+ left->value_token = right->value_token;
+ else
+ left->index_token = right->index_token;
+ }
+ else
+ left->type = ZBX_JSONPATH_VALUE;
+ continue;
+ case ZBX_JSONPATH_TOKEN_OP_AND:
+ if (ZBX_JSONPATH_PATH == left->type)
+ left->type = ZBX_JSONPATH_VALUE;
+
+ if (ZBX_JSONPATH_PATH == right->type)
+ right->type = ZBX_JSONPATH_VALUE;
+
+ if (ZBX_JSONPATH_PATH_OP == left->type && ZBX_JSONPATH_PATH_OP == right->type)
+ continue;
+
+ if ((ZBX_JSONPATH_PATH_OP == left->type || ZBX_JSONPATH_PATH_OP == right->type) &&
+ (ZBX_JSONPATH_VALUE == left->type || ZBX_JSONPATH_VALUE == right->type))
+ {
+ if (ZBX_JSONPATH_PATH_OP != left->type)
+ *left = *right;
+ }
+ else
+ left->type = ZBX_JSONPATH_VALUE;
+ continue;
+ default:
+ left->type = ZBX_JSONPATH_VALUE;
+ left->index_token = NULL;
+ left->value_token = NULL;
+ break;
+ }
+ }
+
+ if (1 == stack.values_num && ZBX_JSONPATH_PATH_OP == stack.values[0].type)
+ {
+ exp->index_token = stack.values[0].index_token;
+ exp->value_token = stack.values[0].value_token;
+ }
+out:
+ zbx_vector_jpi_value_destroy(&stack);
+}
+
/******************************************************************************
* *
* Purpose: parse jsonpath filter expression in format *
@@ -659,7 +1007,7 @@ out:
static int jsonpath_parse_expression(const char *expression, zbx_jsonpath_t *jsonpath, const char **next)
{
int nesting = 1, ret = FAIL;
- zbx_jsonpath_token_t *optoken;
+ zbx_jsonpath_token_t *optoken, *token;
zbx_vector_ptr_t output, operators;
zbx_strloc_t loc = {0, 0};
zbx_jsonpath_token_type_t token_type;
@@ -706,7 +1054,10 @@ static int jsonpath_parse_expression(const char *expression, zbx_jsonpath_t *jso
goto out;
}
- zbx_vector_ptr_append(&output, jsonpath_create_token(token_type, expression, &loc));
+ if (NULL == (token = jsonpath_create_token(token_type, expression, &loc)))
+ goto cleanup;
+
+ zbx_vector_ptr_append(&operators, token);
prev_group = jsonpath_token_group(token_type);
continue;
}
@@ -746,14 +1097,20 @@ static int jsonpath_parse_expression(const char *expression, zbx_jsonpath_t *jso
zbx_vector_ptr_append(&output, optoken);
}
- zbx_vector_ptr_append(&operators, jsonpath_create_token(token_type, expression, &loc));
+ if (NULL == (token = jsonpath_create_token(token_type, expression, &loc)))
+ goto cleanup;
+
+ zbx_vector_ptr_append(&operators, token);
prev_group = jsonpath_token_group(token_type);
continue;
}
if (ZBX_JSONPATH_TOKEN_PAREN_LEFT == token_type)
{
- zbx_vector_ptr_append(&operators, jsonpath_create_token(token_type, expression, &loc));
+ if (NULL == (token = jsonpath_create_token(token_type, expression, &loc)))
+ goto cleanup;
+
+ zbx_vector_ptr_append(&operators, token);
prev_group = ZBX_JSONPATH_TOKEN_GROUP_NONE;
continue;
}
@@ -816,6 +1173,10 @@ out:
zbx_vector_ptr_create(&segment->data.expression.tokens);
zbx_vector_ptr_append_array(&segment->data.expression.tokens, output.values, output.values_num);
+ /* index only json path that has been definite until this point */
+ if (0 != jsonpath->definite)
+ jsonpath_expression_prepare_index(&segment->data.expression);
+
jsonpath->definite = 0;
}
cleanup:
@@ -869,18 +1230,13 @@ static int jsonpath_parse_names(const char *list, zbx_jsonpath_t *jsonpath, cons
}
else if (*start == *end)
{
- zbx_jsonpath_list_node_t *node;
-
if (start + 1 == end)
{
ret = zbx_jsonpath_error(start);
goto out;
}
- node = jsonpath_list_create_node(end - start + 1);
- jsonpath_unquote(node->data, start, end - start + 1);
- node->next = head;
- head = node;
+ head = jsonpath_list_append_name(head, start, (size_t)(end - start));
parsed_name = 1;
start = NULL;
}
@@ -987,19 +1343,13 @@ static int jsonpath_parse_indexes(const char *list, zbx_jsonpath_t *jsonpath, co
if (NULL != start)
{
- int value;
-
if ('-' == *start && end == start + 1)
{
ret = zbx_jsonpath_error(start);
goto out;
}
- node = jsonpath_list_create_node(sizeof(int));
- node->next = head;
- head = node;
- value = atoi(start);
- memcpy(node->data, &value, sizeof(int));
+ head = jsonpath_list_append_index(head, atoi(start), type == ZBX_JSONPATH_SEGMENT_MATCH_LIST);
start = NULL;
parsed_index = 1;
}
@@ -1163,7 +1513,7 @@ static int jsonpath_parse_dot_segment(const char *start, zbx_jsonpath_t *jsonpat
{
zbx_jsonpath_segment_t *segment;
const char *ptr;
- int len;
+ size_t len;
segment = &jsonpath->segments[jsonpath->segments_num];
jsonpath->segments_num++;
@@ -1179,6 +1529,8 @@ static int jsonpath_parse_dot_segment(const char *start, zbx_jsonpath_t *jsonpat
for (ptr = start; 0 != isalnum((unsigned char)*ptr) || '_' == *ptr;)
ptr++;
+ len = (size_t)(ptr - start);
+
if ('(' == *ptr)
{
const char *end = ptr + 1;
@@ -1186,18 +1538,31 @@ static int jsonpath_parse_dot_segment(const char *start, zbx_jsonpath_t *jsonpat
SKIP_WHITESPACE(end);
if (')' == *end)
{
- if (ZBX_CONST_STRLEN("min") == ptr - start && 0 == strncmp(start, "min", ptr - start))
+ if (ZBX_CONST_STRLEN("min") == len && 0 == strncmp(start, "min", len))
+ {
segment->data.function.type = ZBX_JSONPATH_FUNCTION_MIN;
- else if (ZBX_CONST_STRLEN("max") == ptr - start && 0 == strncmp(start, "max", ptr - start))
+ }
+ else if (ZBX_CONST_STRLEN("max") == len && 0 == strncmp(start, "max", len))
+ {
segment->data.function.type = ZBX_JSONPATH_FUNCTION_MAX;
- else if (ZBX_CONST_STRLEN("avg") == ptr - start && 0 == strncmp(start, "avg", ptr - start))
+ }
+ else if (ZBX_CONST_STRLEN("avg") == len && 0 == strncmp(start, "avg", len))
+ {
segment->data.function.type = ZBX_JSONPATH_FUNCTION_AVG;
- else if (ZBX_CONST_STRLEN("length") == ptr - start && 0 == strncmp(start, "length", ptr - start))
+ }
+ else if (ZBX_CONST_STRLEN("length") == len && 0 == strncmp(start, "length", len))
+ {
segment->data.function.type = ZBX_JSONPATH_FUNCTION_LENGTH;
- else if (ZBX_CONST_STRLEN("first") == ptr - start && 0 == strncmp(start, "first", ptr - start))
+ }
+ else if (ZBX_CONST_STRLEN("first") == len && 0 == strncmp(start, "first", len))
+ {
segment->data.function.type = ZBX_JSONPATH_FUNCTION_FIRST;
- else if (ZBX_CONST_STRLEN("sum") == ptr - start && 0 == strncmp(start, "sum", ptr - start))
+ jsonpath->first_match = 1;
+ }
+ else if (ZBX_CONST_STRLEN("sum") == len && 0 == strncmp(start, "sum", len))
+ {
segment->data.function.type = ZBX_JSONPATH_FUNCTION_SUM;
+ }
else
return zbx_jsonpath_error(start);
@@ -1207,7 +1572,7 @@ static int jsonpath_parse_dot_segment(const char *start, zbx_jsonpath_t *jsonpat
}
}
- if (0 < (len = ptr - start))
+ if (0 < len)
{
segment->type = ZBX_JSONPATH_SEGMENT_MATCH_LIST;
segment->data.list.type = ZBX_JSONPATH_LIST_NAME;
@@ -1247,117 +1612,84 @@ static int jsonpath_parse_name_reference(const char *start, zbx_jsonpath_t *json
/******************************************************************************
* *
- * Purpose: convert a pointer to an object/array/value in json data to *
- * json parse structure *
- * *
- * Parameters: pnext - [IN] a pointer to object/array/value data *
- * jp - [OUT] json parse data with start/end set *
- * *
- * Return value: SUCCEED - pointer was converted successfully *
- * FAIL - otherwise *
- * *
- ******************************************************************************/
-static int jsonpath_pointer_to_jp(const char *pnext, struct zbx_json_parse *jp)
-{
- if ('[' == *pnext || '{' == *pnext)
- {
- return zbx_json_brackets_open(pnext, jp);
- }
- else
- {
- jp->start = pnext;
- jp->end = pnext + json_parse_value(pnext, NULL) - 1;
- return SUCCEED;
- }
-}
-
-/******************************************************************************
- * *
* Purpose: perform the rest of jsonpath query on json data *
* *
- * Parameters: jp_root - [IN] the document root *
- * pnext - [IN] a pointer to object/array/value in json data *
- * jsonpath - [IN] the jsonpath *
+ * Parameters: ctx - [IN] the jsonpath query context *
+ * obj - [IN] the json object *
* path_depth - [IN] the jsonpath segment to match *
- * objects - [OUT] the matched json elements (name, value) *
* *
* Return value: SUCCEED - the data were queried successfully *
* FAIL - otherwise *
* *
******************************************************************************/
-static int jsonpath_query_contents(const struct zbx_json_parse *jp_root, const char *pnext,
- const zbx_jsonpath_t *jsonpath, int path_depth, zbx_vector_json_t *objects)
+static int jsonpath_query_contents(zbx_jsonpath_context_t *ctx, zbx_jsonobj_t *obj, int path_depth)
{
- struct zbx_json_parse jp_child;
+ int ret;
- switch (*pnext)
+ switch (obj->type)
{
- case '{':
- if (FAIL == zbx_json_brackets_open(pnext, &jp_child))
- return FAIL;
-
- return jsonpath_query_object(jp_root, &jp_child, jsonpath, path_depth, objects);
- case '[':
- if (FAIL == zbx_json_brackets_open(pnext, &jp_child))
- return FAIL;
-
- return jsonpath_query_array(jp_root, &jp_child, jsonpath, path_depth, objects);
+ case ZBX_JSON_TYPE_OBJECT:
+ ret = jsonpath_query_object(ctx, obj, path_depth);
+ break;
+ case ZBX_JSON_TYPE_ARRAY:
+ ret = jsonpath_query_array(ctx, obj, path_depth);
+ break;
+ default:
+ ret = SUCCEED;
}
- return SUCCEED;
+
+ return ret;
}
/******************************************************************************
* *
* Purpose: query next segment *
* *
- * Parameters: jp_root - [IN] the document root *
+ * Parameters: ctx - [IN] the jsonpath query context *
* name - [IN] name or index of the next json element *
- * pnext - [IN] a pointer to object/array/value in json data *
- * jsonpath - [IN] the jsonpath *
+ * obj - [IN] the current json object *
* path_depth - [IN] the jsonpath segment to match *
- * objects - [OUT] the matched json elements (name, value) *
* *
* Return value: SUCCEED - the segment was queried successfully *
* FAIL - otherwise *
* *
******************************************************************************/
-static int jsonpath_query_next_segment(const struct zbx_json_parse *jp_root, const char *name, const char *pnext,
- const zbx_jsonpath_t *jsonpath, int path_depth, zbx_vector_json_t *objects)
+static int jsonpath_query_next_segment(zbx_jsonpath_context_t *ctx, const char *name, zbx_jsonobj_t *obj,
+ int path_depth)
{
/* check if jsonpath end has been reached, so we have found matching data */
/* (functions are processed afterwards) */
- if (++path_depth == jsonpath->segments_num ||
- ZBX_JSONPATH_SEGMENT_FUNCTION == jsonpath->segments[path_depth].type)
+ if (++path_depth == ctx->path->segments_num ||
+ ZBX_JSONPATH_SEGMENT_FUNCTION == ctx->path->segments[path_depth].type)
{
- zbx_vector_json_add_element(objects, name, pnext);
+ if (1 == ctx->path->first_match)
+ ctx->found = 1;
+
+ zbx_vector_jsonobj_ref_add_object(&ctx->objects, name, obj);
return SUCCEED;
}
- /* continue by matching found data against the rest of jsonpath segments */
- return jsonpath_query_contents(jp_root, pnext, jsonpath, path_depth, objects);
+ /* continue by matching found object against the rest of jsonpath segments */
+ return jsonpath_query_contents(ctx, obj, path_depth);
}
/******************************************************************************
* *
- * Purpose: match object value name against jsonpath segment name list *
+ * Purpose: match object contents against jsonpath segment name list *
* *
- * Parameters: jp_root - [IN] the document root *
- * name - [IN] name or index of the next json element *
- * pnext - [IN] a pointer to object value with the specified *
- * name *
- * jsonpath - [IN] the jsonpath *
+ * Parameters: ctx - [IN] the jsonpath query context *
+ * parent - [IN] parent json object *
* path_depth - [IN] the jsonpath segment to match *
- * objects - [OUT] the matched json elements (name, value) *
* *
* Return value: SUCCEED - no errors, failed match is not an error *
* FAIL - otherwise *
* *
******************************************************************************/
-static int jsonpath_match_name(const struct zbx_json_parse *jp_root, const char *name, const char *pnext,
- const zbx_jsonpath_t *jsonpath, int path_depth, zbx_vector_json_t *objects)
+static int jsonpath_match_name(zbx_jsonpath_context_t *ctx, zbx_jsonobj_t *parent, int path_depth)
{
- const zbx_jsonpath_segment_t *segment = &jsonpath->segments[path_depth];
+ const zbx_jsonpath_segment_t *segment = &ctx->path->segments[path_depth];
const zbx_jsonpath_list_node_t *node;
+ zbx_jsonobj_el_t el_local, *el;
/* object contents can match only name list */
if (ZBX_JSONPATH_LIST_NAME != segment->data.list.type)
@@ -1365,11 +1697,11 @@ static int jsonpath_match_name(const struct zbx_json_parse *jp_root, const char
for (node = segment->data.list.values; NULL != node; node = node->next)
{
- if (0 == strcmp(name, node->data))
+ el_local.name = (char *)node->data;
+ if (NULL != (el = (zbx_jsonobj_el_t *)zbx_hashset_search(&parent->data.object, &el_local)))
{
- if (FAIL == jsonpath_query_next_segment(jp_root, name, pnext, jsonpath, path_depth, objects))
+ if (FAIL == jsonpath_query_next_segment(ctx, el->name, &el->value, path_depth))
return FAIL;
- break;
}
}
@@ -1380,8 +1712,8 @@ static int jsonpath_match_name(const struct zbx_json_parse *jp_root, const char
* *
* Purpose: extract value from json data by the specified path *
* *
- * Parameters: jp - [IN] the parent object *
- * path - [IN] the jsonpath (definite) *
+ * Parameters: obj - [IN] the parent object *
+ * path - [IN] the jsonpath *
* value - [OUT] the extracted value *
* *
* Return value: SUCCEED - the value was extracted successfully *
@@ -1389,35 +1721,28 @@ static int jsonpath_match_name(const struct zbx_json_parse *jp_root, const char
* extract *
* *
******************************************************************************/
-static int jsonpath_extract_value(const struct zbx_json_parse *jp, const char *path, zbx_variant_t *value)
+static int jsonpath_extract_value(zbx_jsonobj_t *obj, zbx_jsonpath_t *path, zbx_variant_t *value)
{
- struct zbx_json_parse jp_child;
- char *data = NULL, *tmp_path = NULL;
- size_t data_alloc = 0;
- int ret = FAIL;
+ int ret = FAIL;
+ zbx_jsonpath_context_t ctx;
- if ('@' == *path)
- {
- tmp_path = zbx_strdup(NULL, path);
- *tmp_path = '$';
- path = tmp_path;
- }
+ ctx.path = path;
+ ctx.found = 0;
+ ctx.root = obj;
+ zbx_vector_jsonobj_ref_create(&ctx.objects);
- if (FAIL == zbx_json_open_path(jp, path, &jp_child))
- goto out;
-
- if (NULL == zbx_json_decodevalue_dyn(jp_child.start, &data, &data_alloc, NULL))
+ if (SUCCEED == jsonpath_query_contents(&ctx, obj, 0) && 0 != ctx.objects.values_num)
{
- size_t len = jp_child.end - jp_child.start + 2;
+ char *str = NULL;
+ size_t str_alloc = 0, str_offset = 0;
- data = (char *)zbx_malloc(NULL, len);
- zbx_strlcpy(data, jp_child.start, len);
+ jsonpath_str_copy_value(&str, &str_alloc, &str_offset, ctx.objects.values[0].value);
+ zbx_variant_set_str(value, str);
+ ret = SUCCEED;
}
- zbx_variant_set_str(value, data);
- ret = SUCCEED;
-out:
- zbx_free(tmp_path);
+ zbx_vector_jsonobj_ref_clear_ext(&ctx.objects);
+ zbx_vector_jsonobj_ref_destroy(&ctx.objects);
return ret;
}
@@ -1452,7 +1777,7 @@ static char *jsonpath_expression_to_str(zbx_jsonpath_expression_t *expression)
case ZBX_JSONPATH_TOKEN_PATH_RELATIVE:
case ZBX_JSONPATH_TOKEN_CONST_STR:
case ZBX_JSONPATH_TOKEN_CONST_NUM:
- zbx_strcpy_alloc(&str, &str_alloc, &str_offset, token->data);
+ zbx_strcpy_alloc(&str, &str_alloc, &str_offset, token->text);
break;
case ZBX_JSONPATH_TOKEN_PAREN_LEFT:
zbx_strcpy_alloc(&str, &str_alloc, &str_offset, "(");
@@ -1604,35 +1929,123 @@ static int jsonpath_regexp_match(const char *text, const char *pattern, double *
/******************************************************************************
* *
+ * Purpose: add matched object to the index *
+ * *
+ * Parameters: index - [IN] the parent object index *
+ * name - [IN] the name of objec to add to index *
+ * obj - [IN] the object to add to index *
+ * value - [IN] the object matched by index path *
+ * *
+ ******************************************************************************/
+static void jsonpath_index_append_result(zbx_hashset_t *index, const char *name, zbx_jsonobj_t *obj,
+ zbx_jsonobj_t *value)
+{
+ zbx_jsonobj_index_el_t el_local = {.value = NULL}, *el;
+ size_t value_alloc = 0, value_offset = 0;
+ zbx_jsonobj_ref_t ref;
+
+ jsonpath_str_copy_value(&el_local.value, &value_alloc, &value_offset, value);
+
+ if (NULL == (el = (zbx_jsonobj_index_el_t *)zbx_hashset_search(index, &el_local)))
+ {
+ el = (zbx_jsonobj_index_el_t *)zbx_hashset_insert(index, &el_local, sizeof(el_local));
+ zbx_vector_jsonobj_ref_create(&el->objects);
+ }
+ else
+ zbx_free(el_local.value);
+
+ ref.name = zbx_strdup(NULL, name);
+ ref.value = obj;
+ ref.external = 0;
+ zbx_vector_jsonobj_ref_append(&el->objects, ref);
+}
+
+/******************************************************************************
+ * *
+ * Purpose: index json object using the expression token index path *
+ * *
+ * Parameters: obj - [IN] the object to index *
+ * index_token - [IN] the expression index token (relative path) *
+ * *
+ ******************************************************************************/
+static void jsonpath_create_index(zbx_jsonobj_t *obj, zbx_jsonpath_token_t *index_token)
+{
+ zbx_jsonpath_context_t ctx;
+
+ jsonobj_init_index(obj, index_token->text);
+
+ ctx.root = obj;
+ ctx.path = index_token->path;
+ zbx_vector_jsonobj_ref_create(&ctx.objects);
+
+ if (ZBX_JSON_TYPE_OBJECT == obj->type)
+ {
+ zbx_hashset_iter_t iter;
+ zbx_jsonobj_el_t *el;
+
+ zbx_hashset_iter_reset(&obj->data.object, &iter);
+ while (NULL != (el = (zbx_jsonobj_el_t *)zbx_hashset_iter_next(&iter)))
+ {
+ ctx.found = 0;
+ if (SUCCEED == jsonpath_query_contents(&ctx, &el->value, 0) && 1 == ctx.objects.values_num)
+ {
+ jsonpath_index_append_result(&obj->index->objects, el->name, &el->value,
+ ctx.objects.values[0].value);
+ }
+
+ zbx_vector_jsonobj_ref_clear_ext(&ctx.objects);
+ }
+ }
+ else
+ {
+ int i;
+
+ for (i = 0; i < obj->data.array.values_num; i++)
+ {
+ char name[MAX_ID_LEN + 1];
+ zbx_jsonobj_t *value = obj->data.array.values[i];
+
+ zbx_snprintf(name, sizeof(name), "%d", i);
+
+ ctx.found = 0;
+ if (SUCCEED == jsonpath_query_contents(&ctx, value, 0) && 1 == ctx.objects.values_num)
+ {
+ jsonpath_index_append_result(&obj->index->objects, name, value,
+ ctx.objects.values[0].value);
+ }
+
+ zbx_vector_jsonobj_ref_clear_ext(&ctx.objects);
+ }
+ }
+
+ zbx_vector_jsonobj_ref_destroy(&ctx.objects);
+}
+
+/******************************************************************************
+ * *
* Purpose: match json array element/object value against jsonpath expression *
* *
- * Parameters: jp_root - [IN] the document root *
+ * Parameters: ctx - [IN] the jsonpath query context *
* name - [IN] name or index of the next json element *
- * pnext - [IN] a pointer to array element/object value *
- * jsonpath - [IN] the jsonpath *
+ * obj - [IN] the jsonobject to match *
* path_depth - [IN] the jsonpath segment to match *
- * objects - [OUT] the matched json elements (name, value) *
* *
* Return value: SUCCEED - no errors, failed match is not an error *
* FAIL - otherwise *
* *
******************************************************************************/
-static int jsonpath_match_expression(const struct zbx_json_parse *jp_root, const char *name, const char *pnext,
- const zbx_jsonpath_t *jsonpath, int path_depth, zbx_vector_json_t *objects)
+static int jsonpath_match_expression(zbx_jsonpath_context_t *ctx, const char *name, zbx_jsonobj_t *obj,
+ int path_depth)
{
- struct zbx_json_parse jp;
zbx_vector_var_t stack;
int i, ret = SUCCEED;
zbx_jsonpath_segment_t *segment;
zbx_variant_t value, *right;
double res;
- if (SUCCEED != jsonpath_pointer_to_jp(pnext, &jp))
- return FAIL;
-
zbx_vector_var_create(&stack);
- segment = &jsonpath->segments[path_depth];
+ segment = &ctx->path->segments[path_depth];
for (i = 0; i < segment->data.expression.tokens.values_num; i++)
{
@@ -1779,25 +2192,25 @@ static int jsonpath_match_expression(const struct zbx_json_parse *jp_root, const
switch (token->type)
{
case ZBX_JSONPATH_TOKEN_PATH_ABSOLUTE:
- if (FAIL == jsonpath_extract_value(jp_root, token->data, &value))
+ if (FAIL == jsonpath_extract_value(ctx->root, token->path, &value))
zbx_variant_set_none(&value);
zbx_vector_var_append_ptr(&stack, &value);
break;
case ZBX_JSONPATH_TOKEN_PATH_RELATIVE:
/* relative path can be applied only to array or object */
- if ('[' != *jp.start && '{' != *jp.start)
+ if (ZBX_JSON_TYPE_ARRAY != obj->type && ZBX_JSON_TYPE_OBJECT != obj->type)
goto out;
- if (FAIL == jsonpath_extract_value(&jp, token->data, &value))
+ if (FAIL == jsonpath_extract_value(obj, token->path, &value))
zbx_variant_set_none(&value);
zbx_vector_var_append_ptr(&stack, &value);
break;
case ZBX_JSONPATH_TOKEN_CONST_STR:
- zbx_variant_set_str(&value, zbx_strdup(NULL, token->data));
+ zbx_variant_set_str(&value, zbx_strdup(NULL, token->text));
zbx_vector_var_append_ptr(&stack, &value);
break;
case ZBX_JSONPATH_TOKEN_CONST_NUM:
- zbx_variant_set_dbl(&value, atof(token->data));
+ zbx_variant_set_dbl(&value, atof(token->text));
zbx_vector_var_append_ptr(&stack, &value);
break;
case ZBX_JSONPATH_TOKEN_OP_NOT:
@@ -1824,7 +2237,7 @@ static int jsonpath_match_expression(const struct zbx_json_parse *jp_root, const
jsonpath_variant_to_boolean(&stack.values[0]);
if (SUCCEED != zbx_double_compare(stack.values[0].data.dbl, 0.0))
- ret = jsonpath_query_next_segment(jp_root, name, pnext, jsonpath, path_depth, objects);
+ ret = jsonpath_query_next_segment(ctx, name, obj, path_depth);
out:
for (i = 0; i < stack.values_num; i++)
zbx_variant_clear(&stack.values[i]);
@@ -1835,47 +2248,91 @@ out:
/******************************************************************************
* *
+ * Purpose: query indexed object fields for jsonpath segment match *
+ * *
+ * Parameters: ctx - [IN] the jsonpath query context *
+ * obj - [IN] the json object to query *
+ * path_depth - [IN] the jsonpath segment to match *
+ * *
+ * Return value: SUCCEED - the object was queried successfully *
+ * FAIL - otherwise *
+ * *
+ ******************************************************************************/
+static int jsonpath_match_indexed_expression(zbx_jsonpath_context_t *ctx, zbx_jsonobj_t *obj, int path_depth)
+{
+ zbx_jsonpath_segment_t *segment = &ctx->path->segments[path_depth];
+ zbx_jsonobj_index_el_t index_local, *el;
+
+ index_local.value = segment->data.expression.value_token->text;
+
+ if (NULL != (el = (zbx_jsonobj_index_el_t *)zbx_hashset_search(&obj->index->objects, &index_local)))
+ {
+ int i;
+
+ for (i = 0; i < el->objects.values_num; i++)
+ {
+ jsonpath_match_expression(ctx, el->objects.values[i].name, el->objects.values[i].value,
+ path_depth);
+ }
+ }
+
+ return SUCCEED;
+}
+
+/******************************************************************************
+ * *
* Purpose: query object fields for jsonpath segment match *
* *
- * Parameters: jp_root - [IN] the document root *
- * jp - [IN] the json object to query *
- * jsonpath - [IN] the jsonpath *
+ * Parameters: ctx - [IN] the jsonpath query context *
+ * obj - [IN] the json object to query *
* path_depth - [IN] the jsonpath segment to match *
- * objects - [OUT] the matched json elements (name, value) *
* *
* Return value: SUCCEED - the object was queried successfully *
* FAIL - otherwise *
* *
******************************************************************************/
-static int jsonpath_query_object(const struct zbx_json_parse *jp_root, const struct zbx_json_parse *jp,
- const zbx_jsonpath_t *jsonpath, int path_depth, zbx_vector_json_t *objects)
+static int jsonpath_query_object(zbx_jsonpath_context_t *ctx, zbx_jsonobj_t *obj, int path_depth)
{
- const char *pnext = NULL;
- char name[MAX_STRING_LEN];
const zbx_jsonpath_segment_t *segment;
int ret = SUCCEED;
+ zbx_hashset_iter_t iter;
+ zbx_jsonobj_el_t *el;
+
+ segment = &ctx->path->segments[path_depth];
+
+ if (ZBX_JSONPATH_SEGMENT_MATCH_LIST == segment->type)
+ {
+ ret = jsonpath_match_name(ctx, obj, path_depth);
+ if (FAIL == ret || 1 != segment->detached)
+ return ret;
+ }
+ else if (ZBX_JSONPATH_SEGMENT_MATCH_EXPRESSION == segment->type && NULL != segment->data.expression.index_token)
+ {
+ if (NULL == obj->index)
+ jsonpath_create_index(obj, segment->data.expression.index_token);
- segment = &jsonpath->segments[path_depth];
+ if (0 == strcmp(obj->index->path, segment->data.expression.index_token->text))
+ return jsonpath_match_indexed_expression(ctx, obj, path_depth);
+ }
- while (NULL != (pnext = zbx_json_pair_next(jp, pnext, name, sizeof(name))) && SUCCEED == ret)
+ zbx_hashset_iter_reset(&obj->data.object, &iter);
+ while (NULL != (el = (zbx_jsonobj_el_t *)zbx_hashset_iter_next(&iter)) && SUCCEED == ret &&
+ 0 == ctx->found)
{
switch (segment->type)
{
case ZBX_JSONPATH_SEGMENT_MATCH_ALL:
- ret = jsonpath_query_next_segment(jp_root, name, pnext, jsonpath, path_depth, objects);
- break;
- case ZBX_JSONPATH_SEGMENT_MATCH_LIST:
- ret = jsonpath_match_name(jp_root, name, pnext, jsonpath, path_depth, objects);
+ ret = jsonpath_query_next_segment(ctx, el->name, &el->value, path_depth);
break;
case ZBX_JSONPATH_SEGMENT_MATCH_EXPRESSION:
- ret = jsonpath_match_expression(jp_root, name, pnext, jsonpath, path_depth, objects);
+ ret = jsonpath_match_expression(ctx, el->name, &el->value, path_depth);
break;
default:
break;
}
if (1 == segment->detached)
- ret = jsonpath_query_contents(jp_root, pnext, jsonpath, path_depth, objects);
+ ret = jsonpath_query_contents(ctx, &el->value, path_depth);
}
return ret;
@@ -1883,25 +2340,19 @@ static int jsonpath_query_object(const struct zbx_json_parse *jp_root, const str
/******************************************************************************
* *
- * Purpose: match array element against segment index list *
+ * Purpose: array elements against segment index list *
* *
- * Parameters: jp_root - [IN] the document root *
- * name - [IN] the json element name (index) *
- * pnext - [IN] a pointer to an array element *
- * jsonpath - [IN] the jsonpath *
+ * Parameters: ctx - [IN] the jsonpath query context *
+ * parent - [IN] the json array *
* path_depth - [IN] the jsonpath segment to match *
- * index - [IN] the array element index *
- * elements_num - [IN] the total number of elements in array *
- * objects - [OUT] the matched json elements (name, value) *
* *
* Return value: SUCCEED - no errors, failed match is not an error *
* FAIL - otherwise *
* *
******************************************************************************/
-static int jsonpath_match_index(const struct zbx_json_parse *jp_root, const char *name, const char *pnext,
- const zbx_jsonpath_t *jsonpath, int path_depth, int index, int elements_num, zbx_vector_json_t *objects)
+static int jsonpath_match_index(zbx_jsonpath_context_t *ctx, zbx_jsonobj_t *parent, int path_depth)
{
- const zbx_jsonpath_segment_t *segment = &jsonpath->segments[path_depth];
+ const zbx_jsonpath_segment_t *segment = &ctx->path->segments[path_depth];
const zbx_jsonpath_list_node_t *node;
/* array contents can match only index list */
@@ -1914,11 +2365,20 @@ static int jsonpath_match_index(const struct zbx_json_parse *jp_root, const char
memcpy(&query_index, node->data, sizeof(query_index));
- if ((query_index >= 0 && index == query_index) || index == elements_num + query_index)
+ if (0 > query_index)
+ query_index += parent->data.array.values_num;
+
+ if (query_index >= 0 && query_index < parent->data.array.values_num)
{
- if (FAIL == jsonpath_query_next_segment(jp_root, name, pnext, jsonpath, path_depth, objects))
+ char name[MAX_ID_LEN + 1];
+
+ zbx_snprintf(name, sizeof(name), "%d", query_index);
+
+ if (FAIL == jsonpath_query_next_segment(ctx, name, parent->data.array.values[query_index],
+ path_depth))
+ {
return FAIL;
- break;
+ }
}
}
@@ -1927,38 +2387,37 @@ static int jsonpath_match_index(const struct zbx_json_parse *jp_root, const char
/******************************************************************************
* *
- * Purpose: match array element against segment index range *
+ * Purpose: match array elements against segment index range *
* *
- * Parameters: jp_root - [IN] the document root *
- * name - [IN] the json element name (index) *
- * pnext - [IN] a pointer to an array element *
- * jsonpath - [IN] the jsonpath *
- * path_depth - [IN] the jsonpath segment to match *
- * index - [IN] the array element index *
- * elements_num - [IN] the total number of elements in array *
- * objects - [OUT] the matched json elements (name, value) *
+ * Parameters: ctx - [IN] the jsonpath query context *
+ * parent - [IN] the json array *
+ * path_depth - [IN] the jsonpath segment to match *
* *
* Return value: SUCCEED - no errors, failed match is not an error *
* FAIL - otherwise *
* *
******************************************************************************/
-static int jsonpath_match_range(const struct zbx_json_parse *jp_root, const char *name, const char *pnext,
- const zbx_jsonpath_t *jsonpath, int path_depth, int index, int elements_num, zbx_vector_json_t *objects)
+static int jsonpath_match_range(zbx_jsonpath_context_t *ctx, zbx_jsonobj_t *parent, int path_depth)
{
- int start_index, end_index;
- const zbx_jsonpath_segment_t *segment = &jsonpath->segments[path_depth];
+ int i, start_index, end_index, values_num;
+ const zbx_jsonpath_segment_t *segment = &ctx->path->segments[path_depth];
+ values_num = parent->data.array.values_num;
start_index = (0 != (segment->data.range.flags & 0x01) ? segment->data.range.start : 0);
- end_index = (0 != (segment->data.range.flags & 0x02) ? segment->data.range.end : elements_num);
+ end_index = (0 != (segment->data.range.flags & 0x02) ? segment->data.range.end : values_num);
if (0 > start_index)
- start_index += elements_num;
+ start_index += values_num;
if (0 > end_index)
- end_index += elements_num;
+ end_index += values_num;
- if (start_index <= index && end_index > index)
+ for (i = start_index; i < end_index; i++)
{
- if (FAIL == jsonpath_query_next_segment(jp_root, name, pnext, jsonpath, path_depth, objects))
+ char name[MAX_ID_LEN + 1];
+
+ zbx_snprintf(name, sizeof(name), "%d", i);
+
+ if (FAIL == jsonpath_query_next_segment(ctx, name, parent->data.array.values[i], path_depth))
return FAIL;
}
@@ -1967,59 +2426,69 @@ static int jsonpath_match_range(const struct zbx_json_parse *jp_root, const char
/******************************************************************************
* *
- * Purpose: query array elements for jsonpath segment match *
+ * Purpose: query json array for jsonpath segment match *
* *
- * Parameters: jp_root - [IN] the document root *
- * jp - [IN] the json array to query *
- * jsonpath - [IN] the jsonpath *
+ * Parameters: ctx - [IN] the jsonpath query context *
+ * array - [IN] the json array to query *
* path_depth - [IN] the jsonpath segment to match *
- * objects - [OUT] the matched json elements (name, value) *
* *
* Return value: SUCCEED - the array was queried successfully *
* FAIL - otherwise *
* *
******************************************************************************/
-static int jsonpath_query_array(const struct zbx_json_parse *jp_root, const struct zbx_json_parse *jp,
- const zbx_jsonpath_t *jsonpath, int path_depth, zbx_vector_json_t *objects)
+static int jsonpath_query_array(zbx_jsonpath_context_t *ctx, zbx_jsonobj_t *array, int path_depth)
{
- const char *pnext = NULL;
- int index = 0, elements_num = 0, ret = SUCCEED;
+ int ret = SUCCEED, i;
zbx_jsonpath_segment_t *segment;
- segment = &jsonpath->segments[path_depth];
+ segment = &ctx->path->segments[path_depth];
- while (NULL != (pnext = zbx_json_next(jp, pnext)))
- elements_num++;
+ switch (segment->type)
+ {
+ case ZBX_JSONPATH_SEGMENT_MATCH_LIST:
+ ret = jsonpath_match_index(ctx, array, path_depth);
+ if (FAIL == ret || 1 != segment->detached)
+ return ret;
+ break;
+ case ZBX_JSONPATH_SEGMENT_MATCH_RANGE:
+ ret = jsonpath_match_range(ctx, array, path_depth);
+ if (FAIL == ret || 1 != segment->detached)
+ return ret;
+ break;
+ case ZBX_JSONPATH_SEGMENT_MATCH_EXPRESSION:
+ if (NULL != segment->data.expression.index_token)
+ {
+ if (NULL == array->index)
+ jsonpath_create_index(array, segment->data.expression.index_token);
- while (NULL != (pnext = zbx_json_next(jp, pnext)) && SUCCEED == ret)
+ if (0 == strcmp(array->index->path, segment->data.expression.index_token->text))
+ return jsonpath_match_indexed_expression(ctx, array, path_depth);
+ }
+ break;
+ default:
+ break;
+ }
+
+ for (i = 0; i < array->data.array.values_num && SUCCEED == ret && 0 == ctx->found; i++)
{
char name[MAX_ID_LEN + 1];
- zbx_snprintf(name, sizeof(name), "%d", index);
+ zbx_snprintf(name, sizeof(name), "%d", i);
+
switch (segment->type)
{
case ZBX_JSONPATH_SEGMENT_MATCH_ALL:
- ret = jsonpath_query_next_segment(jp_root, name, pnext, jsonpath, path_depth, objects);
- break;
- case ZBX_JSONPATH_SEGMENT_MATCH_LIST:
- ret = jsonpath_match_index(jp_root, name, pnext, jsonpath, path_depth, index,
- elements_num, objects);
- break;
- case ZBX_JSONPATH_SEGMENT_MATCH_RANGE:
- ret = jsonpath_match_range(jp_root, name, pnext, jsonpath, path_depth, index,
- elements_num, objects);
+ ret = jsonpath_query_next_segment(ctx, name, array->data.array.values[i], path_depth);
break;
case ZBX_JSONPATH_SEGMENT_MATCH_EXPRESSION:
- ret = jsonpath_match_expression(jp_root, name, pnext, jsonpath, path_depth, objects);
+ ret = jsonpath_match_expression(ctx, name, array->data.array.values[i], path_depth);
break;
default:
break;
}
if (1 == segment->detached)
- ret = jsonpath_query_contents(jp_root, pnext, jsonpath, path_depth, objects);
-
- index++;
+ ret = jsonpath_query_contents(ctx, array->data.array.values[i], path_depth);
}
return ret;
@@ -2027,123 +2496,99 @@ static int jsonpath_query_array(const struct zbx_json_parse *jp_root, const stru
/******************************************************************************
* *
- * Purpose: extract JSON element value from data *
- * *
- * Parameters: ptr - [IN] pointer to the element to extract *
- * element - [OUT] the extracted element *
+ * Purpose: get numeric value from json data *
* *
- * Return value: SUCCEED - the element was extracted successfully *
- * FAIL - the pointer was not pointing to a JSON element *
+ * Parameters: obj - [IN] json object *
+ * value - [OUT] the extracted value *
* *
- * Comments: String value element is unquoted, other elements are copied as *
- * is. *
+ * Return value: SUCCEED - the value was extracted successfully *
+ * FAIL - the pointer was not pointing at numeric value *
* *
******************************************************************************/
-static int jsonpath_extract_element(const char *ptr, char **element)
+static int jsonpath_get_numeric_value(const zbx_jsonobj_t *obj, double *value)
{
- size_t element_size = 0;
-
- if (NULL == zbx_json_decodevalue_dyn(ptr, element, &element_size, NULL))
+ switch (obj->type)
{
- struct zbx_json_parse jp;
-
- if (SUCCEED != zbx_json_brackets_open(ptr, &jp))
+ case ZBX_JSON_TYPE_NUMBER:
+ *value = obj->data.number;
+ return SUCCEED;
+ case ZBX_JSON_TYPE_STRING:
+ if (SUCCEED == zbx_is_double(obj->data.string, value))
+ return SUCCEED;
+ zbx_set_json_strerror("array value is not a number or out of range: %s", obj->data.string);
+ return FAIL;
+ default:
+ zbx_set_json_strerror("array value type is not a number or string");
return FAIL;
-
- *element = jsonpath_strndup(jp.start, jp.end - jp.start + 1);
}
-
- return SUCCEED;
}
/******************************************************************************
* *
- * Purpose: extract numeric value from json data *
- * *
- * Parameters: ptr - [IN] pointer to the value to extract *
- * value - [OUT] the extracted value *
+ * Purpose: get value from json data *
* *
* Return value: SUCCEED - the value was extracted successfully *
* FAIL - the pointer was not pointing at numeric value *
* *
******************************************************************************/
-static int jsonpath_extract_numeric_value(const char *ptr, double *value)
+static int jsonpath_str_copy_value(char **str, size_t *str_alloc, size_t *str_offset, zbx_jsonobj_t *obj)
{
- char buffer[MAX_STRING_LEN];
-
- if (NULL == zbx_json_decodevalue(ptr, buffer, sizeof(buffer), NULL) ||
- SUCCEED != zbx_is_double(buffer, value))
+ switch (obj->type)
{
- zbx_set_json_strerror("array value is not a number or out of range starting with: %s", ptr);
- return FAIL;
+ case ZBX_JSON_TYPE_STRING:
+ zbx_strcpy_alloc(str, str_alloc, str_offset, obj->data.string);
+ return SUCCEED;
+ break;
+ default:
+ return zbx_jsonobj_to_string(str, str_alloc, str_offset, obj);
}
-
- return SUCCEED;
}
/******************************************************************************
* *
* Purpose: apply jsonpath function to the extracted object list *
* *
- * Parameters: objects - [IN] the matched json elements (name, value) *
+ * Parameters: in - [IN] the matched objects *
* type - [IN] the function type *
- * definite_path - [IN] 1 - if the path is definite (pointing at *
- * single object) *
- * 0 - otherwise *
- * output - [OUT] the output value *
+ * definite_path - [IN/OUT] 1 - if the path is definite (pointing *
+ * at single object) *
+ * 0 - otherwise *
+ * out - [OUT] the result objects *
* *
* Return value: SUCCEED - the function was applied successfully *
* FAIL - invalid input data for the function or internal *
* json error *
* *
******************************************************************************/
-static int jsonpath_apply_function(const zbx_vector_json_t *objects, zbx_jsonpath_function_type_t type,
- int definite_path, char **output)
+static int jsonpath_apply_function(const zbx_vector_jsonobj_ref_t *in, zbx_jsonpath_function_type_t type,
+ int *definite_path, zbx_vector_jsonobj_ref_t *out)
{
- int i, ret = FAIL;
- zbx_vector_json_t objects_tmp;
- double result;
+ int i, ret = FAIL;
+ double result;
+ zbx_vector_jsonobj_ref_t tmp;
+ char buffer[64];
- zbx_vector_json_create(&objects_tmp);
+ zbx_vector_jsonobj_ref_create(&tmp);
if (ZBX_JSONPATH_FUNCTION_NAME == type)
{
- if (0 == objects->values_num)
+ if (0 == in->values_num)
{
zbx_set_json_strerror("cannot extract name from empty result");
goto out;
}
- /* For definite paths we have single output value, so return its name. */
- /* Otherwise return array of all output element names. */
- if (0 == definite_path)
- {
- struct zbx_json j;
-
- /* reserve some space for output json, 1k being large enough to satisfy most queries */
- zbx_json_initarray(&j, 1024);
- for (i = 0; i < objects->values_num; i++)
- zbx_json_addstring(&j, NULL, objects->values[i].name, ZBX_JSON_TYPE_STRING);
-
- zbx_json_close(&j);
- *output = zbx_strdup(NULL, j.buffer);
- zbx_json_clean(&j);
- }
- else
- *output = zbx_strdup(NULL, objects->values[0].name);
+ for (i = 0; i < in->values_num; i++)
+ zbx_vector_jsonobj_ref_add_string(out, "", in->values[i].name);
ret = SUCCEED;
goto out;
}
/* convert definite path result to object array if possible */
- if (0 != definite_path)
+ if (0 != *definite_path)
{
- const char *pnext;
- struct zbx_json_parse jp;
- int index = 0;
-
- if (0 == objects->values_num || '[' != *objects->values[0].value)
+ if (0 == in->values_num || ZBX_JSON_TYPE_ARRAY != in->values[0].value->type)
{
/* all functions can be applied only to arrays */
/* attempt to apply a function to non-array will fail */
@@ -2151,51 +2596,51 @@ static int jsonpath_apply_function(const zbx_vector_json_t *objects, zbx_jsonpat
goto out;
}
- if (FAIL == zbx_json_brackets_open(objects->values[0].value, &jp))
- goto out;
-
- for (pnext = NULL; NULL != (pnext = zbx_json_next(&jp, pnext));)
+ for (i = 0; i < in->values[0].value->data.array.values_num; i++)
{
char name[MAX_ID_LEN + 1];
- zbx_snprintf(name, sizeof(name), "%d", index++);
- zbx_vector_json_add_element(&objects_tmp, name, pnext);
+ zbx_snprintf(name, sizeof(name), "%d", i);
+ zbx_vector_jsonobj_ref_add_object(&tmp, name, in->values[0].value->data.array.values[i]);
}
- objects = &objects_tmp;
+ in = &tmp;
+ *definite_path = 0;
}
if (ZBX_JSONPATH_FUNCTION_LENGTH == type)
{
- *output = zbx_dsprintf(NULL, "%d", objects->values_num);
+ zbx_snprintf(buffer, sizeof(buffer), "%d", in->values_num);
+ zbx_vector_jsonobj_ref_add_string(out, "", buffer);
+ *definite_path = 1;
ret = SUCCEED;
goto out;
}
if (ZBX_JSONPATH_FUNCTION_FIRST == type)
{
- if (0 < objects->values_num)
- ret = jsonpath_extract_element(objects->values[0].value, output);
- else
- ret = SUCCEED;
+ if (0 < in->values_num)
+ zbx_vector_jsonobj_ref_add(out, &in->values[0]);
+ *definite_path = 1;
+ ret = SUCCEED;
goto out;
}
- if (0 == objects->values_num)
+ if (0 == in->values_num)
{
zbx_set_json_strerror("cannot apply aggregation function to empty array");
goto out;
}
- if (FAIL == jsonpath_extract_numeric_value(objects->values[0].value, &result))
+ if (FAIL == jsonpath_get_numeric_value(in->values[0].value, &result))
goto out;
- for (i = 1; i < objects->values_num; i++)
+ for (i = 1; i < in->values_num; i++)
{
double value;
- if (FAIL == jsonpath_extract_numeric_value(objects->values[i].value, &value))
+ if (FAIL == jsonpath_get_numeric_value(in->values[i].value, &value))
goto out;
switch (type)
@@ -2218,19 +2663,22 @@ static int jsonpath_apply_function(const zbx_vector_json_t *objects, zbx_jsonpat
}
if (ZBX_JSONPATH_FUNCTION_AVG == type)
- result /= objects->values_num;
+ result /= in->values_num;
- *output = zbx_dsprintf(NULL, ZBX_FS_DBL, result);
- if (SUCCEED != zbx_is_double(*output, NULL))
+ zbx_print_double(buffer, sizeof(buffer), result);
+ if (SUCCEED != zbx_is_double(buffer, NULL))
{
- zbx_set_json_strerror("invalid function result: %s", *output);
+ zbx_set_json_strerror("invalid function result: %s", buffer);
goto out;
}
- zbx_del_zeros(*output);
+
+ zbx_del_zeros(buffer);
+ zbx_vector_jsonobj_ref_add_string(out, "", buffer);
+ *definite_path = 1;
ret = SUCCEED;
out:
- zbx_vector_json_clear_ext(&objects_tmp);
- zbx_vector_json_destroy(&objects_tmp);
+ zbx_vector_jsonobj_ref_clear_ext(&tmp);
+ zbx_vector_jsonobj_ref_destroy(&tmp);
return ret;
}
@@ -2239,58 +2687,47 @@ out:
* *
* Purpose: apply jsonpath function to the extracted object list *
* *
- * Parameters: jp_root - [IN] the document root *
- * objects - [IN] the matched json elements (name, value) *
- * jsonpath - [IN] the jsonpath *
- * path_depth - [IN] the jsonpath segment to match *
- * output - [OUT] the output value *
+ * Parameters: ctx - [IN] the jsonpath query context *
+ * path_depth - [IN] the jsonpath segment to match *
+ * definite_path - [IN/OUT] *
+ * out - [OUT] the result object *
* *
* Return value: SUCCEED - the function was applied successfully *
* FAIL - invalid input data for the function or internal *
* json error *
* *
******************************************************************************/
-static int jsonpath_apply_functions(const struct zbx_json_parse *jp_root, const zbx_vector_json_t *objects,
- const zbx_jsonpath_t *jsonpath, int path_depth, char **output)
+static int jsonpath_apply_functions(zbx_jsonpath_context_t *ctx, int path_depth, int *definite_path,
+ zbx_vector_jsonobj_ref_t *out)
{
- int ret, definite_path;
- zbx_vector_json_t input;
- char *input_json = NULL;
+ int ret;
+ zbx_vector_jsonobj_ref_t in;
- zbx_vector_json_create(&input);
+ zbx_vector_jsonobj_ref_create(&in);
/* when functions are applied directly to the json document (at the start of the jsonpath ) */
/* it makes all document as input object */
if (0 == path_depth)
- zbx_vector_json_add_element(&input, "", jp_root->start);
+ zbx_vector_jsonobj_ref_add_object(&in, "", ctx->root);
else
- zbx_vector_json_copy(&input, objects);
-
- definite_path = jsonpath->definite;
+ zbx_vector_jsonobj_ref_copy(&in, &ctx->objects);
for (;;)
{
- ret = jsonpath_apply_function(&input, jsonpath->segments[path_depth++].data.function.type,
- definite_path, output);
+ ret = jsonpath_apply_function(&in, ctx->path->segments[path_depth++].data.function.type,
+ definite_path, out);
- zbx_vector_json_clear_ext(&input);
- zbx_free(input_json);
+ zbx_vector_jsonobj_ref_clear_ext(&in);
- if (SUCCEED != ret || path_depth == jsonpath->segments_num)
+ if (SUCCEED != ret || path_depth == ctx->path->segments_num)
break;
- if (NULL != *output)
- {
- zbx_vector_json_add_element(&input, "", *output);
- input_json = *output;
- *output = NULL;
- }
-
- /* functions return single value, so for the next functions path becomes definite */
- definite_path = 1;
+ zbx_vector_jsonobj_ref_copy(&in, out);
+ zbx_vector_jsonobj_ref_clear_ext(out);
}
- zbx_vector_json_destroy(&input);
+ zbx_vector_jsonobj_ref_clear_ext(&in);
+ zbx_vector_jsonobj_ref_destroy(&in);
return ret;
}
@@ -2299,49 +2736,37 @@ static int jsonpath_apply_functions(const struct zbx_json_parse *jp_root, const
* *
* Purpose: format query result, depending on jsonpath type *
* *
- * Parameters: objects - [IN] the matched json elements (name, value) *
- * jsonpath - [IN] the jsonpath used to acquire result *
- * output - [OUT] the output value *
+ * Parameters: objects - [IN] the matched json refs (name, value) *
+ * definite_path - [IN] the jsonpath definite flag *
+ * output - [OUT] the output value *
* *
* Return value: SUCCEED - the result was formatted successfully *
* FAIL - invalid result data (internal json error) *
* *
******************************************************************************/
-static int jsonpath_format_query_result(const zbx_vector_json_t *objects, zbx_jsonpath_t *jsonpath, char **output)
+static int jsonpath_format_query_result(const zbx_vector_jsonobj_ref_t *objects, int definite_path, char **output)
{
size_t output_offset = 0, output_alloc;
int i;
+ char delim;
if (0 == objects->values_num)
return SUCCEED;
- if (1 == jsonpath->definite)
- {
- return jsonpath_extract_element(objects->values[0].value, output);
- }
+ if (1 == definite_path)
+ return jsonpath_str_copy_value(output, &output_alloc, &output_offset, objects->values[0].value);
/* reserve 32 bytes per returned object plus array start/end [] and terminating zero */
- output_alloc = objects->values_num * 32 + 3;
+ output_alloc = (size_t)objects->values_num * 32 + 3;
*output = (char *)zbx_malloc(NULL, output_alloc);
- zbx_chrcpy_alloc(output, &output_alloc, &output_offset, '[');
+ delim = '[';
for (i = 0; i < objects->values_num; i++)
{
- struct zbx_json_parse jp;
-
- if (FAIL == jsonpath_pointer_to_jp(objects->values[i].value, &jp))
- {
- zbx_set_json_strerror("cannot format query result, unrecognized json part starting with: %s",
- objects->values[i].value);
- zbx_free(*output);
- return FAIL;
- }
-
- if (0 != i)
- zbx_chrcpy_alloc(output, &output_alloc, &output_offset, ',');
-
- zbx_strncpy_alloc(output, &output_alloc, &output_offset, jp.start, jp.end - jp.start + 1);
+ zbx_chrcpy_alloc(output, &output_alloc, &output_offset, delim);
+ zbx_jsonobj_to_string(output, &output_alloc, &output_offset, objects->values[i].value);
+ delim = ',';
}
zbx_chrcpy_alloc(output, &output_alloc, &output_offset, ']');
@@ -2364,7 +2789,7 @@ void zbx_jsonpath_clear(zbx_jsonpath_t *jsonpath)
* Purpose: compile jsonpath to be used in queries *
* *
* Parameters: path - [IN] the path to parse *
- * jsonpath - [IN/OUT] the compiled jsonpath *
+ * jsonpath - [IN/OUT] the compiled jsonpath *
* *
* Return value: SUCCEED - the segment was parsed successfully *
* FAIL - otherwise *
@@ -2386,6 +2811,7 @@ int zbx_jsonpath_compile(const char *path, zbx_jsonpath_t *jsonpath)
memset(&jpquery, 0, sizeof(zbx_jsonpath_t));
jsonpath_reserve(&jpquery, 4);
jpquery.definite = 1;
+ jpquery.first_match = 0;
for (ptr++; '\0' != *ptr; ptr = next)
{
@@ -2453,7 +2879,10 @@ int zbx_jsonpath_compile(const char *path, zbx_jsonpath_t *jsonpath)
ret = zbx_jsonpath_error(ptr);
if (SUCCEED == ret)
+ {
+ jpquery.first_match |= jpquery.definite;
*jsonpath = jpquery;
+ }
else
zbx_jsonpath_clear(&jpquery);
@@ -2472,37 +2901,89 @@ int zbx_jsonpath_compile(const char *path, zbx_jsonpath_t *jsonpath)
* being counted as successful query) *
* FAIL - otherwise *
* *
+ * Comments: This function is for compatibility purposes. Where possible the *
+ * zbx_jsonobj_query() function must be used. *
+ * *
******************************************************************************/
int zbx_jsonpath_query(const struct zbx_json_parse *jp, const char *path, char **output)
{
+ int ret;
+ zbx_jsonobj_t obj;
+
+ if (SUCCEED != zbx_jsonobj_open(jp->start, &obj))
+ return FAIL;
+
+ ret = zbx_jsonobj_query(&obj, path, output);
+
+ zbx_jsonobj_clear(&obj);
+
+ return ret;
+}
+
+/******************************************************************************
+ * *
+ * Purpose: perform jsonpath query on the specified json object *
+ * *
+ * Parameters: obj - [IN] the json object *
+ * path - [IN] the jsonpath *
+ * output - [OUT] the output value *
+ * *
+ * Return value: SUCCEED - the query was performed successfully (empty result *
+ * being counted as successful query) *
+ * FAIL - otherwise *
+ * *
+ ******************************************************************************/
+int zbx_jsonobj_query(zbx_jsonobj_t *obj, const char *path, char **output)
+{
+ zbx_jsonpath_context_t ctx;
zbx_jsonpath_t jsonpath;
- int path_depth = 0, ret = SUCCEED;
- zbx_vector_json_t objects;
+ int ret = SUCCEED;
if (FAIL == zbx_jsonpath_compile(path, &jsonpath))
return FAIL;
- zbx_vector_json_create(&objects);
+ ctx.found = 0;
+ ctx.root = obj;
+ ctx.path = &jsonpath;
+ zbx_vector_jsonobj_ref_create(&ctx.objects);
- if ('{' == *jp->start)
- ret = jsonpath_query_object(jp, jp, &jsonpath, path_depth, &objects);
- else if ('[' == *jp->start)
- ret = jsonpath_query_array(jp, jp, &jsonpath, path_depth, &objects);
+ switch (obj->type)
+ {
+ case ZBX_JSON_TYPE_OBJECT:
+ ret = jsonpath_query_object(&ctx, obj, 0);
+ break;
+ case ZBX_JSON_TYPE_ARRAY:
+ ret = jsonpath_query_array(&ctx, obj, 0);
+ break;
+ default:
+ break;
+ }
if (SUCCEED == ret)
{
+ zbx_vector_jsonobj_ref_t out;
+ int definite_path = jsonpath.definite, path_depth;
+
+ zbx_vector_jsonobj_ref_create(&out);
+
path_depth = jsonpath.segments_num;
while (0 < path_depth && ZBX_JSONPATH_SEGMENT_FUNCTION == jsonpath.segments[path_depth - 1].type)
path_depth--;
if (path_depth < jsonpath.segments_num)
- ret = jsonpath_apply_functions(jp, &objects, &jsonpath, path_depth, output);
+ {
+ if (SUCCEED == (ret = jsonpath_apply_functions(&ctx, path_depth, &definite_path, &out)))
+ ret = jsonpath_format_query_result(&out, definite_path, output);
+ }
else
- ret = jsonpath_format_query_result(&objects, &jsonpath, output);
+ ret = jsonpath_format_query_result(&ctx.objects, definite_path, output);
+
+ zbx_vector_jsonobj_ref_clear_ext(&out);
+ zbx_vector_jsonobj_ref_destroy(&out);
}
- zbx_vector_json_clear_ext(&objects);
- zbx_vector_json_destroy(&objects);
+ zbx_vector_jsonobj_ref_clear_ext(&ctx.objects);
+ zbx_vector_jsonobj_ref_destroy(&ctx.objects);
zbx_jsonpath_clear(&jsonpath);
return ret;