* 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
This commit is contained in:
parent
5d7c4a8d18
commit
ba7f84afee
29 changed files with 395 additions and 79 deletions
|
|
@ -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/<module_name>:<rpc_procedure> 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
|
||||
|
|
|
|||
|
|
@ -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<glen; j++){
|
||||
char *gname;
|
||||
gname = xml_find_body(gvec[j], "name");
|
||||
if (xpath_first(xrlist,".[group=%s]", gname)!=NULL)
|
||||
if (xpath_first(xrlist,
|
||||
#ifdef XPATH_USE_NEW
|
||||
".[group='%s']",
|
||||
#else
|
||||
".[group=%s]",
|
||||
#endif
|
||||
gname)!=NULL)
|
||||
break; /* found */
|
||||
}
|
||||
if (j==glen) /* not found */
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@
|
|||
/*! Register log notification stream
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] stream Event stream. CLICON is predefined, others are application-defined
|
||||
* @param[in] filter Filter. For xml notification ie xpath: .[name=kalle]
|
||||
* @param[in] filter Filter. For xml notification ie xpath: .[name="kalle"]
|
||||
* @param[in] status 0 for stop, 1 to start
|
||||
* @param[in] fn Callback function called when notification occurs
|
||||
* @param[in] arg Argument to function note
|
||||
|
|
@ -1189,7 +1189,7 @@ cli_unlock(clicon_handle h,
|
|||
* tovar: Name of variable containing name of object to copy to.
|
||||
* @code
|
||||
* cli spec:
|
||||
* copy snd <n1:string> to <n2:string>, cli_copy_config("candidate", "/sender[%s=%s]", "from", "n1", "n2");
|
||||
* copy snd <n1:string> to <n2:string>, 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<strlen(xpath); i++)
|
||||
for (i=0; i<strlen(xpath); i++){
|
||||
if (xpath[i] == '%')
|
||||
j++;
|
||||
#ifndef XPATH_USE_NEW
|
||||
/* This is a horrible kludge due to:
|
||||
* (1) old xpath implementation wrongly did: a[b=x] instead of a[b='x']
|
||||
* (2) cli_copy_config has as 2nd argument such an xpath provided by user.
|
||||
*/
|
||||
if (j==2){
|
||||
int k;
|
||||
if ((xpath[i-1] == '\'' || xpath[i-1] == '\"') &&
|
||||
(xpath[i+2] == '\'' || xpath[i+2] == '\"')){
|
||||
for (k=i-1;k<i+2;k++)
|
||||
xpath[k] = xpath[k+1];
|
||||
for (k=i+1;k<strlen(xpath)+1;k++)
|
||||
xpath[k] = xpath[k+2];
|
||||
i-=1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (j != 2){
|
||||
clicon_err(OE_PLUGIN, 0, "xpath '%s' does not have two '%%'", xpath);
|
||||
goto done;
|
||||
}
|
||||
cprintf(cb, xpath, keyname, fromname);
|
||||
|
||||
/* Get from object configuration and store in x1 */
|
||||
if (clicon_rpc_get_config(h, db, cbuf_get(cb), &x1) < 0)
|
||||
goto done;
|
||||
|
|
|
|||
|
|
@ -285,7 +285,7 @@ yang2cli_var_sub(clicon_handle h,
|
|||
goto done;
|
||||
}
|
||||
}
|
||||
cprintf(cb, "%s]", r);
|
||||
cprintf(cb, "%s]", r); /* range */
|
||||
free(r);
|
||||
r = NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ expand_dbvar(void *h,
|
|||
api_path_fmt = cv_string_get(cv);
|
||||
/* api_path_fmt = /interface/%s/address/%s
|
||||
--> ^/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:
|
||||
* <dbname> "running"|"candidate"|"startup"
|
||||
* <format> "text"|"xml"|"json"|"cli"|"netconf" (see format_enum)
|
||||
* <xpath> xpath expression, that may contain one %, eg "/sender[name=%s]"
|
||||
* <xpath> xpath expression, that may contain one %, eg "/sender[name="%s"]"
|
||||
* <varname> optional name of variable in cvv. If set, xpath must have a '%s'
|
||||
* @code
|
||||
* show config id <n:string>, cli_show_config("running","xml","iface[name=%s]","n");
|
||||
* show config id <n:string>, cli_show_config("running","xml","iface[name="%s"]","n");
|
||||
* @endcode
|
||||
*/
|
||||
int
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -95,6 +95,9 @@ Mapping netconf error-tag -> status code
|
|||
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "clixon_config.h" /* generated by config & autoconf */
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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:string expand_dbvar("candidate","/interfaces/interface=%s/name")>("name of interface to copy from") to("Copy to interface") <toname:string>("Name of interface to copy to"), cli_copy_config("candidate","//interface[%s=%s]","name","name","toname");
|
||||
<name:string expand_dbvar("candidate","/interfaces/interface=%s/name")>("name of interface to copy from") to("Copy to interface") <toname:string>("Name of interface to copy to"), cli_copy_config("candidate","//interface[%s='%s']","name","name","toname");
|
||||
}
|
||||
}
|
||||
discard("Discard edits (rollback 0)"), discard_changes();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -81,9 +81,9 @@
|
|||
#include <clixon/clixon_options.h>
|
||||
#include <clixon/clixon_xml_map.h>
|
||||
#include <clixon/clixon_xml_db.h>
|
||||
#include <clixon/clixon_xsl.h>
|
||||
#include <clixon/clixon_xpath_ctx.h>
|
||||
#include <clixon/clixon_xpath.h>
|
||||
#include <clixon/clixon_xsl.h>
|
||||
#include <clixon/clixon_json.h>
|
||||
#include <clixon/clixon_netconf_lib.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 */
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
|
@ -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; i<xc->xc_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; i<veclen; i++){
|
||||
x = vec[i];
|
||||
if ((xp = xml_parent(x)) != NULL)
|
||||
if (cxvec_append(xp, &xr0->xc_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; i<xc1->xc_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; i<xc1->xc_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; i<veclen; i++){
|
||||
* xn = vec[i];
|
||||
* ...
|
||||
* }
|
||||
* free(vec);
|
||||
* @endcode
|
||||
* @Note that although the returned vector must be freed after use, the returned xml
|
||||
* trees need not be.
|
||||
* @see also xpath_vec This is a specialized version.
|
||||
*/
|
||||
int
|
||||
xpath_vec_nodeset_flag(cxobj *xcur,
|
||||
char *format,
|
||||
uint16_t flags,
|
||||
cxobj ***vec,
|
||||
size_t *veclen,
|
||||
...)
|
||||
{
|
||||
int retval = -1;
|
||||
va_list ap;
|
||||
size_t len;
|
||||
char *xpath = NULL;
|
||||
xp_ctx *xr = NULL;
|
||||
int i;
|
||||
cxobj *x;
|
||||
|
||||
va_start(ap, veclen);
|
||||
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, veclen);
|
||||
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){
|
||||
for (i=0; i<xr->xc_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
|
||||
|
|
|
|||
|
|
@ -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;}
|
||||
|
|
|
|||
|
|
@ -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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -545,7 +545,6 @@ cv_validate1(cg_var *cv,
|
|||
if ((vec = clicon_strsep(str, " \t", &nvec)) == NULL)
|
||||
goto done;
|
||||
for (i=0; i<nvec; i++){
|
||||
clicon_log(LOG_NOTICE, "%s: vec[i]: %s", __FUNCTION__, vec[i]);
|
||||
if ((v = vec[i]) == NULL || !strlen(v))
|
||||
continue;
|
||||
found = 0;
|
||||
|
|
|
|||
|
|
@ -5,6 +5,9 @@
|
|||
testnr=0
|
||||
testname=
|
||||
|
||||
# Set to 1 if new xpath. Set to nothing, or comment if old
|
||||
#XPATH_USE_NEW=1
|
||||
|
||||
# For memcheck
|
||||
#clixon_cli="valgrind --leak-check=full --show-leak-kinds=all clixon_cli"
|
||||
clixon_cli=clixon_cli
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ expectfn "$clixon_cli -1 -f $cfg show conf cli" 0 "^interfaces interface eth/0/0
|
|||
|
||||
new "cli configure using encoded chars data <&"
|
||||
expectfn "$clixon_cli -1 -f $cfg set interfaces interface eth/0/0 description \"foo<&bar\"" 0 ""
|
||||
|
||||
new "cli configure using encoded chars name <&"
|
||||
expectfn "$clixon_cli -1 -f $cfg set interfaces interface fddi&< type ianaift:ethernetCsmacd" 0 ""
|
||||
|
||||
|
|
|
|||
|
|
@ -95,6 +95,9 @@ expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></s
|
|||
new "leafref base commit"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "leafref get config"
|
||||
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><get-config><source><candidate/></source></get-config></rpc>]]>]]>' '^<rpc-reply><data><interfaces><interface><name>eth0</name>'
|
||||
|
||||
new "leafref add wrong ref"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><default-address><absname>eth3</absname><address>10.0.4.6</address></default-address></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ APPNAME=example
|
|||
|
||||
cfg=$dir/conf_yang.xml
|
||||
fyang=$dir/netconf.yang
|
||||
tmp=$dir/tmp.x
|
||||
|
||||
cat <<EOF > $cfg
|
||||
<config>
|
||||
|
|
@ -92,8 +93,18 @@ expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc message-id="101"><get-con
|
|||
new "Add subtree eth/0/0 using none and create which should add eth/0/0"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><interfaces><interface operation="create"><name>eth/0/0</name><type>ex:eth</type></interface></interfaces></config><default-operation>none</default-operation> </edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
# Too many quotes, (single inside double inside single) need to fool bash
|
||||
if [ -n "$XPATH_USE_NEW" ]; then
|
||||
cat <<EOF > $tmp # new
|
||||
<rpc><get-config><source><candidate/></source><filter type="xpath" select="/interfaces/interface[name='eth/0/0']"/></get-config></rpc>]]>]]>
|
||||
EOF
|
||||
else
|
||||
cat <<EOF > $tmp
|
||||
<rpc><get-config><source><candidate/></source><filter type="xpath" select="/interfaces/interface[name=eth/0/0]"/></get-config></rpc>]]>]]>
|
||||
EOF
|
||||
fi
|
||||
new "Check eth/0/0 added using xpath"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/interfaces/interface[name=eth/0/0]"/></get-config></rpc>]]>]]>' "^<rpc-reply><data><interfaces><interface><name>eth/0/0</name><type>ex:eth</type><enabled>true</enabled></interface></interfaces></data></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "$(cat $tmp)" "^<rpc-reply><data><interfaces><interface><name>eth/0/0</name><type>ex:eth</type><enabled>true</enabled></interface></interfaces></data></rpc-reply>]]>]]>$"
|
||||
|
||||
new "Re-create same eth/0/0 which should generate error"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><interfaces><interface operation="create"><name>eth/0/0</name><type>ex:eth</type></interface></interfaces></config><default-operation>none</default-operation> </edit-config></rpc>]]>]]>' "^<rpc-reply><rpc-error>"
|
||||
|
|
@ -110,11 +121,33 @@ expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><can
|
|||
new "netconf edit config"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><interfaces><interface><name>eth/0/0</name></interface><interface><name>eth1</name><enabled>true</enabled><ipv4><address><ip>9.2.3.4</ip><prefix-length>24</prefix-length></address></ipv4></interface></interfaces></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
# Too many quotes
|
||||
if [ -n "$XPATH_USE_NEW" ]; then
|
||||
cat <<EOF > $tmp # new
|
||||
<rpc><get-config><source><candidate/></source><filter type="xpath" select="/interfaces/interface[name='eth1']/enabled"/></get-config></rpc>]]>]]>
|
||||
EOF
|
||||
else
|
||||
cat <<EOF > $tmp # new
|
||||
<rpc><get-config><source><candidate/></source><filter type="xpath" select="/interfaces/interface[name=eth1]/enabled"/></get-config></rpc>]]>]]>
|
||||
EOF
|
||||
fi
|
||||
|
||||
new "netconf get config xpath"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/interfaces/interface[name=eth1]/enabled"/></get-config></rpc>]]>]]>' "^<rpc-reply><data><interfaces><interface><name>eth1</name><enabled>true</enabled></interface></interfaces></data></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "$(cat $tmp)" "^<rpc-reply><data><interfaces><interface><name>eth1</name><enabled>true</enabled></interface></interfaces></data></rpc-reply>]]>]]>$"
|
||||
|
||||
# Too many quotes
|
||||
if [ -n "$XPATH_USE_NEW" ]; then
|
||||
cat <<EOF > $tmp # new
|
||||
<rpc><get-config><source><candidate/></source><filter type="xpath" select="/interfaces/interface[name='eth1']/enabled/../.."/></get-config></rpc>]]>]]>
|
||||
EOF
|
||||
else
|
||||
cat <<EOF > $tmp # old
|
||||
<rpc><get-config><source><candidate/></source><filter type="xpath" select="/interfaces/interface[name=eth1]/enabled/../.."/></get-config></rpc>]]>]]>
|
||||
EOF
|
||||
fi
|
||||
|
||||
new "netconf get config xpath parent"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/interfaces/interface[name=eth1]/enabled/../.."/></get-config></rpc>]]>]]>' "^<rpc-reply><data><interfaces><interface><name>eth/0/0</name><enabled>true</enabled></interface><interface><name>eth1</name><enabled>true</enabled><ipv4><enabled>true</enabled><forwarding>false</forwarding><address><ip>9.2.3.4</ip><prefix-length>24</prefix-length></address></ipv4></interface></interfaces></data></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "$(cat $tmp)" "^<rpc-reply><data><interfaces><interface><name>eth/0/0</name><enabled>true</enabled></interface><interface><name>eth1</name><enabled>true</enabled><ipv4><enabled>true</enabled><forwarding>false</forwarding><address><ip>9.2.3.4</ip><prefix-length>24</prefix-length></address></ipv4></interface></interfaces></data></rpc-reply>]]>]]>$"
|
||||
|
||||
new "netconf validate missing type"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error>"
|
||||
|
|
@ -157,7 +190,7 @@ new "netconf edit CDATA"
|
|||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><interfaces><interface><name>eth/0/0</name><type>ex:eth</type><description><![CDATA[myeth&]]></description></interface></interfaces></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
#new "netconf get CDATA"
|
||||
#expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><candidate/></source><filter type=\"xpath\" select=\"/interfaces/interface[name=eth/0/0]/description\" /></get-config></rpc>]]>]]>" "<rpc-reply><data><interfaces><interface><name>eth/0/0</name><description><![CDATA[myeth&]]></description><enabled>true</enabled></interface></interfaces></data></rpc-reply>]]>]]>"
|
||||
#expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><candidate/></source><filter type=\"xpath\" select=\"/interfaces/interface[name='eth/0/0']/description\" /></get-config></rpc>]]>]]>" "<rpc-reply><data><interfaces><interface><name>eth/0/0</name><description><![CDATA[myeth&]]></description><enabled>true</enabled></interface></interfaces></data></rpc-reply>]]>]]>"
|
||||
|
||||
|
||||
new "netconf discard-changes"
|
||||
|
|
|
|||
|
|
@ -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 "<rpc><get-config><source><running/></source></get-config></rpc>]]>]]>" "^<rpc-reply><data><c><d>hej</d></c><l>hopp</l><y0>d</y0><y0>b</y0><y0>c</y0><y0>a</y0><y1>a</y1><y1>b</y1><y1>c</y1><y1>d</y1><y2><k>d</k><a>bar</a></y2><y2><k>a</k><a>bar</a></y2><y2><k>c</k><a>bar</a></y2><y2><k>b</k><a>bar</a></y2><y3><k>a</k><a>bar</a></y3><y3><k>b</k><a>bar</a></y3><y3><k>c</k><a>bar</a></y3><y3><k>d</k><a>bar</a></y3></data></rpc-reply>]]>]]>$"
|
||||
|
||||
if [ -n "$XPATH_USE_NEW" ]; then #new
|
||||
|
||||
new "get each ordered-by user leaf-list"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><running/></source><filter type=\"xpath\" select=\"/y2[k='a']\"/></get-config></rpc>]]>]]>" "^<rpc-reply><data><y2><k>a</k><a>bar</a></y2></data></rpc-reply>]]>]]>$"
|
||||
|
||||
new "get each ordered-by user leaf-list"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><running/></source><filter type=\"xpath\" select=\"/y3[k='a']\"/></get-config></rpc>]]>]]>" "^<rpc-reply><data><y3><k>a</k><a>bar</a></y3></data></rpc-reply>]]>]]>$"
|
||||
|
||||
new "get each ordered-by user leaf-list"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><running/></source><filter type=\"xpath\" select=\"/y2[k='b']\"/></get-config></rpc>]]>]]>" "^<rpc-reply><data><y2><k>b</k><a>bar</a></y2></data></rpc-reply>]]>]]>$"
|
||||
|
||||
new "get each ordered-by user leaf-list"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><running/></source><filter type=\"xpath\" select=\"/y3[k='b']\"/></get-config></rpc>]]>]]>" "^<rpc-reply><data><y3><k>b</k><a>bar</a></y3></data></rpc-reply>]]>]]>$"
|
||||
|
||||
else # old
|
||||
|
||||
new "get each ordered-by user leaf-list"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><running/></source><filter type=\"xpath\" select=\"/y2[k=a]\"/></get-config></rpc>]]>]]>" "^<rpc-reply><data><y2><k>a</k><a>bar</a></y2></data></rpc-reply>]]>]]>$"
|
||||
|
||||
|
|
@ -132,6 +148,8 @@ expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><runn
|
|||
|
||||
new "get each ordered-by user leaf-list"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><running/></source><filter type=\"xpath\" select=\"/y3[k=b]\"/></get-config></rpc>]]>]]>" "^<rpc-reply><data><y3><k>b</k><a>bar</a></y3></data></rpc-reply>]]>]]>$"
|
||||
|
||||
fi
|
||||
|
||||
new "delete candidate"
|
||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><delete-config><target><candidate/></target></delete-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
|
|
|||
|
|
@ -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 <<EOF > $xml
|
||||
<aaa>
|
||||
<bbb x="hello"><ccc>42</ccc></bbb>
|
||||
<bbb x="bye"><ccc>99</ccc></bbb>
|
||||
<ddd><ccc>22</ccc></ddd>
|
||||
<bbb x="hello">
|
||||
<ccc>42</ccc>
|
||||
</bbb>
|
||||
<bbb x="bye">
|
||||
<ccc>99</ccc>
|
||||
</bbb>
|
||||
<ddd>
|
||||
<ccc>22</ccc>
|
||||
</ddd>
|
||||
</aaa>
|
||||
EOF
|
||||
|
||||
|
|
@ -53,6 +61,19 @@ cat <<EOF > $xml2
|
|||
</aaa>
|
||||
EOF
|
||||
|
||||
# Multiple leaf-list
|
||||
cat <<EOF > $xml3
|
||||
<bbb x="hello">
|
||||
<ccc>foo</ccc>
|
||||
<ccc>42</ccc>
|
||||
<ccc>bar</ccc>
|
||||
</bbb>
|
||||
<bbb x="bye">
|
||||
<ccc>99</ccc>
|
||||
<ccc>foo</ccc>
|
||||
</bbb>
|
||||
EOF
|
||||
|
||||
new "xpath /"
|
||||
expecteof "$PROG -f $xml -p /" 0 "" "^nodeset:0:<aaa><bbb x=\"hello\"><ccc>42</ccc></bbb><bbb x=\"bye\"><ccc>99</ccc></bbb><ddd><ccc>22</ccc></ddd></aaa>$"
|
||||
|
||||
|
|
@ -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:<rib><name>bar</name><address-family>myfamily</address-family></rib>$"
|
||||
|
||||
new "Multiple entries"
|
||||
new "xpath bbb[ccc='foo']"
|
||||
expecteof "$PROG -f $xml3 -p bbb[ccc='foo']" 0 "" "^nodeset:0:<bbb x=\"hello\"><ccc>foo</ccc><ccc>42</ccc><ccc>bar</ccc></bbb>1:<bbb x=\"bye\"><ccc>99</ccc><ccc>foo</ccc></bbb>$"
|
||||
|
||||
new "xpath bbb[ccc='42']"
|
||||
expecteof "$PROG -f $xml3 -p bbb[ccc='42']" 0 "" "^nodeset:0:<bbb x=\"hello\"><ccc>foo</ccc><ccc>42</ccc><ccc>bar</ccc></bbb>$"
|
||||
|
||||
new "xpath bbb[ccc=99] (number w/o quotes)"
|
||||
expecteof "$PROG -f $xml3 -p bbb[ccc=99]" 0 "" "^nodeset:0:<bbb x=\"bye\"><ccc>99</ccc><ccc>foo</ccc></bbb>$"
|
||||
|
||||
new "xpath bbb[ccc='bar']"
|
||||
expecteof "$PROG -f $xml3 -p bbb[ccc='bar']" 0 "" "^nodeset:0:<bbb x=\"hello\"><ccc>foo</ccc><ccc>42</ccc><ccc>bar</ccc></bbb>$"
|
||||
|
||||
new "xpath bbb[ccc='fie']"
|
||||
expecteof "$PROG -f $xml3 -p bbb[ccc='fie']" 0 "" "^nodeset:$"
|
||||
|
||||
rm -rf $dir
|
||||
|
|
|
|||
|
|
@ -136,8 +136,13 @@ expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><can
|
|||
new "netconf get leaf-list"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><candidate/></source><filter type=\"xpath\" select=\"/x/f/e\"/></get-config></rpc>]]>]]>" "^<rpc-reply><data><x><f><e>hej</e><e>hopp</e></f></x></data></rpc-reply>]]>]]>$"
|
||||
|
||||
if [ -n "$XPATH_USE_NEW" ]; then # new
|
||||
new "netconf get leaf-list path"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><candidate/></source><filter type=\"xpath\" select=\"/x/f[e='hej']\"/></get-config></rpc>]]>]]>" "^<rpc-reply><data><x><f><e>hej</e><e>hopp</e></f></x></data></rpc-reply>]]>]]>$"
|
||||
else # old
|
||||
new "netconf get leaf-list path"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><candidate/></source><filter type=\"xpath\" select=\"/x/f[e=hej]\"/></get-config></rpc>]]>]]>" "^<rpc-reply><data><x><f><e>hej</e><e>hopp</e></f></x></data></rpc-reply>]]>]]>$"
|
||||
fi
|
||||
|
||||
new "netconf get (should be some)"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get><filter type=\"xpath\" select=\"/\"/></get></rpc>]]>]]>" "^<rpc-reply><data><x><y><a>1</a><b>2</b><c>5</c><val>one</val></y><d/></x></data></rpc-reply>]]>]]>$"
|
||||
|
|
@ -154,7 +159,10 @@ new "netconf set presence and not present"
|
|||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><edit-config><target><candidate/></target><config><x><nopresence/><presence/></x></config></edit-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "netconf get presence only"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/x/*presence"/></get-config></rpc>]]>]]>' "^<rpc-reply><data><x><presence/></x></data></rpc-reply>]]>]]>$"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/x/presence"/></get-config></rpc>]]>]]>' "^<rpc-reply><data><x><presence/></x></data></rpc-reply>]]>]]>$"
|
||||
|
||||
new "netconf get presence only"
|
||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/x/nopresence"/></get-config></rpc>]]>]]>' "^<rpc-reply><data/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "netconf discard-changes"
|
||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue