diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d533e01..f0afd172 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -99,6 +99,8 @@ Developers may need to change their code ### Minor features +* Added XPATH function `boolean()` + * This caused problem for new NTP YANG in RFC 9249 * Full RFC 7950 if-feature-expr support (Section 7.20.2) * Previous implementation did not handle nested if-feature expressions * As part of fixing: [YANG if-feature does not support nested boolean expression](https://github.com/clicon/clixon/issues/341) diff --git a/lib/src/clixon_text_syntax.c b/lib/src/clixon_text_syntax.c index 8a29acbc..4398e90e 100644 --- a/lib/src/clixon_text_syntax.c +++ b/lib/src/clixon_text_syntax.c @@ -228,7 +228,7 @@ xml2txt1(cxobj *xn, xc = NULL; while ((xc = xml_child_each(xn, xc, -1)) != NULL){ if (xml_type(xc) == CX_ELMNT || xml_type(xc) == CX_BODY){ - if (yang_key_match(yn, xml_name(xc), NULL)) + if (yn && yang_key_match(yn, xml_name(xc), NULL)) continue; /* Skip keys, already printed */ if (xml2txt1(xc, fn, f, level+1, leafl, leaflname) < 0) break; diff --git a/lib/src/clixon_xpath_eval.c b/lib/src/clixon_xpath_eval.c index e5075a9d..459e1720 100644 --- a/lib/src/clixon_xpath_eval.c +++ b/lib/src/clixon_xpath_eval.c @@ -1070,6 +1070,11 @@ xp_eval(xp_ctx *xc, goto done; goto ok; break; + case XPATHFN_BOOLEAN: + if (xp_function_boolean(xc, xs->xs_c0, nsc, localonly, xrp) < 0) + goto done; + goto ok; + break; case XPATHFN_NOT: if (xp_function_not(xc, xs->xs_c0, nsc, localonly, xrp) < 0) goto done; diff --git a/lib/src/clixon_xpath_function.c b/lib/src/clixon_xpath_function.c index 7d86ce00..5d4fc2ee 100644 --- a/lib/src/clixon_xpath_function.c +++ b/lib/src/clixon_xpath_function.c @@ -635,16 +635,22 @@ xp_function_contains(xp_ctx *xc, return retval; } -/*! The not function returns true if its argument is false, and false otherwise. +/*! The boolean function converts its argument to a boolean * - * Signature: boolean not(boolean) + * Conversion is as follows: + * - a number is true if and only if it is neither positive or negative zero nor NaN + * - a node-set is true if and only if it is non-empty + * - a string is true if and only if its length is non-zero + * - an object of a type other than the four basic types is converted to a boolean in a way that + * is dependent on that type + * Signature: boolean boolean(object) */ int -xp_function_not(xp_ctx *xc, - struct xpath_tree *xs, - cvec *nsc, - int localonly, - xp_ctx **xrp) +xp_function_boolean(xp_ctx *xc, + struct xpath_tree *xs, + cvec *nsc, + int localonly, + xp_ctx **xrp) { int retval = -1; xp_ctx *xr = NULL; @@ -664,7 +670,7 @@ xp_function_not(xp_ctx *xc, } memset(xr, 0, sizeof(*xr)); xr->xc_type = XT_BOOL; - xr->xc_bool = !bool; + xr->xc_bool = bool; *xrp = xr; retval = 0; done: @@ -673,6 +679,23 @@ xp_function_not(xp_ctx *xc, return retval; } +/*! The not function returns true if its argument is false, and false otherwise. + * + * Signature: boolean not(boolean) + */ +int +xp_function_not(xp_ctx *xc, + struct xpath_tree *xs, + cvec *nsc, + int localonly, + xp_ctx **xrp) +{ + if (xp_function_boolean(xc, xs, nsc, localonly, xrp) < 0) + return -1; + (*xrp)->xc_bool = !(*xrp)->xc_bool; + return 0; +} + /*! The true function returns true. * * Signature: boolean true() diff --git a/lib/src/clixon_xpath_function.h b/lib/src/clixon_xpath_function.h index a176c2f8..e9980950 100644 --- a/lib/src/clixon_xpath_function.h +++ b/lib/src/clixon_xpath_function.h @@ -71,7 +71,7 @@ enum clixon_xpath_function{ XPATHFN_STRING_LENGTH, /* XPATH 1.0 4.2 NYI */ XPATHFN_NORMALIZE_SPACE, /* XPATH 1.0 4.2 NYI */ XPATHFN_TRANSLATE, /* XPATH 1.0 4.2 NYI */ - XPATHFN_BOOLEAN, /* XPATH 1.0 4.3 NYI */ + XPATHFN_BOOLEAN, /* XPATH 1.0 4.3 */ XPATHFN_NOT, /* XPATH 1.0 4.3 */ XPATHFN_TRUE, /* XPATH 1.0 4.3 */ XPATHFN_FALSE, /* XPATH 1.0 4.3 */ @@ -101,6 +101,7 @@ int xp_function_position(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, int local 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_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); int xp_function_false(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, int localonly, xp_ctx **xrp); diff --git a/lib/src/clixon_xpath_parse.y b/lib/src/clixon_xpath_parse.y index d7f8af73..77c50ad3 100644 --- a/lib/src/clixon_xpath_parse.y +++ b/lib/src/clixon_xpath_parse.y @@ -266,7 +266,6 @@ xp_primary_function(clixon_xpath_yacc *xpy, case XPATHFN_STRING_LENGTH: case XPATHFN_NORMALIZE_SPACE: case XPATHFN_TRANSLATE: - case XPATHFN_BOOLEAN: case XPATHFN_LANG: case XPATHFN_NUMBER: case XPATHFN_SUM: @@ -290,6 +289,7 @@ xp_primary_function(clixon_xpath_yacc *xpy, case XPATHFN_COUNT: case XPATHFN_NAME: case XPATHFN_CONTAINS: + case XPATHFN_BOOLEAN: case XPATHFN_NOT: case XPATHFN_TRUE: case XPATHFN_FALSE: diff --git a/test/test_xpath_functions.sh b/test/test_xpath_functions.sh index 5eb90748..2721383a 100755 --- a/test/test_xpath_functions.sh +++ b/test/test_xpath_functions.sh @@ -123,6 +123,28 @@ module $APPNAME{ } } } + /* This is from ietf-ntp@2022-07-05.yang for testing boolean() + * But note I reversed true/false + */ + container system { + container ntp { + presence + "Enables the NTP client unless the 'enabled' leaf + (which defaults to 'true') is set to 'false'"; + } + } + container ntp { + when 'true() = boolean(/sys:system/sys:ntp)' { + description + "Applicable when the system /sys/ntp/ is not used."; + } + presence "NTP is enabled and system should attempt to + synchronize the system clock with an NTP server + from the 'ntp/associations' list."; + leaf port { + type int16; + } + } } EOF @@ -207,6 +229,18 @@ expecteof_netconf "$clixon_netconf -qf $cfg -D $DBG" 0 "$DEFAULTHELLO" "" "" "e1UP PROMISCUOUSe2PROMISCUOUS" +new "netconf set ntp port" +expecteof_netconf "$clixon_netconf -qf $cfg -D $DBG" 0 "$DEFAULTHELLO" "99" "" "" + +new "netconf validate fail" +expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "applicationoperation-failederrorFailed WHEN condition of ntp in module example (WHEN xpath is true() = boolean(/sys:system/sys:ntp))" + +new "netconf set system boolean" +expecteof_netconf "$clixon_netconf -qf $cfg -D $DBG" 0 "$DEFAULTHELLO" "" "" "" + +new "netconf validate ok" +expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" + if [ $BE -ne 0 ]; then new "Kill backend" # Check if premature kill