New: [feature request: support xpath functions for strings](https://github.com/clicon/clixon/issues/556)
Added: re-match, substring, string, string-length, translate, substring-before, substring-after, starts-with
This commit is contained in:
parent
3188e3cc59
commit
515d30bdd7
7 changed files with 741 additions and 45 deletions
|
|
@ -15,6 +15,10 @@
|
|||
## 7.3.0
|
||||
Expected: January 2025
|
||||
|
||||
### Features
|
||||
|
||||
* New: [feature request: support xpath functions for strings](https://github.com/clicon/clixon/issues/556)
|
||||
* Added: re-match, substring, string, string-length, translate, substring-before, substring-after, starts-with
|
||||
### Corrected Bugs
|
||||
|
||||
* Fixed: [string length validation doesn't work for the entry "" in case it has default value specified](https://github.com/clicon/clixon/issues/563)
|
||||
|
|
|
|||
|
|
@ -1197,6 +1197,11 @@ xp_eval(xp_ctx *xc,
|
|||
goto done;
|
||||
goto ok;
|
||||
break;
|
||||
case XPATHFN_RE_MATCH:
|
||||
if (xp_function_re_match(xc, xs->xs_c0, nsc, localonly, xrp) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
break;
|
||||
case XPATHFN_DEREF:
|
||||
if (xp_function_deref(xc, xs->xs_c0, nsc, localonly, xrp) < 0)
|
||||
goto done;
|
||||
|
|
@ -1232,8 +1237,43 @@ xp_eval(xp_ctx *xc,
|
|||
goto done;
|
||||
goto ok;
|
||||
break;
|
||||
case XPATHFN_STRING:
|
||||
if (xp_function_string(xc, xs->xs_c0, nsc, localonly, xrp) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
break;
|
||||
case XPATHFN_STARTS_WITH:
|
||||
if (xp_function_contains(xc, xs->xs_c0, nsc, 1, localonly, xrp) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
break;
|
||||
case XPATHFN_CONTAINS:
|
||||
if (xp_function_contains(xc, xs->xs_c0, nsc, localonly, xrp) < 0)
|
||||
if (xp_function_contains(xc, xs->xs_c0, nsc, 0, localonly, xrp) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
break;
|
||||
case XPATHFN_SUBSTRING_BEFORE:
|
||||
if (xp_function_substring_str(xc, xs->xs_c0, nsc, 1, localonly, xrp) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
break;
|
||||
case XPATHFN_SUBSTRING_AFTER:
|
||||
if (xp_function_substring_str(xc, xs->xs_c0, nsc, 0, localonly, xrp) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
break;
|
||||
case XPATHFN_SUBSTRING:
|
||||
if (xp_function_substring(xc, xs->xs_c0, nsc, localonly, xrp) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
break;
|
||||
case XPATHFN_STRING_LENGTH:
|
||||
if (xp_function_string_length(xc, xs->xs_c0, nsc, localonly, xrp) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
break;
|
||||
case XPATHFN_TRANSLATE:
|
||||
if (xp_function_translate(xc, xs->xs_c0, nsc, localonly, xrp) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@
|
|||
#include "clixon_log.h"
|
||||
#include "clixon_debug.h"
|
||||
#include "clixon_options.h"
|
||||
#include "clixon_regex.h"
|
||||
#include "clixon_yang_type.h"
|
||||
#include "clixon_xml_map.h"
|
||||
#include "clixon_yang_module.h"
|
||||
|
|
@ -82,7 +83,7 @@
|
|||
static const map_str2int xpath_fnname_map[] = { /* alphabetic order */
|
||||
{"bit-is-set", XPATHFN_BIT_IS_SET},
|
||||
{"boolean", XPATHFN_BOOLEAN},
|
||||
{"eiling", XPATHFN_CEILING},
|
||||
{"ceiling", XPATHFN_CEILING},
|
||||
{"comment", XPATHFN_COMMENT},
|
||||
{"concat", XPATHFN_CONCAT},
|
||||
{"contains", XPATHFN_CONTAINS},
|
||||
|
|
@ -110,6 +111,7 @@ static const map_str2int xpath_fnname_map[] = { /* alphabetic order */
|
|||
{"round", XPATHFN_ROUND},
|
||||
{"starts-with", XPATHFN_STARTS_WITH},
|
||||
{"string", XPATHFN_STRING},
|
||||
{"string-length", XPATHFN_STRING_LENGTH},
|
||||
{"substring", XPATHFN_SUBSTRING},
|
||||
{"substring-after", XPATHFN_SUBSTRING_AFTER},
|
||||
{"substring-before", XPATHFN_SUBSTRING_BEFORE},
|
||||
|
|
@ -136,6 +138,17 @@ xp_fnname_int2str(enum clixon_xpath_function code)
|
|||
return clicon_int2str(xpath_fnname_map, code);
|
||||
}
|
||||
|
||||
/*! Returns a node set with the initial context node as its only member.
|
||||
*
|
||||
* @param[in] xc0 Incoming context
|
||||
* @param[in] xs XPath node tree
|
||||
* @param[in] nsc XML Namespace context
|
||||
* @param[in] localonly Skip prefix and namespace tests (non-standard)
|
||||
* @param[out] xrp Resulting context
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @see RFC 7950 10.1.1
|
||||
*/
|
||||
int
|
||||
xp_function_current(xp_ctx *xc0,
|
||||
struct xpath_tree *xs,
|
||||
|
|
@ -162,6 +175,117 @@ xp_function_current(xp_ctx *xc0,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Returns "true" if the "subject" string matches the regular expression "pattern";
|
||||
*
|
||||
* @param[in] xc Incoming context
|
||||
* @param[in] xs XPath node tree
|
||||
* @param[in] nsc XML Namespace context
|
||||
* @param[in] localonly Skip prefix and namespace tests (non-standard)
|
||||
* @param[out] xrp Resulting context
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @see RFC 7950 10.2.1
|
||||
* @note Uses xml2 regexp if libxml2 enabled, otherwise posix
|
||||
* This means for xml2, you have to configure BOTH cligen and clixon with --with-libxml2
|
||||
* @note Compiling regexp takes a lot of resources, no caching is made of re here
|
||||
* as is done for eg YANG patterns
|
||||
* Example: re-match("1.22.333", "\d{1,3}\.\d{1,3}\.\d{1,3}") returns true
|
||||
*/
|
||||
int
|
||||
xp_function_re_match(xp_ctx *xc,
|
||||
struct xpath_tree *xs,
|
||||
cvec *nsc,
|
||||
int localonly,
|
||||
xp_ctx **xrp)
|
||||
{
|
||||
int retval = -1;
|
||||
xp_ctx *xr0 = NULL;
|
||||
xp_ctx *xr1 = NULL;
|
||||
xp_ctx *xr = NULL;
|
||||
char *s0 = NULL;
|
||||
char *regexp = NULL;
|
||||
char *posix = NULL;
|
||||
void *re = NULL;
|
||||
int ret;
|
||||
|
||||
if (xs == NULL || xs->xs_c0 == NULL || xs->xs_c1 == NULL){
|
||||
clixon_err(OE_XML, EINVAL, "contains expects but did not get two arguments");
|
||||
goto done;
|
||||
}
|
||||
/* contains two arguments in xs: boolean contains(string, string) */
|
||||
if (xp_eval(xc, xs->xs_c0, nsc, localonly, &xr0) < 0)
|
||||
goto done;
|
||||
if (ctx2string(xr0, &s0) < 0)
|
||||
goto done;
|
||||
if (xp_eval(xc, xs->xs_c1, nsc, localonly, &xr1) < 0)
|
||||
goto done;
|
||||
if (ctx2string(xr1, ®exp) < 0)
|
||||
goto done;
|
||||
#ifdef HAVE_LIBXML2
|
||||
if ((ret = cligen_regex_libxml2_compile(regexp, &re)) < 0)
|
||||
goto done;
|
||||
#else
|
||||
if (regexp_xsd2posix(regexp, &posix) < 0)
|
||||
goto done;
|
||||
if ((ret = cligen_regex_posix_compile(posix, &re)) < 0)
|
||||
goto done;
|
||||
#endif
|
||||
if (ret == 0){
|
||||
clixon_err(OE_YANG, 0, "regexp compile fail: \"%s\"", regexp);
|
||||
goto done;
|
||||
}
|
||||
// s0 = "1.22.333";
|
||||
#ifdef HAVE_LIBXML2
|
||||
if ((ret = cligen_regex_libxml2_exec(re, s0)) < 0)
|
||||
goto done;
|
||||
|
||||
#else
|
||||
if ((ret = cligen_regex_posix_exec(re, s0)) < 0)
|
||||
goto done;
|
||||
#endif
|
||||
if ((xr = malloc(sizeof(*xr))) == NULL){
|
||||
clixon_err(OE_UNIX, errno, "malloc");
|
||||
goto done;
|
||||
}
|
||||
memset(xr, 0, sizeof(*xr));
|
||||
xr->xc_type = XT_BOOL;
|
||||
xr->xc_bool = ret;
|
||||
*xrp = xr;
|
||||
xr = NULL;
|
||||
retval = 0;
|
||||
done:
|
||||
if (re){
|
||||
#ifdef HAVE_LIBXML2
|
||||
cligen_regex_libxml2_free(re);
|
||||
#else
|
||||
cligen_regex_posix_free(re);
|
||||
free(re);
|
||||
#endif
|
||||
}
|
||||
if (xr0)
|
||||
ctx_free(xr0);
|
||||
if (xr1)
|
||||
ctx_free(xr1);
|
||||
if (s0)
|
||||
free(s0);
|
||||
if (regexp)
|
||||
free(regexp);
|
||||
if (posix)
|
||||
free(posix);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Follows reference defined by the first node and returns nodes it refers to
|
||||
*
|
||||
* @param[in] xc0 Incoming context
|
||||
* @param[in] xs XPath node tree
|
||||
* @param[in] nsc XML Namespace context
|
||||
* @param[in] localonly Skip prefix and namespace tests (non-standard)
|
||||
* @param[out] xrp Resulting context
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @see RFC 7950 10.3.1
|
||||
*/
|
||||
int
|
||||
xp_function_deref(xp_ctx *xc0,
|
||||
struct xpath_tree *xs,
|
||||
|
|
@ -316,7 +440,7 @@ derived_from_one(char *baseidentity,
|
|||
* @param[out] xrp Resulting context
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @see rfc7950 10.4.1
|
||||
* @see RFC7950 10.4.1
|
||||
* Returns "true" if any node in the argument "nodes" is a node of type "identityref" and its
|
||||
* value is an identity that is derived from (see Section 7.18.2) the identity "identity"
|
||||
* boolean derived-from(node-set nodes, string identity)
|
||||
|
|
@ -542,12 +666,12 @@ xp_function_name(xp_ctx *xc,
|
|||
int localonly,
|
||||
xp_ctx **xrp)
|
||||
{
|
||||
int retval = -1;
|
||||
xp_ctx *xr = NULL;
|
||||
xp_ctx *xr0 = NULL;
|
||||
char *s0 = NULL;
|
||||
int i;
|
||||
cxobj *x;
|
||||
int retval = -1;
|
||||
xp_ctx *xr = NULL;
|
||||
xp_ctx *xr0 = NULL;
|
||||
char *s0 = NULL;
|
||||
int i;
|
||||
cxobj *x;
|
||||
|
||||
if (xs == NULL || xs->xs_c0 == NULL){
|
||||
clixon_err(OE_XML, EINVAL, "not expects but did not get one argument");
|
||||
|
|
@ -583,7 +707,7 @@ xp_function_name(xp_ctx *xc,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Eval xpath function contains
|
||||
/*! Eval xpath function converts an object to a string
|
||||
*
|
||||
* @param[in] xc Incoming context
|
||||
* @param[in] xs XPath node tree
|
||||
|
|
@ -595,18 +719,75 @@ xp_function_name(xp_ctx *xc,
|
|||
* @see https://www.w3.org/TR/xpath-10/#NT-FunctionName 4.2 String Functions
|
||||
*/
|
||||
int
|
||||
xp_function_string(xp_ctx *xc,
|
||||
struct xpath_tree *xs,
|
||||
cvec *nsc,
|
||||
int localonly,
|
||||
xp_ctx **xrp)
|
||||
{
|
||||
int retval = -1;
|
||||
xp_ctx *xr0 = NULL;
|
||||
xp_ctx *xr = NULL;
|
||||
char *s0 = NULL;
|
||||
|
||||
if (xs != NULL && xs->xs_c0){
|
||||
/* contains two arguments in xs: boolean contains(string, string) */
|
||||
if (xp_eval(xc, xs->xs_c0, nsc, localonly, &xr0) < 0)
|
||||
goto done;
|
||||
if (ctx2string(xr0, &s0) < 0)
|
||||
goto done;
|
||||
}
|
||||
else {
|
||||
if ((s0 = strdup("")) == NULL){
|
||||
clixon_err(OE_UNIX, errno, "strdup");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
if ((xr = malloc(sizeof(*xr))) == NULL){
|
||||
clixon_err(OE_UNIX, errno, "malloc");
|
||||
goto done;
|
||||
}
|
||||
memset(xr, 0, sizeof(*xr));
|
||||
xr->xc_type = XT_STRING;
|
||||
xr->xc_string = s0;
|
||||
s0 = NULL;
|
||||
*xrp = xr;
|
||||
xr = NULL;
|
||||
retval = 0;
|
||||
done:
|
||||
if (xr0)
|
||||
ctx_free(xr0);
|
||||
if (s0)
|
||||
free(s0);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Eval xpath function contains sub-string
|
||||
*
|
||||
* @param[in] xc Incoming context
|
||||
* @param[in] xs XPath node tree
|
||||
* @param[in] nsc XML Namespace context
|
||||
* @param[in] starts 0: contains, 1: starts with
|
||||
* @param[in] localonly Skip prefix and namespace tests (non-standard)
|
||||
* @param[out] xrp Resulting context
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @see https://www.w3.org/TR/xpath-10/#NT-FunctionName 4.2 String Functions
|
||||
*/
|
||||
int
|
||||
xp_function_contains(xp_ctx *xc,
|
||||
struct xpath_tree *xs,
|
||||
cvec *nsc,
|
||||
int starts,
|
||||
int localonly,
|
||||
xp_ctx **xrp)
|
||||
{
|
||||
int retval = -1;
|
||||
xp_ctx *xr0 = NULL;
|
||||
xp_ctx *xr1 = NULL;
|
||||
xp_ctx *xr = NULL;
|
||||
char *s0 = NULL;
|
||||
char *s1 = NULL;
|
||||
int retval = -1;
|
||||
xp_ctx *xr0 = NULL;
|
||||
xp_ctx *xr1 = NULL;
|
||||
xp_ctx *xr = NULL;
|
||||
char *s0 = NULL;
|
||||
char *s1 = NULL;
|
||||
|
||||
if (xs == NULL || xs->xs_c0 == NULL || xs->xs_c1 == NULL){
|
||||
clixon_err(OE_XML, EINVAL, "contains expects but did not get two arguments");
|
||||
|
|
@ -627,7 +808,10 @@ xp_function_contains(xp_ctx *xc,
|
|||
}
|
||||
memset(xr, 0, sizeof(*xr));
|
||||
xr->xc_type = XT_BOOL;
|
||||
xr->xc_bool = (strstr(s0, s1) != NULL);
|
||||
if (starts)
|
||||
xr->xc_bool = (strncmp(s0, s1, strlen(s1)) == 0);
|
||||
else
|
||||
xr->xc_bool = (strstr(s0, s1) != NULL);
|
||||
*xrp = xr;
|
||||
xr = NULL;
|
||||
retval = 0;
|
||||
|
|
@ -643,6 +827,363 @@ xp_function_contains(xp_ctx *xc,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Eval xpath function contains sub-string
|
||||
*
|
||||
* @param[in] xc Incoming context
|
||||
* @param[in] xs XPath node tree
|
||||
* @param[in] nsc XML Namespace context
|
||||
* @param[in] before 0:Return substring after, 1: before
|
||||
* @param[in] localonly Skip prefix and namespace tests (non-standard)
|
||||
* @param[out] xrp Resulting context
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @see https://www.w3.org/TR/xpath-10/#NT-FunctionName 4.2 String Functions
|
||||
* Example: substring-before("1999/04/01","/") returns "1999"
|
||||
*/
|
||||
int
|
||||
xp_function_substring_str(xp_ctx *xc,
|
||||
struct xpath_tree *xs,
|
||||
cvec *nsc,
|
||||
int before,
|
||||
int localonly,
|
||||
xp_ctx **xrp)
|
||||
{
|
||||
int retval = -1;
|
||||
xp_ctx *xr0 = NULL;
|
||||
xp_ctx *xr1 = NULL;
|
||||
xp_ctx *xr = NULL;
|
||||
char *s0 = NULL;
|
||||
char *s1 = NULL;
|
||||
char *sp;
|
||||
|
||||
if (xs == NULL || xs->xs_c0 == NULL || xs->xs_c1 == NULL){
|
||||
clixon_err(OE_XML, EINVAL, "contains expects but did not get two arguments");
|
||||
goto done;
|
||||
}
|
||||
/* contains two arguments in xs: boolean contains(string, string) */
|
||||
if (xp_eval(xc, xs->xs_c0, nsc, localonly, &xr0) < 0)
|
||||
goto done;
|
||||
if (ctx2string(xr0, &s0) < 0)
|
||||
goto done;
|
||||
if (xp_eval(xc, xs->xs_c1, nsc, localonly, &xr1) < 0)
|
||||
goto done;
|
||||
if (ctx2string(xr1, &s1) < 0)
|
||||
goto done;
|
||||
if ((xr = malloc(sizeof(*xr))) == NULL){
|
||||
clixon_err(OE_UNIX, errno, "malloc");
|
||||
goto done;
|
||||
}
|
||||
memset(xr, 0, sizeof(*xr));
|
||||
xr->xc_type = XT_STRING;
|
||||
sp = strstr(s0, s1);
|
||||
if (before) {
|
||||
if (sp != NULL)
|
||||
*sp = '\0';
|
||||
else
|
||||
*s0 = '\0';
|
||||
if ((xr->xc_string = strdup(s0)) == NULL){
|
||||
clixon_err(OE_UNIX, errno, "strdup");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (sp)
|
||||
sp += strlen(s1);
|
||||
if (sp == NULL)
|
||||
sp = "";
|
||||
if ((xr->xc_string = strdup(sp)) == NULL){
|
||||
clixon_err(OE_UNIX, errno, "strdup");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
*xrp = xr;
|
||||
xr = NULL;
|
||||
retval = 0;
|
||||
done:
|
||||
if (xr0)
|
||||
ctx_free(xr0);
|
||||
if (xr1)
|
||||
ctx_free(xr1);
|
||||
if (s0)
|
||||
free(s0);
|
||||
if (s1)
|
||||
free(s1);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Eval xpath function return substring
|
||||
*
|
||||
* @param[in] xc Incoming context
|
||||
* @param[in] xs XPath node tree
|
||||
* @param[in] nsc XML Namespace context
|
||||
* @param[in] localonly Skip prefix and namespace tests (non-standard)
|
||||
* @param[out] xrp Resulting context
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @see https://www.w3.org/TR/xpath-10/#NT-FunctionName 4.2 String Functions
|
||||
*/
|
||||
int
|
||||
xp_function_substring(xp_ctx *xc,
|
||||
struct xpath_tree *xs,
|
||||
cvec *nsc,
|
||||
int localonly,
|
||||
xp_ctx **xrp)
|
||||
{
|
||||
int retval = -1;
|
||||
struct xpath_tree *a0;
|
||||
struct xpath_tree *a1;
|
||||
struct xpath_tree *a2;
|
||||
xp_ctx *xr0 = NULL;
|
||||
xp_ctx *xr1 = NULL;
|
||||
xp_ctx *xr2 = NULL;
|
||||
xp_ctx *xr = NULL;
|
||||
char *s0 = NULL;
|
||||
char *s0p;
|
||||
double d1;
|
||||
double d2;
|
||||
int32_t i1;
|
||||
int32_t i10;
|
||||
int32_t i2;
|
||||
int32_t it;
|
||||
|
||||
if (xs == NULL || xs->xs_c0 == NULL || xs->xs_c1 == NULL){
|
||||
clixon_err(OE_XML, EINVAL, "contains expects but did not get two arguments");
|
||||
goto done;
|
||||
}
|
||||
if (xs->xs_c0->xs_c1 != NULL){
|
||||
a0 = xs->xs_c0->xs_c0;
|
||||
a1 = xs->xs_c0->xs_c1;
|
||||
a2 = xs->xs_c1;
|
||||
}
|
||||
else {
|
||||
a0 = xs->xs_c0;
|
||||
a1 = xs->xs_c1;
|
||||
a2 = NULL;
|
||||
}
|
||||
/* contains two arguments in xs: boolean contains(string, string) */
|
||||
if (xp_eval(xc, a0, nsc, localonly, &xr0) < 0)
|
||||
goto done;
|
||||
if (ctx2string(xr0, &s0) < 0)
|
||||
goto done;
|
||||
if (xp_eval(xc, a1, nsc, localonly, &xr1) < 0)
|
||||
goto done;
|
||||
if (ctx2number(xr1, &d1) < 0)
|
||||
goto done;
|
||||
if ((i10 = round(d1)-1) < 0)
|
||||
i1 = 0;
|
||||
else
|
||||
i1 = i10;
|
||||
if ((xr = malloc(sizeof(*xr))) == NULL){
|
||||
clixon_err(OE_UNIX, errno, "malloc");
|
||||
goto done;
|
||||
}
|
||||
memset(xr, 0, sizeof(*xr));
|
||||
xr->xc_type = XT_STRING;
|
||||
if (i1 < strlen(s0))
|
||||
s0p = &s0[i1];
|
||||
else
|
||||
s0p = "";
|
||||
if (a2) {
|
||||
if (xp_eval(xc, a2, nsc, localonly, &xr2) < 0)
|
||||
goto done;
|
||||
if (ctx2number(xr2, &d2) < 0)
|
||||
goto done;
|
||||
if ((i2 = round(d2)) < 0)
|
||||
i2 = 0;
|
||||
it = i10+i2;
|
||||
if (it < (int)strlen(s0)){
|
||||
if (it < 0)
|
||||
*s0p = '\0';
|
||||
else
|
||||
*(s0+i10+i2) = '\0';
|
||||
}
|
||||
}
|
||||
if ((xr->xc_string = strdup(s0p)) == NULL){
|
||||
clixon_err(OE_UNIX, errno, "strdup");
|
||||
goto done;
|
||||
}
|
||||
*xrp = xr;
|
||||
xr = NULL;
|
||||
retval = 0;
|
||||
done:
|
||||
if (xr0)
|
||||
ctx_free(xr0);
|
||||
if (xr1)
|
||||
ctx_free(xr1);
|
||||
if (xr2)
|
||||
ctx_free(xr2);
|
||||
if (s0)
|
||||
free(s0);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Eval xpath function returns the number of characters in the string
|
||||
*
|
||||
* @param[in] xc Incoming context
|
||||
* @param[in] xs XPath node tree
|
||||
* @param[in] nsc XML Namespace context
|
||||
* @param[in] localonly Skip prefix and namespace tests (non-standard)
|
||||
* @param[out] xrp Resulting context
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @see https://www.w3.org/TR/xpath-10/#NT-FunctionName 4.2 String Functions
|
||||
* XXX Dont know how to implement string-length() without arg
|
||||
*/
|
||||
int
|
||||
xp_function_string_length(xp_ctx *xc,
|
||||
struct xpath_tree *xs,
|
||||
cvec *nsc,
|
||||
int localonly,
|
||||
xp_ctx **xrp)
|
||||
{
|
||||
int retval = -1;
|
||||
xp_ctx *xr0 = NULL;
|
||||
xp_ctx *xr = NULL;
|
||||
char *s0 = NULL;
|
||||
|
||||
if (xs != NULL && xs->xs_c0){
|
||||
/* contains two arguments in xs: boolean contains(string, string) */
|
||||
if (xp_eval(xc, xs->xs_c0, nsc, localonly, &xr0) < 0)
|
||||
goto done;
|
||||
if (ctx2string(xr0, &s0) < 0)
|
||||
goto done;
|
||||
}
|
||||
else {
|
||||
if ((s0 = strdup("")) == NULL){
|
||||
clixon_err(OE_UNIX, errno, "strdup");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
if ((xr = malloc(sizeof(*xr))) == NULL){
|
||||
clixon_err(OE_UNIX, errno, "malloc");
|
||||
goto done;
|
||||
}
|
||||
memset(xr, 0, sizeof(*xr));
|
||||
xr->xc_type = XT_NUMBER;
|
||||
xr->xc_number = strlen(s0);
|
||||
s0 = NULL;
|
||||
*xrp = xr;
|
||||
xr = NULL;
|
||||
retval = 0;
|
||||
done:
|
||||
if (xr0)
|
||||
ctx_free(xr0);
|
||||
if (s0)
|
||||
free(s0);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Eval xpath function replaces characters in the first string
|
||||
*
|
||||
* Returns the first argument string with occurrences of characters in the second argument string
|
||||
* replaced by the character at the corresponding position in the third argument string.
|
||||
* @param[in] xc Incoming context
|
||||
* @param[in] xs XPath node tree
|
||||
* @param[in] nsc XML Namespace context
|
||||
* @param[in] localonly Skip prefix and namespace tests (non-standard)
|
||||
* @param[out] xrp Resulting context
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @see https://www.w3.org/TR/xpath-10/#NT-FunctionName 4.2 String Functions
|
||||
*/
|
||||
int
|
||||
xp_function_translate(xp_ctx *xc,
|
||||
struct xpath_tree *xs,
|
||||
cvec *nsc,
|
||||
int localonly,
|
||||
xp_ctx **xrp)
|
||||
{
|
||||
int retval = -1;
|
||||
struct xpath_tree *a0;
|
||||
struct xpath_tree *a1;
|
||||
struct xpath_tree *a2;
|
||||
xp_ctx *xr0 = NULL;
|
||||
xp_ctx *xr1 = NULL;
|
||||
xp_ctx *xr2 = NULL;
|
||||
xp_ctx *xr = NULL;
|
||||
char *s0 = NULL;
|
||||
char *s1 = NULL;
|
||||
char *s2 = NULL;
|
||||
cbuf *cb = NULL;
|
||||
char *p1;
|
||||
char ch;
|
||||
int i;
|
||||
int j;
|
||||
|
||||
if (xs == NULL || xs->xs_c0 == NULL || xs->xs_c1 == NULL){
|
||||
clixon_err(OE_XML, EINVAL, "contains expects but did not get two arguments");
|
||||
goto done;
|
||||
}
|
||||
if (xs->xs_c0->xs_c1 != NULL){
|
||||
a0 = xs->xs_c0->xs_c0;
|
||||
a1 = xs->xs_c0->xs_c1;
|
||||
a2 = xs->xs_c1;
|
||||
}
|
||||
else {
|
||||
a0 = xs->xs_c0;
|
||||
a1 = xs->xs_c1;
|
||||
a2 = NULL;
|
||||
}
|
||||
/* contains two arguments in xs: boolean contains(string, string) */
|
||||
if (xp_eval(xc, a0, nsc, localonly, &xr0) < 0)
|
||||
goto done;
|
||||
if (ctx2string(xr0, &s0) < 0)
|
||||
goto done;
|
||||
if (xp_eval(xc, a1, nsc, localonly, &xr1) < 0)
|
||||
goto done;
|
||||
if (ctx2string(xr1, &s1) < 0)
|
||||
goto done;
|
||||
if (a2) {
|
||||
if (xp_eval(xc, a2, nsc, localonly, &xr2) < 0)
|
||||
goto done;
|
||||
if (ctx2string(xr2, &s2) < 0)
|
||||
goto done;
|
||||
}
|
||||
if ((xr = malloc(sizeof(*xr))) == NULL){
|
||||
clixon_err(OE_UNIX, errno, "malloc");
|
||||
goto done;
|
||||
}
|
||||
memset(xr, 0, sizeof(*xr));
|
||||
xr->xc_type = XT_STRING;
|
||||
if ((cb = cbuf_new()) == NULL){
|
||||
clixon_err(OE_UNIX, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
for (i=0; i<strlen(s0); i++){
|
||||
ch = s0[i];
|
||||
if ((p1 = strchr(s1, s0[i])) != NULL){
|
||||
j = p1 - s1;
|
||||
if (j < strlen(s2))
|
||||
cprintf(cb, "%c", s2[j]);
|
||||
}
|
||||
else
|
||||
cprintf(cb, "%c", ch);
|
||||
}
|
||||
if ((xr->xc_string = strdup(cbuf_get(cb))) == NULL){
|
||||
clixon_err(OE_UNIX, errno, "strdup");
|
||||
goto done;
|
||||
}
|
||||
*xrp = xr;
|
||||
xr = NULL;
|
||||
retval = 0;
|
||||
done:
|
||||
if (xr0)
|
||||
ctx_free(xr0);
|
||||
if (xr1)
|
||||
ctx_free(xr1);
|
||||
if (xr2)
|
||||
ctx_free(xr2);
|
||||
if (s0)
|
||||
free(s0);
|
||||
if (s1)
|
||||
free(s1);
|
||||
if (s2)
|
||||
free(s2);
|
||||
if (cb)
|
||||
cbuf_free(cb);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! The boolean function converts its argument to a boolean
|
||||
*
|
||||
* Conversion is as follows:
|
||||
|
|
|
|||
|
|
@ -42,13 +42,13 @@
|
|||
* Types
|
||||
*/
|
||||
/*
|
||||
* XPath functions from Xpath 1.0 spec or YANG
|
||||
* XPath functions from XPath 1.0 spec or YANG
|
||||
* @see xp_eval,xp_primary_function where they are parsed and checked
|
||||
* @see clixon_xpath_function.ch] for implementation
|
||||
* @see clixon_xpath_function.ch for implementation
|
||||
*/
|
||||
enum clixon_xpath_function{
|
||||
XPATHFN_CURRENT, /* RFC 7950 10.1.1 */
|
||||
XPATHFN_RE_MATCH, /* RFC 7950 10.2.1 NYI */
|
||||
XPATHFN_RE_MATCH, /* RFC 7950 10.2.1 */
|
||||
XPATHFN_DEREF, /* RFC 7950 10.3.1 */
|
||||
XPATHFN_DERIVED_FROM, /* RFC 7950 10.4.1 */
|
||||
XPATHFN_DERIVED_FROM_OR_SELF, /* RFC 7950 10.4.2 */
|
||||
|
|
@ -61,16 +61,16 @@ enum clixon_xpath_function{
|
|||
XPATHFN_LOCAL_NAME, /* XPATH 1.0 4.1 NYI */
|
||||
XPATHFN_NAMESPACE_URI, /* XPATH 1.0 4.1 NYI */
|
||||
XPATHFN_NAME, /* XPATH 1.0 4.1 */
|
||||
XPATHFN_STRING, /* XPATH 1.0 4.2 NYI */
|
||||
XPATHFN_STRING, /* XPATH 1.0 4.2 */
|
||||
XPATHFN_CONCAT, /* XPATH 1.0 4.2 NYI */
|
||||
XPATHFN_STARTS_WITH, /* XPATH 1.0 4.2 NYI */
|
||||
XPATHFN_STARTS_WITH, /* XPATH 1.0 4.2 */
|
||||
XPATHFN_CONTAINS, /* XPATH 1.0 4.2 */
|
||||
XPATHFN_SUBSTRING_BEFORE, /* XPATH 1.0 4.2 NYI */
|
||||
XPATHFN_SUBSTRING_AFTER, /* XPATH 1.0 4.2 NYI */
|
||||
XPATHFN_SUBSTRING, /* XPATH 1.0 4.2 NYI */
|
||||
XPATHFN_STRING_LENGTH, /* XPATH 1.0 4.2 NYI */
|
||||
XPATHFN_SUBSTRING_BEFORE, /* XPATH 1.0 4.2 */
|
||||
XPATHFN_SUBSTRING_AFTER, /* XPATH 1.0 4.2 */
|
||||
XPATHFN_SUBSTRING, /* XPATH 1.0 4.2 */
|
||||
XPATHFN_STRING_LENGTH, /* XPATH 1.0 4.2 */
|
||||
XPATHFN_NORMALIZE_SPACE, /* XPATH 1.0 4.2 NYI */
|
||||
XPATHFN_TRANSLATE, /* XPATH 1.0 4.2 NYI */
|
||||
XPATHFN_TRANSLATE, /* XPATH 1.0 4.2 */
|
||||
XPATHFN_BOOLEAN, /* XPATH 1.0 4.3 */
|
||||
XPATHFN_NOT, /* XPATH 1.0 4.3 */
|
||||
XPATHFN_TRUE, /* XPATH 1.0 4.3 */
|
||||
|
|
@ -94,13 +94,19 @@ int xp_fnname_str2int(char *fnname);
|
|||
const char *xp_fnname_int2str(enum clixon_xpath_function code);
|
||||
|
||||
int xp_function_current(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, int localonly, xp_ctx **xrp);
|
||||
int xp_function_re_match(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, int localonly, xp_ctx **xrp);
|
||||
int xp_function_deref(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, int localonly, xp_ctx **xrp);
|
||||
int xp_function_derived_from(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, int localonly, int self, xp_ctx **xrp);
|
||||
int xp_function_bit_is_set(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, int localonly, xp_ctx **xrp);
|
||||
int xp_function_position(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, int localonly, xp_ctx **xrp);
|
||||
int xp_function_count(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, int localonly, xp_ctx **xrp);
|
||||
int xp_function_name(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, int localonly, xp_ctx **xrp);
|
||||
int xp_function_contains(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, int localonly, xp_ctx **xrp);
|
||||
int xp_function_string(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, int localonly, xp_ctx **xrp);
|
||||
int xp_function_contains(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, int starts, int localonly, xp_ctx **xrp);
|
||||
int xp_function_substring_str(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, int before, int localonly, xp_ctx **xrp);
|
||||
int xp_function_substring(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, int localonly, xp_ctx **xrp);
|
||||
int xp_function_string_length(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, int localonly, xp_ctx **xrp);
|
||||
int xp_function_translate(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, int localonly, xp_ctx **xrp);
|
||||
int xp_function_boolean(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, int localonly, xp_ctx **xrp);
|
||||
int xp_function_not(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, int localonly, xp_ctx **xrp);
|
||||
int xp_function_true(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, int localonly, xp_ctx **xrp);
|
||||
|
|
|
|||
|
|
@ -251,21 +251,13 @@ xp_primary_function(clixon_xpath_yacc *xpy,
|
|||
}
|
||||
fn = ret;
|
||||
switch (fn){
|
||||
case XPATHFN_RE_MATCH: /* Group of NOT IMPLEMENTED xpath functions */
|
||||
case XPATHFN_ENUM_VALUE:
|
||||
case XPATHFN_ENUM_VALUE: /* Group of NOT IMPLEMENTED xpath functions */
|
||||
case XPATHFN_LAST:
|
||||
case XPATHFN_ID:
|
||||
case XPATHFN_LOCAL_NAME:
|
||||
case XPATHFN_NAMESPACE_URI:
|
||||
case XPATHFN_STRING:
|
||||
case XPATHFN_CONCAT:
|
||||
case XPATHFN_STARTS_WITH:
|
||||
case XPATHFN_SUBSTRING_BEFORE:
|
||||
case XPATHFN_SUBSTRING_AFTER:
|
||||
case XPATHFN_SUBSTRING:
|
||||
case XPATHFN_STRING_LENGTH:
|
||||
case XPATHFN_NORMALIZE_SPACE:
|
||||
case XPATHFN_TRANSLATE:
|
||||
case XPATHFN_LANG:
|
||||
case XPATHFN_NUMBER:
|
||||
case XPATHFN_SUM:
|
||||
|
|
@ -280,7 +272,8 @@ xp_primary_function(clixon_xpath_yacc *xpy,
|
|||
clixon_xpath_parseerror(xpy, cbuf_get(cb));
|
||||
goto done;
|
||||
break;
|
||||
case XPATHFN_CURRENT: /* Group of implemented xpath functions */
|
||||
case XPATHFN_RE_MATCH: /* Group of implemented xpath functions */
|
||||
case XPATHFN_CURRENT:
|
||||
case XPATHFN_DEREF:
|
||||
case XPATHFN_DERIVED_FROM:
|
||||
case XPATHFN_BIT_IS_SET:
|
||||
|
|
@ -288,7 +281,14 @@ xp_primary_function(clixon_xpath_yacc *xpy,
|
|||
case XPATHFN_POSITION:
|
||||
case XPATHFN_COUNT:
|
||||
case XPATHFN_NAME:
|
||||
case XPATHFN_STRING:
|
||||
case XPATHFN_STARTS_WITH:
|
||||
case XPATHFN_CONTAINS:
|
||||
case XPATHFN_SUBSTRING_BEFORE:
|
||||
case XPATHFN_SUBSTRING_AFTER:
|
||||
case XPATHFN_SUBSTRING:
|
||||
case XPATHFN_STRING_LENGTH:
|
||||
case XPATHFN_TRANSLATE:
|
||||
case XPATHFN_BOOLEAN:
|
||||
case XPATHFN_NOT:
|
||||
case XPATHFN_TRUE:
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
#!/usr/bin/env bash
|
||||
# XPATH tests
|
||||
# Basic XPATH tests
|
||||
# See also test_xpath_functions.sh for XPaths with YANG conditionals
|
||||
# Some XPATH cases clixon cannot handle
|
||||
# - /aaa/bbb/comment, where "comment" is nodetype
|
||||
# - //b*, combinations of // and "*"
|
||||
# For more (outdated info): https://github.com/clicon/clixon/issues/54
|
||||
# Test has three parts:
|
||||
# - Only XML no YANG
|
||||
# - negative tests with YANG
|
||||
|
|
@ -23,7 +23,6 @@ xmlfn=$dir/xmlfn.xml
|
|||
|
||||
fyang=$dir/clixon-example.yang
|
||||
|
||||
|
||||
cat <<EOF > $xml
|
||||
<aaa>
|
||||
<bbb x="hello">
|
||||
|
|
@ -71,6 +70,8 @@ cat <<EOF > $xml2
|
|||
<ifType>ethernet</ifType>
|
||||
<ifMTU>1500</ifMTU>
|
||||
<namespace>urn:example:foo</namespace>
|
||||
<mylength>7</mylength>
|
||||
<myaddr>10.22.33.44</myaddr>
|
||||
</bbb>
|
||||
</aaa>
|
||||
EOF
|
||||
|
|
@ -167,7 +168,6 @@ expectpart "$($clixon_util_xpath -D $DBG -f $xml -p aaa)" 0 "^nodeset:0:<aaa><bb
|
|||
new "xpath /bbb"
|
||||
expectpart "$($clixon_util_xpath -D $DBG -f $xml -p /bbb)" 0 "^nodeset:$"
|
||||
|
||||
|
||||
new "xpath /aaa/bbb"
|
||||
expectpart "$($clixon_util_xpath -D $DBG -f $xml -p /aaa/bbb)" 0 "^0:<bbb x=\"hello\"><ccc>42</ccc></bbb>
|
||||
1:<bbb x=\"bye\"><ccc>99</ccc></bbb>$"
|
||||
|
|
@ -309,8 +309,112 @@ expectpart "$($clixon_util_xpath -D $DBG -f $xml3 -p 'derived-from(../../change-
|
|||
new "xpath derived-from-or-self"
|
||||
expectpart "$($clixon_util_xpath -D $DBG -f $xml3 -p 'derived-from-or-self(../../change-operation,"modify")')" 0 "bool:false"
|
||||
|
||||
new "xpath contains"
|
||||
expectpart "$($clixon_util_xpath -D $DBG -f $xml3 -p "contains(../../objectClass,'BTSFunction') or contains(../../objectClass,'RNCFunction')")" 0 "bool:false"
|
||||
# re-match
|
||||
new "xpath re-match match true" # example from rfc 7950
|
||||
expectpart "$($clixon_util_xpath -D $DBG -f $xml2 -p 're-match("1.22.333", "\d{1,3}\.\d{1,3}\.\d{1,3}")')" 0 "bool:true"
|
||||
|
||||
new "xpath re-match match path"
|
||||
expectpart "$($clixon_util_xpath -D $DBG -f $xml2 -p 're-match(aaa/bbb/myaddr, "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}")')" 0 "bool:true"
|
||||
|
||||
new "xpath re-match match path fail"
|
||||
expectpart "$($clixon_util_xpath -D $DBG -f $xml2 -p 're-match(aaa/bbb/myaddr, "\d{1,3}\.\d{1,3}\.\d{1,3}")')" 0 "bool:false"
|
||||
|
||||
# string
|
||||
new "xpath string empty"
|
||||
expectpart "$($clixon_util_xpath -D $DBG -f $xml3 -p "string()")" 0 "string:$"
|
||||
|
||||
new "xpath string path"
|
||||
expectpart "$($clixon_util_xpath -D $DBG -f $xml4 -p "string(root/y/a)")" 0 "string:222$"
|
||||
|
||||
# starts-with
|
||||
new "xpath starts-with true"
|
||||
expectpart "$($clixon_util_xpath -D $DBG -f $xml3 -p "starts-with('kalle','kal')")" 0 "bool:true"
|
||||
|
||||
new "xpath starts-with false"
|
||||
expectpart "$($clixon_util_xpath -D $DBG -f $xml3 -p "starts-with('kalle','all')")" 0 "bool:false"
|
||||
|
||||
new "xpath starts-with empty"
|
||||
expectpart "$($clixon_util_xpath -D $DBG -f $xml3 -p "starts-with('kalle','')")" 0 "bool:true"
|
||||
|
||||
new "xpath starts-with too long"
|
||||
expectpart "$($clixon_util_xpath -D $DBG -f $xml3 -p "starts-with('kalle','kalle42')")" 0 "bool:false"
|
||||
|
||||
new "xpath contains direct strings true"
|
||||
expectpart "$($clixon_util_xpath -D $DBG -f $xml3 -p "contains('kalle','all')")" 0 "bool:true"
|
||||
|
||||
new "xpath contains direct strings false"
|
||||
expectpart "$($clixon_util_xpath -D $DBG -f $xml3 -p "contains('kalle','ball')")" 0 "bool:false"
|
||||
|
||||
new "xpath contains path true"
|
||||
expectpart "$($clixon_util_xpath -D $DBG -f $xml2 -p "contains(aaa/bbb/namespace,aaa/name)")" 0 "bool:true"
|
||||
|
||||
new "xpath contains path false"
|
||||
expectpart "$($clixon_util_xpath -D $DBG -f $xml2 -p "contains(aaa/bbb/ifMTU,aaa/name)")" 0 "bool:false"
|
||||
|
||||
# substring-before / after
|
||||
new "xpath substring-before 1"
|
||||
expectpart "$($clixon_util_xpath -D $DBG -f $xml2 -p "substring-before(\"1999/04/01\",\"/\")")" 0 "string:1999" --not-- "1999/"
|
||||
|
||||
new "xpath substring-before 2"
|
||||
expectpart "$($clixon_util_xpath -D $DBG -f $xml2 -p "substring-before(\"1999/04/01\",\"04\")")" 0 "string:1999/" --not-- "04"
|
||||
|
||||
new "xpath substring-before 3"
|
||||
expectpart "$($clixon_util_xpath -D $DBG -f $xml2 -p "substring-before(\"1999/04/01\",\"zzz\")")" 0 "string:" --not-- "string:1"
|
||||
|
||||
new "xpath substring-after 1"
|
||||
expectpart "$($clixon_util_xpath -D $DBG -f $xml2 -p "substring-after(\"1999/04/01\",\"/\")")" 0 "string:04/01"
|
||||
|
||||
new "xpath substring-after 2"
|
||||
expectpart "$($clixon_util_xpath -D $DBG -f $xml2 -p "substring-after(\"1999/04/01\",\"19\")")" 0 "string:99/04/01"
|
||||
|
||||
new "xpath substring-after 3"
|
||||
expectpart "$($clixon_util_xpath -D $DBG -f $xml2 -p "substring-after(\"1999/04/01\",\"z\")")" 0 "string:" --not-- "1999"
|
||||
|
||||
# substring, see examples in https://www.w3.org/TR/xpath-10/ Sections 4.2
|
||||
new "xpath substring 1"
|
||||
expectpart "$($clixon_util_xpath -D $DBG -f $xml2 -p "substring(\"12345\",2,3)")" 0 "string:234" --not-- "45"
|
||||
|
||||
new "xpath substring 2"
|
||||
expectpart "$($clixon_util_xpath -D $DBG -f $xml2 -p "substring(\"12345\",1.5,2.6)")" 0 "string:234" --not-- "45"
|
||||
|
||||
new "xpath substring 3"
|
||||
expectpart "$($clixon_util_xpath -D $DBG -f $xml2 -p "substring(\"12345\",0,3)")" 0 "string:12" --not-- "123"
|
||||
|
||||
new "xpath substring 4"
|
||||
expectpart "$($clixon_util_xpath -D $DBG -f $xml2 -p "substring(\"12345\",0 div 0,3)")" 0 "string:" --not-- "12"
|
||||
|
||||
new "xpath substring 5"
|
||||
expectpart "$($clixon_util_xpath -D $DBG -f $xml2 -p "substring(\"12345\",1, 0 div 0)")" 0 "string:" --not-- "12"
|
||||
|
||||
# XXX cornercase does not work
|
||||
#new "xpath substring 6"
|
||||
#expectpart "$($clixon_util_xpath -D $DBG -f $xml2 -p "substring(\"12345\",-42, 1 div 0)")" 0 "string:12345"
|
||||
|
||||
new "xpath substring 7"
|
||||
expectpart "$($clixon_util_xpath -D $DBG -f $xml2 -p "substring(\"12345\",-1, 1 div 0)")" 0 "string:" --not-- "string:1"
|
||||
|
||||
new "xpath substring paths"
|
||||
expectpart "$($clixon_util_xpath -D $DBG -f $xml2 -p "substring(aaa/bbb/namespace,5,aaa/bbb/mylength)")" 0 "string:example" --not-- "example:"
|
||||
|
||||
# string-length
|
||||
new "xpath string-length empty" # XXX without args not supported
|
||||
expectpart "$($clixon_util_xpath -D $DBG -f $xml2 -p "string-length()")" 0 "number:0"
|
||||
|
||||
new "xpath string-length direct"
|
||||
expectpart "$($clixon_util_xpath -D $DBG -f $xml2 -p "string-length(\"12345\")")" 0 "number:5"
|
||||
|
||||
new "xpath string-length path"
|
||||
expectpart "$($clixon_util_xpath -D $DBG -f $xml2 -p "string-length(aaa/name)")" 0 "number:3"
|
||||
|
||||
# translate
|
||||
new "xpath translate" # modified
|
||||
expectpart "$($clixon_util_xpath -D $DBG -f $xml2 -p "translate(\"bar\", \"abc\",\"DEF\")")" 0 "string:EDr$"
|
||||
|
||||
new "xpath translate remove"
|
||||
expectpart "$($clixon_util_xpath -D $DBG -f $xml2 -p "translate(\"--aaa--\", \"abc-\",\"DEF\")")" 0 "string:DDD$"
|
||||
|
||||
new "xpath translate none"
|
||||
expectpart "$($clixon_util_xpath -D $DBG -f $xml2 -p "translate(\"bar\", \"cde-\",\"fgh\")")" 0 "string:bar$"
|
||||
|
||||
# Nodetests
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
# test xpath functions within YANG conditionals
|
||||
# For basic XPath tests see test_xpath.sh
|
||||
# XPATH base https://www.w3.org/TR/xpath-10/
|
||||
# YANG XPATH functions: https://tools.ietf.org/html/rfc7950
|
||||
# Test of xpath functions:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue