summaryrefslogtreecommitdiffstats
path: root/src/tree_data.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 04:23:18 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 04:23:18 +0000
commitb90161ccd3b318f3314a23cb10c387651ad35831 (patch)
treea47dc087160299ce02d728cbf031d84af6281537 /src/tree_data.c
parentAdding upstream version 2.1.30. (diff)
downloadlibyang2-upstream.tar.xz
libyang2-upstream.zip
Adding upstream version 2.1.148.upstream/2.1.148upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/tree_data.c')
-rw-r--r--src/tree_data.c914
1 files changed, 620 insertions, 294 deletions
diff --git a/src/tree_data.c b/src/tree_data.c
index d6a04ff..82a1ae8 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -52,6 +52,9 @@
#include "xml.h"
#include "xpath.h"
+static LY_ERR lyd_compare_siblings_(const struct lyd_node *node1, const struct lyd_node *node2, uint32_t options,
+ ly_bool parental_schemas_checked);
+
static LYD_FORMAT
lyd_parse_get_format(const struct ly_in *in, LYD_FORMAT format)
{
@@ -96,10 +99,9 @@ static LY_ERR
lyd_parse(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent, struct lyd_node **first_p,
struct ly_in *in, LYD_FORMAT format, uint32_t parse_opts, uint32_t val_opts, struct lyd_node **op)
{
- LY_ERR rc = LY_SUCCESS;
+ LY_ERR r = LY_SUCCESS, rc = LY_SUCCESS;
struct lyd_ctx *lydctx = NULL;
struct ly_set parsed = {0};
- struct lyd_node *first;
uint32_t i, int_opts = 0;
ly_bool subtree_sibling = 0;
@@ -121,36 +123,40 @@ lyd_parse(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct
/* parse the data */
switch (format) {
case LYD_XML:
- rc = lyd_parse_xml(ctx, ext, parent, first_p, in, parse_opts, val_opts, int_opts, &parsed,
+ r = lyd_parse_xml(ctx, ext, parent, first_p, in, parse_opts, val_opts, int_opts, &parsed,
&subtree_sibling, &lydctx);
break;
case LYD_JSON:
- rc = lyd_parse_json(ctx, ext, parent, first_p, in, parse_opts, val_opts, int_opts, &parsed,
+ r = lyd_parse_json(ctx, ext, parent, first_p, in, parse_opts, val_opts, int_opts, &parsed,
&subtree_sibling, &lydctx);
break;
case LYD_LYB:
- rc = lyd_parse_lyb(ctx, ext, parent, first_p, in, parse_opts, val_opts, int_opts, &parsed,
+ r = lyd_parse_lyb(ctx, ext, parent, first_p, in, parse_opts, val_opts, int_opts, &parsed,
&subtree_sibling, &lydctx);
break;
case LYD_UNKNOWN:
LOGARG(ctx, format);
- rc = LY_EINVAL;
+ r = LY_EINVAL;
break;
}
- LY_CHECK_GOTO(rc, cleanup);
+ if (r) {
+ rc = r;
+ if ((r != LY_EVALID) || !lydctx || !(lydctx->val_opts & LYD_VALIDATE_MULTI_ERROR) ||
+ (ly_vecode(ctx) == LYVE_SYNTAX)) {
+ goto cleanup;
+ }
+ }
- if (parent) {
- /* get first top-level sibling */
- for (first = parent; first->parent; first = lyd_parent(first)) {}
- first = lyd_first_sibling(first);
- first_p = &first;
+ if (parent && parsed.count) {
+ /* use the first parsed node */
+ first_p = &parsed.dnodes[0];
}
if (!(parse_opts & LYD_PARSE_ONLY)) {
/* validate data */
- rc = lyd_validate(first_p, NULL, ctx, val_opts, 0, &lydctx->node_when, &lydctx->node_types, &lydctx->meta_types,
+ r = lyd_validate(first_p, NULL, ctx, val_opts, 0, &lydctx->node_when, &lydctx->node_types, &lydctx->meta_types,
&lydctx->ext_node, &lydctx->ext_val, NULL);
- LY_CHECK_GOTO(rc, cleanup);
+ LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
}
/* set the operation node */
@@ -252,28 +258,7 @@ lyd_parse_data_path(const struct ly_ctx *ctx, const char *path, LYD_FORMAT forma
*
* At least one of @p parent, @p tree, or @p op must always be set.
*
- * Specific @p data_type values have different parameter meaning as follows:
- * - ::LYD_TYPE_RPC_NETCONF:
- * - @p parent - must be NULL, the whole RPC is expected;
- * - @p format - must be ::LYD_XML, NETCONF supports only this format;
- * - @p tree - must be provided, all the NETCONF-specific XML envelopes will be returned here as
- * a separate opaque data tree, even if the function fails, this may be returned;
- * - @p op - must be provided, the RPC/action data tree itself will be returned here, pointing to the operation;
- *
- * - ::LYD_TYPE_NOTIF_NETCONF:
- * - @p parent - must be NULL, the whole notification is expected;
- * - @p format - must be ::LYD_XML, NETCONF supports only this format;
- * - @p tree - must be provided, all the NETCONF-specific XML envelopes will be returned here as
- * a separate opaque data tree, even if the function fails, this may be returned;
- * - @p op - must be provided, the notification data tree itself will be returned here, pointing to the operation;
- *
- * - ::LYD_TYPE_REPLY_NETCONF:
- * - @p parent - must be set, pointing to the invoked RPC operation (RPC or action) node;
- * - @p format - must be ::LYD_XML, NETCONF supports only this format;
- * - @p tree - must be provided, all the NETCONF-specific XML envelopes will be returned here as
- * a separate opaque data tree, even if the function fails, this may be returned;
- * - @p op - must be NULL, the reply is appended to the RPC;
- * Note that there are 3 kinds of NETCONF replies - ok, error, and data. Only data reply appends any nodes to the RPC.
+ * Specific @p data_type values have different parameter meaning as mentioned for ::lyd_parse_op().
*
* @param[in] ctx libyang context.
* @param[in] ext Extension instance providing the specific schema tree to match with the data being parsed.
@@ -295,6 +280,7 @@ lyd_parse_op_(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, str
struct ly_set parsed = {0};
struct lyd_node *first = NULL, *envp = NULL;
uint32_t i, parse_opts, val_opts, int_opts = 0;
+ ly_bool proto_msg = 0;
if (!ctx) {
ctx = LYD_CTX(parent);
@@ -316,20 +302,51 @@ lyd_parse_op_(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, str
val_opts = 0;
switch (data_type) {
-
- /* special XML NETCONF data types */
case LYD_TYPE_RPC_NETCONF:
case LYD_TYPE_NOTIF_NETCONF:
LY_CHECK_ARG_RET(ctx, format == LYD_XML, !parent, tree, op, LY_EINVAL);
- /* fallthrough */
+ proto_msg = 1;
+ break;
case LYD_TYPE_REPLY_NETCONF:
- if (data_type == LYD_TYPE_REPLY_NETCONF) {
- LY_CHECK_ARG_RET(ctx, format == LYD_XML, parent, parent->schema->nodetype & (LYS_RPC | LYS_ACTION), tree, !op,
- LY_EINVAL);
- }
+ LY_CHECK_ARG_RET(ctx, format == LYD_XML, parent, parent->schema, parent->schema->nodetype & (LYS_RPC | LYS_ACTION),
+ tree, !op, LY_EINVAL);
+ proto_msg = 1;
+ break;
+ case LYD_TYPE_RPC_RESTCONF:
+ case LYD_TYPE_REPLY_RESTCONF:
+ LY_CHECK_ARG_RET(ctx, parent, parent->schema, parent->schema->nodetype & (LYS_RPC | LYS_ACTION), tree, !op, LY_EINVAL);
+ proto_msg = 1;
+ break;
+ case LYD_TYPE_NOTIF_RESTCONF:
+ LY_CHECK_ARG_RET(ctx, format == LYD_JSON, !parent, tree, op, LY_EINVAL);
+ proto_msg = 1;
+ break;
- /* parse the NETCONF message */
- rc = lyd_parse_xml_netconf(ctx, ext, parent, &first, in, parse_opts, val_opts, data_type, &envp, &parsed, &lydctx);
+ /* set internal opts */
+ case LYD_TYPE_RPC_YANG:
+ int_opts = LYD_INTOPT_RPC | LYD_INTOPT_ACTION | (parent ? LYD_INTOPT_WITH_SIBLINGS : LYD_INTOPT_NO_SIBLINGS);
+ break;
+ case LYD_TYPE_NOTIF_YANG:
+ int_opts = LYD_INTOPT_NOTIF | (parent ? LYD_INTOPT_WITH_SIBLINGS : LYD_INTOPT_NO_SIBLINGS);
+ break;
+ case LYD_TYPE_REPLY_YANG:
+ int_opts = LYD_INTOPT_REPLY | (parent ? LYD_INTOPT_WITH_SIBLINGS : LYD_INTOPT_NO_SIBLINGS);
+ break;
+ case LYD_TYPE_DATA_YANG:
+ LOGINT(ctx);
+ rc = LY_EINT;
+ goto cleanup;
+ }
+
+ /* parse a full protocol message */
+ if (proto_msg) {
+ if (format == LYD_XML) {
+ /* parse the NETCONF (or RESTCONF XML) message */
+ rc = lyd_parse_xml_netconf(ctx, ext, parent, &first, in, parse_opts, val_opts, data_type, &envp, &parsed, &lydctx);
+ } else {
+ /* parse the RESTCONF message */
+ rc = lyd_parse_json_restconf(ctx, ext, parent, &first, in, parse_opts, val_opts, data_type, &envp, &parsed, &lydctx);
+ }
if (rc) {
if (envp) {
/* special situation when the envelopes were parsed successfully */
@@ -349,21 +366,6 @@ lyd_parse_op_(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, str
*op = lydctx->op_node;
}
goto cleanup;
-
- /* set internal opts */
- case LYD_TYPE_RPC_YANG:
- int_opts = LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NO_SIBLINGS;
- break;
- case LYD_TYPE_NOTIF_YANG:
- int_opts = LYD_INTOPT_NOTIF | LYD_INTOPT_NO_SIBLINGS;
- break;
- case LYD_TYPE_REPLY_YANG:
- int_opts = LYD_INTOPT_REPLY | LYD_INTOPT_NO_SIBLINGS;
- break;
- case LYD_TYPE_DATA_YANG:
- LOGINT(ctx);
- rc = LY_EINT;
- goto cleanup;
}
/* parse the data */
@@ -405,7 +407,7 @@ cleanup:
lyd_free_tree(parsed.dnodes[i]);
} while (i);
}
- if (tree && ((format != LYD_XML) || !envp)) {
+ if (tree && !envp) {
*tree = NULL;
}
if (op) {
@@ -484,6 +486,10 @@ lyd_insert_get_next_anchor(const struct lyd_node *first_sibling, const struct ly
/* get the first schema sibling */
schema = lys_getnext(NULL, sparent, new_node->schema->module->compiled, getnext_opts);
+ if (!schema) {
+ /* must be a top-level extension instance data, no anchor */
+ return NULL;
+ }
found = 0;
LY_LIST_FOR(match, match) {
@@ -506,8 +512,12 @@ lyd_insert_get_next_anchor(const struct lyd_node *first_sibling, const struct ly
/* current node (match) is a data node still before the new node, continue search in data */
break;
}
+
schema = lys_getnext(schema, sparent, new_node->schema->module->compiled, getnext_opts);
- assert(schema);
+ if (!schema) {
+ /* must be a top-level extension instance data, no anchor */
+ return NULL;
+ }
}
if (found && (match->schema != new_node->schema)) {
@@ -660,6 +670,14 @@ lyd_insert_node(struct lyd_node *parent, struct lyd_node **first_sibling_p, stru
} else {
/* find the anchor, our next node, so we can insert before it */
anchor = lyd_insert_get_next_anchor(first_sibling, node);
+
+ /* cannot insert data node after opaque nodes */
+ if (!anchor && node->schema && first_sibling && !first_sibling->prev->schema) {
+ anchor = first_sibling->prev;
+ while ((anchor != first_sibling) && !anchor->prev->schema) {
+ anchor = anchor->prev;
+ }
+ }
}
if (anchor) {
@@ -684,7 +702,7 @@ lyd_insert_node(struct lyd_node *parent, struct lyd_node **first_sibling_p, stru
lyd_insert_hash(node);
/* finish hashes for our parent, if needed and possible */
- if (node->schema && (node->schema->flags & LYS_KEY) && parent && lyd_insert_has_keys(parent)) {
+ if (node->schema && (node->schema->flags & LYS_KEY) && parent && parent->schema && lyd_insert_has_keys(parent)) {
lyd_hash(parent);
/* now we can insert even the list into its parent HT */
@@ -756,12 +774,12 @@ lyd_insert_child(struct lyd_node *parent, struct lyd_node *node)
}
if (node->parent || node->prev->next) {
- lyd_unlink_tree(node);
+ lyd_unlink(node);
}
while (node) {
iter = node->next;
- lyd_unlink_tree(node);
+ lyd_unlink(node);
lyd_insert_node(parent, NULL, node, 0);
node = iter;
}
@@ -783,7 +801,7 @@ lyplg_ext_insert(struct lyd_node *parent, struct lyd_node *first)
while (first) {
iter = first->next;
- lyd_unlink_tree(first);
+ lyd_unlink(first);
lyd_insert_node(parent, NULL, first, 1);
first = iter;
}
@@ -807,7 +825,7 @@ lyd_insert_sibling(struct lyd_node *sibling, struct lyd_node *node, struct lyd_n
}
if (node->parent || node->prev->next) {
- lyd_unlink_tree(node);
+ lyd_unlink(node);
}
while (node) {
@@ -817,7 +835,7 @@ lyd_insert_sibling(struct lyd_node *sibling, struct lyd_node *node, struct lyd_n
}
iter = node->next;
- lyd_unlink_tree(node);
+ lyd_unlink(node);
lyd_insert_node(NULL, &sibling, node, 0);
node = iter;
}
@@ -850,7 +868,7 @@ lyd_insert_before(struct lyd_node *sibling, struct lyd_node *node)
return LY_EINVAL;
}
- lyd_unlink_tree(node);
+ lyd_unlink(node);
lyd_insert_before_node(sibling, node);
lyd_insert_hash(node);
@@ -874,26 +892,15 @@ lyd_insert_after(struct lyd_node *sibling, struct lyd_node *node)
return LY_EINVAL;
}
- lyd_unlink_tree(node);
+ lyd_unlink(node);
lyd_insert_after_node(sibling, node);
lyd_insert_hash(node);
return LY_SUCCESS;
}
-LIBYANG_API_DEF void
-lyd_unlink_siblings(struct lyd_node *node)
-{
- struct lyd_node *next, *elem, *first = NULL;
-
- LY_LIST_FOR_SAFE(node, next, elem) {
- lyd_unlink_tree(elem);
- lyd_insert_node(NULL, &first, elem, 1);
- }
-}
-
-LIBYANG_API_DEF void
-lyd_unlink_tree(struct lyd_node *node)
+void
+lyd_unlink(struct lyd_node *node)
{
struct lyd_node *iter;
@@ -941,6 +948,35 @@ lyd_unlink_tree(struct lyd_node *node)
node->prev = node;
}
+LIBYANG_API_DEF void
+lyd_unlink_siblings(struct lyd_node *node)
+{
+ struct lyd_node *next, *elem, *first = NULL;
+
+ LY_LIST_FOR_SAFE(node, next, elem) {
+ if (lysc_is_key(elem->schema) && elem->parent) {
+ LOGERR(LYD_CTX(elem), LY_EINVAL, "Cannot unlink a list key \"%s\", unlink the list instance instead.",
+ LYD_NAME(elem));
+ return;
+ }
+
+ lyd_unlink(elem);
+ lyd_insert_node(NULL, &first, elem, 1);
+ }
+}
+
+LIBYANG_API_DEF void
+lyd_unlink_tree(struct lyd_node *node)
+{
+ if (node && lysc_is_key(node->schema) && node->parent) {
+ LOGERR(LYD_CTX(node), LY_EINVAL, "Cannot unlink a list key \"%s\", unlink the list instance instead.",
+ LYD_NAME(node));
+ return;
+ }
+
+ lyd_unlink(node);
+}
+
void
lyd_insert_meta(struct lyd_node *parent, struct lyd_meta *meta, ly_bool clear_dflt)
{
@@ -973,7 +1009,7 @@ lyd_insert_meta(struct lyd_node *parent, struct lyd_meta *meta, ly_bool clear_df
LY_ERR
lyd_create_meta(struct lyd_node *parent, struct lyd_meta **meta, const struct lys_module *mod, const char *name,
- size_t name_len, const char *value, size_t value_len, ly_bool *dynamic, LY_VALUE_FORMAT format,
+ size_t name_len, const char *value, size_t value_len, ly_bool is_utf8, ly_bool *dynamic, LY_VALUE_FORMAT format,
void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node, ly_bool clear_dflt, ly_bool *incomplete)
{
LY_ERR ret = LY_SUCCESS;
@@ -1005,7 +1041,7 @@ lyd_create_meta(struct lyd_node *parent, struct lyd_meta **meta, const struct ly
mt->parent = parent;
mt->annotation = ant;
lyplg_ext_get_storage(ant, LY_STMT_TYPE, sizeof ant_type, (const void **)&ant_type);
- ret = lyd_value_store(mod->ctx, &mt->value, ant_type, value, value_len, dynamic, format, prefix_data, hints,
+ ret = lyd_value_store(mod->ctx, &mt->value, ant_type, value, value_len, is_utf8, dynamic, format, prefix_data, hints,
ctx_node, incomplete);
LY_CHECK_ERR_GOTO(ret, free(mt), cleanup);
ret = lydict_insert(mod->ctx, name, name_len, &mt->name);
@@ -1110,11 +1146,9 @@ finish:
LIBYANG_API_DEF const struct lyd_node_term *
lyd_target(const struct ly_path *path, const struct lyd_node *tree)
{
- struct lyd_node *target;
+ struct lyd_node *target = NULL;
- if (ly_path_eval(path, tree, &target)) {
- return NULL;
- }
+ lyd_find_target(path, tree, &target);
return (struct lyd_node_term *)target;
}
@@ -1149,15 +1183,6 @@ lyd_compare_schema_equal(const struct lysc_node *schema1, const struct lysc_node
return 0;
}
- if (schema1->module->revision || schema2->module->revision) {
- if (!schema1->module->revision || !schema2->module->revision) {
- return 0;
- }
- if (strcmp(schema1->module->revision, schema2->module->revision)) {
- return 0;
- }
- }
-
return 1;
}
@@ -1269,30 +1294,21 @@ lyd_compare_single_value(const struct lyd_node *node1, const struct lyd_node *no
}
/**
- * @brief Internal implementation of @ref lyd_compare_single.
- * @copydoc lyd_compare_single
- * @param[in] parental_schemas_checked Flag used for optimization.
- * When this function is called for the first time, the flag must be set to 0.
- * The @ref lyd_compare_schema_parents_equal should be called only once during
- * recursive calls, and this is accomplished by setting to 1 in the lyd_compare_single_ body.
+ * @brief Compare 2 data nodes if they are equivalent regarding the schema tree.
+ *
+ * Works correctly even if @p node1 and @p node2 have different contexts.
+ *
+ * @param[in] node1 The first node to compare.
+ * @param[in] node2 The second node to compare.
+ * @param[in] options Various @ref datacompareoptions.
+ * @param[in] parental_schemas_checked Flag set if parent schemas were checked for match.
+ * @return LY_SUCCESS if the nodes are equivalent.
+ * @return LY_ENOT if the nodes are not equivalent.
*/
static LY_ERR
-lyd_compare_single_(const struct lyd_node *node1, const struct lyd_node *node2, uint32_t options,
+lyd_compare_single_schema(const struct lyd_node *node1, const struct lyd_node *node2, uint32_t options,
ly_bool parental_schemas_checked)
{
- const struct lyd_node *iter1, *iter2;
- struct lyd_node_any *any1, *any2;
- int len1, len2;
- LY_ERR r;
-
- if (!node1 || !node2) {
- if (node1 == node2) {
- return LY_SUCCESS;
- } else {
- return LY_ENOT;
- }
- }
-
if (LYD_CTX(node1) == LYD_CTX(node2)) {
/* same contexts */
if (options & LYD_COMPARE_OPAQ) {
@@ -1317,6 +1333,28 @@ lyd_compare_single_(const struct lyd_node *node1, const struct lyd_node *node2,
}
}
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Compare 2 data nodes if they are equivalent regarding the data they contain.
+ *
+ * Works correctly even if @p node1 and @p node2 have different contexts.
+ *
+ * @param[in] node1 The first node to compare.
+ * @param[in] node2 The second node to compare.
+ * @param[in] options Various @ref datacompareoptions.
+ * @return LY_SUCCESS if the nodes are equivalent.
+ * @return LY_ENOT if the nodes are not equivalent.
+ */
+static LY_ERR
+lyd_compare_single_data(const struct lyd_node *node1, const struct lyd_node *node2, uint32_t options)
+{
+ const struct lyd_node *iter1, *iter2;
+ struct lyd_node_any *any1, *any2;
+ int len1, len2;
+ LY_ERR r;
+
if (!(options & LYD_COMPARE_OPAQ) && (node1->hash != node2->hash)) {
return LY_ENOT;
}
@@ -1326,14 +1364,16 @@ lyd_compare_single_(const struct lyd_node *node1, const struct lyd_node *node2,
if (!(options & LYD_COMPARE_OPAQ) && ((node1->schema && !node2->schema) || (!node1->schema && node2->schema))) {
return LY_ENOT;
}
- if ((r = lyd_compare_single_value(node1, node2))) {
- return r;
+ if ((!node1->schema && !node2->schema) || (node1->schema && (node1->schema->nodetype & LYD_NODE_TERM)) ||
+ (node2->schema && (node2->schema->nodetype & LYD_NODE_TERM))) {
+ /* compare values only if there are any to compare */
+ if ((r = lyd_compare_single_value(node1, node2))) {
+ return r;
+ }
}
if (options & LYD_COMPARE_FULL_RECURSION) {
- iter1 = lyd_child(node1);
- iter2 = lyd_child(node2);
- goto all_children_compare;
+ return lyd_compare_siblings_(lyd_child(node1), lyd_child(node2), options, 1);
}
return LY_SUCCESS;
} else {
@@ -1354,50 +1394,38 @@ lyd_compare_single_(const struct lyd_node *node1, const struct lyd_node *node2,
case LYS_RPC:
case LYS_ACTION:
case LYS_NOTIF:
- if (options & LYD_COMPARE_DEFAULTS) {
- if ((node1->flags & LYD_DEFAULT) != (node2->flags & LYD_DEFAULT)) {
- return LY_ENOT;
- }
- }
+ /* implicit container is always equal to a container with non-default descendants */
if (options & LYD_COMPARE_FULL_RECURSION) {
- iter1 = lyd_child(node1);
- iter2 = lyd_child(node2);
- goto all_children_compare;
+ return lyd_compare_siblings_(lyd_child(node1), lyd_child(node2), options, 1);
}
return LY_SUCCESS;
case LYS_LIST:
iter1 = lyd_child(node1);
iter2 = lyd_child(node2);
- if (!(node1->schema->flags & LYS_KEYLESS) && !(options & LYD_COMPARE_FULL_RECURSION)) {
- /* lists with keys, their equivalence is based on their keys */
- for (const struct lysc_node *key = lysc_node_child(node1->schema);
- key && (key->flags & LYS_KEY);
- key = key->next) {
- if (lyd_compare_single_(iter1, iter2, options, parental_schemas_checked)) {
- return LY_ENOT;
- }
- iter1 = iter1->next;
- iter2 = iter2->next;
- }
- } else {
- /* lists without keys, their equivalence is based on equivalence of all the children (both direct and indirect) */
+ if (options & LYD_COMPARE_FULL_RECURSION) {
+ return lyd_compare_siblings_(iter1, iter2, options, 1);
+ } else if (node1->schema->flags & LYS_KEYLESS) {
+ /* always equal */
+ return LY_SUCCESS;
+ }
-all_children_compare:
- if (!iter1 && !iter2) {
- /* no children, nothing to compare */
- return LY_SUCCESS;
+ /* lists with keys, their equivalence is based on their keys */
+ for (const struct lysc_node *key = lysc_node_child(node1->schema);
+ key && (key->flags & LYS_KEY);
+ key = key->next) {
+ if (!iter1 || !iter2) {
+ return (iter1 == iter2) ? LY_SUCCESS : LY_ENOT;
}
+ r = lyd_compare_single_schema(iter1, iter2, options, 1);
+ LY_CHECK_RET(r);
+ r = lyd_compare_single_data(iter1, iter2, options);
+ LY_CHECK_RET(r);
- for ( ; iter1 && iter2; iter1 = iter1->next, iter2 = iter2->next) {
- if (lyd_compare_single_(iter1, iter2, options | LYD_COMPARE_FULL_RECURSION, parental_schemas_checked)) {
- return LY_ENOT;
- }
- }
- if (iter1 || iter2) {
- return LY_ENOT;
- }
+ iter1 = iter1->next;
+ iter2 = iter2->next;
}
+
return LY_SUCCESS;
case LYS_ANYXML:
case LYS_ANYDATA:
@@ -1409,9 +1437,7 @@ all_children_compare:
}
switch (any1->value_type) {
case LYD_ANYDATA_DATATREE:
- iter1 = any1->value.tree;
- iter2 = any2->value.tree;
- goto all_children_compare;
+ return lyd_compare_siblings_(any1->value.tree, any2->value.tree, options, 1);
case LYD_ANYDATA_STRING:
case LYD_ANYDATA_XML:
case LYD_ANYDATA_JSON:
@@ -1441,23 +1467,77 @@ all_children_compare:
return LY_EINT;
}
-LIBYANG_API_DEF LY_ERR
-lyd_compare_single(const struct lyd_node *node1, const struct lyd_node *node2, uint32_t options)
+/**
+ * @brief Compare all siblings at a node level.
+ *
+ * @param[in] node1 First sibling list.
+ * @param[in] node2 Second sibling list.
+ * @param[in] options Various @ref datacompareoptions.
+ * @param[in] parental_schemas_checked Flag set if parent schemas were checked for match.
+ * @return LY_SUCCESS if equal.
+ * @return LY_ENOT if not equal.
+ * @return LY_ERR on error.
+ */
+static LY_ERR
+lyd_compare_siblings_(const struct lyd_node *node1, const struct lyd_node *node2, uint32_t options,
+ ly_bool parental_schemas_checked)
{
- return lyd_compare_single_(node1, node2, options, 0);
+ LY_ERR r;
+ const struct lyd_node *iter2;
+
+ while (node1 && node2) {
+ /* schema match */
+ r = lyd_compare_single_schema(node1, node2, options, parental_schemas_checked);
+ LY_CHECK_RET(r);
+
+ if (node1->schema && (((node1->schema->nodetype == LYS_LIST) && !(node1->schema->flags & LYS_KEYLESS)) ||
+ ((node1->schema->nodetype == LYS_LEAFLIST) && (node1->schema->flags & LYS_CONFIG_W))) &&
+ (node1->schema->flags & LYS_ORDBY_SYSTEM)) {
+ /* find a matching instance in case they are ordered differently */
+ r = lyd_find_sibling_first(node2, node1, (struct lyd_node **)&iter2);
+ if (r == LY_ENOTFOUND) {
+ /* no matching instance, data not equal */
+ r = LY_ENOT;
+ }
+ LY_CHECK_RET(r);
+ } else {
+ /* compare with the current node */
+ iter2 = node2;
+ }
+
+ /* data match */
+ r = lyd_compare_single_data(node1, iter2, options | LYD_COMPARE_FULL_RECURSION);
+ LY_CHECK_RET(r);
+
+ node1 = node1->next;
+ node2 = node2->next;
+ }
+
+ return (node1 || node2) ? LY_ENOT : LY_SUCCESS;
}
LIBYANG_API_DEF LY_ERR
-lyd_compare_siblings(const struct lyd_node *node1, const struct lyd_node *node2, uint32_t options)
+lyd_compare_single(const struct lyd_node *node1, const struct lyd_node *node2, uint32_t options)
{
- for ( ; node1 && node2; node1 = node1->next, node2 = node2->next) {
- LY_CHECK_RET(lyd_compare_single(node1, node2, options));
+ LY_ERR r;
+
+ if (!node1 || !node2) {
+ return (node1 == node2) ? LY_SUCCESS : LY_ENOT;
}
- if (node1 == node2) {
- return LY_SUCCESS;
+ /* schema match */
+ if ((r = lyd_compare_single_schema(node1, node2, options, 0))) {
+ return r;
}
- return LY_ENOT;
+
+ /* data match */
+ return lyd_compare_single_data(node1, node2, options);
+}
+
+LIBYANG_API_DEF LY_ERR
+lyd_compare_siblings(const struct lyd_node *node1, const struct lyd_node *node2, uint32_t options)
+{
+ return lyd_compare_siblings_(node1, node2, options, 0);
}
LIBYANG_API_DEF LY_ERR
@@ -1676,6 +1756,9 @@ lyd_dup_r(const struct lyd_node *node, const struct ly_ctx *trg_ctx, struct lyd_
} else {
dup->flags = (node->flags & (LYD_DEFAULT | LYD_EXT)) | LYD_NEW;
}
+ if (options & LYD_DUP_WITH_PRIV) {
+ dup->priv = node->priv;
+ }
if (trg_ctx == LYD_CTX(node)) {
dup->schema = node->schema;
} else {
@@ -1736,7 +1819,7 @@ lyd_dup_r(const struct lyd_node *node, const struct ly_ctx *trg_ctx, struct lyd_
/* store canonical value in the target context */
val_can = lyd_get_value(node);
type = ((struct lysc_node_leaf *)term->schema)->type;
- ret = lyd_value_store(trg_ctx, &term->value, type, val_can, strlen(val_can), NULL, LY_VALUE_CANON, NULL,
+ ret = lyd_value_store(trg_ctx, &term->value, type, val_can, strlen(val_can), 1, NULL, LY_VALUE_CANON, NULL,
LYD_HINT_DATA, term->schema, NULL);
LY_CHECK_GOTO(ret, error);
}
@@ -1787,10 +1870,11 @@ error:
* @return LY_ERR value.
*/
static LY_ERR
-lyd_dup_get_local_parent(const struct lyd_node *node, const struct ly_ctx *trg_ctx, const struct lyd_node_inner *parent,
- uint32_t options, struct lyd_node **dup_parent, struct lyd_node_inner **local_parent)
+lyd_dup_get_local_parent(const struct lyd_node *node, const struct ly_ctx *trg_ctx, struct lyd_node *parent,
+ uint32_t options, struct lyd_node **dup_parent, struct lyd_node **local_parent)
{
- const struct lyd_node_inner *orig_parent, *iter;
+ const struct lyd_node *orig_parent;
+ struct lyd_node *iter = NULL;
ly_bool repeat = 1, ext_parent = 0;
*dup_parent = NULL;
@@ -1799,38 +1883,38 @@ lyd_dup_get_local_parent(const struct lyd_node *node, const struct ly_ctx *trg_c
if (node->flags & LYD_EXT) {
ext_parent = 1;
}
- for (orig_parent = node->parent; repeat && orig_parent; orig_parent = orig_parent->parent) {
+ for (orig_parent = lyd_parent(node); repeat && orig_parent; orig_parent = lyd_parent(orig_parent)) {
if (ext_parent) {
/* use the standard context */
trg_ctx = LYD_CTX(orig_parent);
}
- if (parent && (parent->schema == orig_parent->schema)) {
+ if (parent && (LYD_CTX(parent) == LYD_CTX(orig_parent)) && (parent->schema == orig_parent->schema)) {
/* stop creating parents, connect what we have into the provided parent */
iter = parent;
repeat = 0;
+ } else if (parent && (LYD_CTX(parent) != LYD_CTX(orig_parent)) &&
+ lyd_compare_schema_equal(parent->schema, orig_parent->schema) &&
+ lyd_compare_schema_parents_equal(parent, orig_parent)) {
+ iter = parent;
+ repeat = 0;
} else {
iter = NULL;
- LY_CHECK_RET(lyd_dup_r((struct lyd_node *)orig_parent, trg_ctx, NULL, 0, (struct lyd_node **)&iter, options,
- (struct lyd_node **)&iter));
- }
- if (!*local_parent) {
- *local_parent = (struct lyd_node_inner *)iter;
- }
- if (iter->child) {
- /* 1) list - add after keys
- * 2) provided parent with some children */
- iter->child->prev->next = *dup_parent;
+ LY_CHECK_RET(lyd_dup_r(orig_parent, trg_ctx, NULL, 0, &iter, options, &iter));
+
+ /* insert into the previous duplicated parent */
if (*dup_parent) {
- (*dup_parent)->prev = iter->child->prev;
- iter->child->prev = *dup_parent;
+ lyd_insert_node(iter, NULL, *dup_parent, 0);
}
- } else {
- ((struct lyd_node_inner *)iter)->child = *dup_parent;
+
+ /* update the last duplicated parent */
+ *dup_parent = iter;
}
- if (*dup_parent) {
- (*dup_parent)->parent = (struct lyd_node_inner *)iter;
+
+ /* set the first parent */
+ if (!*local_parent) {
+ *local_parent = iter;
}
- *dup_parent = (struct lyd_node *)iter;
+
if (orig_parent->flags & LYD_EXT) {
ext_parent = 1;
}
@@ -1838,23 +1922,27 @@ lyd_dup_get_local_parent(const struct lyd_node *node, const struct ly_ctx *trg_c
if (repeat && parent) {
/* given parent and created parents chain actually do not interconnect */
- LOGERR(trg_ctx, LY_EINVAL,
- "Invalid argument parent (%s()) - does not interconnect with the created node's parents chain.", __func__);
+ LOGERR(trg_ctx, LY_EINVAL, "None of the duplicated node \"%s\" schema parents match the provided parent \"%s\".",
+ LYD_NAME(node), LYD_NAME(parent));
return LY_EINVAL;
}
+ if (*dup_parent && parent) {
+ /* last insert into a prevously-existing parent */
+ lyd_insert_node(parent, NULL, *dup_parent, 0);
+ }
return LY_SUCCESS;
}
static LY_ERR
-lyd_dup(const struct lyd_node *node, const struct ly_ctx *trg_ctx, struct lyd_node_inner *parent, uint32_t options,
+lyd_dup(const struct lyd_node *node, const struct ly_ctx *trg_ctx, struct lyd_node *parent, uint32_t options,
ly_bool nosiblings, struct lyd_node **dup)
{
LY_ERR rc;
const struct lyd_node *orig; /* original node to be duplicated */
struct lyd_node *first = NULL; /* the first duplicated node, this is returned */
struct lyd_node *top = NULL; /* the most higher created node */
- struct lyd_node_inner *local_parent = NULL; /* the direct parent node for the duplicated node(s) */
+ struct lyd_node *local_parent = NULL; /* the direct parent node for the duplicated node(s) */
assert(node && trg_ctx);
@@ -1869,7 +1957,7 @@ lyd_dup(const struct lyd_node *node, const struct ly_ctx *trg_ctx, struct lyd_no
if (lysc_is_key(orig->schema)) {
if (local_parent) {
/* the key must already exist in the parent */
- rc = lyd_find_sibling_schema(local_parent->child, orig->schema, first ? NULL : &first);
+ rc = lyd_find_sibling_schema(lyd_child(local_parent), orig->schema, first ? NULL : &first);
LY_CHECK_ERR_GOTO(rc, LOGINT(trg_ctx), error);
} else {
assert(!(options & LYD_DUP_WITH_PARENTS));
@@ -1879,8 +1967,7 @@ lyd_dup(const struct lyd_node *node, const struct ly_ctx *trg_ctx, struct lyd_no
}
} else {
/* if there is no local parent, it will be inserted into first */
- rc = lyd_dup_r(orig, trg_ctx, local_parent ? &local_parent->node : NULL, 0, &first, options,
- first ? NULL : &first);
+ rc = lyd_dup_r(orig, trg_ctx, local_parent, 0, &first, options, first ? NULL : &first);
LY_CHECK_GOTO(rc, error);
}
if (nosiblings) {
@@ -1923,7 +2010,7 @@ lyd_dup_ctx_check(const struct lyd_node *node, const struct lyd_node_inner *pare
for (iter = node; iter && !(iter->flags & LYD_EXT); iter = lyd_parent(iter)) {}
if (!iter || !lyd_parent(iter) || (LYD_CTX(lyd_parent(iter)) != LYD_CTX(parent))) {
- LOGERR(NULL, LY_EINVAL, "Different contexts used in node duplication.");
+ LOGERR(LYD_CTX(node), LY_EINVAL, "Different contexts used in node duplication.");
return LY_EINVAL;
}
}
@@ -1937,7 +2024,7 @@ lyd_dup_single(const struct lyd_node *node, struct lyd_node_inner *parent, uint3
LY_CHECK_ARG_RET(NULL, node, LY_EINVAL);
LY_CHECK_RET(lyd_dup_ctx_check(node, parent));
- return lyd_dup(node, LYD_CTX(node), parent, options, 1, dup);
+ return lyd_dup(node, LYD_CTX(node), (struct lyd_node *)parent, options, 1, dup);
}
LIBYANG_API_DEF LY_ERR
@@ -1946,7 +2033,7 @@ lyd_dup_single_to_ctx(const struct lyd_node *node, const struct ly_ctx *trg_ctx,
{
LY_CHECK_ARG_RET(trg_ctx, node, trg_ctx, LY_EINVAL);
- return lyd_dup(node, trg_ctx, parent, options, 1, dup);
+ return lyd_dup(node, trg_ctx, (struct lyd_node *)parent, options, 1, dup);
}
LIBYANG_API_DEF LY_ERR
@@ -1955,7 +2042,7 @@ lyd_dup_siblings(const struct lyd_node *node, struct lyd_node_inner *parent, uin
LY_CHECK_ARG_RET(NULL, node, LY_EINVAL);
LY_CHECK_RET(lyd_dup_ctx_check(node, parent));
- return lyd_dup(node, LYD_CTX(node), parent, options, 0, dup);
+ return lyd_dup(node, LYD_CTX(node), (struct lyd_node *)parent, options, 0, dup);
}
LIBYANG_API_DEF LY_ERR
@@ -1964,7 +2051,7 @@ lyd_dup_siblings_to_ctx(const struct lyd_node *node, const struct ly_ctx *trg_ct
{
LY_CHECK_ARG_RET(trg_ctx, node, trg_ctx, LY_EINVAL);
- return lyd_dup(node, trg_ctx, parent, options, 0, dup);
+ return lyd_dup(node, trg_ctx, (struct lyd_node *)parent, options, 0, dup);
}
LIBYANG_API_DEF LY_ERR
@@ -2019,13 +2106,13 @@ finish:
*/
static LY_ERR
lyd_merge_sibling_r(struct lyd_node **first_trg, struct lyd_node *parent_trg, const struct lyd_node **sibling_src_p,
- lyd_merge_cb merge_cb, void *cb_data, uint16_t options, struct lyd_dup_inst **dup_inst)
+ lyd_merge_cb merge_cb, void *cb_data, uint16_t options, struct ly_ht **dup_inst)
{
const struct lyd_node *child_src, *tmp, *sibling_src;
struct lyd_node *match_trg, *dup_src, *elem;
struct lyd_node_opaq *opaq_trg, *opaq_src;
struct lysc_type *type;
- struct lyd_dup_inst *child_dup_inst = NULL;
+ struct ly_ht *child_dup_inst = NULL;
LY_ERR ret;
ly_bool first_inst = 0;
@@ -2110,7 +2197,7 @@ lyd_merge_sibling_r(struct lyd_node **first_trg, struct lyd_node *parent_trg, co
/* node not found, merge it */
if (options & LYD_MERGE_DESTRUCT) {
dup_src = (struct lyd_node *)sibling_src;
- lyd_unlink_tree(dup_src);
+ lyd_unlink(dup_src);
/* spend it */
*sibling_src_p = NULL;
} else {
@@ -2147,7 +2234,7 @@ lyd_merge(struct lyd_node **target, const struct lyd_node *source, const struct
lyd_merge_cb merge_cb, void *cb_data, uint16_t options, ly_bool nosiblings)
{
const struct lyd_node *sibling_src, *tmp;
- struct lyd_dup_inst *dup_inst = NULL;
+ struct ly_ht *dup_inst = NULL;
ly_bool first;
LY_ERR ret = LY_SUCCESS;
@@ -2357,9 +2444,9 @@ lyd_path(const struct lyd_node *node, LYD_PATH_TYPE pathtype, char *buffer, size
for (iter = node, i = 1; i < depth; iter = lyd_parent(iter), ++i) {}
iter_print:
/* get the module */
- mod = iter->schema ? iter->schema->module : lyd_owner_module(iter);
+ mod = lyd_node_module(iter);
parent = lyd_parent(iter);
- prev_mod = (parent && parent->schema) ? parent->schema->module : lyd_owner_module(parent);
+ prev_mod = lyd_node_module(parent);
if (prev_mod == mod) {
mod = NULL;
}
@@ -2429,15 +2516,17 @@ lyd_path_set(const struct ly_set *dnodes, LYD_PATH_TYPE pathtype)
for (depth = 1; depth <= dnodes->count; ++depth) {
/* current node */
iter = dnodes->dnodes[depth - 1];
- mod = iter->schema ? iter->schema->module : lyd_owner_module(iter);
+ mod = lyd_node_module(iter);
/* parent */
parent = (depth > 1) ? dnodes->dnodes[depth - 2] : NULL;
- assert(!parent || !iter->schema || !parent->schema || (lysc_data_parent(iter->schema) == parent->schema) ||
- (!lysc_data_parent(iter->schema) && (LYD_CTX(iter) != LYD_CTX(parent))));
+ assert(!parent || !iter->schema || !parent->schema || (parent->schema->nodetype & LYD_NODE_ANY) ||
+ (lysc_data_parent(iter->schema) == parent->schema) ||
+ (!lysc_data_parent(iter->schema) && (LYD_CTX(iter) != LYD_CTX(parent))) ||
+ (parent->schema->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)));
/* get module to print, if any */
- prev_mod = (parent && parent->schema) ? parent->schema->module : lyd_owner_module(parent);
+ prev_mod = lyd_node_module(parent);
if (prev_mod == mod) {
mod = NULL;
}
@@ -2567,14 +2656,14 @@ lyd_find_sibling_first(const struct lyd_node *siblings, const struct lyd_node *t
siblings = lyd_first_sibling(siblings);
parent = siblings->parent;
- if (parent && parent->schema && parent->children_ht) {
+ if (target->schema && parent && parent->schema && parent->children_ht) {
assert(target->hash);
if (lysc_is_dup_inst_list(target->schema)) {
/* we must search the instances from beginning to find the first matching one */
found = 0;
LYD_LIST_FOR_INST(siblings, target->schema, iter) {
- if (!lyd_compare_single(target, iter, 0)) {
+ if (!lyd_compare_single(target, iter, LYD_COMPARE_FULL_RECURSION)) {
found = 1;
break;
}
@@ -2594,10 +2683,16 @@ lyd_find_sibling_first(const struct lyd_node *siblings, const struct lyd_node *t
}
}
} else {
- /* no children hash table */
+ /* no children hash table or cannot be used */
for ( ; siblings; siblings = siblings->next) {
- if (!lyd_compare_single(siblings, target, LYD_COMPARE_OPAQ)) {
- break;
+ if (lysc_is_dup_inst_list(target->schema)) {
+ if (!lyd_compare_single(siblings, target, LYD_COMPARE_FULL_RECURSION)) {
+ break;
+ }
+ } else {
+ if (!lyd_compare_single(siblings, target, 0)) {
+ break;
+ }
}
}
}
@@ -2661,7 +2756,7 @@ lyd_find_sibling_val(const struct lyd_node *siblings, const struct lysc_node *sc
/* create a data node and find the instance */
if (schema->nodetype == LYS_LEAFLIST) {
/* target used attributes: schema, hash, value */
- rc = lyd_create_term(schema, key_or_value, val_len, NULL, LY_VALUE_JSON, NULL, LYD_HINT_DATA, NULL, &target);
+ rc = lyd_create_term(schema, key_or_value, val_len, 0, NULL, LY_VALUE_JSON, NULL, LYD_HINT_DATA, NULL, &target);
LY_CHECK_RET(rc);
} else {
/* target used attributes: schema, hash, child (all keys) */
@@ -2684,6 +2779,7 @@ lyd_find_sibling_dup_inst_set(const struct lyd_node *siblings, const struct lyd_
{
struct lyd_node **match_p, *first, *iter;
struct lyd_node_inner *parent;
+ uint32_t comp_opts;
LY_CHECK_ARG_RET(NULL, target, set, LY_EINVAL);
LY_CHECK_CTX_EQUAL_RET(siblings ? LYD_CTX(siblings) : NULL, LYD_CTX(target), LY_EINVAL);
@@ -2695,6 +2791,9 @@ lyd_find_sibling_dup_inst_set(const struct lyd_node *siblings, const struct lyd_
return LY_ENOTFOUND;
}
+ /* set options */
+ comp_opts = (lysc_is_dup_inst_list(target->schema) ? LYD_COMPARE_FULL_RECURSION : 0);
+
/* get first sibling */
siblings = lyd_first_sibling(siblings);
@@ -2719,7 +2818,7 @@ lyd_find_sibling_dup_inst_set(const struct lyd_node *siblings, const struct lyd_
}
while (iter) {
/* add all found nodes into the set */
- if ((iter != first) && !lyd_compare_single(iter, target, 0) && ly_set_add(*set, iter, 1, NULL)) {
+ if ((iter != first) && !lyd_compare_single(iter, target, comp_opts) && ly_set_add(*set, iter, 1, NULL)) {
goto error;
}
@@ -2734,7 +2833,7 @@ lyd_find_sibling_dup_inst_set(const struct lyd_node *siblings, const struct lyd_
} else {
/* no children hash table */
LY_LIST_FOR(siblings, siblings) {
- if (!lyd_compare_single(target, siblings, LYD_COMPARE_OPAQ)) {
+ if (!lyd_compare_single(target, siblings, comp_opts)) {
ly_set_add(*set, (void *)siblings, 1, NULL);
}
}
@@ -2756,8 +2855,22 @@ lyd_find_sibling_opaq_next(const struct lyd_node *first, const char *name, struc
{
LY_CHECK_ARG_RET(NULL, name, LY_EINVAL);
+ if (first && first->schema) {
+ first = first->prev;
+ if (first->schema) {
+ /* no opaque nodes */
+ first = NULL;
+ } else {
+ /* opaque nodes are at the end, find quickly the first */
+ while (!first->prev->schema) {
+ first = first->prev;
+ }
+ }
+ }
+
for ( ; first; first = first->next) {
- if (!first->schema && !strcmp(LYD_NAME(first), name)) {
+ assert(!first->schema);
+ if (!strcmp(LYD_NAME(first), name)) {
break;
}
}
@@ -2769,58 +2882,19 @@ lyd_find_sibling_opaq_next(const struct lyd_node *first, const char *name, struc
}
LIBYANG_API_DEF LY_ERR
-lyd_find_xpath4(const struct lyd_node *ctx_node, const struct lyd_node *tree, const char *xpath, LY_VALUE_FORMAT format,
- void *prefix_data, const struct lyxp_var *vars, struct ly_set **set)
+lyd_find_xpath(const struct lyd_node *ctx_node, const char *xpath, struct ly_set **set)
{
- LY_ERR ret = LY_SUCCESS;
- struct lyxp_set xp_set = {0};
- struct lyxp_expr *exp = NULL;
- uint32_t i;
-
- LY_CHECK_ARG_RET(NULL, tree, xpath, format, set, LY_EINVAL);
-
- *set = NULL;
-
- /* parse expression */
- ret = lyxp_expr_parse((struct ly_ctx *)LYD_CTX(tree), xpath, 0, 1, &exp);
- LY_CHECK_GOTO(ret, cleanup);
-
- /* evaluate expression */
- ret = lyxp_eval(LYD_CTX(tree), exp, NULL, format, prefix_data, ctx_node, ctx_node, tree, vars, &xp_set,
- LYXP_IGNORE_WHEN);
- LY_CHECK_GOTO(ret, cleanup);
-
- if (xp_set.type != LYXP_SET_NODE_SET) {
- LOGERR(LYD_CTX(tree), LY_EINVAL, "XPath \"%s\" result is not a node set.", xpath);
- ret = LY_EINVAL;
- goto cleanup;
- }
-
- /* allocate return set */
- ret = ly_set_new(set);
- LY_CHECK_GOTO(ret, cleanup);
+ LY_CHECK_ARG_RET(NULL, ctx_node, xpath, set, LY_EINVAL);
- /* transform into ly_set, allocate memory for all the elements once (even though not all items must be
- * elements but most likely will be) */
- (*set)->objs = malloc(xp_set.used * sizeof *(*set)->objs);
- LY_CHECK_ERR_GOTO(!(*set)->objs, LOGMEM(LYD_CTX(tree)); ret = LY_EMEM, cleanup);
- (*set)->size = xp_set.used;
+ return lyd_find_xpath4(ctx_node, ctx_node, xpath, LY_VALUE_JSON, NULL, NULL, set);
+}
- for (i = 0; i < xp_set.used; ++i) {
- if (xp_set.val.nodes[i].type == LYXP_NODE_ELEM) {
- ret = ly_set_add(*set, xp_set.val.nodes[i].node, 1, NULL);
- LY_CHECK_GOTO(ret, cleanup);
- }
- }
+LIBYANG_API_DEF LY_ERR
+lyd_find_xpath2(const struct lyd_node *ctx_node, const char *xpath, const struct lyxp_var *vars, struct ly_set **set)
+{
+ LY_CHECK_ARG_RET(NULL, ctx_node, xpath, set, LY_EINVAL);
-cleanup:
- lyxp_set_free_content(&xp_set);
- lyxp_expr_free((struct ly_ctx *)LYD_CTX(tree), exp);
- if (ret) {
- ly_set_free(*set, NULL);
- *set = NULL;
- }
- return ret;
+ return lyd_find_xpath4(ctx_node, ctx_node, xpath, LY_VALUE_JSON, NULL, vars, set);
}
LIBYANG_API_DEF LY_ERR
@@ -2833,63 +2907,263 @@ lyd_find_xpath3(const struct lyd_node *ctx_node, const struct lyd_node *tree, co
}
LIBYANG_API_DEF LY_ERR
-lyd_find_xpath2(const struct lyd_node *ctx_node, const char *xpath, const struct lyxp_var *vars, struct ly_set **set)
+lyd_find_xpath4(const struct lyd_node *ctx_node, const struct lyd_node *tree, const char *xpath, LY_VALUE_FORMAT format,
+ void *prefix_data, const struct lyxp_var *vars, struct ly_set **set)
{
- LY_CHECK_ARG_RET(NULL, ctx_node, xpath, set, LY_EINVAL);
+ LY_CHECK_ARG_RET(NULL, tree, xpath, set, LY_EINVAL);
- return lyd_find_xpath4(ctx_node, ctx_node, xpath, LY_VALUE_JSON, NULL, vars, set);
+ *set = NULL;
+
+ return lyd_eval_xpath4(ctx_node, tree, NULL, xpath, format, prefix_data, vars, NULL, set, NULL, NULL, NULL);
}
LIBYANG_API_DEF LY_ERR
-lyd_find_xpath(const struct lyd_node *ctx_node, const char *xpath, struct ly_set **set)
+lyd_eval_xpath(const struct lyd_node *ctx_node, const char *xpath, ly_bool *result)
{
- LY_CHECK_ARG_RET(NULL, ctx_node, xpath, set, LY_EINVAL);
+ return lyd_eval_xpath3(ctx_node, NULL, xpath, LY_VALUE_JSON, NULL, NULL, result);
+}
- return lyd_find_xpath4(ctx_node, ctx_node, xpath, LY_VALUE_JSON, NULL, NULL, set);
+LIBYANG_API_DEF LY_ERR
+lyd_eval_xpath2(const struct lyd_node *ctx_node, const char *xpath, const struct lyxp_var *vars, ly_bool *result)
+{
+ return lyd_eval_xpath3(ctx_node, NULL, xpath, LY_VALUE_JSON, NULL, vars, result);
}
LIBYANG_API_DEF LY_ERR
lyd_eval_xpath3(const struct lyd_node *ctx_node, const struct lys_module *cur_mod, const char *xpath,
LY_VALUE_FORMAT format, void *prefix_data, const struct lyxp_var *vars, ly_bool *result)
{
+ return lyd_eval_xpath4(ctx_node, ctx_node, cur_mod, xpath, format, prefix_data, vars, NULL, NULL, NULL, NULL, result);
+}
+
+LIBYANG_API_DEF LY_ERR
+lyd_eval_xpath4(const struct lyd_node *ctx_node, const struct lyd_node *tree, const struct lys_module *cur_mod,
+ const char *xpath, LY_VALUE_FORMAT format, void *prefix_data, const struct lyxp_var *vars, LY_XPATH_TYPE *ret_type,
+ struct ly_set **node_set, char **string, long double *number, ly_bool *boolean)
+{
LY_ERR ret = LY_SUCCESS;
struct lyxp_set xp_set = {0};
struct lyxp_expr *exp = NULL;
+ uint32_t i;
- LY_CHECK_ARG_RET(NULL, ctx_node, xpath, result, LY_EINVAL);
+ LY_CHECK_ARG_RET(NULL, tree, xpath, ((ret_type && node_set && string && number && boolean) ||
+ (node_set && !string && !number && !boolean) || (!node_set && string && !number && !boolean) ||
+ (!node_set && !string && number && !boolean) || (!node_set && !string && !number && boolean)), LY_EINVAL);
- /* compile expression */
- ret = lyxp_expr_parse((struct ly_ctx *)LYD_CTX(ctx_node), xpath, 0, 1, &exp);
+ /* parse expression */
+ ret = lyxp_expr_parse((struct ly_ctx *)LYD_CTX(tree), xpath, 0, 1, &exp);
LY_CHECK_GOTO(ret, cleanup);
/* evaluate expression */
- ret = lyxp_eval(LYD_CTX(ctx_node), exp, cur_mod, format, prefix_data, ctx_node, ctx_node, ctx_node, vars, &xp_set,
+ ret = lyxp_eval(LYD_CTX(tree), exp, cur_mod, format, prefix_data, ctx_node, ctx_node, tree, vars, &xp_set,
LYXP_IGNORE_WHEN);
LY_CHECK_GOTO(ret, cleanup);
- /* transform into boolean */
- ret = lyxp_set_cast(&xp_set, LYXP_SET_BOOLEAN);
- LY_CHECK_GOTO(ret, cleanup);
+ /* return expected result type without or with casting */
+ if (node_set) {
+ /* node set */
+ if (xp_set.type == LYXP_SET_NODE_SET) {
+ /* transform into a set */
+ LY_CHECK_GOTO(ret = ly_set_new(node_set), cleanup);
+ (*node_set)->objs = malloc(xp_set.used * sizeof *(*node_set)->objs);
+ LY_CHECK_ERR_GOTO(!(*node_set)->objs, LOGMEM(LYD_CTX(tree)); ret = LY_EMEM, cleanup);
+ (*node_set)->size = xp_set.used;
+ for (i = 0; i < xp_set.used; ++i) {
+ if (xp_set.val.nodes[i].type == LYXP_NODE_ELEM) {
+ ret = ly_set_add(*node_set, xp_set.val.nodes[i].node, 1, NULL);
+ LY_CHECK_GOTO(ret, cleanup);
+ }
+ }
+ if (ret_type) {
+ *ret_type = LY_XPATH_NODE_SET;
+ }
+ } else if (!string && !number && !boolean) {
+ LOGERR(LYD_CTX(tree), LY_EINVAL, "XPath \"%s\" result is not a node set.", xpath);
+ ret = LY_EINVAL;
+ goto cleanup;
+ }
+ }
- /* set result */
- *result = xp_set.val.bln;
+ if (string) {
+ if ((xp_set.type != LYXP_SET_STRING) && !node_set) {
+ /* cast into string */
+ LY_CHECK_GOTO(ret = lyxp_set_cast(&xp_set, LYXP_SET_STRING), cleanup);
+ }
+ if (xp_set.type == LYXP_SET_STRING) {
+ /* string */
+ *string = xp_set.val.str;
+ xp_set.val.str = NULL;
+ if (ret_type) {
+ *ret_type = LY_XPATH_STRING;
+ }
+ }
+ }
+
+ if (number) {
+ if ((xp_set.type != LYXP_SET_NUMBER) && !node_set) {
+ /* cast into number */
+ LY_CHECK_GOTO(ret = lyxp_set_cast(&xp_set, LYXP_SET_NUMBER), cleanup);
+ }
+ if (xp_set.type == LYXP_SET_NUMBER) {
+ /* number */
+ *number = xp_set.val.num;
+ if (ret_type) {
+ *ret_type = LY_XPATH_NUMBER;
+ }
+ }
+ }
+
+ if (boolean) {
+ if ((xp_set.type != LYXP_SET_BOOLEAN) && !node_set) {
+ /* cast into boolean */
+ LY_CHECK_GOTO(ret = lyxp_set_cast(&xp_set, LYXP_SET_BOOLEAN), cleanup);
+ }
+ if (xp_set.type == LYXP_SET_BOOLEAN) {
+ /* boolean */
+ *boolean = xp_set.val.bln;
+ if (ret_type) {
+ *ret_type = LY_XPATH_BOOLEAN;
+ }
+ }
+ }
cleanup:
lyxp_set_free_content(&xp_set);
- lyxp_expr_free((struct ly_ctx *)LYD_CTX(ctx_node), exp);
+ lyxp_expr_free((struct ly_ctx *)LYD_CTX(tree), exp);
return ret;
}
-LIBYANG_API_DEF LY_ERR
-lyd_eval_xpath2(const struct lyd_node *ctx_node, const char *xpath, const struct lyxp_var *vars, ly_bool *result)
+/**
+ * @brief Hash table node equal callback.
+ */
+static ly_bool
+lyd_trim_equal_cb(void *val1_p, void *val2_p, ly_bool UNUSED(mod), void *UNUSED(cb_data))
{
- return lyd_eval_xpath3(ctx_node, NULL, xpath, LY_VALUE_JSON, NULL, vars, result);
+ struct lyd_node *node1, *node2;
+
+ node1 = *(struct lyd_node **)val1_p;
+ node2 = *(struct lyd_node **)val2_p;
+
+ return node1 == node2;
}
LIBYANG_API_DEF LY_ERR
-lyd_eval_xpath(const struct lyd_node *ctx_node, const char *xpath, ly_bool *result)
+lyd_trim_xpath(struct lyd_node **tree, const char *xpath, const struct lyxp_var *vars)
{
- return lyd_eval_xpath3(ctx_node, NULL, xpath, LY_VALUE_JSON, NULL, NULL, result);
+ LY_ERR ret = LY_SUCCESS;
+ struct ly_ctx *ctx;
+ struct lyxp_set xp_set = {0};
+ struct lyxp_expr *exp = NULL;
+ struct lyd_node *node, *parent;
+ struct lyxp_set_hash_node hnode;
+ struct ly_ht *parent_ht = NULL;
+ struct ly_set free_set = {0};
+ uint32_t i, hash;
+ ly_bool is_result;
+
+ LY_CHECK_ARG_RET(NULL, tree, xpath, LY_EINVAL);
+
+ if (!*tree) {
+ /* nothing to do */
+ goto cleanup;
+ }
+
+ *tree = lyd_first_sibling(*tree);
+ ctx = (struct ly_ctx *)LYD_CTX(*tree);
+
+ /* parse expression */
+ ret = lyxp_expr_parse(ctx, xpath, 0, 1, &exp);
+ LY_CHECK_GOTO(ret, cleanup);
+
+ /* evaluate expression */
+ ret = lyxp_eval(ctx, exp, NULL, LY_VALUE_JSON, NULL, *tree, *tree, *tree, vars, &xp_set, LYXP_IGNORE_WHEN);
+ LY_CHECK_GOTO(ret, cleanup);
+
+ /* create hash table for all the parents of results */
+ parent_ht = lyht_new(32, sizeof node, lyd_trim_equal_cb, NULL, 1);
+ LY_CHECK_GOTO(!parent_ht, cleanup);
+
+ for (i = 0; i < xp_set.used; ++i) {
+ if (xp_set.val.nodes[i].type != LYXP_NODE_ELEM) {
+ /* ignore */
+ continue;
+ }
+
+ for (parent = lyd_parent(xp_set.val.nodes[i].node); parent; parent = lyd_parent(parent)) {
+ /* add the parent into parent_ht */
+ ret = lyht_insert(parent_ht, &parent, parent->hash, NULL);
+ if (ret == LY_EEXIST) {
+ /* shared parent, we are done */
+ break;
+ }
+ LY_CHECK_GOTO(ret, cleanup);
+ }
+ }
+
+ hnode.type = LYXP_NODE_ELEM;
+ LY_LIST_FOR(*tree, parent) {
+ LYD_TREE_DFS_BEGIN(parent, node) {
+ if (lysc_is_key(node->schema)) {
+ /* ignore */
+ goto next_iter;
+ }
+
+ /* check the results */
+ is_result = 0;
+ if (xp_set.ht) {
+ hnode.node = node;
+ hash = lyht_hash_multi(0, (const char *)&hnode.node, sizeof hnode.node);
+ hash = lyht_hash_multi(hash, (const char *)&hnode.type, sizeof hnode.type);
+ hash = lyht_hash_multi(hash, NULL, 0);
+
+ if (!lyht_find(xp_set.ht, &hnode, hash, NULL)) {
+ is_result = 1;
+ }
+ } else {
+ /* not enough elements for a hash table */
+ for (i = 0; i < xp_set.used; ++i) {
+ if (xp_set.val.nodes[i].type != LYXP_NODE_ELEM) {
+ /* ignore */
+ continue;
+ }
+
+ if (xp_set.val.nodes[i].node == node) {
+ is_result = 1;
+ break;
+ }
+ }
+ }
+
+ if (is_result) {
+ /* keep the whole subtree if the node is in the results */
+ LYD_TREE_DFS_continue = 1;
+ } else if (lyht_find(parent_ht, &node, node->hash, NULL)) {
+ /* free the whole subtree if the node is not even among the selected parents */
+ ret = ly_set_add(&free_set, node, 1, NULL);
+ LY_CHECK_GOTO(ret, cleanup);
+ LYD_TREE_DFS_continue = 1;
+ } /* else keep the parent node because a subtree is in the results */
+
+next_iter:
+ LYD_TREE_DFS_END(parent, node);
+ }
+ }
+
+ /* free */
+ for (i = 0; i < free_set.count; ++i) {
+ node = free_set.dnodes[i];
+ if (*tree == node) {
+ *tree = (*tree)->next;
+ }
+ lyd_free_tree(node);
+ }
+
+cleanup:
+ lyxp_set_free_content(&xp_set);
+ lyxp_expr_free(ctx, exp);
+ lyht_free(parent_ht, NULL);
+ ly_set_erase(&free_set, NULL);
+ return ret;
}
LIBYANG_API_DEF LY_ERR
@@ -2903,7 +3177,7 @@ lyd_find_path(const struct lyd_node *ctx_node, const char *path, ly_bool output,
/* parse the path */
ret = ly_path_parse(LYD_CTX(ctx_node), ctx_node->schema, path, strlen(path), 0, LY_PATH_BEGIN_EITHER,
- LY_PATH_PREFIX_OPTIONAL, LY_PATH_PRED_SIMPLE, &expr);
+ LY_PATH_PREFIX_FIRST, LY_PATH_PRED_SIMPLE, &expr);
LY_CHECK_GOTO(ret, cleanup);
/* compile the path */
@@ -2912,7 +3186,7 @@ lyd_find_path(const struct lyd_node *ctx_node, const char *path, ly_bool output,
LY_CHECK_GOTO(ret, cleanup);
/* evaluate the path */
- ret = ly_path_eval_partial(lypath, ctx_node, NULL, match);
+ ret = ly_path_eval_partial(lypath, ctx_node, NULL, 0, NULL, match);
cleanup:
lyxp_expr_free(LYD_CTX(ctx_node), expr);
@@ -2928,7 +3202,7 @@ lyd_find_target(const struct ly_path *path, const struct lyd_node *tree, struct
LY_CHECK_ARG_RET(NULL, path, LY_EINVAL);
- ret = ly_path_eval(path, tree, &m);
+ ret = ly_path_eval(path, tree, NULL, &m);
if (ret) {
if (match) {
*match = NULL;
@@ -2941,3 +3215,55 @@ lyd_find_target(const struct ly_path *path, const struct lyd_node *tree, struct
}
return LY_SUCCESS;
}
+
+LIBYANG_API_DEF struct lyd_node *
+lyd_parent(const struct lyd_node *node)
+{
+ if (!node || !node->parent) {
+ return NULL;
+ }
+
+ return &node->parent->node;
+}
+
+LIBYANG_API_DEF struct lyd_node *
+lyd_child(const struct lyd_node *node)
+{
+ if (!node) {
+ return NULL;
+ }
+
+ if (!node->schema) {
+ /* opaq node */
+ return ((const struct lyd_node_opaq *)node)->child;
+ }
+
+ switch (node->schema->nodetype) {
+ case LYS_CONTAINER:
+ case LYS_LIST:
+ case LYS_RPC:
+ case LYS_ACTION:
+ case LYS_NOTIF:
+ return ((const struct lyd_node_inner *)node)->child;
+ default:
+ return NULL;
+ }
+}
+
+LIBYANG_API_DEF const char *
+lyd_get_value(const struct lyd_node *node)
+{
+ if (!node) {
+ return NULL;
+ }
+
+ if (!node->schema) {
+ return ((const struct lyd_node_opaq *)node)->value;
+ } else if (node->schema->nodetype & LYD_NODE_TERM) {
+ const struct lyd_value *value = &((const struct lyd_node_term *)node)->value;
+
+ return value->_canonical ? value->_canonical : lyd_value_get_canonical(LYD_CTX(node), value);
+ }
+
+ return NULL;
+}