* 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)
|
## 3.7.0 (Upcoming)
|
||||||
### Major changes:
|
### Major changes:
|
||||||
|
|
||||||
* Full support of XPATH 1.0 according to https://www.w3.org/TR/xpath-10 using yacc/lex
|
* Much better support for XPATH 1.0 according to https://www.w3.org/TR/xpath-10 using yacc/lex
|
||||||
* The previous XPATH imlementation was very restricted.
|
* 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"]`
|
||||||
* The only function implemented is the Yang extension "current()". No other functions are implemented (eg last(), count()).
|
* 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.
|
* 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
|
* 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
|
* 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)
|
if (username == NULL)
|
||||||
goto step10;
|
goto step10;
|
||||||
/* User's group */
|
/* 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;
|
goto done;
|
||||||
/* 5. If no groups are found, continue with step 10. */
|
/* 5. If no groups are found, continue with step 10. */
|
||||||
if (glen == 0)
|
if (glen == 0)
|
||||||
|
|
@ -1002,7 +1008,13 @@ nacm_access(clicon_handle h,
|
||||||
for (j=0; j<glen; j++){
|
for (j=0; j<glen; j++){
|
||||||
char *gname;
|
char *gname;
|
||||||
gname = xml_find_body(gvec[j], "name");
|
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 */
|
break; /* found */
|
||||||
}
|
}
|
||||||
if (j==glen) /* not found */
|
if (j==glen) /* not found */
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@
|
||||||
/*! Register log notification stream
|
/*! Register log notification stream
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
* @param[in] stream Event stream. CLICON is predefined, others are application-defined
|
* @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] status 0 for stop, 1 to start
|
||||||
* @param[in] fn Callback function called when notification occurs
|
* @param[in] fn Callback function called when notification occurs
|
||||||
* @param[in] arg Argument to function note
|
* @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.
|
* tovar: Name of variable containing name of object to copy to.
|
||||||
* @code
|
* @code
|
||||||
* cli spec:
|
* 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:
|
* cli command:
|
||||||
* copy snd from to to
|
* copy snd from to to
|
||||||
* @endcode
|
* @endcode
|
||||||
|
|
@ -1244,17 +1244,34 @@ cli_copy_config(clicon_handle h,
|
||||||
clicon_err(OE_PLUGIN, errno, "cbuf_new");
|
clicon_err(OE_PLUGIN, errno, "cbuf_new");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* Sanity check that xpath contains exactly one %s */
|
/* Sanity check that xpath contains exactly two %s, ie [%s='%s'] */
|
||||||
j = 0;
|
j = 0;
|
||||||
for (i=0; i<strlen(xpath); i++)
|
for (i=0; i<strlen(xpath); i++){
|
||||||
if (xpath[i] == '%')
|
if (xpath[i] == '%')
|
||||||
j++;
|
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){
|
if (j != 2){
|
||||||
clicon_err(OE_PLUGIN, 0, "xpath '%s' does not have two '%%'", xpath);
|
clicon_err(OE_PLUGIN, 0, "xpath '%s' does not have two '%%'", xpath);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
cprintf(cb, xpath, keyname, fromname);
|
cprintf(cb, xpath, keyname, fromname);
|
||||||
|
|
||||||
/* Get from object configuration and store in x1 */
|
/* Get from object configuration and store in x1 */
|
||||||
if (clicon_rpc_get_config(h, db, cbuf_get(cb), &x1) < 0)
|
if (clicon_rpc_get_config(h, db, cbuf_get(cb), &x1) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
|
||||||
|
|
@ -285,7 +285,7 @@ yang2cli_var_sub(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cprintf(cb, "%s]", r);
|
cprintf(cb, "%s]", r); /* range */
|
||||||
free(r);
|
free(r);
|
||||||
r = NULL;
|
r = NULL;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -148,7 +148,7 @@ expand_dbvar(void *h,
|
||||||
api_path_fmt = cv_string_get(cv);
|
api_path_fmt = cv_string_get(cv);
|
||||||
/* api_path_fmt = /interface/%s/address/%s
|
/* api_path_fmt = /interface/%s/address/%s
|
||||||
--> ^/interface/eth0/address/.*$
|
--> ^/interface/eth0/address/.*$
|
||||||
--> /interface/[name=eth0]/address
|
--> /interface/[name="eth0"]/address
|
||||||
*/
|
*/
|
||||||
if (api_path_fmt2xpath(api_path_fmt, cvv, &xpath) < 0)
|
if (api_path_fmt2xpath(api_path_fmt, cvv, &xpath) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -417,10 +417,10 @@ show_yang(clicon_handle h,
|
||||||
* Format of argv:
|
* Format of argv:
|
||||||
* <dbname> "running"|"candidate"|"startup"
|
* <dbname> "running"|"candidate"|"startup"
|
||||||
* <format> "text"|"xml"|"json"|"cli"|"netconf" (see format_enum)
|
* <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'
|
* <varname> optional name of variable in cvv. If set, xpath must have a '%s'
|
||||||
* @code
|
* @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
|
* @endcode
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
|
|
|
||||||
|
|
@ -82,12 +82,15 @@
|
||||||
static int
|
static int
|
||||||
netconf_hello(cxobj *xn)
|
netconf_hello(cxobj *xn)
|
||||||
{
|
{
|
||||||
|
#ifdef nyi
|
||||||
cxobj *x;
|
cxobj *x;
|
||||||
|
|
||||||
x = NULL;
|
x = NULL;
|
||||||
|
|
||||||
while ((x = xpath_each(xn, "//capability", x)) != NULL) {
|
while ((x = xpath_each(xn, "//capability", x)) != NULL) {
|
||||||
//fprintf(stderr, "cap: %s\n", xml_body(x));
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
return 0;
|
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 <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@
|
||||||
*
|
*
|
||||||
* Alternative for xmlkeyfmt would be eg:
|
* Alternative for xmlkeyfmt would be eg:
|
||||||
* RESTCONF: /interfaces/interface=%s/ipv4/address/ip=%s (used)
|
* 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)
|
* Paths through the code (for coverage)
|
||||||
* cli_callback_generate +----------------+
|
* cli_callback_generate +----------------+
|
||||||
|
|
@ -375,7 +375,7 @@ get(char *dbname,
|
||||||
arg = valvec[j++];
|
arg = valvec[j++];
|
||||||
if (uri_percent_decode(arg, &argdec) < 0)
|
if (uri_percent_decode(arg, &argdec) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
cprintf(cb, "[%s=%s]", cv_string_get(cvi), argdec);
|
cprintf(cb, "[%s='%s']", cv_string_get(cvi), argdec);
|
||||||
free(argdec);
|
free(argdec);
|
||||||
argdec=NULL;
|
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 */
|
cli_output(stderr, "arg = %s\n", cv_string_get(cvec_i(argv,0))); /* get string value */
|
||||||
|
|
||||||
/* Show eth0 interfaces config using XPATH */
|
/* 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)
|
&xret) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ debug("Debugging parts of the system"), cli_debug_cli((int32)1);{
|
||||||
}
|
}
|
||||||
copy("Copy and create a new object") {
|
copy("Copy and create a new object") {
|
||||||
interface("Copy interface"){
|
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();
|
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
|
/* Full xmlns validation check is made only if XML has associated YANG spec
|
||||||
*/
|
*/
|
||||||
#define XMLNS_YANG_ONLY 1
|
#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_options.h>
|
||||||
#include <clixon/clixon_xml_map.h>
|
#include <clixon/clixon_xml_map.h>
|
||||||
#include <clixon/clixon_xml_db.h>
|
#include <clixon/clixon_xml_db.h>
|
||||||
|
#include <clixon/clixon_xsl.h>
|
||||||
#include <clixon/clixon_xpath_ctx.h>
|
#include <clixon/clixon_xpath_ctx.h>
|
||||||
#include <clixon/clixon_xpath.h>
|
#include <clixon/clixon_xpath.h>
|
||||||
#include <clixon/clixon_xsl.h>
|
|
||||||
#include <clixon/clixon_json.h>
|
#include <clixon/clixon_json.h>
|
||||||
#include <clixon/clixon_netconf_lib.h>
|
#include <clixon/clixon_netconf_lib.h>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -85,11 +85,30 @@ extern const map_str2int xpopmap[];
|
||||||
*/
|
*/
|
||||||
#if defined(__GNUC__) && __GNUC__ >= 3
|
#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(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)));
|
int xpath_vec_bool(cxobj *xcur, char *format, ...) __attribute__ ((format (printf, 2, 3)));
|
||||||
|
|
||||||
#else
|
#else
|
||||||
int xpath_vec_nodeset(cxobj *xcur, char *format, cxobj ***vec, size_t *veclen, ...);
|
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, ...);
|
int xpath_vec_bool(cxobj *xcur, char *format, ...);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
int xpath_vec_ctx(cxobj *xcur, char *xpath, xp_ctx **xrp);
|
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 */
|
#endif /* _CLIXON_XPATH_H */
|
||||||
|
|
|
||||||
|
|
@ -40,16 +40,17 @@
|
||||||
* Prototypes
|
* Prototypes
|
||||||
*/
|
*/
|
||||||
#if defined(__GNUC__) && __GNUC__ >= 3
|
#if defined(__GNUC__) && __GNUC__ >= 3
|
||||||
cxobj *xpath_first(cxobj *cxtop, char *format, ...) __attribute__ ((format (printf, 2, 3)));
|
cxobj *xpath_first_xsl(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)));
|
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,
|
int xpath_vec_flag(cxobj *cxtop, char *format, uint16_t flags,
|
||||||
cxobj ***vec, size_t *veclen, ...) __attribute__ ((format (printf, 2, 6)));
|
cxobj ***vec, size_t *veclen, ...) __attribute__ ((format (printf, 2, 6)));
|
||||||
#else
|
#else
|
||||||
cxobj *xpath_first(cxobj *cxtop, char *format, ...);
|
cxobj *xpath_first_xsl(cxobj *cxtop, char *format, ...);
|
||||||
int xpath_vec(cxobj *cxtop, char *format, cxobj ***vec, size_t *veclen, ...);
|
int xpath_vec_xsl(cxobj *cxtop, char *format, cxobj ***vec, size_t *veclen, ...);
|
||||||
int xpath_vec_flag(cxobj *cxtop, char *xpath, uint16_t flags,
|
int xpath_vec_flag_xsl(cxobj *cxtop, char *xpath, uint16_t flags,
|
||||||
cxobj ***vec, size_t *veclen, ...);
|
cxobj ***vec, size_t *veclen, ...);
|
||||||
#endif
|
#endif
|
||||||
cxobj *xpath_each(cxobj *xn_top, char *xpath, cxobj *prev);
|
cxobj *xpath_each(cxobj *xn_top, char *xpath, cxobj *prev);
|
||||||
|
|
||||||
|
|
||||||
#endif /* _CLIXON_XSL_H */
|
#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
|
* Turn this on to get a json parse and pretty print test program
|
||||||
* Usage: xpath
|
* Usage: json
|
||||||
* read json from input
|
* read json from input
|
||||||
* Example compile:
|
* Example compile:
|
||||||
gcc -g -o json -I. -I../clixon ./clixon_json.c -lclixon -lcligen
|
gcc -g -o json -I. -I../clixon ./clixon_json.c -lclixon -lcligen
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,8 @@
|
||||||
#include "clixon_xml.h"
|
#include "clixon_xml.h"
|
||||||
#include "clixon_plugin.h"
|
#include "clixon_plugin.h"
|
||||||
#include "clixon_xsl.h"
|
#include "clixon_xsl.h"
|
||||||
|
#include "clixon_xpath_ctx.h"
|
||||||
|
#include "clixon_xpath.h"
|
||||||
#include "clixon_xml_map.h"
|
#include "clixon_xml_map.h"
|
||||||
|
|
||||||
/* Mapping between Clicon startup modes string <--> constants,
|
/* Mapping between Clicon startup modes string <--> constants,
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,9 @@
|
||||||
#include "clixon_xml.h"
|
#include "clixon_xml.h"
|
||||||
#include "clixon_plugin.h"
|
#include "clixon_plugin.h"
|
||||||
#include "clixon_xsl.h"
|
#include "clixon_xsl.h"
|
||||||
|
#include "clixon_string.h"
|
||||||
|
#include "clixon_xpath_ctx.h"
|
||||||
|
#include "clixon_xpath.h"
|
||||||
#include "clixon_proto.h"
|
#include "clixon_proto.h"
|
||||||
#include "clixon_err.h"
|
#include "clixon_err.h"
|
||||||
#include "clixon_proto_client.h"
|
#include "clixon_proto_client.h"
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,8 @@
|
||||||
#include "clixon_options.h"
|
#include "clixon_options.h"
|
||||||
#include "clixon_xml.h"
|
#include "clixon_xml.h"
|
||||||
#include "clixon_plugin.h"
|
#include "clixon_plugin.h"
|
||||||
|
#include "clixon_xpath_ctx.h"
|
||||||
|
#include "clixon_xpath.h"
|
||||||
#include "clixon_xsl.h"
|
#include "clixon_xsl.h"
|
||||||
#include "clixon_log.h"
|
#include "clixon_log.h"
|
||||||
#include "clixon_err.h"
|
#include "clixon_err.h"
|
||||||
|
|
@ -439,7 +441,7 @@ xml_yang_validate_all(cxobj *xt,
|
||||||
case Y_LEAF_LIST:
|
case Y_LEAF_LIST:
|
||||||
/* Special case if leaf is leafref, then first check against
|
/* Special case if leaf is leafref, then first check against
|
||||||
current xml tree
|
current xml tree
|
||||||
*/
|
*/
|
||||||
if ((yc = yang_find((yang_node*)ys, Y_TYPE, NULL)) != NULL){
|
if ((yc = yang_find((yang_node*)ys, Y_TYPE, NULL)) != NULL){
|
||||||
if (strcmp(yc->ys_argument, "leafref") == 0){
|
if (strcmp(yc->ys_argument, "leafref") == 0){
|
||||||
if (validate_leafref(xt, yc) < 0)
|
if (validate_leafref(xt, yc) < 0)
|
||||||
|
|
@ -995,7 +997,7 @@ api_path_fmt2api_path(char *api_path_fmt,
|
||||||
* @example
|
* @example
|
||||||
* api_path_fmt: /interface/%s/address/%s
|
* api_path_fmt: /interface/%s/address/%s
|
||||||
* cvv: name=eth0
|
* cvv: name=eth0
|
||||||
* xpath: /interface/[name=eth0]/address
|
* xpath: /interface/[name='eth0']/address
|
||||||
* @example
|
* @example
|
||||||
* api_path_fmt: /ip/me/%s (if key)
|
* api_path_fmt: /ip/me/%s (if key)
|
||||||
* cvv: -
|
* cvv: -
|
||||||
|
|
@ -1038,7 +1040,13 @@ api_path_fmt2xpath(char *api_path_fmt,
|
||||||
clicon_err(OE_UNIX, errno, "cv2str_dup");
|
clicon_err(OE_UNIX, errno, "cv2str_dup");
|
||||||
goto done;
|
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);
|
free(str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1455,7 +1463,13 @@ api_path2xpath_cvv(yang_spec *yspec,
|
||||||
cprintf(xpath, "/%s", name);
|
cprintf(xpath, "/%s", name);
|
||||||
v = val;
|
v = val;
|
||||||
while ((cvi = cvec_each(cvk, cvi)) != NULL){
|
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;
|
v += strlen(v)+1;
|
||||||
}
|
}
|
||||||
if (val)
|
if (val)
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,10 @@
|
||||||
|
|
||||||
* Clixon XML XPATH 1.0 according to https://www.w3.org/TR/xpath-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 <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
@ -246,16 +250,15 @@ xp_eval_step(xp_ctx *xc0,
|
||||||
xpath_tree *xs,
|
xpath_tree *xs,
|
||||||
xp_ctx **xrp)
|
xp_ctx **xrp)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
int i;
|
int i;
|
||||||
cxobj *x;
|
cxobj *x;
|
||||||
cxobj *xv;
|
cxobj *xv;
|
||||||
cxobj *xp;
|
cxobj *xp;
|
||||||
cxobj **vec = NULL;
|
cxobj **vec = NULL;
|
||||||
size_t veclen = 0;
|
size_t veclen = 0;
|
||||||
xpath_tree *nodetest = xs->xs_c0;
|
xpath_tree *nodetest = xs->xs_c0;
|
||||||
xp_ctx *xr0 = NULL;
|
xp_ctx *xc = NULL;
|
||||||
xp_ctx *xc = NULL;
|
|
||||||
|
|
||||||
/* Create new xc */
|
/* Create new xc */
|
||||||
if ((xc = ctx_dup(xc0)) == NULL)
|
if ((xc = ctx_dup(xc0)) == NULL)
|
||||||
|
|
@ -312,16 +315,14 @@ xp_eval_step(xp_ctx *xc0,
|
||||||
case A_NAMESPACE: /* principal node type is namespace */
|
case A_NAMESPACE: /* principal node type is namespace */
|
||||||
break;
|
break;
|
||||||
case A_PARENT:
|
case A_PARENT:
|
||||||
if ((xr0 = malloc(sizeof(*xr0))) == NULL){
|
veclen = xc->xc_size;
|
||||||
clicon_err(OE_UNIX, errno, "malloc");
|
vec = xc->xc_nodeset;
|
||||||
goto done;
|
xc->xc_size = 0;
|
||||||
}
|
xc->xc_nodeset = NULL;
|
||||||
memset(xr0, 0, sizeof(*xr0));
|
for (i=0; i<veclen; i++){
|
||||||
xr0->xc_initial = xc->xc_initial;
|
x = vec[i];
|
||||||
for (i=0; i<xc->xc_size; i++){
|
|
||||||
x = xc->xc_nodeset[i];
|
|
||||||
if ((xp = xml_parent(x)) != NULL)
|
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;
|
goto done;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -330,19 +331,20 @@ xp_eval_step(xp_ctx *xc0,
|
||||||
case A_PRECEEDING_SIBLING:
|
case A_PRECEEDING_SIBLING:
|
||||||
break;
|
break;
|
||||||
case A_SELF:
|
case A_SELF:
|
||||||
xr0 = ctx_dup(xc);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
clicon_err(OE_XML, 0, "No such axisname: %d", xs->xs_int);
|
clicon_err(OE_XML, 0, "No such axisname: %d", xs->xs_int);
|
||||||
goto done;
|
goto done;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (xr0)
|
|
||||||
*xrp = xr0;
|
|
||||||
if (xs->xs_c1){
|
if (xs->xs_c1){
|
||||||
if (xp_eval(xc, xs->xs_c1, xrp) < 0)
|
if (xp_eval(xc, xs->xs_c1, xrp) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
else{
|
||||||
|
*xrp = xc;
|
||||||
|
xc = NULL;
|
||||||
|
}
|
||||||
assert(*xrp);
|
assert(*xrp);
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
|
|
@ -623,8 +625,8 @@ xp_relop(xp_ctx *xc1,
|
||||||
if (xc1->xc_type == xc2->xc_type){ /* cases (2-3) above */
|
if (xc1->xc_type == xc2->xc_type){ /* cases (2-3) above */
|
||||||
switch (xc1->xc_type){
|
switch (xc1->xc_type){
|
||||||
case XT_NODESET:
|
case XT_NODESET:
|
||||||
/* If both are node-sets, then it is true iff the string value of a
|
/* If both are node-sets, then it is true iff the string value of one
|
||||||
node in the first node-set and in the second node-set is true */
|
node in the first node-set and one in the second node-set is true */
|
||||||
for (i=0; i<xc1->xc_size; i++){
|
for (i=0; i<xc1->xc_size; i++){
|
||||||
if ((s1 = xml_body(xc1->xc_nodeset[i])) == NULL){
|
if ((s1 = xml_body(xc1->xc_nodeset[i])) == NULL){
|
||||||
xr->xc_bool = 0;
|
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));
|
clicon_err(OE_XML, 0, "Operator %s not supported for nodeset/nodeset comparison", clicon_int2str(xpopmap,op));
|
||||||
goto done;
|
goto done;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (xr->xc_bool) /* enough to find a single node */
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
if (xr->xc_bool) /* enough to find a single node */
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case XT_BOOL:
|
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
|
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
|
performing the comparison on the string-value of the node and
|
||||||
the other string is true.*/
|
the other string is true.*/
|
||||||
|
s2 = xc2->xc_string;
|
||||||
for (i=0; i<xc1->xc_size; i++){
|
for (i=0; i<xc1->xc_size; i++){
|
||||||
x = xc1->xc_nodeset[i]; /* node in nodeset */
|
x = xc1->xc_nodeset[i]; /* node in nodeset */
|
||||||
s1 = xml_body(x);
|
s1 = xml_body(x);
|
||||||
s2 = xc2->xc_string;
|
|
||||||
switch(op){
|
switch(op){
|
||||||
case XO_EQ:
|
case XO_EQ:
|
||||||
xr->xc_bool = (strcmp(s1, s2)==0);
|
xr->xc_bool = (strcmp(s1, s2)==0);
|
||||||
|
|
@ -727,6 +733,8 @@ xp_relop(xp_ctx *xc1,
|
||||||
goto done;
|
goto done;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (xr->xc_bool) /* enough to find a single node */
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case XT_NUMBER:
|
case XT_NUMBER:
|
||||||
|
|
@ -759,6 +767,8 @@ xp_relop(xp_ctx *xc1,
|
||||||
goto done;
|
goto done;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (xr->xc_bool) /* enough to find a single node */
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
@ -862,7 +872,7 @@ xp_eval(xp_ctx *xc,
|
||||||
x = xc->xc_node;
|
x = xc->xc_node;
|
||||||
while (xml_parent(x) != NULL)
|
while (xml_parent(x) != NULL)
|
||||||
x = xml_parent(x);
|
x = xml_parent(x);
|
||||||
// xc->xc_node = x;
|
xc->xc_node = x;
|
||||||
xc->xc_nodeset[0] = x;
|
xc->xc_nodeset[0] = x;
|
||||||
xc->xc_size=1;
|
xc->xc_size=1;
|
||||||
/* // is short for /descendant-or-self::node()/ */
|
/* // 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) {
|
while ((x = xml_child_each(xc->xc_node, x, CX_ELMNT)) != NULL) {
|
||||||
if (cxvec_append(x, &xr0->xc_nodeset, &xr0->xc_size) < 0)
|
if (cxvec_append(x, &xr0->xc_nodeset, &xr0->xc_size) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -1027,7 +1036,6 @@ xp_eval(xp_ctx *xc,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Given XML tree and xpath, returns xpath context
|
/*! Given XML tree and xpath, returns xpath context
|
||||||
|
|
||||||
* @param[in] xcur XML-tree where to search
|
* @param[in] xcur XML-tree where to search
|
||||||
* @param[in] xpath String with XPATH 1.0 syntax
|
* @param[in] xpath String with XPATH 1.0 syntax
|
||||||
* @param[out] xrp Return XPATH context
|
* @param[out] xrp Return XPATH context
|
||||||
|
|
@ -1081,6 +1089,45 @@ xpath_vec_ctx(cxobj *xcur,
|
||||||
return retval;
|
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
|
/*! Given XML tree and xpath, returns nodeset as xml node vector
|
||||||
* If result is not nodeset, return empty nodeset
|
* If result is not nodeset, return empty nodeset
|
||||||
* @param[in] xcur xml-tree where to search
|
* @param[in] xcur xml-tree where to search
|
||||||
|
|
@ -1135,6 +1182,81 @@ xpath_vec_nodeset(cxobj *xcur,
|
||||||
return retval;
|
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
|
/*! Given XML tree and xpath, returns boolean
|
||||||
* @param[in] xcur xml-tree where to search
|
* @param[in] xcur xml-tree where to search
|
||||||
* @param[in] xpath stdarg string with XPATH 1.0 syntax
|
* @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); }
|
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-> ."); }
|
| '.' predicates { $$=xp_new(XP_STEP,A_SELF, 0.0,NULL, NULL, NULL, $2); clicon_debug(1,"step-> ."); }
|
||||||
| DOUBLEDOT { $$=xp_new(XP_STEP, A_PARENT, 0.0,NULL, NULL, NULL, NULL); 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;}
|
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 primary syntactic construct in XPath is the expression. An expression matches
|
||||||
the production Expr (see https://www.w3.org/TR/xpath-10/#NT-Expr)
|
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 <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
@ -896,7 +900,7 @@ xpath_first0(cxobj *xcur,
|
||||||
* @see also xpath_vec.
|
* @see also xpath_vec.
|
||||||
*/
|
*/
|
||||||
cxobj *
|
cxobj *
|
||||||
xpath_first(cxobj *xcur,
|
xpath_first_xsl(cxobj *xcur,
|
||||||
char *format,
|
char *format,
|
||||||
...)
|
...)
|
||||||
{
|
{
|
||||||
|
|
@ -1012,7 +1016,7 @@ xpath_each(cxobj *xcur,
|
||||||
* @see also xpath_first, xpath_each.
|
* @see also xpath_first, xpath_each.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
xpath_vec(cxobj *xcur,
|
xpath_vec_xsl(cxobj *xcur,
|
||||||
char *format,
|
char *format,
|
||||||
cxobj ***vec,
|
cxobj ***vec,
|
||||||
size_t *veclen,
|
size_t *veclen,
|
||||||
|
|
@ -1048,7 +1052,6 @@ xpath_vec(cxobj *xcur,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* A restricted xpath that returns a vector of matches (only nodes marked with flags)
|
/* A restricted xpath that returns a vector of matches (only nodes marked with flags)
|
||||||
* @param[in] xcur xml-tree where to search
|
* @param[in] xcur xml-tree where to search
|
||||||
* @param[in] xpath string with XPATH syntax
|
* @param[in] xpath string with XPATH syntax
|
||||||
|
|
@ -1073,12 +1076,12 @@ xpath_vec(cxobj *xcur,
|
||||||
* @see also xpath_vec This is a specialized version.
|
* @see also xpath_vec This is a specialized version.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
xpath_vec_flag(cxobj *xcur,
|
xpath_vec_flag_xsl(cxobj *xcur,
|
||||||
char *format,
|
char *format,
|
||||||
uint16_t flags,
|
uint16_t flags,
|
||||||
cxobj ***vec,
|
cxobj ***vec,
|
||||||
size_t *veclen,
|
size_t *veclen,
|
||||||
...)
|
...)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
|
|
||||||
|
|
@ -545,7 +545,6 @@ cv_validate1(cg_var *cv,
|
||||||
if ((vec = clicon_strsep(str, " \t", &nvec)) == NULL)
|
if ((vec = clicon_strsep(str, " \t", &nvec)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
for (i=0; i<nvec; i++){
|
for (i=0; i<nvec; i++){
|
||||||
clicon_log(LOG_NOTICE, "%s: vec[i]: %s", __FUNCTION__, vec[i]);
|
|
||||||
if ((v = vec[i]) == NULL || !strlen(v))
|
if ((v = vec[i]) == NULL || !strlen(v))
|
||||||
continue;
|
continue;
|
||||||
found = 0;
|
found = 0;
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,9 @@
|
||||||
testnr=0
|
testnr=0
|
||||||
testname=
|
testname=
|
||||||
|
|
||||||
|
# Set to 1 if new xpath. Set to nothing, or comment if old
|
||||||
|
#XPATH_USE_NEW=1
|
||||||
|
|
||||||
# For memcheck
|
# For memcheck
|
||||||
#clixon_cli="valgrind --leak-check=full --show-leak-kinds=all clixon_cli"
|
#clixon_cli="valgrind --leak-check=full --show-leak-kinds=all clixon_cli"
|
||||||
clixon_cli=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 <&"
|
new "cli configure using encoded chars data <&"
|
||||||
expectfn "$clixon_cli -1 -f $cfg set interfaces interface eth/0/0 description \"foo<&bar\"" 0 ""
|
expectfn "$clixon_cli -1 -f $cfg set interfaces interface eth/0/0 description \"foo<&bar\"" 0 ""
|
||||||
|
|
||||||
new "cli configure using encoded chars name <&"
|
new "cli configure using encoded chars name <&"
|
||||||
expectfn "$clixon_cli -1 -f $cfg set interfaces interface fddi&< type ianaift:ethernetCsmacd" 0 ""
|
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"
|
new "leafref base commit"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
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"
|
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>]]>]]>$"
|
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
|
cfg=$dir/conf_yang.xml
|
||||||
fyang=$dir/netconf.yang
|
fyang=$dir/netconf.yang
|
||||||
|
tmp=$dir/tmp.x
|
||||||
|
|
||||||
cat <<EOF > $cfg
|
cat <<EOF > $cfg
|
||||||
<config>
|
<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"
|
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>]]>]]>$"
|
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"
|
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"
|
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>"
|
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"
|
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>]]>]]>$"
|
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"
|
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"
|
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"
|
new "netconf validate missing type"
|
||||||
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply><rpc-error>"
|
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>]]>]]>$"
|
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"
|
#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"
|
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"
|
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>]]>]]>$"
|
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"
|
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>]]>]]>$"
|
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"
|
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>]]>]]>$"
|
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"
|
new "delete candidate"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><delete-config><target><candidate/></target></delete-config></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
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 file (alt provide it in stdin after xpath)
|
||||||
xml=$dir/xml.xml
|
xml=$dir/xml.xml
|
||||||
xml2=$dir/xml2.xml
|
xml2=$dir/xml2.xml
|
||||||
|
xml3=$dir/xml3.xml
|
||||||
|
xml4=$dir/xml4.xml
|
||||||
|
|
||||||
cat <<EOF > $xml
|
cat <<EOF > $xml
|
||||||
<aaa>
|
<aaa>
|
||||||
<bbb x="hello"><ccc>42</ccc></bbb>
|
<bbb x="hello">
|
||||||
<bbb x="bye"><ccc>99</ccc></bbb>
|
<ccc>42</ccc>
|
||||||
<ddd><ccc>22</ccc></ddd>
|
</bbb>
|
||||||
|
<bbb x="bye">
|
||||||
|
<ccc>99</ccc>
|
||||||
|
</bbb>
|
||||||
|
<ddd>
|
||||||
|
<ccc>22</ccc>
|
||||||
|
</ddd>
|
||||||
</aaa>
|
</aaa>
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
|
@ -53,6 +61,19 @@ cat <<EOF > $xml2
|
||||||
</aaa>
|
</aaa>
|
||||||
EOF
|
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 /"
|
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>$"
|
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)"
|
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$"
|
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
|
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"
|
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>]]>]]>$"
|
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"
|
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>]]>]]>$"
|
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)"
|
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>]]>]]>$"
|
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>]]>]]>$"
|
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"
|
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"
|
new "netconf discard-changes"
|
||||||
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
|
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