XPath: refactored XPath match, documented localonly and prefixonly api
This commit is contained in:
parent
6c73c36fb7
commit
081a541c6b
13 changed files with 384 additions and 105 deletions
|
|
@ -153,7 +153,7 @@ static inline int clixon_debug_isset(unsigned n)
|
|||
}
|
||||
|
||||
/* Is detail set ?, return detail level 0-7 */
|
||||
static inline int clixon_debug_detail()
|
||||
static inline int clixon_debug_detail(void)
|
||||
{
|
||||
unsigned level = clixon_debug_get();
|
||||
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ int xml_nsctx_node(cxobj *x, cvec **ncp);
|
|||
int xml_nsctx_yang(yang_stmt *yn, cvec **ncp);
|
||||
int xml_nsctx_yangspec(yang_stmt *yspec, cvec **ncp);
|
||||
int xml_nsctx_cbuf(cbuf *cb, cvec *nsc);
|
||||
int xml2ns(cxobj *x, char *localname, char **ns);
|
||||
int xml2ns(cxobj *x, char *prefix, char **ns);
|
||||
int xml2ns_recurse(cxobj *x);
|
||||
int xmlns_set(cxobj *x, char *prefix, char *ns);
|
||||
int xmlns_set_all(cxobj *x, cvec *nsc);
|
||||
|
|
|
|||
|
|
@ -134,7 +134,7 @@ int xpath_tree_eq(xpath_tree *xt1, xpath_tree *xt2, xpath_tree ***vec, size_t
|
|||
xpath_tree *xpath_tree_traverse(xpath_tree *xt, ...);
|
||||
int xpath_tree_free(xpath_tree *xs);
|
||||
int xpath_parse(const char *xpath, xpath_tree **xptree);
|
||||
int xpath_vec_ctx(cxobj *xcur, cvec *nsc, const char *xpath, int localonly, xp_ctx **xrp);
|
||||
int xpath_vec_ctx(cxobj *xcur, cvec *nsc, const char *xpath, int localonly, xp_ctx **xrp);
|
||||
|
||||
int xpath_vec_bool(cxobj *xcur, cvec *nsc, const char *xpformat, ...) __attribute__ ((format (printf, 3, 4)));
|
||||
int xpath_vec_flag(cxobj *xcur, cvec *nsc, const char *xpformat, uint16_t flags,
|
||||
|
|
|
|||
|
|
@ -58,7 +58,9 @@ enum xp_objtype{
|
|||
XT_STRING
|
||||
};
|
||||
|
||||
/* Expression evaluation occurs with respect to a context. XSLT and XPointer specify how the
|
||||
/*! XPath context and result
|
||||
*
|
||||
* Expression evaluation occurs with respect to a context. XSLT and XPointer specify how the
|
||||
* context is determined for XPath expressions used in XSLT and XPointer respectively. The
|
||||
* context consists of:
|
||||
* a node (the context node)
|
||||
|
|
|
|||
|
|
@ -60,7 +60,10 @@
|
|||
* of the xpath-tree, which is context-dependent.
|
||||
* Best is to send it as a (read-only) parameter to the xp_eval family of functions
|
||||
* as an exlicit namespace context.
|
||||
*
|
||||
* 3) localonly flag refers to https://www.w3.org/TR/REC-xml-names/, where :
|
||||
* PrefixedName ::= Prefix ':' LocalPart
|
||||
* "localonly" means to skip the "Prefix" part, ie namespaces
|
||||
* see nodetest_eval_node() for the semantics of prefix/namespace processing
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "clixon_config.h" /* generated by config & autoconf */
|
||||
|
|
@ -328,8 +331,8 @@ xpath_tree2cbuf(xpath_tree *xs,
|
|||
cprintf(xcb, "%s", clicon_int2str(xpopmap, xs->xs_int));
|
||||
break;
|
||||
case XP_PATHEXPR:
|
||||
/* [19] PathExpr ::= | FilterExpr '/' RelativeLocationPath
|
||||
| FilterExpr '//' RelativeLocationPath
|
||||
/* [19] PathExpr ::= | FilterExpr '/' RelativeLocationPath
|
||||
| FilterExpr '//' RelativeLocationPath
|
||||
*/
|
||||
if (xs->xs_s0)
|
||||
cprintf(xcb, "%s", xs->xs_s0);
|
||||
|
|
@ -608,7 +611,7 @@ xpath_parse(const char *xpath,
|
|||
* @param[in] xcur XML-tree where to search
|
||||
* @param[in] nsc External XML namespace context, or NULL
|
||||
* @param[in] xpath String with XPath 1.0 syntax
|
||||
* @param[in] localonly Skip prefix and namespace tests (non-standard)
|
||||
* @param[in] localonly Skip prefix and namespace tests
|
||||
* @param[out] xrp Return XPath context
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
|
|
|
|||
|
|
@ -44,9 +44,9 @@
|
|||
* select="/t:top/t:users/t:user[t:name='fred']"/>
|
||||
* </get-config>
|
||||
* We need to add namespace context to the cpath tree, typically in eval. How do
|
||||
* we do that?
|
||||
* we do that?
|
||||
* One observation is that the namespace context is static, so it can not be a part
|
||||
* of the xpath-tree, which is context-dependent.
|
||||
* of the xpath-tree, which is context-dependent.
|
||||
* Best is to send it as a (read-only) parameter to the xp_eval family of functions
|
||||
* as an exlicit namespace context.
|
||||
* For that you need an API to get/set namespaces: clixon_xml_nscache.c?
|
||||
|
|
@ -86,6 +86,7 @@
|
|||
#include "clixon_xml_sort.h"
|
||||
#include "clixon_xml_nsctx.h"
|
||||
#include "clixon_xpath_ctx.h"
|
||||
#include "clixon_string.h"
|
||||
#include "clixon_xpath.h"
|
||||
#include "clixon_xpath_optimize.h"
|
||||
#include "clixon_xpath_function.h"
|
||||
|
|
@ -110,99 +111,148 @@ const map_str2int xpopmap[] = {
|
|||
{NULL, -1}
|
||||
};
|
||||
|
||||
/*! Eval an XPath nodetest
|
||||
/*! Eval an XPath nodetest with full namespace test
|
||||
*
|
||||
* @retval 1 Match
|
||||
* @retval 0 No match
|
||||
* @retval -1 Error XXX: retval -1 not properly handled
|
||||
* XML x -> prefix1 + name1
|
||||
* XPATH xs -> prefix2 + name2
|
||||
* Unless name2=*, if name1 != name2 -> fail
|
||||
* Lookup(prefix1, XML) -> ns1
|
||||
* Lookup(prefix2, NSC) -> ns2
|
||||
* if ns1 = NULL -> fail
|
||||
* if ns2 = NULL -> fail (see XPATH_NS_ACCEPT_UNRESOLVED)
|
||||
* if ns1 = ns2 -> match
|
||||
* otherwise fail
|
||||
* @param[in] x XML sub-tree given by the the context node
|
||||
* @param[in] xs XPath stack of type XP_NODE or XP_NODE_FN
|
||||
* @param[in] nsc XML Namespace context as given by xpath_vec_ctx()
|
||||
* @retval 1 Match
|
||||
* @retval 0 No match
|
||||
* @retval -1 Error
|
||||
*/
|
||||
static int
|
||||
nodetest_eval_node(cxobj *x,
|
||||
xpath_tree *xs,
|
||||
cvec *nsc)
|
||||
nodetest_eval_namespace(cxobj *x,
|
||||
xpath_tree *xs,
|
||||
cvec *nsc)
|
||||
{
|
||||
int retval = -1;
|
||||
char *name1 = xml_name(x);
|
||||
char *prefix1 = xml_prefix(x);
|
||||
char *nsxml = NULL; /* xml body namespace */
|
||||
char *nsxpath = NULL; /* xpath context namespace */
|
||||
char *prefix2 = NULL;
|
||||
char *name2 = NULL;
|
||||
int retval = -1;
|
||||
char *name1;
|
||||
char *prefix1;
|
||||
char *prefix2;
|
||||
char *name2;
|
||||
char *ns1 = NULL; /* xml namespace */
|
||||
char *ns2 = NULL; /* xpath namespace */
|
||||
|
||||
/* Namespaces is s0, name is s1 */
|
||||
if (strcmp(xs->xs_s1, "*")==0)
|
||||
return 1;
|
||||
/* get namespace of xml tree */
|
||||
if (xml2ns(x, prefix1, &nsxml) < 0)
|
||||
goto done;
|
||||
/* XML x -> prefix1 + name1 */
|
||||
prefix1 = xml_prefix(x);
|
||||
name1 = xml_name(x);
|
||||
/* XPATH xs -> prefix2 + name2 */
|
||||
prefix2 = xs->xs_s0;
|
||||
name2 = xs->xs_s1;
|
||||
/* Before going into namespaces, check name equality and filter out noteq */
|
||||
if (strcmp(name1, name2) != 0){
|
||||
retval = 0; /* no match */
|
||||
clixon_debug(CLIXON_DBG_XPATH | CLIXON_DBG_DETAIL, "%s %s", name1, name2);
|
||||
if (strcmp(name2, "*") != 0){
|
||||
/* if name1 != name2 -> fail */
|
||||
if (strcmp(name1, name2) != 0)
|
||||
goto fail;
|
||||
}
|
||||
/* get namespace of xml tree */
|
||||
if (xml2ns(x, prefix1, &ns1) < 0)
|
||||
goto done;
|
||||
}
|
||||
/* Here names are equal
|
||||
* Now look for namespaces
|
||||
* 1) prefix1 and prefix2 point to same namespace <<-- try this first
|
||||
* 2) prefix1 is equal to prefix2 <<-- then try this
|
||||
* (1) is strict yang xml
|
||||
* (2) without yang
|
||||
*/
|
||||
if (nsc != NULL) { /* solution (1) */
|
||||
nsxpath = xml_nsctx_get(nsc, prefix2);
|
||||
if (nsxml != NULL && nsxpath != NULL)
|
||||
retval = (strcmp(nsxml, nsxpath) == 0);
|
||||
else if (nsxpath == NULL){
|
||||
/* We have a namespace from xml, but none in yang.
|
||||
* This can happen in eg augments and ../foo, where foo is
|
||||
* augmented from another namespace
|
||||
*/
|
||||
retval = 1;
|
||||
}
|
||||
else
|
||||
retval = (nsxml == nsxpath); /* True only if both are NULL */
|
||||
}
|
||||
else{ /* solution (2) */
|
||||
if (prefix1 == NULL && prefix2 == NULL)
|
||||
retval = 1;
|
||||
else if (prefix1 == NULL || prefix2 == NULL)
|
||||
retval = 0;
|
||||
else
|
||||
retval = strcmp(prefix1, prefix2) == 0;
|
||||
}
|
||||
#if 0 /* debugging */
|
||||
/* If retval == 0 here, then there is name match, but not ns match */
|
||||
if (retval == 0){
|
||||
fprintf(stderr, "%s NOMATCH xml: (%s)%s\n\t\t xpath: (%s)%s\n", __FUNCTION__,
|
||||
name1, nsxml,
|
||||
name2, nsxpath);
|
||||
}
|
||||
if (ns1 == NULL)
|
||||
goto fail;
|
||||
ns2 = xml_nsctx_get(nsc, prefix2);
|
||||
if (ns2 == NULL){
|
||||
#ifdef XPATH_NS_ACCEPT_UNRESOLVED
|
||||
goto ok;
|
||||
#else
|
||||
goto fail;
|
||||
#endif
|
||||
}
|
||||
else if (strcmp(ns1, ns2) != 0)
|
||||
goto fail;
|
||||
#ifdef XPATH_NS_ACCEPT_UNRESOLVED
|
||||
ok:
|
||||
#endif
|
||||
retval = 1;
|
||||
done: /* retval set in preceding statement */
|
||||
return retval;
|
||||
fail:
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*! Eval an XPath nodetest but skip namespace tests
|
||||
*
|
||||
* XML x -> prefix1 + name1
|
||||
* XPATH xs -> prefix2 + name2
|
||||
* Unless name2=*, if name1 != name2 -> fail
|
||||
* if prefix1 and prefix2 are string-equal or both NULL -> match
|
||||
* else -> fail
|
||||
* @param[in] x XML node
|
||||
* @param[in] xs XPath stack of type XP_NODE or XP_NODE_FN
|
||||
* @retval 1 Match
|
||||
* @retval 0 No match
|
||||
* @retval -1 Error XXX: retval -1 not properly handled
|
||||
*/
|
||||
static int
|
||||
nodetest_eval_prefixonly(cxobj *x,
|
||||
xpath_tree *xs)
|
||||
{
|
||||
int retval = -1;
|
||||
char *name1;
|
||||
char *prefix1;
|
||||
char *prefix2;
|
||||
char *name2;
|
||||
int ret;
|
||||
|
||||
/* XML x -> prefix1 + name1 */
|
||||
prefix1 = xml_prefix(x);
|
||||
name1 = xml_name(x);
|
||||
/* XPATH xs -> prefix2 + name2 */
|
||||
prefix2 = xs->xs_s0;
|
||||
name2 = xs->xs_s1;
|
||||
clixon_debug(CLIXON_DBG_XPATH | CLIXON_DBG_DETAIL, "%s:%s %s:%s", prefix1, name1, prefix2, name2);
|
||||
if (strcmp(name2, "*") != 0){
|
||||
/* if name1 != name2 -> fail */
|
||||
if (strcmp(name1, name2) != 0)
|
||||
goto fail;
|
||||
}
|
||||
ret = clicon_strcmp(prefix1, prefix2);
|
||||
if (ret != 0)
|
||||
goto fail;
|
||||
retval = 1;
|
||||
done: /* retval set in preceding statement */
|
||||
return retval;
|
||||
fail:
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*! Eval an XPath nodetest but skip prefix and namespace tests
|
||||
*
|
||||
* This is NOT according to standard
|
||||
* If name2 = "*" -> match # A node test * is true for any node of the principal node type.
|
||||
* If name1 = name2 -> match (string-equal or both NULL)
|
||||
* @param[in] x XML node
|
||||
* @param[in] xs XPath stack of type XP_NODE or XP_NODE_FN
|
||||
* @retval 1 Match
|
||||
* @retval 0 No match
|
||||
* @retval -1 Error
|
||||
*/
|
||||
static int
|
||||
nodetest_eval_node_localonly(cxobj *x,
|
||||
xpath_tree *xs,
|
||||
cvec *nsc)
|
||||
nodetest_eval_localonly(cxobj *x,
|
||||
xpath_tree *xs)
|
||||
{
|
||||
int retval = -1;
|
||||
char *name1 = xml_name(x);
|
||||
char *name2 = NULL;
|
||||
char *name1;
|
||||
char *name2;
|
||||
|
||||
/* Namespaces is s0, name is s1 */
|
||||
if (strcmp(xs->xs_s1, "*")==0){
|
||||
name1 = xml_name(x);
|
||||
name2 = xs->xs_s1;
|
||||
clixon_debug(CLIXON_DBG_XPATH | CLIXON_DBG_DETAIL, "%s %s", name1, name2);
|
||||
if (strcmp(name2, "*")==0){
|
||||
retval = 1;
|
||||
goto done;
|
||||
}
|
||||
name2 = xs->xs_s1;
|
||||
/* Before going into namespaces, check name equality and filter out noteq */
|
||||
/* Check name only */
|
||||
if (strcmp(name1, name2) == 0){
|
||||
retval = 1;
|
||||
goto done;
|
||||
|
|
@ -219,7 +269,7 @@ nodetest_eval_node_localonly(cxobj *x,
|
|||
* @param[in] nsc XML Namespace context
|
||||
* @param[in] localonly Skip prefix and namespace tests (non-standard)
|
||||
* @retval 1 Match
|
||||
* @retval 0 No match
|
||||
* @retval 0 No match
|
||||
* @retval -1 Error
|
||||
* - node() is true for any node of any type whatsoever.
|
||||
* - text() is true for any text node.
|
||||
|
|
@ -234,9 +284,11 @@ nodetest_eval(cxobj *x,
|
|||
|
||||
if (xs->xs_type == XP_NODE){
|
||||
if (localonly)
|
||||
retval = nodetest_eval_node_localonly(x, xs, nsc);
|
||||
retval = nodetest_eval_localonly(x, xs);
|
||||
else if (nsc == NULL)
|
||||
retval = nodetest_eval_prefixonly(x, xs);
|
||||
else
|
||||
retval = nodetest_eval_node(x, xs, nsc);
|
||||
retval = nodetest_eval_namespace(x, xs, nsc);
|
||||
}
|
||||
else if (xs->xs_type == XP_NODE_FN){
|
||||
switch (xs->xs_int){
|
||||
|
|
@ -295,7 +347,7 @@ nodetest_recursive(cxobj *xn,
|
|||
retval = 0;
|
||||
*vec0 = vec;
|
||||
*vec0len = veclen;
|
||||
done:
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
@ -309,7 +361,7 @@ nodetest_recursive(cxobj *xn,
|
|||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*
|
||||
* - A node test that is a QName is true if and only if the type of the node (see [5 Data Model])
|
||||
* - A node test that is a QName is true if and only if the type of the node (see [5 Data Model])
|
||||
* is the principal node type and has an expanded-name equal to the expanded-name specified by the QName.
|
||||
* - A node test * is true for any node of the principal node type.
|
||||
* - node() is true for any node of any type whatsoever.
|
||||
|
|
@ -1019,7 +1071,7 @@ xp_relop(xp_ctx *xc1,
|
|||
break;
|
||||
default:
|
||||
clixon_err(OE_XML, 0, "Operator %s not supported for nodeset and string", clicon_int2str(xpopmap,op));
|
||||
goto done;
|
||||
goto done;
|
||||
break;
|
||||
}
|
||||
if (xr->xc_bool) /* enough to find a single node */
|
||||
|
|
@ -1055,7 +1107,7 @@ xp_relop(xp_ctx *xc1,
|
|||
break;
|
||||
default:
|
||||
clixon_err(OE_XML, 0, "Operator %s not supported for nodeset and number", clicon_int2str(xpopmap,op));
|
||||
goto done;
|
||||
goto done;
|
||||
break;
|
||||
}
|
||||
if (xr->xc_bool) /* enough to find a single node */
|
||||
|
|
@ -1203,7 +1255,7 @@ xp_eval(xp_ctx *xc,
|
|||
goto ok;
|
||||
break;
|
||||
case XPATHFN_DEREF:
|
||||
if (xp_function_deref(xc, xs->xs_c0, nsc, localonly, xrp) < 0)
|
||||
if (xp_function_deref(xc, xs->xs_c0, nsc, xrp) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
break;
|
||||
|
|
@ -1223,7 +1275,7 @@ xp_eval(xp_ctx *xc,
|
|||
goto ok;
|
||||
break;
|
||||
case XPATHFN_POSITION:
|
||||
if (xp_function_position(xc, xs->xs_c0, nsc, localonly, xrp) < 0)
|
||||
if (xp_function_position(xc, xs->xs_c0, nsc, xrp) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
break;
|
||||
|
|
@ -1288,12 +1340,12 @@ xp_eval(xp_ctx *xc,
|
|||
goto ok;
|
||||
break;
|
||||
case XPATHFN_TRUE:
|
||||
if (xp_function_true(xc, xs->xs_c0, nsc, localonly, xrp) < 0)
|
||||
if (xp_function_true(xc, xs->xs_c0, nsc, xrp) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
break;
|
||||
case XPATHFN_FALSE:
|
||||
if (xp_function_false(xc, xs->xs_c0, nsc, localonly, xrp) < 0)
|
||||
if (xp_function_false(xc, xs->xs_c0, nsc, xrp) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -280,7 +280,6 @@ xp_function_re_match(xp_ctx *xc,
|
|||
* @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
|
||||
|
|
@ -290,7 +289,6 @@ int
|
|||
xp_function_deref(xp_ctx *xc0,
|
||||
struct xpath_tree *xs,
|
||||
cvec *nsc,
|
||||
int localonly,
|
||||
xp_ctx **xrp)
|
||||
{
|
||||
int retval = -1;
|
||||
|
|
@ -587,7 +585,6 @@ xp_function_bit_is_set(xp_ctx *xc,
|
|||
* @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
|
||||
|
|
@ -596,7 +593,6 @@ int
|
|||
xp_function_position(xp_ctx *xc,
|
||||
struct xpath_tree *xs,
|
||||
cvec *nsc,
|
||||
int localonly,
|
||||
xp_ctx **xrp)
|
||||
{
|
||||
int retval = -1;
|
||||
|
|
@ -1253,7 +1249,6 @@ int
|
|||
xp_function_true(xp_ctx *xc,
|
||||
struct xpath_tree *xs,
|
||||
cvec *nsc,
|
||||
int localonly,
|
||||
xp_ctx **xrp)
|
||||
{
|
||||
int retval = -1;
|
||||
|
|
@ -1280,7 +1275,6 @@ int
|
|||
xp_function_false(xp_ctx *xc,
|
||||
struct xpath_tree *xs,
|
||||
cvec *nsc,
|
||||
int localonly,
|
||||
xp_ctx **xrp)
|
||||
{
|
||||
int retval = -1;
|
||||
|
|
|
|||
|
|
@ -95,10 +95,10 @@ 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_deref(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, 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_position(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, 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_string(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, int localonly, xp_ctx **xrp);
|
||||
|
|
@ -109,7 +109,7 @@ int xp_function_string_length(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, int
|
|||
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);
|
||||
int xp_function_false(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, xp_ctx **xrp);
|
||||
int xp_function_false(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, xp_ctx **xrp);
|
||||
|
||||
#endif /* _CLIXON_XPATH_FUNCTION_H */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue