diff --git a/CHANGELOG.md b/CHANGELOG.md index 0cfa055e..45eae3fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,9 +3,11 @@ ## 3.7.0 (Upcoming) ### Major changes: -* Full support of XPATH 1.0 according to https://www.w3.org/TR/xpath-10 using yacc/lex - * The previous XPATH imlementation was very restricted. - * The only function implemented is the Yang extension "current()". No other functions are implemented (eg last(), count()). +* Much better support for XPATH 1.0 according to https://www.w3.org/TR/xpath-10 using yacc/lex + * NOTE: Due to an error in the previous implementation, all XPATH calls on the form `x[a=str]` where `str` is a string (not a number or XML symbol), must be changed to: `x[a='str'] or x[a="str"]` + * This includes all calls to `xpath_vec, xpath_first`, etc. + * All calls to cli_copy_config in CLI spec files must replace 2nd argument from `x[%s=%s]` to `x[%s='%s']` + * The old API is stillenabled. To define the new, define XPATH_USE_NEW in include/clixon_custom.h and recompile * Conformance of restconf(RFC-8040) operations where prefix was used instead of module name. * Proper specification for an operation is POST /restconf/operations/: HTTP/1.1 * See https://github.com/clicon/clixon/issues/31, https://github.com/clicon/clixon/pull/32 and https://github.com/clicon/clixon/issues/30 diff --git a/apps/backend/backend_client.c b/apps/backend/backend_client.c index e917f75d..19184c46 100644 --- a/apps/backend/backend_client.c +++ b/apps/backend/backend_client.c @@ -985,7 +985,13 @@ nacm_access(clicon_handle h, if (username == NULL) goto step10; /* User's group */ - if (xpath_vec(xacm, "groups/group[user-name=%s]", &gvec, &glen, username) < 0) + if (xpath_vec(xacm, +#ifdef XPATH_USE_NEW + "groups/group[user-name='%s']", +#else + "groups/group[user-name=%s]", +#endif + &gvec, &glen, username) < 0) goto done; /* 5. If no groups are found, continue with step 10. */ if (glen == 0) @@ -1002,7 +1008,13 @@ nacm_access(clicon_handle h, for (j=0; j to , cli_copy_config("candidate", "/sender[%s=%s]", "from", "n1", "n2"); + * copy snd to , cli_copy_config("candidate", "/sender[%s='%s']", "from", "n1", "n2"); * cli command: * copy snd from to to * @endcode @@ -1244,17 +1244,34 @@ cli_copy_config(clicon_handle h, clicon_err(OE_PLUGIN, errno, "cbuf_new"); goto done; } - /* Sanity check that xpath contains exactly one %s */ + /* Sanity check that xpath contains exactly two %s, ie [%s='%s'] */ j = 0; - for (i=0; i ^/interface/eth0/address/.*$ - --> /interface/[name=eth0]/address + --> /interface/[name="eth0"]/address */ if (api_path_fmt2xpath(api_path_fmt, cvv, &xpath) < 0) goto done; @@ -417,10 +417,10 @@ show_yang(clicon_handle h, * Format of argv: * "running"|"candidate"|"startup" * "text"|"xml"|"json"|"cli"|"netconf" (see format_enum) - * xpath expression, that may contain one %, eg "/sender[name=%s]" + * xpath expression, that may contain one %, eg "/sender[name="%s"]" * optional name of variable in cvv. If set, xpath must have a '%s' * @code - * show config id , cli_show_config("running","xml","iface[name=%s]","n"); + * show config id , cli_show_config("running","xml","iface[name="%s"]","n"); * @endcode */ int diff --git a/apps/netconf/netconf_hello.c b/apps/netconf/netconf_hello.c index 833a1c5c..9fc0c2c2 100644 --- a/apps/netconf/netconf_hello.c +++ b/apps/netconf/netconf_hello.c @@ -82,12 +82,15 @@ static int netconf_hello(cxobj *xn) { +#ifdef nyi cxobj *x; x = NULL; + while ((x = xpath_each(xn, "//capability", x)) != NULL) { - //fprintf(stderr, "cap: %s\n", xml_body(x)); + } +#endif return 0; } diff --git a/apps/restconf/restconf_methods.c b/apps/restconf/restconf_methods.c index 62580cd6..d75dafd9 100644 --- a/apps/restconf/restconf_methods.c +++ b/apps/restconf/restconf_methods.c @@ -95,6 +95,9 @@ Mapping netconf error-tag -> status code */ +#ifdef HAVE_CONFIG_H +#include "clixon_config.h" /* generated by config & autoconf */ +#endif #include #include #include diff --git a/datastore/keyvalue/clixon_keyvalue.c b/datastore/keyvalue/clixon_keyvalue.c index aa529477..4e77418d 100644 --- a/datastore/keyvalue/clixon_keyvalue.c +++ b/datastore/keyvalue/clixon_keyvalue.c @@ -64,7 +64,7 @@ * * Alternative for xmlkeyfmt would be eg: * RESTCONF: /interfaces/interface=%s/ipv4/address/ip=%s (used) - * XPATH: /interfaces/interface[name=%s]/ipv4/address/[ip=%s] + * XPATH: /interfaces/interface[name='%s']/ipv4/address/[ip'=%s'] * * Paths through the code (for coverage) * cli_callback_generate +----------------+ @@ -375,7 +375,7 @@ get(char *dbname, arg = valvec[j++]; if (uri_percent_decode(arg, &argdec) < 0) goto done; - cprintf(cb, "[%s=%s]", cv_string_get(cvi), argdec); + cprintf(cb, "[%s='%s']", cv_string_get(cvi), argdec); free(argdec); argdec=NULL; } diff --git a/example/example_cli.c b/example/example_cli.c index 35aa6b25..5248eef4 100644 --- a/example/example_cli.c +++ b/example/example_cli.c @@ -67,7 +67,12 @@ mycallback(clicon_handle h, cvec *cvv, cvec *argv) cli_output(stderr, "arg = %s\n", cv_string_get(cvec_i(argv,0))); /* get string value */ /* Show eth0 interfaces config using XPATH */ - if (clicon_rpc_get_config(h, "running","/interfaces/interface[name=eth0]", + if (clicon_rpc_get_config(h, "running", +#ifdef XPATH_USE_NEW + "/interfaces/interface[name='eth0']", +#else + "/interfaces/interface[name=eth0]", +#endif &xret) < 0) goto done; diff --git a/example/example_cli.cli b/example/example_cli.cli index 1040f834..3703e8ba 100644 --- a/example/example_cli.cli +++ b/example/example_cli.cli @@ -24,7 +24,7 @@ debug("Debugging parts of the system"), cli_debug_cli((int32)1);{ } copy("Copy and create a new object") { interface("Copy interface"){ - ("name of interface to copy from") to("Copy to interface") ("Name of interface to copy to"), cli_copy_config("candidate","//interface[%s=%s]","name","name","toname"); + ("name of interface to copy from") to("Copy to interface") ("Name of interface to copy to"), cli_copy_config("candidate","//interface[%s='%s']","name","name","toname"); } } discard("Discard edits (rollback 0)"), discard_changes(); diff --git a/include/clixon_custom.h b/include/clixon_custom.h index d95ce399..2afb9606 100644 --- a/include/clixon_custom.h +++ b/include/clixon_custom.h @@ -55,3 +55,8 @@ int strverscmp (__const char *__s1, __const char *__s2); /* Full xmlns validation check is made only if XML has associated YANG spec */ #define XMLNS_YANG_ONLY 1 + +/* Set if you want all old xpath functions in clixon_xsl.* to use the new + * xpath functions in clixon_xpath.* +*/ +#undef XPATH_USE_NEW diff --git a/lib/clixon/clixon.h.in b/lib/clixon/clixon.h.in index 25cc653c..dfa82bc4 100644 --- a/lib/clixon/clixon.h.in +++ b/lib/clixon/clixon.h.in @@ -81,9 +81,9 @@ #include #include #include +#include #include #include -#include #include #include diff --git a/lib/clixon/clixon_xpath.h b/lib/clixon/clixon_xpath.h index c045237d..0c0c6769 100644 --- a/lib/clixon/clixon_xpath.h +++ b/lib/clixon/clixon_xpath.h @@ -85,11 +85,30 @@ extern const map_str2int xpopmap[]; */ #if defined(__GNUC__) && __GNUC__ >= 3 int xpath_vec_nodeset(cxobj *xcur, char *format, cxobj ***vec, size_t *veclen, ...) __attribute__ ((format (printf, 2, 5))); +int xpath_vec_nodeset_flag(cxobj *xcur, char *format, uint16_t flags, + cxobj ***vec, size_t *veclen, ...) __attribute__ ((format (printf, 2, 6))); +cxobj *xpath_first_nodeset(cxobj *xcur, char *format, ...) __attribute__ ((format (printf, 2, 3))); int xpath_vec_bool(cxobj *xcur, char *format, ...) __attribute__ ((format (printf, 2, 3))); + #else int xpath_vec_nodeset(cxobj *xcur, char *format, cxobj ***vec, size_t *veclen, ...); +int xpath_vec_nodeset_flag(cxobj *xcur, char *format, uint16_t flags, + cxobj ***vec, size_t *veclen, ...); +cxobj *xpath_first_nodeset(cxobj *xcur, char *format, ...); int xpath_vec_bool(cxobj *xcur, char *format, ...); + #endif int xpath_vec_ctx(cxobj *xcur, char *xpath, xp_ctx **xrp); +/* backward compatible */ +#ifdef XPATH_USE_NEW +#define xpath_first(cxtop, format, args...) xpath_first_nodeset(cxtop, format, ##args) +#define xpath_vec(cxtop, format, vec, veclen, args...) xpath_vec_nodeset(cxtop, format, vec, veclen, ##args) +#define xpath_vec_flag(cxtop, format, flags, vec, veclen, args...) xpath_vec_nodeset_flag(cxtop, format, flags, vec, veclen, ##args) +#else +#define xpath_first(cxtop, format, args...) xpath_first_xsl(cxtop, format, ##args) +#define xpath_vec(cxtop, format, vec, veclen, args...) xpath_vec_xsl(cxtop, format, vec, veclen, ##args) +#define xpath_vec_flag(cxtop, format, flags, vec, veclen, args...) xpath_vec_flag_xsl(cxtop, format, flags, vec, veclen, ##args) +#endif + #endif /* _CLIXON_XPATH_H */ diff --git a/lib/clixon/clixon_xsl.h b/lib/clixon/clixon_xsl.h index 3499cc97..2f19623d 100644 --- a/lib/clixon/clixon_xsl.h +++ b/lib/clixon/clixon_xsl.h @@ -40,16 +40,17 @@ * Prototypes */ #if defined(__GNUC__) && __GNUC__ >= 3 -cxobj *xpath_first(cxobj *cxtop, char *format, ...) __attribute__ ((format (printf, 2, 3))); -int xpath_vec(cxobj *cxtop, char *format, cxobj ***vec, size_t *veclen, ...) __attribute__ ((format (printf, 2, 5))); +cxobj *xpath_first_xsl(cxobj *cxtop, char *format, ...) __attribute__ ((format (printf, 2, 3))); +int xpath_vec_xsl(cxobj *cxtop, char *format, cxobj ***vec, size_t *veclen, ...) __attribute__ ((format (printf, 2, 5))); int xpath_vec_flag(cxobj *cxtop, char *format, uint16_t flags, cxobj ***vec, size_t *veclen, ...) __attribute__ ((format (printf, 2, 6))); #else -cxobj *xpath_first(cxobj *cxtop, char *format, ...); -int xpath_vec(cxobj *cxtop, char *format, cxobj ***vec, size_t *veclen, ...); -int xpath_vec_flag(cxobj *cxtop, char *xpath, uint16_t flags, +cxobj *xpath_first_xsl(cxobj *cxtop, char *format, ...); +int xpath_vec_xsl(cxobj *cxtop, char *format, cxobj ***vec, size_t *veclen, ...); +int xpath_vec_flag_xsl(cxobj *cxtop, char *xpath, uint16_t flags, cxobj ***vec, size_t *veclen, ...); #endif cxobj *xpath_each(cxobj *xn_top, char *xpath, cxobj *prev); + #endif /* _CLIXON_XSL_H */ diff --git a/lib/src/clixon_json.c b/lib/src/clixon_json.c index 38418def..794b35f2 100644 --- a/lib/src/clixon_json.c +++ b/lib/src/clixon_json.c @@ -774,7 +774,7 @@ json_parse_file(int fd, /* * Turn this on to get a json parse and pretty print test program - * Usage: xpath + * Usage: json * read json from input * Example compile: gcc -g -o json -I. -I../clixon ./clixon_json.c -lclixon -lcligen diff --git a/lib/src/clixon_options.c b/lib/src/clixon_options.c index 61c8e828..cfd0d76c 100644 --- a/lib/src/clixon_options.c +++ b/lib/src/clixon_options.c @@ -68,6 +68,8 @@ #include "clixon_xml.h" #include "clixon_plugin.h" #include "clixon_xsl.h" +#include "clixon_xpath_ctx.h" +#include "clixon_xpath.h" #include "clixon_xml_map.h" /* Mapping between Clicon startup modes string <--> constants, diff --git a/lib/src/clixon_proto_client.c b/lib/src/clixon_proto_client.c index 7e255208..35c4b28c 100644 --- a/lib/src/clixon_proto_client.c +++ b/lib/src/clixon_proto_client.c @@ -65,6 +65,9 @@ #include "clixon_xml.h" #include "clixon_plugin.h" #include "clixon_xsl.h" +#include "clixon_string.h" +#include "clixon_xpath_ctx.h" +#include "clixon_xpath.h" #include "clixon_proto.h" #include "clixon_err.h" #include "clixon_proto_client.h" diff --git a/lib/src/clixon_xml_map.c b/lib/src/clixon_xml_map.c index 2b21b174..08015a59 100644 --- a/lib/src/clixon_xml_map.c +++ b/lib/src/clixon_xml_map.c @@ -83,6 +83,8 @@ #include "clixon_options.h" #include "clixon_xml.h" #include "clixon_plugin.h" +#include "clixon_xpath_ctx.h" +#include "clixon_xpath.h" #include "clixon_xsl.h" #include "clixon_log.h" #include "clixon_err.h" @@ -439,7 +441,7 @@ xml_yang_validate_all(cxobj *xt, case Y_LEAF_LIST: /* Special case if leaf is leafref, then first check against current xml tree - */ + */ if ((yc = yang_find((yang_node*)ys, Y_TYPE, NULL)) != NULL){ if (strcmp(yc->ys_argument, "leafref") == 0){ if (validate_leafref(xt, yc) < 0) @@ -995,7 +997,7 @@ api_path_fmt2api_path(char *api_path_fmt, * @example * api_path_fmt: /interface/%s/address/%s * cvv: name=eth0 - * xpath: /interface/[name=eth0]/address + * xpath: /interface/[name='eth0']/address * @example * api_path_fmt: /ip/me/%s (if key) * cvv: - @@ -1038,7 +1040,13 @@ api_path_fmt2xpath(char *api_path_fmt, clicon_err(OE_UNIX, errno, "cv2str_dup"); goto done; } - cprintf(cb, "[%s=%s]", cv_name_get(cv), str); + cprintf(cb, +#ifdef XPATH_USE_NEW + "[%s='%s']", +#else + "[%s=%s]", +#endif + cv_name_get(cv), str); free(str); } } @@ -1455,7 +1463,13 @@ api_path2xpath_cvv(yang_spec *yspec, cprintf(xpath, "/%s", name); v = val; while ((cvi = cvec_each(cvk, cvi)) != NULL){ - cprintf(xpath, "[%s=%s]", cv_string_get(cvi), v); + cprintf(xpath, +#ifdef XPATH_USE_NEW + "[%s='%s']", +#else + "[%s=%s]", +#endif + cv_string_get(cvi), v); v += strlen(v)+1; } if (val) diff --git a/lib/src/clixon_xpath.c b/lib/src/clixon_xpath.c index 96825c7d..8e5d310a 100644 --- a/lib/src/clixon_xpath.c +++ b/lib/src/clixon_xpath.c @@ -33,6 +33,10 @@ * Clixon XML XPATH 1.0 according to https://www.w3.org/TR/xpath-10 */ +#ifdef HAVE_CONFIG_H +#include "clixon_config.h" /* generated by config & autoconf */ +#endif + #include #include #include @@ -246,16 +250,15 @@ xp_eval_step(xp_ctx *xc0, xpath_tree *xs, xp_ctx **xrp) { - int retval = -1; - int i; - cxobj *x; - cxobj *xv; - cxobj *xp; - cxobj **vec = NULL; - size_t veclen = 0; - xpath_tree *nodetest = xs->xs_c0; - xp_ctx *xr0 = NULL; - xp_ctx *xc = NULL; + int retval = -1; + int i; + cxobj *x; + cxobj *xv; + cxobj *xp; + cxobj **vec = NULL; + size_t veclen = 0; + xpath_tree *nodetest = xs->xs_c0; + xp_ctx *xc = NULL; /* Create new xc */ if ((xc = ctx_dup(xc0)) == NULL) @@ -312,16 +315,14 @@ xp_eval_step(xp_ctx *xc0, case A_NAMESPACE: /* principal node type is namespace */ break; case A_PARENT: - if ((xr0 = malloc(sizeof(*xr0))) == NULL){ - clicon_err(OE_UNIX, errno, "malloc"); - goto done; - } - memset(xr0, 0, sizeof(*xr0)); - xr0->xc_initial = xc->xc_initial; - for (i=0; ixc_size; i++){ - x = xc->xc_nodeset[i]; + veclen = xc->xc_size; + vec = xc->xc_nodeset; + xc->xc_size = 0; + xc->xc_nodeset = NULL; + for (i=0; ixc_nodeset, &xr0->xc_size) < 0) + if (cxvec_append(xp, &xc->xc_nodeset, &xc->xc_size) < 0) goto done; } break; @@ -330,19 +331,20 @@ xp_eval_step(xp_ctx *xc0, case A_PRECEEDING_SIBLING: break; case A_SELF: - xr0 = ctx_dup(xc); break; default: clicon_err(OE_XML, 0, "No such axisname: %d", xs->xs_int); goto done; break; } - if (xr0) - *xrp = xr0; if (xs->xs_c1){ if (xp_eval(xc, xs->xs_c1, xrp) < 0) goto done; } + else{ + *xrp = xc; + xc = NULL; + } assert(*xrp); retval = 0; done: @@ -623,8 +625,8 @@ xp_relop(xp_ctx *xc1, if (xc1->xc_type == xc2->xc_type){ /* cases (2-3) above */ switch (xc1->xc_type){ case XT_NODESET: - /* If both are node-sets, then it is true iff the string value of a - node in the first node-set and in the second node-set is true */ + /* If both are node-sets, then it is true iff the string value of one + node in the first node-set and one in the second node-set is true */ for (i=0; ixc_size; i++){ if ((s1 = xml_body(xc1->xc_nodeset[i])) == NULL){ xr->xc_bool = 0; @@ -658,8 +660,12 @@ xp_relop(xp_ctx *xc1, clicon_err(OE_XML, 0, "Operator %s not supported for nodeset/nodeset comparison", clicon_int2str(xpopmap,op)); goto done; break; - } + } + if (xr->xc_bool) /* enough to find a single node */ + break; } + if (xr->xc_bool) /* enough to find a single node */ + break; } break; case XT_BOOL: @@ -711,10 +717,10 @@ xp_relop(xp_ctx *xc1, if there is a node in the node-set such that the result of performing the comparison on the string-value of the node and the other string is true.*/ + s2 = xc2->xc_string; for (i=0; ixc_size; i++){ x = xc1->xc_nodeset[i]; /* node in nodeset */ s1 = xml_body(x); - s2 = xc2->xc_string; switch(op){ case XO_EQ: xr->xc_bool = (strcmp(s1, s2)==0); @@ -727,6 +733,8 @@ xp_relop(xp_ctx *xc1, goto done; break; } + if (xr->xc_bool) /* enough to find a single node */ + break; } break; case XT_NUMBER: @@ -759,6 +767,8 @@ xp_relop(xp_ctx *xc1, goto done; break; } + if (xr->xc_bool) /* enough to find a single node */ + break; } break; default: @@ -862,7 +872,7 @@ xp_eval(xp_ctx *xc, x = xc->xc_node; while (xml_parent(x) != NULL) x = xml_parent(x); - // xc->xc_node = x; + xc->xc_node = x; xc->xc_nodeset[0] = x; xc->xc_size=1; /* // is short for /descendant-or-self::node()/ */ @@ -921,7 +931,6 @@ xp_eval(xp_ctx *xc, while ((x = xml_child_each(xc->xc_node, x, CX_ELMNT)) != NULL) { if (cxvec_append(x, &xr0->xc_nodeset, &xr0->xc_size) < 0) goto done; - break; } } break; @@ -1027,7 +1036,6 @@ xp_eval(xp_ctx *xc, } /*! Given XML tree and xpath, returns xpath context - * @param[in] xcur XML-tree where to search * @param[in] xpath String with XPATH 1.0 syntax * @param[out] xrp Return XPATH context @@ -1081,6 +1089,45 @@ xpath_vec_ctx(cxobj *xcur, return retval; } +cxobj * +xpath_first_nodeset(cxobj *xcur, + char *format, + ...) +{ + cxobj *cx = NULL; + va_list ap; + size_t len; + char *xpath = NULL; + xp_ctx *xr = NULL; + + va_start(ap, format); + len = vsnprintf(NULL, 0, format, ap); + va_end(ap); + /* allocate a message string exactly fitting the message length */ + if ((xpath = malloc(len+1)) == NULL){ + clicon_err(OE_UNIX, errno, "malloc"); + goto done; + } + /* second round: compute write message from reason and args */ + va_start(ap, format); + if (vsnprintf(xpath, len+1, format, ap) < 0){ + clicon_err(OE_UNIX, errno, "vsnprintf"); + va_end(ap); + goto done; + } + va_end(ap); + if (xpath_vec_ctx(xcur, xpath, &xr) < 0) + goto done; + if (xr && xr->xc_type == XT_NODESET && xr->xc_size) + cx = xr->xc_nodeset[0]; + done: + if (xr) + ctx_free(xr); + if (xpath) + free(xpath); + return cx; +} + /*! Given XML tree and xpath, returns nodeset as xml node vector * If result is not nodeset, return empty nodeset * @param[in] xcur xml-tree where to search @@ -1135,6 +1182,81 @@ xpath_vec_nodeset(cxobj *xcur, return retval; } +/* A restricted xpath that returns a vector of matches (only nodes marked with flags) + * @param[in] xcur xml-tree where to search + * @param[in] xpath string with XPATH syntax + * @param[in] flags Set of flags that return nodes must match (0 if all) + * @param[out] vec vector of xml-trees. Vector must be free():d after use + * @param[out] veclen returns length of vector in return value + * @retval 0 OK + * @retval -1 error. + * @code + * cxobj **vec; + * size_t veclen; + * if (xpath_vec_flag(xcur, "//symbol/foo", XML_FLAG_ADD, &vec, &veclen) < 0) + * goto err; + * for (i=0; ixc_type == XT_NODESET){ + for (i=0; ixc_size; i++){ + x = xr->xc_nodeset[i]; + if (flags==0x0 || xml_flag(x, flags)) + if (cxvec_append(x, vec, veclen) < 0) + goto done; + } + } + retval = 0; + done: + if (xr) + ctx_free(xr); + if (xpath) + free(xpath); + return retval; +} + /*! Given XML tree and xpath, returns boolean * @param[in] xcur xml-tree where to search * @param[in] xpath stdarg string with XPATH 1.0 syntax diff --git a/lib/src/clixon_xpath_parse.y b/lib/src/clixon_xpath_parse.y index e7eca0a1..0e601167 100644 --- a/lib/src/clixon_xpath_parse.y +++ b/lib/src/clixon_xpath_parse.y @@ -239,8 +239,8 @@ rellocpath : step { $$=xp_new(XP_RELLOCPATH,A_NAN,0.0,NULL,NULL ; step : axisspec nodetest predicates {$$=xp_new(XP_STEP,$1,0.0, NULL, NULL, $2, $3);clicon_debug(1,"step->axisspec(%d) nodetest", $1); } - | '.' { $$=xp_new(XP_STEP,A_SELF, 0.0,NULL, NULL, NULL, NULL); clicon_debug(1,"step-> ."); } - | DOUBLEDOT { $$=xp_new(XP_STEP, A_PARENT, 0.0,NULL, NULL, NULL, NULL); clicon_debug(1,"step-> .."); } + | '.' predicates { $$=xp_new(XP_STEP,A_SELF, 0.0,NULL, NULL, NULL, $2); clicon_debug(1,"step-> ."); } + | DOUBLEDOT predicates { $$=xp_new(XP_STEP, A_PARENT, 0.0,NULL, NULL, NULL, $2); clicon_debug(1,"step-> .."); } ; axisspec : AXISNAME DOUBLECOLON { clicon_debug(1,"axisspec-> AXISNAME(%d) ::", $1); $$=$1;} diff --git a/lib/src/clixon_xsl.c b/lib/src/clixon_xsl.c index ef47eab3..8f34a0a1 100644 --- a/lib/src/clixon_xsl.c +++ b/lib/src/clixon_xsl.c @@ -42,6 +42,10 @@ The code is implemented according to XPATH 1.0: The primary syntactic construct in XPath is the expression. An expression matches the production Expr (see https://www.w3.org/TR/xpath-10/#NT-Expr) */ +#ifdef HAVE_CONFIG_H +#include "clixon_config.h" /* generated by config & autoconf */ +#endif + #include #include #include @@ -896,7 +900,7 @@ xpath_first0(cxobj *xcur, * @see also xpath_vec. */ cxobj * -xpath_first(cxobj *xcur, +xpath_first_xsl(cxobj *xcur, char *format, ...) { @@ -1012,7 +1016,7 @@ xpath_each(cxobj *xcur, * @see also xpath_first, xpath_each. */ int -xpath_vec(cxobj *xcur, +xpath_vec_xsl(cxobj *xcur, char *format, cxobj ***vec, size_t *veclen, @@ -1048,7 +1052,6 @@ xpath_vec(cxobj *xcur, return retval; } - /* A restricted xpath that returns a vector of matches (only nodes marked with flags) * @param[in] xcur xml-tree where to search * @param[in] xpath string with XPATH syntax @@ -1073,12 +1076,12 @@ xpath_vec(cxobj *xcur, * @see also xpath_vec This is a specialized version. */ int -xpath_vec_flag(cxobj *xcur, - char *format, - uint16_t flags, - cxobj ***vec, - size_t *veclen, - ...) +xpath_vec_flag_xsl(cxobj *xcur, + char *format, + uint16_t flags, + cxobj ***vec, + size_t *veclen, + ...) { int retval = -1; va_list ap; diff --git a/lib/src/clixon_yang_type.c b/lib/src/clixon_yang_type.c index a67500db..68204c9b 100644 --- a/lib/src/clixon_yang_type.c +++ b/lib/src/clixon_yang_type.c @@ -545,7 +545,6 @@ cv_validate1(cg_var *cv, if ((vec = clicon_strsep(str, " \t", &nvec)) == NULL) goto done; for (i=0; i]]>]]>" "^]]>]]>$" +new "leafref get config" +expecteof "$clixon_netconf -qf $cfg" 0 ']]>]]>' '^eth0' + new "leafref add wrong ref" expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "eth3
10.0.4.6
]]>]]>" "^]]>]]>$" diff --git a/test/test_netconf.sh b/test/test_netconf.sh index e0364e1a..5496f69e 100755 --- a/test/test_netconf.sh +++ b/test/test_netconf.sh @@ -6,6 +6,7 @@ APPNAME=example cfg=$dir/conf_yang.xml fyang=$dir/netconf.yang +tmp=$dir/tmp.x cat < $cfg @@ -92,8 +93,18 @@ expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 'eth/0/0ex:ethnone ]]>]]>' "^]]>]]>$" +# Too many quotes, (single inside double inside single) need to fool bash +if [ -n "$XPATH_USE_NEW" ]; then +cat < $tmp # new +]]>]]> +EOF +else +cat < $tmp +]]>]]> +EOF +fi new "Check eth/0/0 added using xpath" -expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 ']]>]]>' "^eth/0/0ex:ethtrue]]>]]>$" +expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "$(cat $tmp)" "^eth/0/0ex:ethtrue]]>]]>$" new "Re-create same eth/0/0 which should generate error" expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 'eth/0/0ex:ethnone ]]>]]>' "^" @@ -110,11 +121,33 @@ expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 'eth/0/0eth1true
9.2.3.424
]]>]]>" "^]]>]]>$" +# Too many quotes +if [ -n "$XPATH_USE_NEW" ]; then +cat < $tmp # new +]]>]]> +EOF +else +cat < $tmp # new +]]>]]> +EOF +fi + new "netconf get config xpath" -expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 ']]>]]>' "^eth1true]]>]]>$" +expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "$(cat $tmp)" "^eth1true]]>]]>$" + +# Too many quotes +if [ -n "$XPATH_USE_NEW" ]; then +cat < $tmp # new +]]>]]> +EOF +else +cat < $tmp # old +]]>]]> +EOF +fi new "netconf get config xpath parent" -expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 ']]>]]>' "^eth/0/0trueeth1truetruefalse
9.2.3.424
]]>]]>$" +expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "$(cat $tmp)" "^eth/0/0trueeth1truetruefalse
9.2.3.424
]]>]]>$" new "netconf validate missing type" expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "]]>]]>" "^" @@ -157,7 +190,7 @@ new "netconf edit CDATA" expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "eth/0/0ex:eth]]>]]>" "^]]>]]>$" #new "netconf get CDATA" -#expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "]]>]]>" "eth/0/0true]]>]]>" +#expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "]]>]]>" "eth/0/0true]]>]]>" new "netconf discard-changes" diff --git a/test/test_order.sh b/test/test_order.sh index 64eaace4..d0536dbf 100755 --- a/test/test_order.sh +++ b/test/test_order.sh @@ -121,6 +121,22 @@ fi new "verify running from start, should be: l,c,y0,y1,y2,y3; y1 and y3 sorted. Note this fails if XML_SORT set to false" expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "]]>]]>" "^hejhoppdbcaabcddbarabarcbarbbarabarbbarcbardbar]]>]]>$" +if [ -n "$XPATH_USE_NEW" ]; then #new + +new "get each ordered-by user leaf-list" +expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "]]>]]>" "^abar]]>]]>$" + +new "get each ordered-by user leaf-list" +expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "]]>]]>" "^abar]]>]]>$" + +new "get each ordered-by user leaf-list" +expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "]]>]]>" "^bbar]]>]]>$" + +new "get each ordered-by user leaf-list" +expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "]]>]]>" "^bbar]]>]]>$" + +else # old + new "get each ordered-by user leaf-list" expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "]]>]]>" "^abar]]>]]>$" @@ -132,6 +148,8 @@ expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "]]>]]>" "^bbar]]>]]>$" + +fi new "delete candidate" expecteof "$clixon_netconf -qf $cfg" 0 "]]>]]>" "^]]>]]>$" diff --git a/test/test_xpath.sh b/test/test_xpath.sh index 35ee692a..4d23996a 100755 --- a/test/test_xpath.sh +++ b/test/test_xpath.sh @@ -8,12 +8,20 @@ PROG=../lib/src/clixon_util_xpath # XML file (alt provide it in stdin after xpath) xml=$dir/xml.xml xml2=$dir/xml2.xml +xml3=$dir/xml3.xml +xml4=$dir/xml4.xml cat < $xml - 42 - 99 - 22 + + 42 + + + 99 + + + 22 + EOF @@ -53,6 +61,19 @@ cat < $xml2 EOF +# Multiple leaf-list +cat < $xml3 + + foo + 42 + bar + + + 99 + foo + +EOF + new "xpath /" expecteof "$PROG -f $xml -p /" 0 "" "^nodeset:0:429922$" @@ -148,4 +169,23 @@ expecteof "$PROG -f $xml2 -i /aaa/bbb" 0 "ifType != \"ethernet\" and ifMTU = 140 new "xpath ifType != \"atm\" or (ifMTU <= 17966 and ifMTU >= 64)" expecteof "$PROG -f $xml2 -i /aaa/bbb" 0 "ifType != \"atm\" or (ifMTU <= 17966 and ifMTU >= 64)" "^bool:true$" +new "xpath .[name='bar']" +expecteof "$PROG -f $xml2 -p .[name='bar'] -i /aaa/bbb/routing/ribs/rib" 0 "" "^nodeset:0:barmyfamily$" + +new "Multiple entries" +new "xpath bbb[ccc='foo']" +expecteof "$PROG -f $xml3 -p bbb[ccc='foo']" 0 "" "^nodeset:0:foo42bar1:99foo$" + +new "xpath bbb[ccc='42']" +expecteof "$PROG -f $xml3 -p bbb[ccc='42']" 0 "" "^nodeset:0:foo42bar$" + +new "xpath bbb[ccc=99] (number w/o quotes)" +expecteof "$PROG -f $xml3 -p bbb[ccc=99]" 0 "" "^nodeset:0:99foo$" + +new "xpath bbb[ccc='bar']" +expecteof "$PROG -f $xml3 -p bbb[ccc='bar']" 0 "" "^nodeset:0:foo42bar$" + +new "xpath bbb[ccc='fie']" +expecteof "$PROG -f $xml3 -p bbb[ccc='fie']" 0 "" "^nodeset:$" + rm -rf $dir diff --git a/test/test_yang.sh b/test/test_yang.sh index 3522500c..7b5a7af6 100755 --- a/test/test_yang.sh +++ b/test/test_yang.sh @@ -136,8 +136,13 @@ expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "]]>]]>" "^hejhopp]]>]]>$" +if [ -n "$XPATH_USE_NEW" ]; then # new +new "netconf get leaf-list path" +expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "]]>]]>" "^hejhopp]]>]]>$" +else # old new "netconf get leaf-list path" expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "]]>]]>" "^hejhopp]]>]]>$" +fi new "netconf get (should be some)" expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "]]>]]>" "^125one]]>]]>$" @@ -154,7 +159,10 @@ new "netconf set presence and not present" expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "]]>]]>" "^]]>]]>$" new "netconf get presence only" -expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 ']]>]]>' "^]]>]]>$" +expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 ']]>]]>' "^]]>]]>$" + +new "netconf get presence only" +expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 ']]>]]>' "^]]>]]>$" new "netconf discard-changes" expecteof "$clixon_netconf -qf $cfg" 0 "]]>]]>" "^]]>]]>$"