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
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@
|
|||
|
||||
#include "clixon_queue.h"
|
||||
#include "clixon_hash.h"
|
||||
#include "clixon_handle.h"
|
||||
#include "clixon_handle.h"
|
||||
#include "clixon_yang.h"
|
||||
#include "clixon_xml.h"
|
||||
#include "clixon_err.h"
|
||||
|
|
@ -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:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue