diff --git a/apps/backend/backend_get.c b/apps/backend/backend_get.c index 14afe1de..f07a005b 100644 --- a/apps/backend/backend_get.c +++ b/apps/backend/backend_get.c @@ -656,6 +656,7 @@ get_list_pagination(clixon_handle h, int j; int ret; dispatcher_entry_t *htable = NULL; + cvec *wherens = NULL; // int extflag = 0; #ifdef LIST_PAGINATION_REMAINING cxobj *xcache; @@ -715,6 +716,8 @@ get_list_pagination(clixon_handle h, (where = xml_body(x)) != NULL){ if (strcmp(where, "unfiltered") == 0) where = NULL; + else if (xml_nsctx_node(x, &wherens) < 0) + goto done; } /* then the "sort-by" parameter (see Section 3.1.2) */ if ((x = xml_find_type(xe, NULL, "sort-by", CX_ELMNT)) != NULL){ @@ -907,6 +910,8 @@ get_list_pagination(clixon_handle h, ok: retval = 0; done: + if (wherens) + cvec_free(wherens); if (xvec) free(xvec); if (cbmsg) diff --git a/include/clixon_custom.h b/include/clixon_custom.h index ca386f7c..97248fda 100644 --- a/include/clixon_custom.h +++ b/include/clixon_custom.h @@ -214,3 +214,13 @@ * worse case an overwrite. */ #undef SYSTEM_ONLY_CONFIG_CANDIDATE_CLEAR + +/*! In full XPath namespace resolve, match even if namespace not resolved + * + * In the case of xpath lookup functions (eg xpath_vec_ctx) where nsc is defined, then + * matching with XML requires equal namespaces. + * However, some code is OK with the XPATH NSC being unresolved to NULL, even if the XML + * namespace is defined. + * This seems wrong and should be changed, but need further investigation + */ +#define XPATH_NS_ACCEPT_UNRESOLVED diff --git a/lib/clixon/clixon_debug.h b/lib/clixon/clixon_debug.h index 09efa745..c392fa98 100644 --- a/lib/clixon/clixon_debug.h +++ b/lib/clixon/clixon_debug.h @@ -153,7 +153,7 @@ static inline int clixon_debug_isset(unsigned n) } /* Is detail set ?, return detail level 0-7 */ -static inline int clixon_debug_detail() +static inline int clixon_debug_detail(void) { unsigned level = clixon_debug_get(); diff --git a/lib/clixon/clixon_xml_nsctx.h b/lib/clixon/clixon_xml_nsctx.h index 8e69e96a..1af9db8a 100644 --- a/lib/clixon/clixon_xml_nsctx.h +++ b/lib/clixon/clixon_xml_nsctx.h @@ -60,7 +60,7 @@ int xml_nsctx_node(cxobj *x, cvec **ncp); int xml_nsctx_yang(yang_stmt *yn, cvec **ncp); int xml_nsctx_yangspec(yang_stmt *yspec, cvec **ncp); int xml_nsctx_cbuf(cbuf *cb, cvec *nsc); -int xml2ns(cxobj *x, char *localname, char **ns); +int xml2ns(cxobj *x, char *prefix, char **ns); int xml2ns_recurse(cxobj *x); int xmlns_set(cxobj *x, char *prefix, char *ns); int xmlns_set_all(cxobj *x, cvec *nsc); diff --git a/lib/clixon/clixon_xpath.h b/lib/clixon/clixon_xpath.h index 8e1cc062..876a9988 100644 --- a/lib/clixon/clixon_xpath.h +++ b/lib/clixon/clixon_xpath.h @@ -134,7 +134,7 @@ int xpath_tree_eq(xpath_tree *xt1, xpath_tree *xt2, xpath_tree ***vec, size_t xpath_tree *xpath_tree_traverse(xpath_tree *xt, ...); int xpath_tree_free(xpath_tree *xs); int xpath_parse(const char *xpath, xpath_tree **xptree); -int xpath_vec_ctx(cxobj *xcur, cvec *nsc, const char *xpath, int localonly, xp_ctx **xrp); +int xpath_vec_ctx(cxobj *xcur, cvec *nsc, const char *xpath, int localonly, xp_ctx **xrp); int xpath_vec_bool(cxobj *xcur, cvec *nsc, const char *xpformat, ...) __attribute__ ((format (printf, 3, 4))); int xpath_vec_flag(cxobj *xcur, cvec *nsc, const char *xpformat, uint16_t flags, diff --git a/lib/clixon/clixon_xpath_ctx.h b/lib/clixon/clixon_xpath_ctx.h index 77d92cda..cfbd49d7 100644 --- a/lib/clixon/clixon_xpath_ctx.h +++ b/lib/clixon/clixon_xpath_ctx.h @@ -58,7 +58,9 @@ enum xp_objtype{ XT_STRING }; -/* Expression evaluation occurs with respect to a context. XSLT and XPointer specify how the +/*! XPath context and result + * + * Expression evaluation occurs with respect to a context. XSLT and XPointer specify how the * context is determined for XPath expressions used in XSLT and XPointer respectively. The * context consists of: * a node (the context node) diff --git a/lib/src/clixon_xpath.c b/lib/src/clixon_xpath.c index 99070fdd..69c080bf 100644 --- a/lib/src/clixon_xpath.c +++ b/lib/src/clixon_xpath.c @@ -60,7 +60,10 @@ * of the xpath-tree, which is context-dependent. * Best is to send it as a (read-only) parameter to the xp_eval family of functions * as an exlicit namespace context. - * + * 3) localonly flag refers to https://www.w3.org/TR/REC-xml-names/, where : + * PrefixedName ::= Prefix ':' LocalPart + * "localonly" means to skip the "Prefix" part, ie namespaces + * see nodetest_eval_node() for the semantics of prefix/namespace processing */ #ifdef HAVE_CONFIG_H #include "clixon_config.h" /* generated by config & autoconf */ @@ -328,8 +331,8 @@ xpath_tree2cbuf(xpath_tree *xs, cprintf(xcb, "%s", clicon_int2str(xpopmap, xs->xs_int)); break; case XP_PATHEXPR: - /* [19] PathExpr ::= | FilterExpr '/' RelativeLocationPath - | FilterExpr '//' RelativeLocationPath + /* [19] PathExpr ::= | FilterExpr '/' RelativeLocationPath + | FilterExpr '//' RelativeLocationPath */ if (xs->xs_s0) cprintf(xcb, "%s", xs->xs_s0); @@ -608,7 +611,7 @@ xpath_parse(const char *xpath, * @param[in] xcur XML-tree where to search * @param[in] nsc External XML namespace context, or NULL * @param[in] xpath String with XPath 1.0 syntax - * @param[in] localonly Skip prefix and namespace tests (non-standard) + * @param[in] localonly Skip prefix and namespace tests * @param[out] xrp Return XPath context * @retval 0 OK * @retval -1 Error diff --git a/lib/src/clixon_xpath_eval.c b/lib/src/clixon_xpath_eval.c index 5f8f5dd8..fecf8ce3 100644 --- a/lib/src/clixon_xpath_eval.c +++ b/lib/src/clixon_xpath_eval.c @@ -44,9 +44,9 @@ * select="/t:top/t:users/t:user[t:name='fred']"/> * * We need to add namespace context to the cpath tree, typically in eval. How do - * we do that? + * we do that? * One observation is that the namespace context is static, so it can not be a part - * of the xpath-tree, which is context-dependent. + * of the xpath-tree, which is context-dependent. * Best is to send it as a (read-only) parameter to the xp_eval family of functions * as an exlicit namespace context. * For that you need an API to get/set namespaces: clixon_xml_nscache.c? @@ -86,6 +86,7 @@ #include "clixon_xml_sort.h" #include "clixon_xml_nsctx.h" #include "clixon_xpath_ctx.h" +#include "clixon_string.h" #include "clixon_xpath.h" #include "clixon_xpath_optimize.h" #include "clixon_xpath_function.h" @@ -110,99 +111,148 @@ const map_str2int xpopmap[] = { {NULL, -1} }; -/*! Eval an XPath nodetest +/*! Eval an XPath nodetest with full namespace test * - * @retval 1 Match - * @retval 0 No match - * @retval -1 Error XXX: retval -1 not properly handled + * XML x -> prefix1 + name1 + * XPATH xs -> prefix2 + name2 + * Unless name2=*, if name1 != name2 -> fail + * Lookup(prefix1, XML) -> ns1 + * Lookup(prefix2, NSC) -> ns2 + * if ns1 = NULL -> fail + * if ns2 = NULL -> fail (see XPATH_NS_ACCEPT_UNRESOLVED) + * if ns1 = ns2 -> match + * otherwise fail + * @param[in] x XML sub-tree given by the the context node + * @param[in] xs XPath stack of type XP_NODE or XP_NODE_FN + * @param[in] nsc XML Namespace context as given by xpath_vec_ctx() + * @retval 1 Match + * @retval 0 No match + * @retval -1 Error */ static int -nodetest_eval_node(cxobj *x, - xpath_tree *xs, - cvec *nsc) +nodetest_eval_namespace(cxobj *x, + xpath_tree *xs, + cvec *nsc) { - int retval = -1; - char *name1 = xml_name(x); - char *prefix1 = xml_prefix(x); - char *nsxml = NULL; /* xml body namespace */ - char *nsxpath = NULL; /* xpath context namespace */ - char *prefix2 = NULL; - char *name2 = NULL; + int retval = -1; + char *name1; + char *prefix1; + char *prefix2; + char *name2; + char *ns1 = NULL; /* xml namespace */ + char *ns2 = NULL; /* xpath namespace */ - /* Namespaces is s0, name is s1 */ - if (strcmp(xs->xs_s1, "*")==0) - return 1; - /* get namespace of xml tree */ - if (xml2ns(x, prefix1, &nsxml) < 0) - goto done; + /* XML x -> prefix1 + name1 */ + prefix1 = xml_prefix(x); + name1 = xml_name(x); + /* XPATH xs -> prefix2 + name2 */ prefix2 = xs->xs_s0; name2 = xs->xs_s1; - /* Before going into namespaces, check name equality and filter out noteq */ - if (strcmp(name1, name2) != 0){ - retval = 0; /* no match */ + clixon_debug(CLIXON_DBG_XPATH | CLIXON_DBG_DETAIL, "%s %s", name1, name2); + if (strcmp(name2, "*") != 0){ + /* if name1 != name2 -> fail */ + if (strcmp(name1, name2) != 0) + goto fail; + } + /* get namespace of xml tree */ + if (xml2ns(x, prefix1, &ns1) < 0) goto done; - } - /* Here names are equal - * Now look for namespaces - * 1) prefix1 and prefix2 point to same namespace <<-- try this first - * 2) prefix1 is equal to prefix2 <<-- then try this - * (1) is strict yang xml - * (2) without yang - */ - if (nsc != NULL) { /* solution (1) */ - nsxpath = xml_nsctx_get(nsc, prefix2); - if (nsxml != NULL && nsxpath != NULL) - retval = (strcmp(nsxml, nsxpath) == 0); - else if (nsxpath == NULL){ - /* We have a namespace from xml, but none in yang. - * This can happen in eg augments and ../foo, where foo is - * augmented from another namespace - */ - retval = 1; - } - else - retval = (nsxml == nsxpath); /* True only if both are NULL */ - } - else{ /* solution (2) */ - if (prefix1 == NULL && prefix2 == NULL) - retval = 1; - else if (prefix1 == NULL || prefix2 == NULL) - retval = 0; - else - retval = strcmp(prefix1, prefix2) == 0; - } -#if 0 /* debugging */ - /* If retval == 0 here, then there is name match, but not ns match */ - if (retval == 0){ - fprintf(stderr, "%s NOMATCH xml: (%s)%s\n\t\t xpath: (%s)%s\n", __FUNCTION__, - name1, nsxml, - name2, nsxpath); - } + if (ns1 == NULL) + goto fail; + ns2 = xml_nsctx_get(nsc, prefix2); + if (ns2 == NULL){ +#ifdef XPATH_NS_ACCEPT_UNRESOLVED + goto ok; +#else + goto fail; #endif + } + else if (strcmp(ns1, ns2) != 0) + goto fail; +#ifdef XPATH_NS_ACCEPT_UNRESOLVED + ok: +#endif + retval = 1; done: /* retval set in preceding statement */ return retval; + fail: + retval = 0; + goto done; +} + +/*! Eval an XPath nodetest but skip namespace tests + * + * XML x -> prefix1 + name1 + * XPATH xs -> prefix2 + name2 + * Unless name2=*, if name1 != name2 -> fail + * if prefix1 and prefix2 are string-equal or both NULL -> match + * else -> fail + * @param[in] x XML node + * @param[in] xs XPath stack of type XP_NODE or XP_NODE_FN + * @retval 1 Match + * @retval 0 No match + * @retval -1 Error XXX: retval -1 not properly handled + */ +static int +nodetest_eval_prefixonly(cxobj *x, + xpath_tree *xs) +{ + int retval = -1; + char *name1; + char *prefix1; + char *prefix2; + char *name2; + int ret; + + /* XML x -> prefix1 + name1 */ + prefix1 = xml_prefix(x); + name1 = xml_name(x); + /* XPATH xs -> prefix2 + name2 */ + prefix2 = xs->xs_s0; + name2 = xs->xs_s1; + clixon_debug(CLIXON_DBG_XPATH | CLIXON_DBG_DETAIL, "%s:%s %s:%s", prefix1, name1, prefix2, name2); + if (strcmp(name2, "*") != 0){ + /* if name1 != name2 -> fail */ + if (strcmp(name1, name2) != 0) + goto fail; + } + ret = clicon_strcmp(prefix1, prefix2); + if (ret != 0) + goto fail; + retval = 1; + done: /* retval set in preceding statement */ + return retval; + fail: + retval = 0; + goto done; } /*! Eval an XPath nodetest but skip prefix and namespace tests * - * This is NOT according to standard + * If name2 = "*" -> match # A node test * is true for any node of the principal node type. + * If name1 = name2 -> match (string-equal or both NULL) + * @param[in] x XML node + * @param[in] xs XPath stack of type XP_NODE or XP_NODE_FN + * @retval 1 Match + * @retval 0 No match + * @retval -1 Error */ static int -nodetest_eval_node_localonly(cxobj *x, - xpath_tree *xs, - cvec *nsc) +nodetest_eval_localonly(cxobj *x, + xpath_tree *xs) { int retval = -1; - char *name1 = xml_name(x); - char *name2 = NULL; + char *name1; + char *name2; - /* Namespaces is s0, name is s1 */ - if (strcmp(xs->xs_s1, "*")==0){ + name1 = xml_name(x); + name2 = xs->xs_s1; + clixon_debug(CLIXON_DBG_XPATH | CLIXON_DBG_DETAIL, "%s %s", name1, name2); + if (strcmp(name2, "*")==0){ retval = 1; goto done; } - name2 = xs->xs_s1; - /* Before going into namespaces, check name equality and filter out noteq */ + /* Check name only */ if (strcmp(name1, name2) == 0){ retval = 1; goto done; @@ -219,7 +269,7 @@ nodetest_eval_node_localonly(cxobj *x, * @param[in] nsc XML Namespace context * @param[in] localonly Skip prefix and namespace tests (non-standard) * @retval 1 Match - * @retval 0 No match + * @retval 0 No match * @retval -1 Error * - node() is true for any node of any type whatsoever. * - text() is true for any text node. @@ -234,9 +284,11 @@ nodetest_eval(cxobj *x, if (xs->xs_type == XP_NODE){ if (localonly) - retval = nodetest_eval_node_localonly(x, xs, nsc); + retval = nodetest_eval_localonly(x, xs); + else if (nsc == NULL) + retval = nodetest_eval_prefixonly(x, xs); else - retval = nodetest_eval_node(x, xs, nsc); + retval = nodetest_eval_namespace(x, xs, nsc); } else if (xs->xs_type == XP_NODE_FN){ switch (xs->xs_int){ @@ -295,7 +347,7 @@ nodetest_recursive(cxobj *xn, retval = 0; *vec0 = vec; *vec0len = veclen; - done: + done: return retval; } @@ -309,7 +361,7 @@ nodetest_recursive(cxobj *xn, * @retval 0 OK * @retval -1 Error * - * - A node test that is a QName is true if and only if the type of the node (see [5 Data Model]) + * - A node test that is a QName is true if and only if the type of the node (see [5 Data Model]) * is the principal node type and has an expanded-name equal to the expanded-name specified by the QName. * - A node test * is true for any node of the principal node type. * - node() is true for any node of any type whatsoever. @@ -1019,7 +1071,7 @@ xp_relop(xp_ctx *xc1, break; default: clixon_err(OE_XML, 0, "Operator %s not supported for nodeset and string", clicon_int2str(xpopmap,op)); - goto done; + goto done; break; } if (xr->xc_bool) /* enough to find a single node */ @@ -1055,7 +1107,7 @@ xp_relop(xp_ctx *xc1, break; default: clixon_err(OE_XML, 0, "Operator %s not supported for nodeset and number", clicon_int2str(xpopmap,op)); - goto done; + goto done; break; } if (xr->xc_bool) /* enough to find a single node */ @@ -1203,7 +1255,7 @@ xp_eval(xp_ctx *xc, goto ok; break; case XPATHFN_DEREF: - if (xp_function_deref(xc, xs->xs_c0, nsc, localonly, xrp) < 0) + if (xp_function_deref(xc, xs->xs_c0, nsc, xrp) < 0) goto done; goto ok; break; @@ -1223,7 +1275,7 @@ xp_eval(xp_ctx *xc, goto ok; break; case XPATHFN_POSITION: - if (xp_function_position(xc, xs->xs_c0, nsc, localonly, xrp) < 0) + if (xp_function_position(xc, xs->xs_c0, nsc, xrp) < 0) goto done; goto ok; break; @@ -1288,12 +1340,12 @@ xp_eval(xp_ctx *xc, goto ok; break; case XPATHFN_TRUE: - if (xp_function_true(xc, xs->xs_c0, nsc, localonly, xrp) < 0) + if (xp_function_true(xc, xs->xs_c0, nsc, xrp) < 0) goto done; goto ok; break; case XPATHFN_FALSE: - if (xp_function_false(xc, xs->xs_c0, nsc, localonly, xrp) < 0) + if (xp_function_false(xc, xs->xs_c0, nsc, xrp) < 0) goto done; goto ok; break; diff --git a/lib/src/clixon_xpath_function.c b/lib/src/clixon_xpath_function.c index 2bd19473..9c661689 100644 --- a/lib/src/clixon_xpath_function.c +++ b/lib/src/clixon_xpath_function.c @@ -280,7 +280,6 @@ xp_function_re_match(xp_ctx *xc, * @param[in] xc0 Incoming context * @param[in] xs XPath node tree * @param[in] nsc XML Namespace context - * @param[in] localonly Skip prefix and namespace tests (non-standard) * @param[out] xrp Resulting context * @retval 0 OK * @retval -1 Error @@ -290,7 +289,6 @@ int xp_function_deref(xp_ctx *xc0, struct xpath_tree *xs, cvec *nsc, - int localonly, xp_ctx **xrp) { int retval = -1; @@ -587,7 +585,6 @@ xp_function_bit_is_set(xp_ctx *xc, * @param[in] xc Incoming context * @param[in] xs XPath node tree * @param[in] nsc XML Namespace context - * @param[in] localonly Skip prefix and namespace tests (non-standard) * @param[out] xrp Resulting context * @retval 0 OK * @retval -1 Error @@ -596,7 +593,6 @@ int xp_function_position(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, - int localonly, xp_ctx **xrp) { int retval = -1; @@ -1253,7 +1249,6 @@ int xp_function_true(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, - int localonly, xp_ctx **xrp) { int retval = -1; @@ -1280,7 +1275,6 @@ int xp_function_false(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, - int localonly, xp_ctx **xrp) { int retval = -1; diff --git a/lib/src/clixon_xpath_function.h b/lib/src/clixon_xpath_function.h index 64206eb0..9c883b86 100644 --- a/lib/src/clixon_xpath_function.h +++ b/lib/src/clixon_xpath_function.h @@ -95,10 +95,10 @@ const char *xp_fnname_int2str(enum clixon_xpath_function code); int xp_function_current(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, int localonly, xp_ctx **xrp); int xp_function_re_match(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, int localonly, xp_ctx **xrp); -int xp_function_deref(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, int localonly, xp_ctx **xrp); +int xp_function_deref(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, xp_ctx **xrp); int xp_function_derived_from(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, int localonly, int self, xp_ctx **xrp); int xp_function_bit_is_set(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, int localonly, xp_ctx **xrp); -int xp_function_position(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, int localonly, xp_ctx **xrp); +int xp_function_position(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, xp_ctx **xrp); int xp_function_count(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, int localonly, xp_ctx **xrp); int xp_function_name(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, int localonly, xp_ctx **xrp); int xp_function_string(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, int localonly, xp_ctx **xrp); @@ -109,7 +109,7 @@ int xp_function_string_length(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, int int xp_function_translate(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, int localonly, xp_ctx **xrp); int xp_function_boolean(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, int localonly, xp_ctx **xrp); int xp_function_not(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, int localonly, xp_ctx **xrp); -int xp_function_true(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, int localonly, xp_ctx **xrp); -int xp_function_false(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, int localonly, xp_ctx **xrp); +int xp_function_true(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, xp_ctx **xrp); +int xp_function_false(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, xp_ctx **xrp); #endif /* _CLIXON_XPATH_FUNCTION_H */ diff --git a/test/test_pagination_extra.sh b/test/test_pagination_extra.sh index da377bcd..0e3e5c5c 100755 --- a/test/test_pagination_extra.sh +++ b/test/test_pagination_extra.sh @@ -242,17 +242,17 @@ expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" " new "A.3.6.2. where, match on descendent string containing a substring" # bob, eric, alice, lin, joe # Confusing: all match -expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" ".[contains (email-address,'@example.com')]" "bob.*eric.*alice.*lin.*joe" +expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" ".[contains (es:email-address,'@example.com')]" "bob.*eric.*alice.*lin.*joe" new "A.3.6.3. where, match on decendent timestamp starting with a substring" # bob, eric, alice, joe, # starts-with NYI, replaced with contains # posts//post[starts-with(timestamp,'2020')] -expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "posts/post[contains(timestamp,'2020')]" "bob.*eric.*alice.*joe" +expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "es:posts/es:post[contains(es:timestamp,'2020')]" "bob.*eric.*alice.*joe" new "A.3.9.1. All six parameters at once" # eric, bob -expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "//post[contains(timestamp,'2020')]member-idbackwards22" "eric.*bob" +expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "//es:post[contains(es:timestamp,'2020')]member-idbackwards22" "eric.*bob" if [ $BE -ne 0 ]; then new "Kill backend" diff --git a/test/test_xpath.sh b/test/test_xpath.sh index 7224c010..be7ff841 100755 --- a/test/test_xpath.sh +++ b/test/test_xpath.sh @@ -447,7 +447,6 @@ new "xpath /root/*/*[.='111']" expecteof "$clixon_util_xpath -D $DBG -f $xml4 -p /root/*/*[.='111']" 0 "" "nodeset:0:1111:1112:111" # Try functionnames in place of node nc-names - new "xpath nodetest: node" expectpart "$($clixon_util_xpath -D $DBG -f $xmlfn -p "count(/root/count)")" 0 "number:1" diff --git a/test/test_xpath_crossref.sh b/test/test_xpath_crossref.sh new file mode 100755 index 00000000..68a0ed8a --- /dev/null +++ b/test/test_xpath_crossref.sh @@ -0,0 +1,214 @@ +#!/usr/bin/env bash +# XPath crossref tests +# Load datastrore XML as follows: +# 1. Without prefix +# 2. With canonical prefix +# 3. With non-canonical prefix +# Access using XPath: +# 1. Without prefix +# 2. With canonical prefix +# 3. With non-canonical prefix +# With namespace context: +# 1. Yes +# 2. No +# Magic line must be first in script (see README.md) +s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi + +: ${clixon_util_xpath:=clixon_util_xpath} + +# XML file (alt provide it in stdin after xpath) +xml1=$dir/xml1.xml +xml2=$dir/xml2.xml +xml3=$dir/xml3.xml + +fyang=$dir/clixon-example.yang + +cat < $fyang +module clixon-example { + yang-version 1.1; + namespace "urn:example:clixon"; + prefix ex; + container table1 { + description "1. Without prefix"; + list parameter { + key name; + leaf name { + type string; + } + } + } + container table2 { + description "2. With canonical prefix"; + list parameter { + key name; + leaf name { + type string; + } + } + } + container table3 { + description "3. With non-canonical prefix"; + list parameter { + key name; + leaf name { + type string; + } + } + } +} +EOF + +# +cat < $xml1 + + + A + + +EOF +cat < $xml2 + + + B + + +EOF +cat < $xml3 + + + C + + +EOF + +unset y +#-------------------------------------- Name only +prefix=xxx: +localonly="-L" +nsc= +xi=1 +xml=$dir/xml$xi.xml +new "Name only $xi" +expectpart "$($clixon_util_xpath -D $DBG -f $xml ${localonly} -p ${prefix}table$xi/${prefix}parameter $y $nsc)" 0 "nodeset:0:A" + +new "Name only $xi" +expectpart "$($clixon_util_xpath -D $DBG -f $xml ${localonly} -p ${prefix}table$xi/${prefix}xxx $y $nsc)" 0 "nodeset:$" + +xi=2 +xml=$dir/xml$xi.xml +new "Name only $xi" +expectpart "$($clixon_util_xpath -D $DBG -f $xml ${localonly} -p ${prefix}table$xi/${prefix}parameter $y $nsc)" 0 "nodeset:0:B" + +xi=3 +xml=$dir/xml$xi.xml +new "Name only $xi" +expectpart "$($clixon_util_xpath -D $DBG -f $xml ${localonly} -p ${prefix}table$xi/${prefix}parameter $y $nsc)" 0 "nodeset:0:C" + +#-------------------------------------- Prefix only +localonly= +nsc= + +xi=1 +xml=$dir/xml$xi.xml +unset prefix +new "Prefix only $xi prefix=$prefix" +expectpart "$($clixon_util_xpath -D $DBG -f $xml ${localonly} -p ${prefix}table$xi/${prefix}parameter $y $nsc)" 0 "nodeset:0:A" + +prefix=xe: +new "Prefix only $xi prefix=$prefix fail" +expectpart "$($clixon_util_xpath -D $DBG -f $xml ${localonly} -p ${prefix}table$xi/${prefix}parameter $y $nsc)" 0 "nodeset:$" + +xi=2 +xml=$dir/xml$xi.xml +unset prefix +new "Prefix only $xi prefix=$prefix" +expectpart "$($clixon_util_xpath -D $DBG -f $xml ${localonly} -p ${prefix}table$xi/${prefix}parameter $y $nsc)" 0 "nodeset:$" + +prefix=ex: +new "Prefix only $xi prefix=$prefix" +expectpart "$($clixon_util_xpath -D $DBG -f $xml ${localonly} -p ${prefix}table$xi/${prefix}parameter $y $nsc)" 0 "nodeset:0:B" + +prefix=xe: +new "Prefix only $xi prefix=$prefix" +expectpart "$($clixon_util_xpath -D $DBG -f $xml ${localonly} -p ${prefix}table$xi/${prefix}parameter $y $nsc)" 0 "nodeset:$" + +xi=3 +xml=$dir/xml$xi.xml +unset prefix +new "Prefix only $xi prefix=$prefix" +expectpart "$($clixon_util_xpath -D $DBG -f $xml ${localonly} -p ${prefix}table$xi/${prefix}parameter $y $nsc)" 0 "nodeset:$" + +prefix=ex: +new "Prefix only $xi prefix=$prefix" +expectpart "$($clixon_util_xpath -D $DBG -f $xml ${localonly} -p ${prefix}table$xi/${prefix}parameter $y $nsc)" 0 "nodeset:$" + +prefix=xe: +new "Prefix only $xi prefix=$prefix" +expectpart "$($clixon_util_xpath -D $DBG -f $xml ${localonly} -p ${prefix}table$xi/${prefix}parameter $y $nsc)" 0 "nodeset:0:C" + +#-------------------------------------- Namespace +localonly= +nsc="-n null:urn:example:clixon" +xi=1 +xml=$dir/xml$xi.xml +prefix= +new "Namespace $xi prefix=$prefix nsc=$nsc" +expectpart "$($clixon_util_xpath -D $DBG -f $xml ${localonly} -p ${prefix}table$xi/${prefix}parameter $y $nsc)" 0 "nodeset:0:A" + +nsc="-n m:urn:example:clixon" +prefix=m: +new "Namespace $xi prefix=$prefix nsc=$nsc" +expectpart "$($clixon_util_xpath -D $DBG -f $xml ${localonly} -p ${prefix}table$xi/${prefix}parameter $y $nsc)" 0 "nodeset:0:A" + +if false; then # SEE XPATH_NS_ACCEPT_UNRESOLVED + nsc="-n n:urn:example:clixon" + prefix=m: + new "Namespace $xi prefix=$prefix nsc=$nsc" + #echo "$clixon_util_xpath -D $DBG -f $xml ${localonly} -p ${prefix}table$xi/${prefix}parameter $y $nsc" + expectpart "$($clixon_util_xpath -D $DBG -f $xml ${localonly} -p ${prefix}table$xi/${prefix}parameter $y $nsc)" 0 "nodeset:$" +fi + +xi=2 +xml=$dir/xml$xi.xml + +nsc="-n null:urn:example:clixon" +prefix= +new "Namespace $xi prefix=$prefix nsc=$nsc" +expectpart "$($clixon_util_xpath -D $DBG -f $xml ${localonly} -p ${prefix}table$xi/${prefix}parameter $y $nsc)" 0 "nodeset:0:B" + +nsc="-n ex:urn:example:clixon" +prefix=ex: +new "Namespace $xi prefix=$prefix nsc=$nsc" +expectpart "$($clixon_util_xpath -D $DBG -f $xml ${localonly} -p ${prefix}table$xi/${prefix}parameter $y $nsc)" 0 "nodeset:0:B" + +nsc="-n xe:urn:example:clixon" +prefix=xe: +new "Namespace $xi prefix=$prefix nsc=$nsc" +expectpart "$($clixon_util_xpath -D $DBG -f $xml ${localonly} -p ${prefix}table$xi/${prefix}parameter $y $nsc)" 0 "nodeset:0:B" + +nsc="-n xe:urn:example:xxx" +prefix=xe: +new "Namespace $xi prefix=$prefix nsc=$nsc" +expectpart "$($clixon_util_xpath -D $DBG -f $xml ${localonly} -p ${prefix}table$xi/${prefix}parameter $y $nsc)" 0 "nodeset:$" + +xi=3 +xml=$dir/xml$xi.xml +nsc="-n null:urn:example:clixon" +prefix= +new "Namespace $xi prefix=$prefix nsc=$nsc" +expectpart "$($clixon_util_xpath -D $DBG -f $xml ${localonly} -p ${prefix}table$xi/${prefix}parameter $y $nsc)" 0 "nodeset:0:C" + +nsc="-n ex:urn:example:clixon" +prefix=ex: +new "Namespace $xi prefix=$prefix nsc=$nsc" +expectpart "$($clixon_util_xpath -D $DBG -f $xml ${localonly} -p ${prefix}table$xi/${prefix}parameter $y $nsc)" 0 "nodeset:0:C" + +nsc="-n xe:urn:example:clixon" +prefix=xe: +new "Namespace $xi prefix=$prefix nsc=$nsc" +expectpart "$($clixon_util_xpath -D $DBG -f $xml ${localonly} -p ${prefix}table$xi/${prefix}parameter $y $nsc)" 0 "nodeset:0:C" + +rm -rf $dir + +new "endtest" +endtest