schema tree FEATURE lys_atomize_xpath API function
Tests included.
diff --git a/src/tree_schema.c b/src/tree_schema.c
index f5a70b7..f0c386e 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -30,6 +30,7 @@
#include "dict.h"
#include "log.h"
#include "set.h"
+#include "xpath.h"
#include "tree.h"
#include "tree_schema.h"
#include "tree_schema_internal.h"
@@ -284,6 +285,50 @@
return NULL;
}
+API LY_ERR
+lys_atomize_xpath(const struct lysc_node *ctx_node, const char *xpath, int options, struct ly_set **set)
+{
+ LY_ERR ret = LY_SUCCESS;
+ struct lyxp_set xp_set;
+ struct lyxp_expr *exp;
+ uint32_t i;
+
+ LY_CHECK_ARG_RET(NULL, ctx_node, xpath, set, LY_EINVAL);
+ if (!(options & LYXP_SCNODE_ALL)) {
+ options = LYXP_SCNODE;
+ }
+
+ memset(&xp_set, 0, sizeof xp_set);
+
+ /* compile expression */
+ exp = lyxp_expr_parse(ctx_node->module->ctx, xpath);
+ LY_CHECK_ERR_GOTO(!exp, ret = LY_EINVAL, cleanup);
+
+ /* atomize expression */
+ ret = lyxp_atomize(exp, LYD_JSON, ctx_node->module, ctx_node, LYXP_NODE_ELEM, &xp_set, options);
+ LY_CHECK_GOTO(ret, cleanup);
+
+ /* allocate return set */
+ *set = ly_set_new();
+ LY_CHECK_ERR_GOTO(!*set, LOGMEM(ctx_node->module->ctx); ret = LY_EMEM, cleanup);
+
+ /* transform into ly_set */
+ (*set)->objs = malloc(xp_set.used * sizeof *(*set)->objs);
+ LY_CHECK_ERR_GOTO(!(*set)->objs, LOGMEM(ctx_node->module->ctx); ret = LY_EMEM, cleanup);
+ (*set)->size = xp_set.used;
+
+ for (i = 0; i < xp_set.used; ++i) {
+ if (xp_set.val.nodes[i].type == LYXP_NODE_ELEM) {
+ ly_set_add(*set, xp_set.val.scnodes[i].scnode, LY_SET_OPT_USEASLIST);
+ }
+ }
+
+cleanup:
+ lyxp_set_free_content(&xp_set);
+ lyxp_expr_free(ctx_node->module->ctx, exp);
+ return ret;
+}
+
char *
lysc_path_until(const struct lysc_node *node, const struct lysc_node *parent, LYSC_PATH_TYPE pathtype, char *buffer,
size_t buflen)
diff --git a/src/tree_schema.h b/src/tree_schema.h
index b3139dc..7764c64 100644
--- a/src/tree_schema.h
+++ b/src/tree_schema.h
@@ -1731,14 +1731,30 @@
* @brief Get the current status of the provided feature.
*
* @param[in] feature Compiled feature statement to examine.
- * @return
- * - 1 if feature is enabled,
- * - 0 if feature is disabled,
- * - -1 in case of error (invalid argument)
+ * @return 1 if feature is enabled,
+ * @return 0 if feature is disabled,
+ * @return -1 in case of error (invalid argument)
*/
int lysc_feature_value(const struct lysc_feature *feature);
/**
+ * @brief Get all the schema nodes (atoms) that are required for \p xpath to be evaluated.
+ *
+ * @param[in] ctx_node XPath schema context node.
+ * @param[in] xpath Data XPath expression filtering the matching nodes. ::LYD_JSON format is expected.
+ * @param[in] options Whether to apply some node access restrictions, one of the options should always be used.
+ * If none is set, ::LYXP_SCNODE is used.
+ * @param[out] set Set of found atoms (schema nodes).
+ * @return LY_SUCCESS on success, @p set is returned.
+ * @return LY_ERR value if an error occurred.
+ */
+LY_ERR lys_atomize_xpath(const struct lysc_node *ctx_node, const char *xpath, int options, struct ly_set **set);
+
+#define LYXP_SCNODE 0x02 /**< No special tree access modifiers. */
+#define LYXP_SCNODE_SCHEMA 0x04 /**< Apply node access restrictions defined for 'when' and 'must' evaluation. */
+#define LYXP_SCNODE_OUTPUT 0x08 /**< Search RPC/action output nodes instead of input ones. */
+
+/**
* @brief Types of the different schema paths.
*/
typedef enum {
diff --git a/src/xpath.c b/src/xpath.c
index 4bbf305..5eb0998 100644
--- a/src/xpath.c
+++ b/src/xpath.c
@@ -5455,7 +5455,7 @@
{
int i, orig_used, idx, temp_ctx = 0, getnext_opts;
uint32_t mod_idx;
- const struct lysc_node *sub, *start_parent;
+ const struct lysc_node *iter, *start_parent;
if (!set) {
return LY_SUCCESS;
@@ -5492,11 +5492,11 @@
* so use it directly (root node itself is useless in this case) */
mod_idx = 0;
while (mod || (mod = (struct lys_module *)ly_ctx_get_module_iter(set->ctx, &mod_idx))) {
- sub = NULL;
+ iter = NULL;
/* module may not be implemented */
- while (mod->implemented && (sub = lys_getnext(sub, NULL, mod->compiled, getnext_opts))) {
- if (!moveto_scnode_check(sub, set->root_type, ncname, mod)) {
- idx = lyxp_set_scnode_insert_node(set, sub, LYXP_NODE_ELEM);
+ while (mod->implemented && (iter = lys_getnext(iter, NULL, mod->compiled, getnext_opts))) {
+ if (!moveto_scnode_check(iter, set->root_type, ncname, mod)) {
+ idx = lyxp_set_scnode_insert_node(set, iter, LYXP_NODE_ELEM);
/* we need to prevent these nodes from being considered in this moveto */
if ((idx < orig_used) && (idx > i)) {
set->val.scnodes[idx].in_ctx = 2;
@@ -5513,12 +5513,11 @@
mod = NULL;
}
- /* skip nodes without children - leaves, leaflists, and anyxmls (ouput root will eval to true) */
- } else if (!(start_parent->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
- sub = NULL;
- while ((sub = lys_getnext(sub, start_parent, NULL, getnext_opts))) {
- if (!moveto_scnode_check(sub, set->root_type, ncname, (mod ? mod : set->local_mod))) {
- idx = lyxp_set_scnode_insert_node(set, sub, LYXP_NODE_ELEM);
+ } else if (set->val.scnodes[i].type == LYXP_NODE_ELEM) {
+ iter = NULL;
+ while ((iter = lys_getnext(iter, start_parent, NULL, getnext_opts))) {
+ if (!moveto_scnode_check(iter, set->root_type, ncname, (mod ? mod : set->local_mod))) {
+ idx = lyxp_set_scnode_insert_node(set, iter, LYXP_NODE_ELEM);
if ((idx < orig_used) && (idx > i)) {
set->val.scnodes[idx].in_ctx = 2;
temp_ctx = 1;
@@ -6041,8 +6040,10 @@
static LY_ERR
moveto_scnode_self(struct lyxp_set *set, int all_desc, int options)
{
- const struct lysc_node *sub;
- uint32_t i;
+ int getnext_opts;
+ uint32_t i, mod_idx;
+ const struct lysc_node *iter, *start_parent;
+ const struct lys_module *mod;
if (!set) {
return LY_SUCCESS;
@@ -6058,39 +6059,53 @@
return LY_SUCCESS;
}
- /* add all the children, they get added recursively */
+ /* getnext opts */
+ getnext_opts = LYS_GETNEXT_NOSTATECHECK;
+ if (options & LYXP_SCNODE_OUTPUT) {
+ getnext_opts |= LYS_GETNEXT_OUTPUT;
+ }
+
+ /* add all the children, recursively as they are being added into the same set */
for (i = 0; i < set->used; ++i) {
if (set->val.scnodes[i].in_ctx != 1) {
if (set->val.scnodes[i].in_ctx != -2) {
continue;
}
- /* remember context node (it was traversed again so it changes to a normal node) */
- set->val.scnodes[i].in_ctx = 1;
+ /* remember context node */
+ set->val.scnodes[i].in_ctx = -1;
+ } else {
+ set->val.scnodes[i].in_ctx = 0;
}
- /* add all the children */
- if (set->val.scnodes[i].scnode->nodetype & (LYS_LIST | LYS_CONTAINER)) {
- sub = NULL;
- while ((sub = lys_getnext(sub, set->val.scnodes[i].scnode, NULL, LYS_GETNEXT_NOSTATECHECK))) {
- /* RPC input/output check */
- if (options & LYXP_SCNODE_OUTPUT) {
- if (sub->parent->nodetype == LYS_INPUT) {
- continue;
- }
- } else {
- if (sub->parent->nodetype == LYS_OUTPUT) {
- continue;
- }
- }
+ start_parent = set->val.scnodes[i].scnode;
+ if ((set->val.scnodes[i].type == LYXP_NODE_ROOT_CONFIG) || (set->val.scnodes[i].type == LYXP_NODE_ROOT)) {
+ /* it can actually be in any module, it's all <running> */
+ mod_idx = 0;
+ while ((mod = (struct lys_module *)ly_ctx_get_module_iter(set->ctx, &mod_idx))) {
+ iter = NULL;
+ /* module may not be implemented */
+ while (mod->implemented && (iter = lys_getnext(iter, NULL, mod->compiled, getnext_opts))) {
+ /* context check */
+ if ((set->root_type == LYXP_NODE_ROOT_CONFIG) && (iter->flags & LYS_CONFIG_R)) {
+ continue;
+ }
+
+ lyxp_set_scnode_insert_node(set, iter, LYXP_NODE_ELEM);
+ /* throw away the insert index, we want to consider that node again, recursively */
+ }
+ }
+
+ } else if (set->val.scnodes[i].type == LYXP_NODE_ELEM) {
+ iter = NULL;
+ while ((iter = lys_getnext(iter, start_parent, NULL, getnext_opts))) {
/* context check */
- if ((set->root_type == LYXP_NODE_ROOT_CONFIG) && (sub->flags & LYS_CONFIG_R)) {
+ if ((set->root_type == LYXP_NODE_ROOT_CONFIG) && (iter->flags & LYS_CONFIG_R)) {
continue;
}
- lyxp_set_scnode_insert_node(set, sub, LYXP_NODE_ELEM);
- /* throw away the insert index, we want to consider that node again, recursively */
+ lyxp_set_scnode_insert_node(set, iter, LYXP_NODE_ELEM);
}
}
}
diff --git a/src/xpath.h b/src/xpath.h
index 33dc688..57845c7 100644
--- a/src/xpath.h
+++ b/src/xpath.h
@@ -3,7 +3,7 @@
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief YANG XPath evaluation functions header
*
- * Copyright (c) 2015 - 2019 CESNET, z.s.p.o.
+ * Copyright (c) 2015 - 2020 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
@@ -287,9 +287,6 @@
/**
* @brief Get all the partial XPath nodes (atoms) that are required for @p exp to be evaluated.
*
- * If any LYXP_SCNODE* options is set, only fatal errors are printed, otherwise they are downgraded
- * to warnings.
- *
* @param[in] exp Parsed XPath expression to be evaluated.
* @param[in] format Format of the XPath expression (more specifcally, of any used prefixes).
* @param[in] local_mod Local module relative to the @p exp.
@@ -305,11 +302,7 @@
LY_ERR lyxp_atomize(struct lyxp_expr *exp, LYD_FORMAT format, const struct lys_module *local_mod, const struct lysc_node *ctx_scnode,
enum lyxp_node_type ctx_scnode_type, struct lyxp_set *set, int options);
-/* these are used only internally */
-#define LYXP_SCNODE 0x02 /**< No special data tree access modifiers. */
-#define LYXP_SCNODE_SCHEMA 0x04 /**< Apply schema node access restrictions defined for 'when' and 'must' evaluation. */
-#define LYXP_SCNODE_OUTPUT 0x08 /**< Search RPC/action output instead of input. */
-
+/* used only internally */
#define LYXP_SCNODE_ALL 0x0E
/**