libyang CHANGE api functions xpath format unified
For data, JSON path is always used and for schema,
augment target path is always used.
diff --git a/src/common.c b/src/common.c
index d6e4d7c..370c3bb 100644
--- a/src/common.c
+++ b/src/common.c
@@ -833,6 +833,157 @@
return NULL;
}
+static int
+transform_json2xpath_subexpr(const struct lys_module *cur_module, const struct lys_module *prev_mod, struct lyxp_expr *exp,
+ uint32_t *i, enum lyxp_token end_token, char **out, size_t *out_used, size_t *out_size)
+{
+ const char *cur_expr, *end, *ptr;
+ size_t name_len;
+ char *name;
+ const struct lys_module *mod;
+
+ while (*i < exp->used) {
+ if (exp->tokens[*i] == end_token) {
+ return 0;
+ }
+
+ cur_expr = &exp->expr[exp->expr_pos[*i]];
+
+ /* copy WS */
+ if (*i && ((end = exp->expr + exp->expr_pos[*i - 1] + exp->tok_len[*i - 1]) != cur_expr)) {
+ strncpy(*out + *out_used, end, cur_expr - end);
+ *out_used += cur_expr - end;
+ }
+
+ if (exp->tokens[*i] == LYXP_TOKEN_BRACK1) {
+ /* copy "[" */
+ strncpy(*out + *out_used, &exp->expr[exp->expr_pos[*i]], exp->tok_len[*i]);
+ *out_used += exp->tok_len[*i];
+ ++(*i);
+
+ /* call recursively because we need to remember current prev_mod for after the predicate */
+ if (transform_json2xpath_subexpr(cur_module, prev_mod, exp, i, LYXP_TOKEN_BRACK2, out, out_used, out_size)) {
+ return -1;
+ }
+
+ /* copy "]" */
+ strncpy(*out + *out_used, &exp->expr[exp->expr_pos[*i]], exp->tok_len[*i]);
+ *out_used += exp->tok_len[*i];
+ } else if (exp->tokens[*i] == LYXP_TOKEN_NAMETEST) {
+ if ((end = strnchr(cur_expr, ':', exp->tok_len[*i]))) {
+ /* there is a prefix, get the module */
+ name_len = end - cur_expr;
+ name = strndup(cur_expr, name_len);
+ prev_mod = ly_ctx_get_module(cur_module->ctx, name, NULL);
+ if (!prev_mod) {
+ LOGVAL(LYE_INMOD_LEN, LY_VLOG_NONE, NULL, name_len ? name_len : exp->tok_len[*i], cur_expr);
+ return -1;
+ }
+ free(name);
+ /* skip ":" */
+ ++end;
+ ++name_len;
+ } else {
+ end = cur_expr;
+ name_len = 0;
+ }
+
+ /* do we print the module name? */
+ if (prev_mod != cur_module) {
+ /* adjust out size (it can even decrease in some strange cases) */
+ *out_size += (strlen(prev_mod->name) - name_len) + 1;
+ *out = ly_realloc(*out, *out_size);
+ LY_CHECK_ERR_RETURN(!*out, LOGMEM, -1);
+
+ /* copy the model name */
+ strcpy(*out + *out_used, prev_mod->name);
+ *out_used += strlen(prev_mod->name);
+
+ /* print ":" */
+ (*out)[*out_used] = ':';
+ ++(*out_used);
+ }
+
+ /* copy the rest */
+ strncpy(*out + *out_used, end, exp->tok_len[*i] - name_len);
+ *out_used += exp->tok_len[*i] - name_len;
+ } else if ((exp->tokens[*i] == LYXP_TOKEN_LITERAL) && (end = strnchr(cur_expr, ':', exp->tok_len[*i]))) {
+ ptr = end;
+ while (isalnum(ptr[-1]) || (ptr[-1] == '_') || (ptr[-1] == '-') || (ptr[-1] == '.')) {
+ --ptr;
+ }
+
+ /* get the module, but it may actually not be a module name */
+ name_len = end - ptr;
+ name = strndup(ptr, name_len);
+ mod = ly_ctx_get_module(cur_module->ctx, name, NULL);
+ free(name);
+
+ if (mod && (mod != cur_module)) {
+ /* adjust out size (it can even decrease in some strange cases) */
+ *out_size += strlen(mod->name) - name_len;
+ *out = ly_realloc(*out, *out_size);
+ LY_CHECK_ERR_RETURN(!*out, LOGMEM, -1);
+
+ /* copy any beginning */
+ strncpy(*out + *out_used, cur_expr, ptr - cur_expr);
+ *out_used += ptr - cur_expr;
+
+ /* copy the model name */
+ strcpy(*out + *out_used, mod->name);
+ *out_used += strlen(mod->name);
+
+ /* copy the rest */
+ strncpy(*out + *out_used, end, (exp->tok_len[*i] - name_len) - (ptr - cur_expr));
+ *out_used += (exp->tok_len[*i] - name_len) - (ptr - cur_expr);
+ } else {
+ strncpy(*out + *out_used, &exp->expr[exp->expr_pos[*i]], exp->tok_len[*i]);
+ *out_used += exp->tok_len[*i];
+ }
+ } else {
+ strncpy(*out + *out_used, &exp->expr[exp->expr_pos[*i]], exp->tok_len[*i]);
+ *out_used += exp->tok_len[*i];
+ }
+
+ ++(*i);
+ }
+
+ return 0;
+}
+
+char *
+transform_json2xpath(const struct lys_module *cur_module, const char *expr)
+{
+ char *out;
+ size_t out_size, out_used;
+ uint32_t i;
+ struct lyxp_expr *exp;
+
+ assert(cur_module && expr);
+
+ out_size = strlen(expr) + 1;
+ out = malloc(out_size);
+ LY_CHECK_ERR_RETURN(!out, LOGMEM, NULL);
+ out_used = 0;
+
+ exp = lyxp_parse_expr(expr);
+ LY_CHECK_ERR_RETURN(!exp, free(out), NULL);
+
+ i = 0;
+ if (transform_json2xpath_subexpr(cur_module, cur_module, exp, &i, LYXP_TOKEN_NONE, &out, &out_used, &out_size)) {
+ goto error;
+ }
+ out[out_used] = '\0';
+
+ lyxp_expr_free(exp);
+ return out;
+
+error:
+ free(out);
+ lyxp_expr_free(exp);
+ return NULL;
+}
+
int
ly_new_node_validity(const struct lys_node *schema)
{
diff --git a/src/common.h b/src/common.h
index 31795b8..7eb4358 100644
--- a/src/common.h
+++ b/src/common.h
@@ -265,7 +265,7 @@
#define LOGPATH(elem_type, elem) \
ly_vlog(LYE_PATH, elem_type, elem);
-void ly_vlog_build_path_reverse(enum LY_VLOG_ELEM elem_type, const void *elem, char *path, uint16_t *index, int prefix_all);
+void ly_vlog_build_path_reverse(enum LY_VLOG_ELEM elem_type, const void *elem, char *path, uint16_t *index);
/*
* - if \p module specified, it searches for submodules, they can be loaded only from a file or via module callback,
@@ -374,6 +374,12 @@
const char *transform_iffeat_schema2json(const struct lys_module *module, const char *expr);
/**
+ * @brief Transform an XPath expression in JSON node naming conventions into
+ * standard YANG XPath.
+ */
+char *transform_json2xpath(const struct lys_module *cur_module, const char *expr);
+
+/**
* @brief Get a new node (non-validated) validity value.
*
* @param[in] schema Schema node of the new data node.
diff --git a/src/context.c b/src/context.c
index ec3ac20..eac8661 100644
--- a/src/context.c
+++ b/src/context.c
@@ -1510,19 +1510,3 @@
return root;
}
-
-API const struct lys_node *
-ly_ctx_get_node(struct ly_ctx *ctx, const struct lys_node *start, const char *nodeid)
-{
- const struct lys_node *node;
-
- if (!ctx || !nodeid || ((nodeid[0] != '/') && !start)) {
- ly_errno = LY_EINVAL;
- return NULL;
- }
-
- /* sets error and everything */
- node = resolve_json_nodeid(nodeid, ctx, start);
-
- return node;
-}
diff --git a/src/libyang.h.in b/src/libyang.h.in
index 2c7c650..e3f9850 100644
--- a/src/libyang.h.in
+++ b/src/libyang.h.in
@@ -856,10 +856,27 @@
/**
* @page howtoxpath XPath Addressing
*
- * Internally, XPath evaluation is performed on \b when and \b must conditions in the schema. For that almost
- * a full XPath 1.0 evaluator was implemented except that only node sets are returned. This XPath implementation
- * is available on data trees by calling lyd_find_xpath() and on schema trees by calling lys_find_xpath().
- * This XPath conforms to the YANG specification (RFC 6020 section 6.4). Some useful examples:
+ * Internally, XPath evaluation is performed on __when__ and __must__ conditions in the schema. For that almost
+ * a full XPath 1.0 evaluator was implemented. In YANG models you can also find paths identifying __augment__
+ * targets, __leafref__ targets, and trivial paths in __choice default__ and __unique__ statements argument.
+ * The exact format of all those paths can be found in the relevant RFCs. Further will only be discussed
+ * paths that are used directly in libyang API functions.
+ *
+ * Schema
+ * ======
+ *
+ * Regarding identifying schema nodes, we use a slightly modified version of YANG __augment__ target path:
+ * - strictly speaking, most XPath expressions are not accepted, only simple paths (no predicates,
+ * numbers, literals, operators, ...),
+ * - whenever a prefix is used for a node, it is not the import prefix, but the __module name__ itself,
+ * - __current module__ is specified separately for _absolute_ paths and is the module of the start
+ * (current) node for _relative_ paths,
+ * - unprefixed nodes all use the prefix of the __current module__ so all nodes from other modules than
+ * the __current module__ _MUST_ have prefixes,
+ * - nodes from the __current module__ _MAY_ have prefixes,
+ *
+ * Examples
+ * --------
*
* - get all top-level nodes of the __module-name__
*
@@ -869,67 +886,53 @@
*
* /module-name:container//\asterisk
*
- * - get __list__ instance with __key1__ of value __1__ and __key2__ of value __2__ (this can return more __list__ instances if there are more keys than __key1__ and __key2__)
- *
- * /module-name:container/module-name:list[module-name:key1='1'][module-name:key2='2']
- *
- * - get __leaf-list__ instance with the value __val__
- *
- * /module-name:container/module-name:leaf-list[.='val']
- *
* - get __aug-leaf__, which was added to __module-name__ from an augment module __augment-module__
*
- * /module-name:container/module-name:container2/augment-module:aug-cont/augment-module:aug-leaf
- *
- * It is important to know what prefix is used for node names without one. It is the prefix of the context node, not
- * of the parent or any other. Example:
- *
- * - get __child__ of __container__ having __container__ as the context node (either of the two)
- *
- * /container/child
- * /child
- *
- * - get __aug-leaf__, which was added to __container__ from an augment module __augment-module__ having __container__
- * as the context node
- *
- * /container/augment-module:aug-leaf
- *
- * A very small subset of this full XPath is recognized by lyd_new_path(). Basically, only a relative or absolute
- * path can be specified to identify a new data node. However, lists must be identified by either all their keys and created
- * with all of them or using their relative position on their level starting from 1, so for those cases predicates are
- * allowed. List positions can be learned using lyd_list_pos(). Key predicates must be ordered the way the keys are
- * ordered and all the keys must be specified. Every predicate includes a single key with its value. If an instance
- * with such particular set of keys or with such relative position does not exist or no predicate is specified, list
- * instance is created. Optionally, leaves and leaf-lists can have predicates specifying their value in the path itself.
- * All these paths are valid XPath expressions. Example (ietf-yang-library:modules-state is the context node):
- *
- * /modules-state/module[name='ietf-yang-library'][revision='']/conformance[.='implement']
- * /modules-state/module[1]/conformance[.='implement']
- *
- * Almost the same XPath is accepted by ly_ctx_get_node(). The difference is that it is not used on data, but schema,
- * which means there are no key values and only one node matches one path. In effect, lists do not have to have any
- * predicates. If they do, they do not need to have all the keys specified and if values are included, they are ignored.
- * Nevertheless, any such expression is still a valid XPath, but can return more nodes if executed on a data tree.
- * Examples (all returning the same node, ietf-yang-library:modules-state is the context node):
- *
- * /modules-state/module/submodules
- * /modules-state/module[name]/submodules
- * /modules-state/module[name][revision]/submodules
- * /modules-state/module[name='ietf-yang-library'][revision]/submodules
- *
- * Also, `choice`, `case`, `input`, and `output` nodes need to be specified and cannot be skipped in schema XPaths. Use
- * lys_find_xpath() if you want to search based on a data XPath.
- *
- * Also note, that in all cases the node's prefix is specified as the name of the appropriate YANG schema. Any node
- * can be prefixed by the module name. However, if the prefix is omitted, the module name is inherited from the previous
- * (parent) node. It means, that the first node in the path is always supposed to have a prefix.
+ * /module-name:container/container2/augment-module:aug-cont/augment-module:aug-leaf
*
* Functions List
* --------------
- * - lyd_find_xpath()
- * - lys_find_xpath()
+ * - lys_find_path()
+ * - lys_path()
+ *
+ *
+ * Data
+ * ====
+ *
+ * As for paths evaluated on YANG data, we opted for standardized JSON paths ([RFC 7951](https://tools.ietf.org/html/rfc7951#section-6.11)). Summarized, it follows these conventions:
+ * - generally, you can use almost a full XPath in these paths where it makes sense, but only data nodes (node sets)
+ * will always be returned (except for paths, predicates are mostly used),
+ * - as per the specification, prefixes are actually __module names__,
+ * - also in the specification, for _absolute_ paths, the first (leftmost) node _MUST_ have a prefix,
+ * - for _relative_ paths, you specify the __context node__, which then acts as a parent for the first node in the path,
+ * - nodes always inherit their module (prefix) from their __parent node__ so whenever a node is from a different
+ * module than its parent, it _MUST_ have a prefix,
+ * - nodes from the same module as their __parent__ _MUST NOT_ have a prefix,
+ * - different from schema paths, non-data nodes (choice, case, uses, input, output) are skipped and not included
+ * in the path.
+ *
+ * Examples
+ * --------
+ *
+ * - get __list__ instance with __key1__ of value __1__ and __key2__ of value __2__ (this can return more __list__ instances if there are more keys than __key1__ and __key2__)
+ *
+ * /module-name:container/list[key1='1'][key2='2']
+ *
+ * - get __leaf-list__ instance with the value __val__
+ *
+ * /module-name:container/leaf-list[.='val']
+ *
+ * - get __aug-list__ with __aug-list-key__, which was added to __module-name__ from an augment module __augment-module__
+ *
+ * /module-name:container/container2/augment-module:aug-cont/aug-list[aug-list-key='value']
+ *
+ * Functions List
+ * --------------
+ * - lyd_find_path()
* - lyd_new_path()
- * - ly_ctx_get_node()
+ * - lyd_path()
+ * - lys_data_path()
+ *
*/
/**
@@ -1337,30 +1340,6 @@
const struct lys_submodule *ly_ctx_get_submodule2(const struct lys_module *main_module, const char *submodule);
/**
- * @brief Get schema node according to the given schema node identifier in JSON format.
- *
- * If the \p nodeid is absolute, the first node identifier must be prefixed with
- * the module name. Then every other identifier either has an explicit module name or
- * the module name of the previous node is assumed. Examples:
- *
- * /ietf-netconf-monitoring:get-schema/input/identifier
- * /ietf-interfaces:interfaces/interface/ietf-ip:ipv4/address/ip
- *
- * If the \p nodeid is relative, \p start is mandatory and is the starting point
- * for the resolution. The first node identifier does not need a module name.
- *
- * Predicates on lists are accepted (ignored) in the form of "<key>(=<value>)"
- * and on leaves/leaf-lists ".(=<value>)".
- *
- * @param[in] ctx Context to work in.
- * @param[in] start Starting node for a relative schema node identifier, in which
- * case it is mandatory.
- * @param[in] nodeid JSON schema node identifier.
- * @return Resolved schema node or NULL.
- */
-const struct lys_node *ly_ctx_get_node(struct ly_ctx *ctx, const struct lys_node *start, const char *nodeid);
-
-/**
* @brief Remove the specified module from its context.
*
* Beside the selected module, also all other modules depending on all the modules being removed
diff --git a/src/log.c b/src/log.c
index 4fa4d28..16f53a0 100644
--- a/src/log.c
+++ b/src/log.c
@@ -425,13 +425,13 @@
}
void
-ly_vlog_build_path_reverse(enum LY_VLOG_ELEM elem_type, const void *elem, char *path, uint16_t *index, int prefix_all)
+ly_vlog_build_path_reverse(enum LY_VLOG_ELEM elem_type, const void *elem, char *path, uint16_t *index)
{
int i, j;
struct lys_node_list *slist;
- struct lys_node *sparent;
+ struct lys_node *sparent = NULL;
struct lyd_node *dlist, *diter;
- struct lys_module *top_module = NULL;
+ const struct lys_module *top_smodule = NULL;
const char *name, *prefix = NULL, *val_end, *val_start;
char *str;
size_t len;
@@ -444,14 +444,9 @@
elem = ((struct lyxml_elem *)elem)->parent;
break;
case LY_VLOG_LYS:
- if (!top_module) {
- /* find and store the top-level node module */
- if (((struct lys_node *)elem)->nodetype == LYS_EXT) {
- top_module = ((struct lys_ext_instance *)elem)->module;
- } else {
- for (sparent = (struct lys_node *)elem; lys_parent(sparent); sparent = lys_parent(sparent));
- top_module = lys_node_module(sparent);
- }
+ if (!top_smodule) {
+ /* remember the top module, it will act as the current module */
+ top_smodule = lys_node_module((struct lys_node *)elem);
}
if (((struct lys_node *)elem)->nodetype & (LYS_AUGMENT | LYS_GROUPING)) {
@@ -474,7 +469,7 @@
name = ((struct lys_node *)elem)->name;
}
- if (prefix_all || !lys_parent((struct lys_node *)elem) || (lys_node_module((struct lys_node *)elem) != top_module)) {
+ if (lys_node_module((struct lys_node *)elem) != top_smodule) {
prefix = lys_node_module((struct lys_node *)elem)->name;
} else {
prefix = NULL;
@@ -496,14 +491,9 @@
} while (elem && (((struct lys_node *)elem)->nodetype == LYS_USES));
break;
case LY_VLOG_LYD:
- if (!top_module) {
- /* find and store the top-level node module */
- for (diter = (struct lyd_node *)elem; diter->parent; diter = diter->parent);
- top_module = lyd_node_module(diter);
- }
-
name = ((struct lyd_node *)elem)->schema->name;
- if (prefix_all || !((struct lyd_node *)elem)->parent || (lyd_node_module((struct lyd_node *)elem) != top_module)) {
+ if (!((struct lyd_node *)elem)->parent ||
+ lyd_node_module((struct lyd_node *)elem) != lyd_node_module(((struct lyd_node *)elem)->parent)) {
prefix = lyd_node_module((struct lyd_node *)elem)->name;
} else {
prefix = NULL;
@@ -540,7 +530,7 @@
len = strlen(diter->schema->name);
(*index) -= len;
memcpy(&path[(*index)], diter->schema->name, len);
- if (prefix_all || (lyd_node_module(diter) != top_module)) {
+ if (lyd_node_module(dlist) != lyd_node_module(diter)) {
path[--(*index)] = ':';
len = strlen(lyd_node_module(diter)->name);
(*index) -= len;
@@ -658,7 +648,7 @@
/* top-level */
path[--(*index)] = '/';
} else {
- ly_vlog_build_path_reverse(elem_type, elem, path, index, 0);
+ ly_vlog_build_path_reverse(elem_type, elem, path, index);
}
} else if (elem_type == LY_VLOG_NONE) {
/* erase path, the rest will be erased by log_vprintf() since it will get NULL path parameter */
diff --git a/src/parser.c b/src/parser.c
index c3416b6..6497904 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -3412,11 +3412,18 @@
for (i = 0; i < module->deviation_size; i++) {
target = NULL;
- resolve_augment_schema_nodeid(module->deviation[i].target_name, NULL, module, (const struct lys_node **)&target);
- if (!target) {
+ extset = NULL;
+ j = resolve_schema_nodeid(module->deviation[i].target_name, NULL, module, &extset, 0, 0);
+ if (j == -1) {
+ return EXIT_FAILURE;
+ } else if (!extset) {
/* LY_DEVIATE_NO */
+ ly_set_free(extset);
continue;
}
+ target = extset->set.s[0];
+ ly_set_free(extset);
+
for (j = 0; j < module->deviation[i].deviate_size; j++) {
dev = &module->deviation[i].deviate[j];
if (!dev->ext_size) {
diff --git a/src/parser_yang.c b/src/parser_yang.c
index 2564696..a8ec395 100644
--- a/src/parser_yang.c
+++ b/src/parser_yang.c
@@ -4336,7 +4336,7 @@
int rc;
uint i;
struct lys_node *dev_target = NULL, *parent;
- struct ly_set *dflt_check = ly_set_new();
+ struct ly_set *dflt_check = ly_set_new(), *set;
unsigned int u;
const char *value, *target_name;
struct lys_node_leaflist *llist;
@@ -4345,12 +4345,15 @@
struct lys_module *mod;
/* resolve target node */
-
- rc = resolve_augment_schema_nodeid(dev->target_name, NULL, module, (const struct lys_node **)&dev_target);
- if (rc || !dev_target) {
+ rc = resolve_schema_nodeid(dev->target_name, NULL, module, &set, 0, 1);
+ if (rc == -1) {
LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, dev->target_name, "deviation");
+ ly_set_free(set);
goto error;
}
+ dev_target = set->set.s[0];
+ ly_set_free(set);
+
if (dev_target->module == lys_main_module(module)) {
LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, dev->target_name, "deviation");
LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Deviating own module is not allowed.");
diff --git a/src/parser_yin.c b/src/parser_yin.c
index 7d73e93..5f564ea 100644
--- a/src/parser_yin.c
+++ b/src/parser_yin.c
@@ -2013,7 +2013,7 @@
struct lys_node *node = NULL, *parent, *dev_target = NULL;
struct lys_node_choice *choice = NULL;
struct lys_node_leaf *leaf = NULL;
- struct ly_set *dflt_check = ly_set_new();
+ struct ly_set *dflt_check = ly_set_new(), *set;
struct lys_node_list *list = NULL;
struct lys_node_leaflist *llist = NULL;
struct lys_type *t = NULL;
@@ -2032,11 +2032,15 @@
}
/* resolve target node */
- rc = resolve_augment_schema_nodeid(dev->target_name, NULL, module, (const struct lys_node **)&dev_target);
- if (rc || !dev_target) {
+ rc = resolve_schema_nodeid(dev->target_name, NULL, module, &set, 0, 1);
+ if (rc == -1) {
LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, dev->target_name, yin->name);
+ ly_set_free(set);
goto error;
}
+ dev_target = set->set.s[0];
+ ly_set_free(set);
+
if (dev_target->module == lys_main_module(module)) {
LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, dev->target_name, yin->name);
LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Deviating own module is not allowed.");
diff --git a/src/resolve.c b/src/resolve.c
index 803a123..128120f 100644
--- a/src/resolve.c
+++ b/src/resolve.c
@@ -155,37 +155,92 @@
* @param[out] mod_name_len Length of the module name, 0 if there is not any.
* @param[out] name Points to the node name.
* @param[out] nam_len Length of the node name.
+ * @param[out] all_desc Whether the path starts with '/', only supported in extended paths.
+ * @param[in] extended Whether to accept an extended path (support for [prefix:]*, /[prefix:]*, /[prefix:].).
*
* @return Number of characters successfully parsed,
* positive on success, negative on failure.
*/
static int
-parse_node_identifier(const char *id, const char **mod_name, int *mod_name_len, const char **name, int *nam_len)
+parse_node_identifier(const char *id, const char **mod_name, int *mod_name_len, const char **name, int *nam_len,
+ int *all_desc, int extended)
{
int parsed = 0, ret;
assert(id);
+ assert((mod_name && mod_name_len) || (!mod_name && !mod_name_len));
+ assert((name && nam_len) || (!name && !nam_len));
+ assert(!extended || all_desc);
+
if (mod_name) {
*mod_name = NULL;
- }
- if (mod_name_len) {
*mod_name_len = 0;
}
if (name) {
*name = NULL;
- }
- if (nam_len) {
*nam_len = 0;
}
+ if (extended) {
+ /* try to parse only the extended expressions */
+ if (id[parsed] == '/') {
+ *all_desc = 1;
+ } else {
+ *all_desc = 0;
+ }
+
+ /* is there a prefix? */
+ ret = parse_identifier(id + *all_desc);
+ if (ret > 0) {
+ if (id[*all_desc + ret] != ':') {
+ /* this is not a prefix, so not an extended id */
+ goto standard_id;
+ }
+
+ if (mod_name) {
+ *mod_name = id + *all_desc;
+ *mod_name_len = ret;
+ }
+
+ /* "/" and ":" */
+ ret += *all_desc + 1;
+ } else {
+ ret = *all_desc;
+ }
+
+ /* parse either "*" or "." */
+ if (!strcmp(id + ret, "*")) {
+ if (name) {
+ *name = id + ret;
+ *nam_len = 1;
+ }
+ ++ret;
+
+ return ret;
+ } else if (!strcmp(id + ret, ".")) {
+ if (!*all_desc) {
+ /* /. is redundant expression, we do not accept it */
+ return -ret;
+ }
+
+ if (name) {
+ *name = id + ret;
+ *nam_len = 1;
+ }
+ ++ret;
+
+ return ret;
+ }
+ /* else a standard id, parse it all again */
+ }
+
+standard_id:
if ((ret = parse_identifier(id)) < 1) {
return ret;
}
if (mod_name) {
*mod_name = id;
- }
- if (mod_name_len) {
*mod_name_len = ret;
}
@@ -223,8 +278,6 @@
if (name) {
*name = id;
- }
- if (nam_len) {
*nam_len = ret;
}
@@ -291,7 +344,7 @@
++id;
}
- if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
+ if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len, NULL, 0)) < 1) {
return -parsed+ret;
}
@@ -478,8 +531,8 @@
}
/* all parent references must be parsed at this point */
- if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
- return -parsed+ret;
+ if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len, NULL, 0)) < 1) {
+ return -parsed + ret;
}
parsed += ret;
@@ -564,8 +617,8 @@
++id;
/* node-identifier ([prefix:]identifier) */
- if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
- return -parsed-ret;
+ if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len, NULL, 0)) < 1) {
+ return -parsed - ret;
}
if (prefix && !(*prefix)) {
/* actually we always need prefix even it is not specified */
@@ -756,7 +809,7 @@
++id;
} else {
- if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len)) < 1) {
+ if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len, NULL, 0)) < 1) {
return -parsed+ret;
} else if (model && !*model) {
return -parsed;
@@ -847,30 +900,20 @@
* on the first call, must not be changed between consecutive calls.
* @param[out] has_predicate Flag to mark whether there is a predicate specified. It cannot be
* based on the grammar, in those cases use NULL.
+ * @param[in] extended Whether to accept an extended path (support for /[prefix:]*, //[prefix:]*, //[prefix:].).
*
* @return Number of characters successfully parsed,
* positive on success, negative on failure.
*/
int
parse_schema_nodeid(const char *id, const char **mod_name, int *mod_name_len, const char **name, int *nam_len,
- int *is_relative, int *has_predicate)
+ int *is_relative, int *has_predicate, int *all_desc, int extended)
{
int parsed = 0, ret;
assert(id);
assert(is_relative);
- if (mod_name) {
- *mod_name = NULL;
- }
- if (mod_name_len) {
- *mod_name_len = 0;
- }
- if (name) {
- *name = NULL;
- }
- if (nam_len) {
- *nam_len = 0;
- }
+
if (has_predicate) {
*has_predicate = 0;
}
@@ -893,8 +936,8 @@
++id;
}
- if ((ret = parse_node_identifier(id, mod_name, mod_name_len, name, nam_len)) < 1) {
- return -parsed+ret;
+ if ((ret = parse_node_identifier(id, mod_name, mod_name_len, name, nam_len, all_desc, extended)) < 1) {
+ return -parsed + ret;
}
parsed += ret;
@@ -993,7 +1036,7 @@
if (nam_len) {
*nam_len = ret;
}
- } else if ((ret = parse_node_identifier(id, mod_name, mod_name_len, name, nam_len)) < 1) {
+ } else if ((ret = parse_node_identifier(id, mod_name, mod_name_len, name, nam_len, NULL, 0)) < 1) {
return -parsed + ret;
}
@@ -1086,7 +1129,7 @@
assert(feature);
/* check prefix */
- if ((i = parse_node_identifier(feat_name, &mod_name, &mod_name_len, &name, &nam_len)) < 1) {
+ if ((i = parse_node_identifier(feat_name, &mod_name, &mod_name_len, &name, &nam_len, NULL, 0)) < 1) {
LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, feat_name[-i], &feat_name[-i]);
return -1;
}
@@ -1576,63 +1619,134 @@
return result;
}
-/*
- * 0 - ok (done)
- * 1 - continue
- * 2 - break
- * -1 - error
- */
int
-schema_nodeid_siblingcheck(const struct lys_node *sibling, const char *id, const struct lys_module *module,
- const char *mod_name, int mod_name_len)
+schema_nodeid_siblingcheck(const struct lys_node *sibling, const struct lys_module *cur_module, const char *mod_name,
+ int mod_name_len, const char *name, int nam_len)
{
const struct lys_module *prefix_mod;
+ /* name check */
+ if ((name[0] != '*') && (name[0] != '.') && (strncmp(name, sibling->name, nam_len) || sibling->name[nam_len])) {
+ return 1;
+ }
+
/* module check */
- prefix_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
- if (!prefix_mod) {
- return -1;
+ if (mod_name) {
+ prefix_mod = lys_get_import_module(cur_module, NULL, 0, mod_name, mod_name_len);
+ if (!prefix_mod) {
+ return -1;
+ }
+ } else {
+ prefix_mod = cur_module;
}
if (prefix_mod != lys_node_module(sibling)) {
return 1;
}
- /* the result node? */
- if (!id[0]) {
+ /* match */
+ switch (name[0]) {
+ case '*':
+ return 2;
+ case '.':
+ return 3;
+ default:
return 0;
}
-
- /* move down the tree, if possible */
- if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
- return -1;
- }
-
- return 2;
}
-/* start - relative, module - absolute, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1
+/* keys do not have to be ordered and do not have to be all of them */
+static int
+resolve_extended_schema_nodeid_predicate(const char *nodeid, const struct lys_node *node,
+ const struct lys_module *cur_module, int *nodeid_end)
+{
+ int mod_len, nam_len, has_predicate, r, i;
+ const char *model, *name;
+ struct lys_node_list *list;
+
+ if (!(node->nodetype & (LYS_LIST | LYS_LEAFLIST))) {
+ return 1;
+ }
+
+ list = (struct lys_node_list *)node;
+ do {
+ r = parse_schema_json_predicate(nodeid, &model, &mod_len, &name, &nam_len, NULL, NULL, &has_predicate);
+ if (r < 1) {
+ LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, nodeid[r], &nodeid[r]);
+ return -1;
+ }
+ nodeid += r;
+
+ if (node->nodetype == LYS_LEAFLIST) {
+ /* just check syntax */
+ if (model || !name || (name[0] != '.') || has_predicate) {
+ return 1;
+ }
+ break;
+ } else {
+ /* check the key */
+ for (i = 0; i < list->keys_size; ++i) {
+ if (strncmp(list->keys[i]->name, name, nam_len) || list->keys[i]->name[nam_len]) {
+ continue;
+ }
+ if (model) {
+ if (strncmp(lys_node_module((struct lys_node *)list->keys[i])->name, model, mod_len)
+ || lys_node_module((struct lys_node *)list->keys[i])->name[mod_len]) {
+ continue;
+ }
+ } else {
+ if (lys_node_module((struct lys_node *)list->keys[i]) != cur_module) {
+ continue;
+ }
+ }
+
+ /* match */
+ break;
+ }
+
+ if (i == list->keys_size) {
+ return 1;
+ }
+ }
+ } while (has_predicate);
+
+ if (!nodeid[0]) {
+ *nodeid_end = 1;
+ }
+ return 0;
+}
+
+/* start - relative, module - absolute, -1 error (logged), EXIT_SUCCESS ok
*/
int
-resolve_augment_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_module *cur_module,
- const struct lys_node **ret)
+resolve_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_module *cur_module,
+ struct ly_set **ret, int extended, int no_node_error)
{
const char *name, *mod_name, *id;
- const struct lys_node *sibling, *start_parent;
+ const struct lys_node *sibling, *start_parent, *next, *elem;
struct lys_node_augment *last_aug;
- int r, nam_len, mod_name_len = 0, is_relative = -1;
+ int r, nam_len, mod_name_len = 0, is_relative = -1, all_desc, has_predicate, nodeid_end = 0;
/* resolved import module from the start module, it must match the next node-name-match sibling */
const struct lys_module *start_mod, *aux_mod;
+ char *str;
- assert(nodeid && (start || cur_module) && !(start && cur_module) && ret);
+ assert(nodeid && (start || cur_module) && ret);
+ *ret = NULL;
+ if (!cur_module) {
+ cur_module = lys_node_module(start);
+ }
id = nodeid;
- if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL)) < 1) {
- return ((id - nodeid) - r) + 1;
+ r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate,
+ (extended ? &all_desc : NULL), extended);
+ if (r < 1) {
+ LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[r], &id[r]);
+ return -1;
}
id += r;
- if ((is_relative && !start) || (!is_relative && !cur_module)) {
+ if (is_relative && !start) {
+ LOGINT;
return -1;
}
@@ -1645,6 +1759,9 @@
} else {
start_mod = lys_get_import_module(cur_module, NULL, 0, mod_name, mod_name_len);
if (!start_mod) {
+ str = strndup(mod_name, mod_name_len);
+ LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
+ free(str);
return -1;
}
start_parent = NULL;
@@ -1660,6 +1777,9 @@
/* we are getting into another module (augment) */
aux_mod = lys_get_import_module(cur_module, NULL, 0, mod_name, mod_name_len);
if (!aux_mod) {
+ str = strndup(mod_name, mod_name_len);
+ LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
+ free(str);
return -1;
}
} else {
@@ -1670,7 +1790,7 @@
}
/* if the module is implemented, all the augments will be connected */
- if (!aux_mod->implemented) {
+ if (!aux_mod->implemented && !extended) {
get_next_augment:
last_aug = lys_getnext_target_aug(last_aug, aux_mod, start_parent);
}
@@ -1678,21 +1798,88 @@
while ((sibling = lys_getnext(sibling, (last_aug ? (struct lys_node *)last_aug : start_parent), start_mod,
LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_PARENTUSES))) {
- /* name match */
- if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
- r = schema_nodeid_siblingcheck(sibling, id, cur_module, mod_name, mod_name_len);
- if (r == 0) {
- *ret = sibling;
- return EXIT_SUCCESS;
- } else if (r == 1) {
+ r = schema_nodeid_siblingcheck(sibling, cur_module, mod_name, mod_name_len, name, nam_len);
+
+ /* resolve predicate */
+ if (extended && ((r == 0) || (r == 2) || (r == 3)) && has_predicate) {
+ r = resolve_extended_schema_nodeid_predicate(id, sibling, cur_module, &nodeid_end);
+ if (r == 1) {
continue;
- } else if (r == 2) {
- start_parent = sibling;
- break;
- } else {
+ } else if (r == -1) {
return -1;
}
+ } else if (!id[0]) {
+ nodeid_end = 1;
}
+
+ if (r == 0) {
+ /* one matching result */
+ if (nodeid_end) {
+ *ret = ly_set_new();
+ LY_CHECK_ERR_RETURN(!*ret, LOGMEM, -1);
+ ly_set_add(*ret, (void *)sibling, LY_SET_OPT_USEASLIST);
+ } else {
+ if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
+ return -1;
+ }
+ start_parent = sibling;
+ }
+ break;
+ } else if (r == 1) {
+ continue;
+ } else if (r == 2) {
+ /* "*" */
+ if (!*ret) {
+ *ret = ly_set_new();
+ LY_CHECK_ERR_RETURN(!*ret, LOGMEM, -1);
+ }
+ ly_set_add(*ret, (void *)sibling, LY_SET_OPT_USEASLIST);
+ if (all_desc) {
+ LY_TREE_DFS_BEGIN(sibling, next, elem) {
+ if (elem != sibling) {
+ ly_set_add(*ret, (void *)elem, LY_SET_OPT_USEASLIST);
+ }
+
+ LY_TREE_DFS_END(sibling, next, elem);
+ }
+ }
+ } else if (r == 3) {
+ /* "." */
+ if (!*ret) {
+ *ret = ly_set_new();
+ LY_CHECK_ERR_RETURN(!*ret, LOGMEM, -1);
+ ly_set_add(*ret, (void *)start_parent, LY_SET_OPT_USEASLIST);
+ }
+ ly_set_add(*ret, (void *)sibling, LY_SET_OPT_USEASLIST);
+ if (all_desc) {
+ LY_TREE_DFS_BEGIN(sibling, next, elem) {
+ if (elem != sibling) {
+ ly_set_add(*ret, (void *)elem, LY_SET_OPT_USEASLIST);
+ }
+
+ LY_TREE_DFS_END(sibling, next, elem);
+ }
+ }
+ } else {
+ LOGINT;
+ return -1;
+ }
+ }
+
+ /* skip predicate */
+ if (extended && has_predicate) {
+ while (id[0] == '[') {
+ id = strchr(id, ']');
+ if (!id) {
+ LOGINT;
+ return -1;
+ }
+ ++id;
+ }
+ }
+
+ if (nodeid_end && ((r == 0) || (r == 2) || (r == 3))) {
+ return EXIT_SUCCESS;
}
/* no match */
@@ -1701,12 +1888,21 @@
/* it still could be in another augment */
goto get_next_augment;
}
+ if (no_node_error) {
+ str = strndup(nodeid, (name - nodeid) + nam_len);
+ LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
+ free(str);
+ return -1;
+ }
*ret = NULL;
return EXIT_SUCCESS;
}
- if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL)) < 1) {
- return ((id - nodeid) - r) + 1;
+ r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate,
+ (extended ? &all_desc : NULL), extended);
+ if (r < 1) {
+ LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[r], &id[r]);
+ return -1;
}
id += r;
}
@@ -1740,9 +1936,9 @@
}
id = nodeid;
- module = start->module;
+ module = lys_node_module(start);
- if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL)) < 1) {
+ if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL, NULL, 0)) < 1) {
return ((id - nodeid) - r) + 1;
}
id += r;
@@ -1760,24 +1956,22 @@
sibling = NULL;
while ((sibling = lys_getnext(sibling, start_parent, module,
LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_PARENTUSES))) {
- /* name match */
- if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
- r = schema_nodeid_siblingcheck(sibling, id, module, mod_name, mod_name_len);
- if (r == 0) {
+ r = schema_nodeid_siblingcheck(sibling, module, mod_name, mod_name_len, name, nam_len);
+ if (r == 0) {
+ if (!id[0]) {
if (!(sibling->nodetype & ret_nodetype)) {
/* wrong node type, too bad */
continue;
}
*ret = sibling;
return EXIT_SUCCESS;
- } else if (r == 1) {
- continue;
- } else if (r == 2) {
- start_parent = sibling;
- break;
- } else {
- return -1;
}
+ start_parent = sibling;
+ break;
+ } else if (r == 1) {
+ continue;
+ } else {
+ return -1;
}
}
@@ -1790,7 +1984,7 @@
return -2;
}
- if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL)) < 1) {
+ if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL, NULL, 0)) < 1) {
return ((id - nodeid) - r) + 1;
}
id += r;
@@ -1822,7 +2016,7 @@
int i, mod_prefix_len, nam_len;
/* parse the identifier, it must be parsed on one call */
- if (((i = parse_node_identifier(nodeid, &mod_prefix, &mod_prefix_len, &name, &nam_len)) < 1) || nodeid[i]) {
+ if (((i = parse_node_identifier(nodeid, &mod_prefix, &mod_prefix_len, &name, &nam_len, NULL, 0)) < 1) || nodeid[i]) {
return -i + 1;
}
@@ -1854,7 +2048,7 @@
id = nodeid;
start_parent = NULL;
- if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL)) < 1) {
+ if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL, NULL, 0)) < 1) {
return ((id - nodeid) - r) + 1;
}
id += r;
@@ -1872,24 +2066,22 @@
sibling = NULL;
while ((sibling = lys_getnext(sibling, start_parent, abs_start_mod, LYS_GETNEXT_WITHCHOICE
| LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_WITHGROUPING))) {
- /* name match */
- if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
- r = schema_nodeid_siblingcheck(sibling, id, module, mod_name, mod_name_len);
- if (r == 0) {
+ r = schema_nodeid_siblingcheck(sibling, module, mod_name, mod_name_len, name, nam_len);
+ if (r == 0) {
+ if (!id[0]) {
if (!(sibling->nodetype & ret_nodetype)) {
/* wrong node type, too bad */
continue;
}
*ret = sibling;
return EXIT_SUCCESS;
- } else if (r == 1) {
- continue;
- } else if (r == 2) {
- start_parent = sibling;
- break;
- } else {
- return -1;
}
+ start_parent = sibling;
+ break;
+ } else if (r == 1) {
+ continue;
+ } else {
+ return -1;
}
}
@@ -1899,7 +2091,7 @@
return EXIT_SUCCESS;
}
- if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL)) < 1) {
+ if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL, NULL, 0)) < 1) {
return ((id - nodeid) - r) + 1;
}
id += r;
@@ -1911,8 +2103,7 @@
}
static int
-resolve_json_schema_list_predicate(const char *predicate, const struct lys_node_list *list,
- const struct lys_module *cur_module, int *parsed)
+resolve_json_schema_list_predicate(const char *predicate, const struct lys_node_list *list, int *parsed)
{
const char *mod_name, *name;
int mod_name_len, nam_len, has_predicate, i;
@@ -1931,15 +2122,7 @@
for (i = 0; i < list->keys_size; ++i) {
key = (struct lys_node *)list->keys[i];
if (!strncmp(key->name, name, nam_len) && !key->name[nam_len]) {
- if (mod_name) {
- if (!strncmp(lys_node_module(key)->name, mod_name, mod_name_len) && !lys_node_module(key)->name[mod_name_len]) {
- break;
- }
- } else {
- if (!strcmp(lys_node_module(key)->name, cur_module->name)) {
- break;
- }
- }
+ break;
}
}
@@ -1951,7 +2134,7 @@
/* more predicates? */
if (has_predicate) {
- return resolve_json_schema_list_predicate(predicate, list, cur_module, parsed);
+ return resolve_json_schema_list_predicate(predicate, list, parsed);
}
return 0;
@@ -1966,7 +2149,7 @@
const struct lys_node *sibling, *start_parent;
int r, nam_len, mod_name_len, is_relative = -1, has_predicate;
/* resolved import module from the start module, it must match the next node-name-match sibling */
- const struct lys_module *prefix_mod, *cur_module;
+ const struct lys_module *prefix_mod, *module, *prev_mod;
assert(nodeid && (ctx || start));
if (!ctx) {
@@ -1975,7 +2158,7 @@
id = nodeid;
- if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate)) < 1) {
+ if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate, NULL, 0)) < 1) {
LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
return NULL;
}
@@ -1987,7 +2170,7 @@
while (start_parent && (start_parent->nodetype == LYS_USES)) {
start_parent = lys_parent(start_parent);
}
- cur_module = start->module;
+ module = start->module;
} else {
if (!mod_name) {
str = strndup(nodeid, (name + nam_len) - nodeid);
@@ -2006,7 +2189,7 @@
memmove(module_name, mod_name, mod_name_len);
module_name[mod_name_len] = '\0';
- cur_module = ly_ctx_get_module(ctx, module_name, NULL);
+ module = ly_ctx_get_module(ctx, module_name, NULL);
if (buf_backup) {
/* return previous internal buffer content */
@@ -2016,7 +2199,7 @@
}
ly_buf_used--;
- if (!cur_module) {
+ if (!module) {
str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
free(str);
@@ -2029,9 +2212,11 @@
mod_name_len = 0;
}
+ prev_mod = module;
+
while (1) {
sibling = NULL;
- while ((sibling = lys_getnext(sibling, start_parent, cur_module,
+ while ((sibling = lys_getnext(sibling, start_parent, module,
LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT))) {
/* name match */
if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
@@ -2067,7 +2252,7 @@
return NULL;
}
} else {
- prefix_mod = cur_module;
+ prefix_mod = prev_mod;
}
if (prefix_mod != lys_node_module(sibling)) {
continue;
@@ -2082,7 +2267,7 @@
return NULL;
}
} else if (sibling->nodetype == LYS_LIST) {
- if (resolve_json_schema_list_predicate(id, (const struct lys_node_list *)sibling, cur_module, &r)) {
+ if (resolve_json_schema_list_predicate(id, (const struct lys_node_list *)sibling, &r)) {
return NULL;
}
} else {
@@ -2103,6 +2288,9 @@
return NULL;
}
start_parent = sibling;
+
+ /* update prev mod */
+ prev_mod = (start_parent->child ? lys_node_module(start_parent->child) : module);
break;
}
}
@@ -2115,7 +2303,7 @@
return NULL;
}
- if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate)) < 1) {
+ if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate, NULL, 0)) < 1) {
LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
return NULL;
}
@@ -2129,7 +2317,7 @@
static int
resolve_partial_json_data_list_predicate(const char *predicate, const char *node_name, struct lyd_node *node,
- int position, const struct lys_module *cur_module, int *parsed)
+ int position, int *parsed)
{
const char *mod_name, *name, *value, *key_val;
int mod_name_len, nam_len, val_len, has_predicate = 1, r;
@@ -2194,13 +2382,21 @@
}
if (mod_name) {
+ /* specific module, check that the found key is from that module */
if (strncmp(lyd_node_module((struct lyd_node *)key)->name, mod_name, mod_name_len)
|| lyd_node_module((struct lyd_node *)key)->name[mod_name_len]) {
LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
return -1;
}
+
+ /* but if the module is the same as the parent, it should have been omitted */
+ if (lyd_node_module((struct lyd_node *)key) == lyd_node_module(node)) {
+ LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
+ return -1;
+ }
} else {
- if (strcmp(lyd_node_module((struct lyd_node *)key)->name, cur_module->name)) {
+ /* no module, so it must be the same as the list (parent) */
+ if (lyd_node_module((struct lyd_node *)key) != lyd_node_module(node)) {
LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
return -1;
}
@@ -2250,7 +2446,7 @@
int has_predicate, last_parsed, llval_len, pred_name_len, last_has_pred;
struct lyd_node *sibling, *last_match = NULL;
struct lyd_node_leaf_list *llist;
- const struct lys_module *prefix_mod, *cur_module;
+ const struct lys_module *prefix_mod, *prev_mod;
struct ly_ctx *ctx;
assert(nodeid && start && parsed);
@@ -2258,7 +2454,7 @@
ctx = start->schema->module->ctx;
id = nodeid;
- if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate)) < 1) {
+ if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate, NULL, 0)) < 1) {
LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
*parsed = -1;
return NULL;
@@ -2268,11 +2464,11 @@
last_parsed = r;
if (is_relative) {
- cur_module = lyd_node_module(start);
+ prev_mod = lyd_node_module(start);
start = start->child;
} else {
for (; start->parent; start = start->parent);
- cur_module = lyd_node_module(start);
+ prev_mod = lyd_node_module(start);
}
while (1) {
@@ -2333,7 +2529,7 @@
return NULL;
}
} else {
- prefix_mod = cur_module;
+ prefix_mod = prev_mod;
}
if (prefix_mod != lyd_node_module(sibling)) {
continue;
@@ -2390,7 +2586,7 @@
++list_instance_position;
r = 0;
- ret = resolve_partial_json_data_list_predicate(id, name, sibling, list_instance_position, cur_module, &r);
+ ret = resolve_partial_json_data_list_predicate(id, name, sibling, list_instance_position, &r);
if (ret == -1) {
*parsed = -1;
return NULL;
@@ -2416,6 +2612,7 @@
return NULL;
}
last_match = sibling;
+ prev_mod = lyd_node_module(sibling);
start = sibling->child;
break;
}
@@ -2426,7 +2623,7 @@
return last_match;
}
- if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate)) < 1) {
+ if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate, NULL, 0)) < 1) {
LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
*parsed = -1;
return NULL;
@@ -3973,6 +4170,7 @@
int rc;
struct lys_node *sub;
struct lys_module *mod;
+ struct ly_set *set;
assert(aug);
mod = lys_main_module(aug->module);
@@ -3983,18 +4181,17 @@
/* it can already be resolved in case we returned EXIT_FAILURE from if block below */
if (!aug->target) {
/* resolve target node */
- rc = resolve_augment_schema_nodeid(aug->target_name, siblings, (siblings ? NULL : aug->module),
- (const struct lys_node **)&aug->target);
+ rc = resolve_schema_nodeid(aug->target_name, siblings, (siblings ? NULL : lys_node_module((struct lys_node *)aug)), &set, 0, 0);
if (rc == -1) {
- return -1;
- } else if (rc > 0) {
- LOGVAL(LYE_INCHAR, LY_VLOG_LYS, aug, aug->target_name[rc - 1], &aug->target_name[rc - 1]);
+ LOGVAL(LYE_PATH, LY_VLOG_LYS, aug);
return -1;
}
- if (!aug->target) {
+ if (!set) {
LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, aug, "augment", aug->target_name);
return EXIT_FAILURE;
}
+ aug->target = set->set.s[0];
+ ly_set_free(set);
}
/* check for mandatory nodes - if the target node is in another module
@@ -5016,7 +5213,7 @@
resolve_identref(struct lys_type *type, const char *ident_name, struct lyd_node *node, struct lys_module *mod, int dflt)
{
const char *mod_name, *name;
- int mod_name_len, rc, i, j;
+ int mod_name_len, nam_len, rc, i, j;
int make_implemented = 0;
unsigned int u;
struct lys_ident *der, *cur;
@@ -5028,7 +5225,7 @@
return NULL;
}
- rc = parse_node_identifier(ident_name, &mod_name, &mod_name_len, &name, NULL);
+ rc = parse_node_identifier(ident_name, &mod_name, &mod_name_len, &name, &nam_len, NULL, 0);
if (rc < 1) {
LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[-rc], &ident_name[-rc]);
return NULL;
@@ -7003,7 +7200,7 @@
}
/* find the first schema node */
- set = lys_find_xpath(sleaf, buf, 0);
+ set = lys_find_path(NULL, sleaf, buf);
if (!set || !set->number) {
free(buf);
ly_set_free(set);
@@ -7155,7 +7352,7 @@
*ret = NULL;
/* syntax was already checked, so just evaluate the path using standard XPath */
- set = lyd_find_xpath((struct lyd_node *)leaf, path);
+ set = lyd_find_path((struct lyd_node *)leaf, path);
if (!set) {
return -1;
}
diff --git a/src/resolve.h b/src/resolve.h
index 4df8c10..65c1348 100644
--- a/src/resolve.h
+++ b/src/resolve.h
@@ -143,7 +143,7 @@
int parse_identifier(const char *id);
int parse_schema_nodeid(const char *id, const char **mod_name, int *mod_name_len, const char **name, int *nam_len,
- int *is_relative, int *has_predicate);
+ int *is_relative, int *has_predicate, int *all_desc, int extended);
int parse_schema_json_predicate(const char *id, const char **mod_name, int *mod_name_len, const char **name,
int *nam_len, const char **value, int *val_len, int *has_predicate);
@@ -164,8 +164,8 @@
struct lyd_node *resolve_data_descendant_schema_nodeid(const char *nodeid, struct lyd_node *start);
-int resolve_augment_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_module *module,
- const struct lys_node **ret);
+int resolve_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_module *cur_module,
+ struct ly_set **ret, int extended, int no_node_error);
int resolve_descendant_schema_nodeid(const char *nodeid, const struct lys_node *start, int ret_nodetype,
int no_innerlist, const struct lys_node **ret);
@@ -237,7 +237,7 @@
void unres_data_del(struct unres_data *unres, uint32_t i);
int resolve_unres_data(struct unres_data *unres, struct lyd_node **root, int options);
-int schema_nodeid_siblingcheck(const struct lys_node *sibling, const char *id, const struct lys_module *module,
- const char *mod_name, int mod_name_len);
+int schema_nodeid_siblingcheck(const struct lys_node *sibling, const struct lys_module *cur_module,
+ const char *mod_name, int mod_name_len, const char *name, int nam_len);
#endif /* _RESOLVE_H */
diff --git a/src/tree_data.c b/src/tree_data.c
index 9a12c6a..b6e185f 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -1028,8 +1028,7 @@
}
static int
-lyd_new_path_list_predicate(struct lyd_node *list, const char *list_name, const char *predicate,
- const struct lys_module *cur_module, int *parsed)
+lyd_new_path_list_predicate(struct lyd_node *list, const char *list_name, const char *predicate, int *parsed)
{
const char *mod_name, *name, *value;
char *key_val;
@@ -1079,7 +1078,7 @@
*parsed += r;
predicate += r;
- if (!value || (!mod_name && strcmp(lys_node_module(key)->name, cur_module->name))
+ if (!value || (!mod_name && (lys_node_module(key) != lys_node_module((struct lys_node *)slist)))
|| (mod_name && (strncmp(lys_node_module(key)->name, mod_name, mod_name_len) || lys_node_module(key)->name[mod_name_len]))
|| strncmp(key->name, name, nam_len) || key->name[nam_len]) {
LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
@@ -1205,7 +1204,7 @@
struct lyd_node *ret = NULL, *node, *parent = NULL;
const struct lys_node *schild, *sparent, *tmp;
const struct lys_node_list *slist;
- const struct lys_module *cur_module;
+ const struct lys_module *module, *prev_mod;
int r, i, parsed = 0, mod_name_len, nam_len, val_name_len, val_len;
int is_relative = -1, has_predicate, first_iter = 1;
@@ -1246,7 +1245,7 @@
}
}
- if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate)) < 1) {
+ if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate, NULL, 0)) < 1) {
LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
return NULL;
}
@@ -1263,7 +1262,7 @@
parent = data_tree;
}
sparent = parent->schema;
- cur_module = lys_node_module(sparent);
+ module = prev_mod = lys_node_module(sparent);
} else {
/* we are starting from scratch, absolute path */
assert(!parent);
@@ -1284,7 +1283,7 @@
memmove(module_name, mod_name, mod_name_len);
module_name[mod_name_len] = '\0';
- cur_module = ly_ctx_get_module(ctx, module_name, NULL);
+ module = ly_ctx_get_module(ctx, module_name, NULL);
if (buf_backup) {
/* return previous internal buffer content */
@@ -1293,7 +1292,7 @@
}
ly_buf_used--;
- if (!cur_module) {
+ if (!module) {
str = strndup(path, (mod_name + mod_name_len) - path);
LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
free(str);
@@ -1301,6 +1300,7 @@
}
mod_name = NULL;
mod_name_len = 0;
+ prev_mod = module;
sparent = NULL;
}
@@ -1309,7 +1309,7 @@
while (1) {
/* find the schema node */
schild = NULL;
- while ((schild = lys_getnext(schild, sparent, cur_module, 0))) {
+ while ((schild = lys_getnext(schild, sparent, module, 0))) {
if (schild->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST
| LYS_ANYDATA | LYS_NOTIF | LYS_RPC | LYS_ACTION)) {
/* module comparison */
@@ -1318,7 +1318,7 @@
if (strncmp(node_mod_name, mod_name, mod_name_len) || node_mod_name[mod_name_len]) {
continue;
}
- } else if (lys_node_module(schild) != cur_module) {
+ } else if (lys_node_module(schild) != prev_mod) {
continue;
}
@@ -1453,8 +1453,7 @@
}
parsed = 0;
- if ((schild->nodetype == LYS_LIST) && has_predicate
- && lyd_new_path_list_predicate(node, name, id, cur_module, &parsed)) {
+ if ((schild->nodetype == LYS_LIST) && has_predicate && lyd_new_path_list_predicate(node, name, id, &parsed)) {
lyd_free(ret);
return NULL;
}
@@ -1474,9 +1473,10 @@
/* prepare for another iteration */
parent = node;
sparent = schild;
+ prev_mod = lys_node_module(schild);
/* parse another node */
- if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate)) < 1) {
+ if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate, NULL, 0)) < 1) {
LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
lyd_free(ret);
return NULL;
@@ -5035,7 +5035,7 @@
case LYS_CONTAINER:
if (last) {
/* find instance in the data */
- r = lyd_find_xpath(last, parent->name);
+ r = lyd_find_path(last, parent->name);
if (!r || r->number > 1) {
ly_set_free(r);
LOGINT;
@@ -5093,8 +5093,8 @@
return dflt;
}
-static char *
-_lyd_path(const struct lyd_node *node, int prefix_all)
+API char *
+lyd_path(const struct lyd_node *node)
{
char *buf_backup = NULL, *buf = ly_buf(), *result = NULL;
uint16_t index = LY_BUF_SIZE - 1;
@@ -5112,7 +5112,7 @@
/* build the path */
buf[index] = '\0';
- ly_vlog_build_path_reverse(LY_VLOG_LYD, node, buf, &index, prefix_all);
+ ly_vlog_build_path_reverse(LY_VLOG_LYD, node, buf, &index);
result = strdup(&buf[index]);
if (!result) {
LOGMEM;
@@ -5129,18 +5129,6 @@
return result;
}
-API char *
-lyd_path(const struct lyd_node *node)
-{
- return _lyd_path(node, 0);
-}
-
-API char *
-lyd_qualified_path(const struct lyd_node *node)
-{
- return _lyd_path(node, 1);
-}
-
static int
lyd_build_relative_data_path(const struct lys_module *module, const struct lyd_node *node, const char *schema_id,
char *buf)
@@ -5154,7 +5142,7 @@
schema = node->schema;
while (*schema_id) {
- if ((r = parse_schema_nodeid(schema_id, &mod_name, &mod_name_len, &name, &name_len, &is_relative, NULL)) < 1) {
+ if ((r = parse_schema_nodeid(schema_id, &mod_name, &mod_name_len, &name, &name_len, &is_relative, NULL, NULL, 0)) < 1) {
LOGINT;
return -1;
}
@@ -5162,17 +5150,14 @@
snode = NULL;
while ((snode = lys_getnext(snode, schema, NULL, LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE))) {
- /* name match */
- if (!strncmp(name, snode->name, name_len) && !snode->name[name_len]) {
- r = schema_nodeid_siblingcheck(snode, schema_id, module, mod_name, mod_name_len);
- if (r == 0 || r == 2) {
- schema = snode;
- break;
- } else if (r == 1) {
- continue;
- } else {
- return -1;
- }
+ r = schema_nodeid_siblingcheck(snode, module, mod_name, mod_name_len, name, name_len);
+ if (r == 0) {
+ schema = snode;
+ break;
+ } else if (r == 1) {
+ continue;
+ } else {
+ return -1;
}
}
/* no match */
@@ -5295,8 +5280,8 @@
idx1 = idx2 = LY_BUF_SIZE - 1;
path1[idx1] = '\0';
path2[idx2] = '\0';
- ly_vlog_build_path_reverse(LY_VLOG_LYD, first, path1, &idx1, 0);
- ly_vlog_build_path_reverse(LY_VLOG_LYD, second, path2, &idx2, 0);
+ ly_vlog_build_path_reverse(LY_VLOG_LYD, first, path1, &idx1);
+ ly_vlog_build_path_reverse(LY_VLOG_LYD, second, path2, &idx2);
/* use internal buffer to rebuild the unique string */
if (ly_buf_used && uniq_str[0]) {
@@ -5373,28 +5358,34 @@
}
API struct ly_set *
-lyd_find_xpath(const struct lyd_node *ctx_node, const char *expr)
+lyd_find_path(const struct lyd_node *ctx_node, const char *path)
{
struct lyxp_set xp_set;
struct ly_set *set;
+ char *yang_xpath;
uint16_t i;
- if (!ctx_node || !expr) {
+ if (!ctx_node || !path) {
ly_errno = LY_EINVAL;
return NULL;
}
+ /* transform JSON into YANG XPATH */
+ yang_xpath = transform_json2xpath(lyd_node_module(ctx_node), path);
+ if (!yang_xpath) {
+ return NULL;
+ }
+
memset(&xp_set, 0, sizeof xp_set);
- if (lyxp_eval(expr, ctx_node, LYXP_NODE_ELEM, lyd_node_module(ctx_node), &xp_set, 0) != EXIT_SUCCESS) {
+ if (lyxp_eval(yang_xpath, ctx_node, LYXP_NODE_ELEM, lyd_node_module(ctx_node), &xp_set, 0) != EXIT_SUCCESS) {
+ free(yang_xpath);
return NULL;
}
+ free(yang_xpath);
set = ly_set_new();
- if (!set) {
- LOGMEM;
- return NULL;
- }
+ LY_CHECK_ERR_RETURN(!set, LOGMEM, NULL);
if (xp_set.type == LYXP_SET_NODE_SET) {
for (i = 0; i < xp_set.used; ++i) {
diff --git a/src/tree_data.h b/src/tree_data.h
index 9519108..93bd6c9 100644
--- a/src/tree_data.h
+++ b/src/tree_data.h
@@ -378,7 +378,7 @@
/**@} diffoptions */
/**
- * @brief Build path (usable as XPath) of the data node.
+ * @brief Build data path (usable as path, see @ref howtoxpath) of the data node.
* @param[in] node Data node to be processed. Note that the node should be from a complete data tree, having a subtree
* (after using lyd_unlink()) can cause generating invalid paths.
* @return NULL on error, on success the buffer for the resulting path is allocated and caller is supposed to free it
@@ -387,16 +387,6 @@
char *lyd_path(const struct lyd_node *node);
/**
- * @brief Build path (usable as instance-identified) of the data node with all the nodes fully qualified (having their
- * model as prefix).
- * @param[in] node Data node to be processed. Note that the node should be from a complete data tree, having a subtree
- * (after using lyd_unlink()) can cause generating invalid paths.
- * @return NULL on error, on success the buffer for the resulting path is allocated and caller is supposed to free it
- * with free().
- */
-char *lyd_qualified_path(const struct lyd_node *node);
-
-/**
* @defgroup parseroptions Data parser options
* @ingroup datatree
*
@@ -784,13 +774,12 @@
* @param[in] data_tree Existing data tree to add to/modify. If creating RPCs/actions, there should only be one
* RPC/action and either input or output, not both. Can be NULL.
* @param[in] ctx Context to use. Mandatory if \p data_tree is NULL.
- * @param[in] path Simple absolute data XPath of the new node. It can contain only simple node addressing with optional
- * module names as prefixes. List nodes can have predicates, one for each list key in the correct order and
- * with its value as well or using specific instance position, leaves and leaf-lists can have predicates too that
- * have preference over \p value, see @ref howtoxpath.
+ * @param[in] path Simple data path (see @ref howtoxpath). List nodes can have predicates, one for each list key
+ * in the correct order and with its value as well or using specific instance position, leaves and leaf-lists
+ * can have predicates too that have preference over \p value.
* @param[in] value Value of the new leaf/lealf-list (const char*). If creating anydata or anyxml, the following
- * \p value_type parameter is required to be specified correctly. If creating nodes of other types, the
- * parameter is ignored.
+ * \p value_type parameter is required to be specified correctly. If creating nodes of other types, the
+ * parameter is ignored.
* @param[in] value_type Type of the provided \p value parameter in case of creating anydata or anyxml node.
* @param[in] options Bitmask of options flags, see @ref pathoptions.
* @return First created (or updated with #LYD_PATH_OPT_UPDATE) node,
@@ -1000,20 +989,16 @@
int lyd_schema_sort(struct lyd_node *sibling, int recursive);
/**
- * @brief Search in the given data for instances of nodes matching the provided XPath expression.
+ * @brief Search in the given data for instances of nodes matching the provided path.
*
- * The XPath expression is evaluated on data -> skip all non-data nodes (input, output, choice, case).
+ * Learn more about the path format on page @ref howtoxpath.
*
- * Expr examples:
- * "/modules-state/module[name = 'ietf-yang-library']/namespace" with context node "ietf-yang-library:modules-state"
- * "/ietf-netconf:get-config/ietf-netconf:source" with an arbitrary context node (all node names are prefixed)
- *
- * @param[in] ctx_node Context node.
- * @param[in] expr XPath expression filtering the matching nodes.
- * @return Set of found data nodes. If no nodes are matching \p expr or the result
+ * @param[in] ctx_node Path context node.
+ * @param[in] path Data path expression filtering the matching nodes.
+ * @return Set of found data nodes. If no nodes are matching \p path or the result
* would be a number, a string, or a boolean, the returned set is empty. In case of an error, NULL is returned.
*/
-struct ly_set *lyd_find_xpath(const struct lyd_node *ctx_node, const char *expr);
+struct ly_set *lyd_find_path(const struct lyd_node *ctx_node, const char *path);
/**
* @brief Search in the given data for instances of the provided schema node.
diff --git a/src/tree_schema.c b/src/tree_schema.c
index 2ca4352..9ceec0f 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -3843,65 +3843,6 @@
#endif
API struct ly_set *
-lys_find_xpath(const struct lys_node *ctx_node, const char *expr, int options)
-{
- struct lyxp_set set;
- struct ly_set *ret_set;
- uint32_t i;
- int opts;
-
- if (!ctx_node || !expr) {
- ly_errno = LY_EINVAL;
- return NULL;
- }
-
- memset(&set, 0, sizeof set);
-
- opts = LYXP_SNODE;
- if (options & LYS_FIND_OUTPUT) {
- opts |= LYXP_SNODE_OUTPUT;
- }
-
- if (lyxp_atomize(expr, ctx_node, LYXP_NODE_ELEM, &set, opts, NULL)) {
- /* just find a relevant node to put in path, if it fails, use the original one */
- for (i = 0; i < set.used; ++i) {
- if (set.val.snodes[i].in_ctx == 1) {
- ctx_node = set.val.snodes[i].snode;
- break;
- }
- }
- free(set.val.snodes);
- LOGVAL(LYE_SPEC, LY_VLOG_LYS, ctx_node, "Resolving XPath expression \"%s\" failed.", expr);
- return NULL;
- }
-
- ret_set = ly_set_new();
-
- for (i = 0; i < set.used; ++i) {
- if (!set.val.snodes[i].in_ctx) {
- continue;
- }
- assert(set.val.snodes[i].in_ctx == 1);
-
- switch (set.val.snodes[i].type) {
- case LYXP_NODE_ELEM:
- if (ly_set_add(ret_set, set.val.snodes[i].snode, LY_SET_OPT_USEASLIST) == -1) {
- ly_set_free(ret_set);
- free(set.val.snodes);
- return NULL;
- }
- break;
- default:
- /* ignore roots, text and attr should not ever appear */
- break;
- }
- }
-
- free(set.val.snodes);
- return ret_set;
-}
-
-API struct ly_set *
lys_xpath_atomize(const struct lys_node *ctx_node, enum lyxp_node_type ctx_node_type, const char *expr, int options)
{
struct lyxp_set set;
@@ -4140,6 +4081,7 @@
int ret;
char *parent_path;
struct lys_node *target = NULL, *parent;
+ struct ly_set *set;
if (!dev->deviate) {
return;
@@ -4178,12 +4120,16 @@
} else {
/* non-augment, non-toplevel */
parent_path = strndup(dev->target_name, strrchr(dev->target_name, '/') - dev->target_name);
- ret = resolve_augment_schema_nodeid(parent_path, NULL, module, (const struct lys_node **)&target);
+ ret = resolve_schema_nodeid(parent_path, NULL, module, &set, 0, 1);
free(parent_path);
- if (ret || !target) {
+ if (ret == -1) {
LOGINT;
+ ly_set_free(set);
return;
}
+ target = set->set.s[0];
+ ly_set_free(set);
+
lys_node_addchild(target, NULL, dev->orig_node);
}
} else {
@@ -4194,11 +4140,14 @@
dev->orig_node = NULL;
} else {
/* adding not-supported deviation */
- ret = resolve_augment_schema_nodeid(dev->target_name, NULL, module, (const struct lys_node **)&target);
- if (ret || !target) {
+ ret = resolve_schema_nodeid(dev->target_name, NULL, module, &set, 0, 1);
+ if (ret == -1) {
LOGINT;
+ ly_set_free(set);
return;
}
+ target = set->set.s[0];
+ ly_set_free(set);
/* unlink and store the original node */
parent = target->parent;
@@ -4212,11 +4161,14 @@
dev->orig_node = target;
}
} else {
- ret = resolve_augment_schema_nodeid(dev->target_name, NULL, module, (const struct lys_node **)&target);
- if (ret || !target) {
+ ret = resolve_schema_nodeid(dev->target_name, NULL, module, &set, 0, 1);
+ if (ret == -1) {
LOGINT;
+ ly_set_free(set);
return;
}
+ target = set->set.s[0];
+ ly_set_free(set);
lys_node_switch(target, dev->orig_node);
dev->orig_node = target;
@@ -4604,7 +4556,7 @@
/* build the path */
buf[index] = '\0';
- ly_vlog_build_path_reverse(LY_VLOG_LYS, node, buf, &index, 0);
+ ly_vlog_build_path_reverse(LY_VLOG_LYS, node, buf, &index);
result = strdup(&buf[index]);
if (!result) {
LOGMEM;
@@ -4621,6 +4573,59 @@
return result;
}
+API char *
+lys_data_path(const struct lys_node *node)
+{
+ char *buf_backup = NULL, *buf = ly_buf(), *result = NULL;
+ int i, used;
+ struct ly_set *set;
+ const struct lys_module *prev_mod;
+
+ if (!node) {
+ LOGERR(LY_EINVAL, "%s: NULL node parameter", __func__);
+ return NULL;
+ }
+
+ /* backup the shared internal buffer */
+ if (ly_buf_used && buf[0]) {
+ buf_backup = strndup(buf, LY_BUF_SIZE - 1);
+ }
+ ly_buf_used++;
+
+ set = ly_set_new();
+ LY_CHECK_ERR_GOTO(!set, LOGMEM, error);
+
+ while (node) {
+ ly_set_add(set, (void *)node, 0);
+ do {
+ node = lys_parent(node);
+ } while (node && (node->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE | LYS_INPUT | LYS_OUTPUT)));
+ }
+
+ prev_mod = NULL;
+ used = 0;
+ for (i = set->number - 1; i > -1; --i) {
+ node = set->set.s[i];
+ used += sprintf(buf + used, "/%s%s%s", (lys_node_module(node) == prev_mod ? "" : lys_node_module(node)->name),
+ (lys_node_module(node) == prev_mod ? "" : ":"), node->name);
+ prev_mod = lys_node_module(node);
+ }
+
+ result = strdup(buf);
+ LY_CHECK_ERR_GOTO(!result, LOGMEM, error);
+
+error:
+ ly_set_free(set);
+ /* restore the shared internal buffer */
+ if (buf_backup) {
+ strcpy(buf, buf_backup);
+ free(buf_backup);
+ }
+ ly_buf_used--;
+
+ return result;
+}
+
struct lys_node_augment *
lys_getnext_target_aug(struct lys_node_augment *last, const struct lys_module *mod, const struct lys_node *aug_target)
{
@@ -4674,6 +4679,24 @@
return NULL;
}
+API struct ly_set *
+lys_find_path(const struct lys_module *cur_module, const struct lys_node *cur_node, const char *path)
+{
+ struct ly_set *ret;
+ int rc;
+
+ if ((!cur_module && !cur_node) || !path) {
+ return NULL;
+ }
+
+ rc = resolve_schema_nodeid(path, cur_node, cur_module, &ret, 1, 1);
+ if (rc == -1) {
+ return NULL;
+ }
+
+ return ret;
+}
+
static void
lys_extcomplex_free_str(struct ly_ctx *ctx, struct lys_ext_instance_complex *ext, LY_STMT stmt)
{
diff --git a/src/tree_schema.h b/src/tree_schema.h
index fc0fc5f..4a296be 100644
--- a/src/tree_schema.h
+++ b/src/tree_schema.h
@@ -2102,21 +2102,18 @@
#define LYS_GETNEXT_PARENTUSES 0x80 /**< lys_getnext() option to allow parent to be #LYS_USES, in which case only the direct children are traversed */
/**
- * @brief Search for schema nodes matching the provided XPath expression.
+ * @brief Search for schema nodes matching the provided path.
*
- * XPath always requires a context node to be able to evaluate an expression because
- * non-prefixed node names will use its module prefix. However, if \p expr is absolute
- * and all the node names are prefixed, the context node can be an arbitrary node.
+ * Learn more about the path format at page @ref howtoxpath.
+ * Either \p cur_module or \p cur_node must be set.
*
- * @param[in] ctx_node Context schema node.
- * @param[in] expr XPath expression filtering the matching nodes.
- * @param[in] options Bitmask of LYS_FIND_* options.
- * @return Set of found schema nodes. If no nodes are matching \p expr or the result
- * would be a number, a string, or a boolean, the returned set is empty. In case of an error, NULL is returned.
+ * @param[in] cur_module Current module name.
+ * @param[in] cur_node Current (context) schema node.
+ * @param[in] path Schema path expression filtering the matching nodes.
+ * @return Set of found schema nodes. If no nodes are matching \p path the returned set is empty.
+ * In case of an error, NULL is returned.
*/
-struct ly_set *lys_find_xpath(const struct lys_node *ctx_node, const char *expr, int options);
-
-#define LYS_FIND_OUTPUT 0x01 /**< lys_find_xpath() option to search RPC output nodes instead input ones */
+struct ly_set *lys_find_path(const struct lys_module *cur_module, const struct lys_node *cur_node, const char *path);
/**
* @brief Types of context nodes, #LYXP_NODE_ROOT_CONFIG used only in when or must conditions.
@@ -2139,7 +2136,8 @@
* and then this node can be any node from the module (so, for example, do not put node added by an augment from another module).
* @param[in] ctx_node_type Context (current) schema node type. Most commonly is #LYXP_NODE_ELEM, but if
* your context node is supposed to be the root, you can specify what kind of root it is.
- * @param[in] expr XPath expression to be evaluated. Must be in JSON data format (prefixes are model names).
+ * @param[in] expr XPath expression to be evaluated. Must be in JSON data format (prefixes are model names). Otherwise
+ * follows must or when YANG expression syntax (XPath 1.0).
* @param[in] options Whether to apply some evaluation restrictions #LYXP_MUST or #LYXP_WHEN.
*
* @return Set of atoms (schema nodes), NULL on error.
@@ -2163,7 +2161,7 @@
#define LYXP_NO_LOCAL 0x02 /**< lys_node_xpath_atomize() option to discard schema node dependencies from the local subtree */
/**
- * @brief Build path (usable as XPath) of the schema node.
+ * @brief Build schema path (usable as path, see @ref howtoxpath) of the schema node.
* @param[in] node Schema node to be processed.
* @return NULL on error, on success the buffer for the resulting path is allocated and caller is supposed to free it
* with free().
@@ -2171,6 +2169,14 @@
char *lys_path(const struct lys_node *node);
/**
+ * @brief Build data path (usable as path, see @ref howtoxpath) of the schema node.
+ * @param[in] node Schema node to be processed.
+ * @return NULL on error, on success the buffer for the resulting path is allocated and caller is supposed to free it
+ * with free().
+ */
+char *lys_data_path(const struct lys_node *node);
+
+/**
* @brief Return parent node in the schema tree.
*
* In case of augmenting node, it returns the target tree node where the augmenting