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