* XPath parser: fixing lexical issues cornercases
* Some complexities in Section 3.7 Lexical Structure of XPath 1.0 spec * There used to be some cornercases where function-names could not be used as nodes * For example, `node()` is a nodetest, so `/node/` caused an error. * In the grammar these include: axisnames, nodetests, functionnames * The NCNames vs functionnames is now impölemented according to the lexical structure section
This commit is contained in:
parent
f1300d7a12
commit
a51abd0063
9 changed files with 357 additions and 138 deletions
|
|
@ -68,6 +68,12 @@ Users may have to change how they access the system
|
||||||
* Instead of removing YANG which is disabled by `if-feature`, replace it with an yang `anydata` node.
|
* Instead of removing YANG which is disabled by `if-feature`, replace it with an yang `anydata` node.
|
||||||
* This means XML specified by such YANG is ignored, and it is not an error to access it
|
* This means XML specified by such YANG is ignored, and it is not an error to access it
|
||||||
* Note the similarity with `CLICON_YANG_UNKNOWN_ANYDATA`
|
* Note the similarity with `CLICON_YANG_UNKNOWN_ANYDATA`
|
||||||
|
* XPath parser: fixing lexical issues cornercases
|
||||||
|
* Some complexities in Section 3.7 Lexical Structure of XPath 1.0 spec
|
||||||
|
* There used to be some cornercases where function-names could not be used as nodes
|
||||||
|
* For example, `node()` is a nodetest, so `/node/` caused an error.
|
||||||
|
* In the grammar these include: axisnames, nodetests, functionnames
|
||||||
|
* The NCNames vs functionnames is now impölemented according to the lexical structure section
|
||||||
* [provide support for load config of cli format along with json and xml format as save config is supported for all 3 formats](https://github.com/clicon/clixon/issues/320)
|
* [provide support for load config of cli format along with json and xml format as save config is supported for all 3 formats](https://github.com/clicon/clixon/issues/320)
|
||||||
* [prevent clixon-restconf@2021-05-20.yang module from loading](https://github.com/clicon/clixon/issues/318)
|
* [prevent clixon-restconf@2021-05-20.yang module from loading](https://github.com/clicon/clixon/issues/318)
|
||||||
* Instead of always loading it, load it to datastore YANGs only if `CLICON_BACKEND_RESTCONF_PROCESS` is `true`
|
* Instead of always loading it, load it to datastore YANGs only if `CLICON_BACKEND_RESTCONF_PROCESS` is `true`
|
||||||
|
|
|
||||||
|
|
@ -124,6 +124,7 @@ typedef struct xpath_tree xpath_tree;
|
||||||
* Prototypes
|
* Prototypes
|
||||||
*/
|
*/
|
||||||
char* axis_type_int2str(int axis_type);
|
char* axis_type_int2str(int axis_type);
|
||||||
|
int axis_type_str2int(char *name);
|
||||||
char* xpath_tree_int2str(int nodetype);
|
char* xpath_tree_int2str(int nodetype);
|
||||||
int xpath_tree_print_cb(cbuf *cb, xpath_tree *xs);
|
int xpath_tree_print_cb(cbuf *cb, xpath_tree *xs);
|
||||||
int xpath_tree_print(FILE *f, xpath_tree *xs);
|
int xpath_tree_print(FILE *f, xpath_tree *xs);
|
||||||
|
|
|
||||||
|
|
@ -160,6 +160,11 @@ axis_type_int2str(int axis_type)
|
||||||
return (char*)clicon_int2str(axis_type_map, axis_type);
|
return (char*)clicon_int2str(axis_type_map, axis_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
axis_type_str2int(char *name)
|
||||||
|
{
|
||||||
|
return clicon_str2int(axis_type_map, name);
|
||||||
|
}
|
||||||
|
|
||||||
/*! Map from xpath_tree node name int to string
|
/*! Map from xpath_tree node name int to string
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@ struct clixon_xpath_yacc{
|
||||||
const char *xpy_name; /* Name of syntax (for error string) */
|
const char *xpy_name; /* Name of syntax (for error string) */
|
||||||
int xpy_linenum; /* Number of \n in parsed buffer */
|
int xpy_linenum; /* Number of \n in parsed buffer */
|
||||||
const char *xpy_parse_string; /* original (copy of) parse string */
|
const char *xpy_parse_string; /* original (copy of) parse string */
|
||||||
|
int xpy_lex_string_state; /* lex start condition (STRING) */
|
||||||
void *xpy_lexbuf; /* internal parse buffer from lex */
|
void *xpy_lexbuf; /* internal parse buffer from lex */
|
||||||
xpath_tree *xpy_top;
|
xpath_tree *xpy_top;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,26 @@
|
||||||
|
|
||||||
***** END LICENSE BLOCK *****
|
***** END LICENSE BLOCK *****
|
||||||
|
|
||||||
|
There are some special lexical rules in https://www.w3.org/TR/xpath-10
|
||||||
|
|
||||||
|
1. If there is a preceding token and the preceding token is not one of
|
||||||
|
@, ::, (, [, , or an Operator, then a * must be recognized as a
|
||||||
|
MultiplyOperator and an NCName must be recognized as an
|
||||||
|
OperatorName. (and,or,div,mod)
|
||||||
|
2. If the character following an NCName (possibly after intervening
|
||||||
|
ExprWhitespace) is (, then the token must be recognized as a
|
||||||
|
NodeType or a FunctionName.
|
||||||
|
3. If the two characters following an NCName (possibly after
|
||||||
|
intervening ExprWhitespace) are ::, then the token must be
|
||||||
|
recognized as an AxisName.
|
||||||
|
4. Otherwise, the token must not be recognized as a MultiplyOperator,
|
||||||
|
an OperatorName, a NodeType, a FunctionName, or an AxisName.
|
||||||
|
|
||||||
|
These rules are implemented in this parser by two states: TOKEN0 and TOKEN2.
|
||||||
|
TOKEN0 is the start and normative state and has only a basic NCNAME rule
|
||||||
|
TOKEN2 is only entered after some of the rules above, and has special nodetest rules
|
||||||
|
(maybe function/axisname as well?).
|
||||||
|
This state is left immediately to TOKEN0 after a single token
|
||||||
*/
|
*/
|
||||||
|
|
||||||
%{
|
%{
|
||||||
|
|
@ -58,6 +78,7 @@
|
||||||
#include "clixon_xpath_ctx.h"
|
#include "clixon_xpath_ctx.h"
|
||||||
#include "clixon_xpath.h"
|
#include "clixon_xpath.h"
|
||||||
#include "clixon_xpath_parse.h"
|
#include "clixon_xpath_parse.h"
|
||||||
|
#include "clixon_xpath_function.h"
|
||||||
#include "clixon_xpath_eval.h"
|
#include "clixon_xpath_eval.h"
|
||||||
|
|
||||||
/* Redefine main lex function so that you can send arguments to it: _yy is added to arg list */
|
/* Redefine main lex function so that you can send arguments to it: _yy is added to arg list */
|
||||||
|
|
@ -76,8 +97,8 @@ clixon_xpath_parsewrap(void)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* strip last char */
|
/* strip last char: kludge to peek to next character */
|
||||||
void
|
static void
|
||||||
striplast(char *s)
|
striplast(char *s)
|
||||||
{
|
{
|
||||||
s[strlen(s)-1] = 0;
|
s[strlen(s)-1] = 0;
|
||||||
|
|
@ -92,60 +113,83 @@ real ({digit}+[.]{digit}*)|({digit}*[.]{digit}+)
|
||||||
namestart [A-Z_a-z]
|
namestart [A-Z_a-z]
|
||||||
namechar [A-Z_a-z\-\.0-9]
|
namechar [A-Z_a-z\-\.0-9]
|
||||||
ncname {namestart}{namechar}*
|
ncname {namestart}{namechar}*
|
||||||
fnname {ncname}\(
|
|
||||||
|
|
||||||
%x TOKEN
|
%s TOKEN0
|
||||||
|
%s TOKEN2
|
||||||
%s QLITERAL
|
%s QLITERAL
|
||||||
%s ALITERAL
|
%s ALITERAL
|
||||||
|
|
||||||
%%
|
%%
|
||||||
<TOKEN>[ \t]
|
<TOKEN0>[ \t]
|
||||||
<TOKEN>\n { _XPY->xpy_linenum++; }
|
<TOKEN0>\n { _XPY->xpy_linenum++; }
|
||||||
<TOKEN>\r { }
|
<TOKEN0>\r { }
|
||||||
<TOKEN><<EOF>> { return X_EOF; }
|
<TOKEN0><<EOF>> { return X_EOF; }
|
||||||
<TOKEN>".." { return DOUBLEDOT; }
|
<TOKEN0>".." { return DOUBLEDOT; }
|
||||||
<TOKEN>[()\[\]\.,/:|] { return *yytext; }
|
<TOKEN0>:: { BEGIN(TOKEN2); return DOUBLECOLON; /* axisname */ }
|
||||||
<TOKEN>and { clixon_xpath_parselval.intval = clicon_str2int(xpopmap, yytext); return LOGOP; }
|
<TOKEN0>[(\[] { BEGIN(TOKEN2); return *yytext; }
|
||||||
<TOKEN>or { clixon_xpath_parselval.intval = clicon_str2int(xpopmap, yytext); return LOGOP; }
|
<TOKEN0>[)\]\.,/:|] { return *yytext; }
|
||||||
<TOKEN>div { clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext); return ADDOP; }
|
<TOKEN0>and { BEGIN(TOKEN2);clixon_xpath_parselval.intval = clicon_str2int(xpopmap, yytext); return LOGOP; }
|
||||||
<TOKEN>mod { clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext); return ADDOP; }
|
<TOKEN0>or { BEGIN(TOKEN2);clixon_xpath_parselval.intval = clicon_str2int(xpopmap, yytext); return LOGOP; }
|
||||||
<TOKEN>[+*\-] { clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext); return ADDOP; }
|
<TOKEN0>div { BEGIN(TOKEN2);clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext); return ADDOP; }
|
||||||
<TOKEN>\? { return *yytext; }
|
<TOKEN0>mod { BEGIN(TOKEN2);clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext); return ADDOP; }
|
||||||
<TOKEN>"//" { return DOUBLESLASH; }
|
<TOKEN0>[+*\-] { BEGIN(TOKEN2);clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext); return ADDOP; }
|
||||||
<TOKEN>"!=" { clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext); return RELOP; }
|
<TOKEN0>\? { return *yytext; }
|
||||||
<TOKEN>">=" { clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext);return RELOP; }
|
<TOKEN0>"//" { BEGIN(TOKEN2);return DOUBLESLASH; }
|
||||||
<TOKEN>"<=" { clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext);return RELOP; }
|
<TOKEN0>"!=" { BEGIN(TOKEN2);clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext); return RELOP; }
|
||||||
<TOKEN>[<>=] { clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext);return RELOP; }
|
<TOKEN0>">=" { BEGIN(TOKEN2);clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext);return RELOP; }
|
||||||
|
<TOKEN0>"<=" { BEGIN(TOKEN2);clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext);return RELOP; }
|
||||||
|
<TOKEN0>[<>=] { BEGIN(TOKEN2);clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext);return RELOP; }
|
||||||
|
|
||||||
<TOKEN>{fnname} { clixon_xpath_parselval.string = strdup(yytext); striplast(clixon_xpath_parselval.string); return FUNCTIONNAME; }
|
<TOKEN0>@ { BEGIN(TOKEN2); return *yytext; }
|
||||||
|
<TOKEN0>\" { _XPY->xpy_lex_string_state = TOKEN0; BEGIN(QLITERAL); return QUOTE; }
|
||||||
|
<TOKEN0>\' { _XPY->xpy_lex_string_state = TOKEN0; BEGIN(ALITERAL); return APOST; }
|
||||||
|
<TOKEN0>\-?({integer}|{real}) { clixon_xpath_parselval.string = strdup(yytext); return NUMBER; }
|
||||||
|
|
||||||
<TOKEN>@ { return *yytext; }
|
<TOKEN0>{ncname} { /* See lexical rules 2 and 3 in the file header */
|
||||||
<TOKEN>ancestor:: { clixon_xpath_parselval.intval = A_ANCESTOR; return AXISNAME; }
|
clixon_xpath_parselval.string = strdup(yytext);
|
||||||
<TOKEN>ancestor-or-self:: { clixon_xpath_parselval.intval = A_ANCESTOR_OR_SELF; return AXISNAME; }
|
return NCNAME;
|
||||||
<TOKEN>attribute:: { clixon_xpath_parselval.intval = A_ATTRIBUTE; return AXISNAME; }
|
|
||||||
<TOKEN>child:: { clixon_xpath_parselval.intval = A_CHILD; return AXISNAME; }
|
|
||||||
<TOKEN>descendant:: { clixon_xpath_parselval.intval = A_DESCENDANT; return AXISNAME; }
|
|
||||||
<TOKEN>descendant-or-self:: { clixon_xpath_parselval.intval = A_DESCENDANT_OR_SELF; return AXISNAME; }
|
|
||||||
<TOKEN>following:: { clixon_xpath_parselval.intval = A_FOLLOWING; return AXISNAME; }
|
|
||||||
<TOKEN>following-sibling:: { clixon_xpath_parselval.intval = A_FOLLOWING_SIBLING; return AXISNAME; }
|
|
||||||
<TOKEN>namespace:: { clixon_xpath_parselval.intval = A_NAMESPACE; return AXISNAME; }
|
|
||||||
<TOKEN>parent:: { clixon_xpath_parselval.intval = A_PARENT; return AXISNAME; }
|
|
||||||
<TOKEN>preceding:: { clixon_xpath_parselval.intval = A_PRECEDING; return AXISNAME; }
|
|
||||||
<TOKEN>preceding-sibling:: { clixon_xpath_parselval.intval = A_PRECEDING_SIBLING; return AXISNAME; }
|
|
||||||
<TOKEN>self:: { clixon_xpath_parselval.intval = A_SELF; return AXISNAME; }
|
|
||||||
|
|
||||||
<TOKEN>\" { BEGIN(QLITERAL); return QUOTE; }
|
|
||||||
<TOKEN>\' { BEGIN(ALITERAL); return APOST; }
|
|
||||||
<TOKEN>\-?({integer}|{real}) { clixon_xpath_parselval.string = strdup(yytext); return NUMBER; }
|
|
||||||
<TOKEN>{ncname} { clixon_xpath_parselval.string = strdup(yytext);
|
|
||||||
return NAME; /* rather be catch-all */
|
|
||||||
}
|
}
|
||||||
<TOKEN>. { fprintf(stderr,"LEXICAL ERROR\n"); return -1; }
|
<TOKEN0>. { fprintf(stderr,"LEXICAL ERROR\n"); return -1; }
|
||||||
|
|
||||||
<QLITERAL>\" { BEGIN(TOKEN); return QUOTE; }
|
<TOKEN2>[ \t]
|
||||||
|
<TOKEN2>\n { _XPY->xpy_linenum++; }
|
||||||
|
<TOKEN2>\r { }
|
||||||
|
<TOKEN2><<EOF>> { return X_EOF; }
|
||||||
|
<TOKEN2>".." { BEGIN(TOKEN0); return DOUBLEDOT; }
|
||||||
|
<TOKEN2>:: { BEGIN(TOKEN0); return DOUBLECOLON; /* axisname */ }
|
||||||
|
<TOKEN2>[()\[\]\.,/:|] { BEGIN(TOKEN0); return *yytext; }
|
||||||
|
<TOKEN2>and { BEGIN(TOKEN0); clixon_xpath_parselval.intval = clicon_str2int(xpopmap, yytext); return LOGOP; }
|
||||||
|
<TOKEN2>or { BEGIN(TOKEN0); clixon_xpath_parselval.intval = clicon_str2int(xpopmap, yytext); return LOGOP; }
|
||||||
|
<TOKEN2>div { BEGIN(TOKEN0); clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext); return ADDOP; }
|
||||||
|
<TOKEN2>mod { BEGIN(TOKEN0); clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext); return ADDOP; }
|
||||||
|
<TOKEN2>[+*\-] { BEGIN(TOKEN0); clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext); return ADDOP; }
|
||||||
|
<TOKEN2>\? { BEGIN(TOKEN0); return *yytext; }
|
||||||
|
<TOKEN2>"//" { BEGIN(TOKEN0); return DOUBLESLASH; }
|
||||||
|
<TOKEN2>"!=" { BEGIN(TOKEN0); clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext); return RELOP; }
|
||||||
|
<TOKEN2>">=" { BEGIN(TOKEN0); clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext);return RELOP; }
|
||||||
|
<TOKEN2>"<=" { BEGIN(TOKEN0); clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext);return RELOP; }
|
||||||
|
<TOKEN2>[<>=] { BEGIN(TOKEN0); clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext);return RELOP; }
|
||||||
|
|
||||||
|
<TOKEN2>@ { BEGIN(TOKEN0); return *yytext; }
|
||||||
|
<TOKEN2>\" { BEGIN(TOKEN0); _XPY->xpy_lex_string_state=TOKEN2; BEGIN(QLITERAL); return QUOTE; }
|
||||||
|
<TOKEN2>\' { BEGIN(TOKEN0); _XPY->xpy_lex_string_state=TOKEN2; BEGIN(ALITERAL); return APOST; }
|
||||||
|
<TOKEN2>\-?({integer}|{real}) { BEGIN(TOKEN0); clixon_xpath_parselval.string = strdup(yytext); return NUMBER; }
|
||||||
|
|
||||||
|
<TOKEN2>comment\( { BEGIN(TOKEN0); clixon_xpath_parselval.string = strdup(yytext); striplast(clixon_xpath_parselval.string); return NODETYPE; }
|
||||||
|
<TOKEN2>text\( { BEGIN(TOKEN0); clixon_xpath_parselval.string = strdup(yytext); striplast(clixon_xpath_parselval.string); return NODETYPE; }
|
||||||
|
<TOKEN2>processing-instructions\( { BEGIN(TOKEN0); clixon_xpath_parselval.string = strdup(yytext); striplast(clixon_xpath_parselval.string); return NODETYPE; }
|
||||||
|
<TOKEN2>node\( { BEGIN(TOKEN0); clixon_xpath_parselval.string = strdup(yytext); striplast(clixon_xpath_parselval.string); return NODETYPE; }
|
||||||
|
<TOKEN2>{ncname} { /* See lexical rules 2 and 3 in the file header */
|
||||||
|
BEGIN(TOKEN0);
|
||||||
|
clixon_xpath_parselval.string = strdup(yytext);
|
||||||
|
return NCNAME;
|
||||||
|
}
|
||||||
|
<TOKEN2>. { fprintf(stderr,"LEXICAL ERROR\n"); return -1; }
|
||||||
|
|
||||||
|
<QLITERAL>\" { BEGIN(_XPY->xpy_lex_string_state); return QUOTE; }
|
||||||
<QLITERAL>[^"]+ { clixon_xpath_parselval.string = strdup(yytext);
|
<QLITERAL>[^"]+ { clixon_xpath_parselval.string = strdup(yytext);
|
||||||
return CHARS;}
|
return CHARS;}
|
||||||
<ALITERAL>\' { BEGIN(TOKEN); return APOST; }
|
<ALITERAL>\' { BEGIN(_XPY->xpy_lex_string_state); return APOST; }
|
||||||
<ALITERAL>[^']+ { clixon_xpath_parselval.string = strdup(yytext);
|
<ALITERAL>[^']+ { clixon_xpath_parselval.string = strdup(yytext);
|
||||||
return CHARS;}
|
return CHARS;}
|
||||||
|
|
||||||
|
|
@ -157,7 +201,7 @@ fnname {ncname}\(
|
||||||
int
|
int
|
||||||
xpath_scan_init(clixon_xpath_yacc *xpy)
|
xpath_scan_init(clixon_xpath_yacc *xpy)
|
||||||
{
|
{
|
||||||
BEGIN(TOKEN);
|
BEGIN(TOKEN0);
|
||||||
xpy->xpy_lexbuf = yy_scan_string (xpy->xpy_parse_string);
|
xpy->xpy_lexbuf = yy_scan_string (xpy->xpy_parse_string);
|
||||||
#if 1 /* XXX: just to use unput to avoid warning */
|
#if 1 /* XXX: just to use unput to avoid warning */
|
||||||
if (0)
|
if (0)
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,6 @@
|
||||||
void *stack; /* xpath_tree */
|
void *stack; /* xpath_tree */
|
||||||
}
|
}
|
||||||
|
|
||||||
%token <intval> AXISNAME
|
|
||||||
%token <intval> LOGOP
|
%token <intval> LOGOP
|
||||||
%token <intval> ADDOP
|
%token <intval> ADDOP
|
||||||
%token <intval> RELOP
|
%token <intval> RELOP
|
||||||
|
|
@ -59,12 +58,15 @@
|
||||||
%token <string> QUOTE
|
%token <string> QUOTE
|
||||||
%token <string> APOST
|
%token <string> APOST
|
||||||
%token <string> CHARS
|
%token <string> CHARS
|
||||||
%token <string> NAME
|
%token <string> NCNAME
|
||||||
|
%token <string> NODETYPE
|
||||||
%token <string> DOUBLEDOT
|
%token <string> DOUBLEDOT
|
||||||
|
%token <string> DOUBLECOLON
|
||||||
%token <string> DOUBLESLASH
|
%token <string> DOUBLESLASH
|
||||||
%token <string> FUNCTIONNAME
|
%token <string> FUNCTIONNAME
|
||||||
|
|
||||||
%type <intval> axisspec
|
%type <intval> axisspec
|
||||||
|
%type <intval> abbreviatedaxisspec
|
||||||
|
|
||||||
%type <string> string
|
%type <string> string
|
||||||
%type <stack> args
|
%type <stack> args
|
||||||
|
|
@ -79,9 +81,13 @@
|
||||||
%type <stack> abslocpath
|
%type <stack> abslocpath
|
||||||
%type <stack> rellocpath
|
%type <stack> rellocpath
|
||||||
%type <stack> step
|
%type <stack> step
|
||||||
|
%type <stack> abbreviatedstep
|
||||||
%type <stack> nodetest
|
%type <stack> nodetest
|
||||||
|
%type <stack> nametest
|
||||||
%type <stack> predicates
|
%type <stack> predicates
|
||||||
%type <stack> primaryexpr
|
%type <stack> primaryexpr
|
||||||
|
%type <stack> literal
|
||||||
|
%type <stack> functioncall
|
||||||
|
|
||||||
%lex-param {void *_xpy} /* Add this argument to parse() and lex() function */
|
%lex-param {void *_xpy} /* Add this argument to parse() and lex() function */
|
||||||
%parse-param {void *_xpy}
|
%parse-param {void *_xpy}
|
||||||
|
|
@ -319,15 +325,13 @@ xp_primary_function(clixon_xpath_yacc *xpy,
|
||||||
*/
|
*/
|
||||||
static xpath_tree *
|
static xpath_tree *
|
||||||
xp_nodetest_function(clixon_xpath_yacc *xpy,
|
xp_nodetest_function(clixon_xpath_yacc *xpy,
|
||||||
char *name,
|
char *name)
|
||||||
xpath_tree *xpt)
|
|
||||||
{
|
{
|
||||||
xpath_tree *xtret = NULL;
|
xpath_tree *xtret = NULL;
|
||||||
enum clixon_xpath_function fn;
|
|
||||||
cbuf *cb = NULL;
|
cbuf *cb = NULL;
|
||||||
int ret;
|
enum clixon_xpath_function fn;
|
||||||
|
|
||||||
if ((ret = xp_fnname_str2int(name)) < 0){
|
if ((fn = xp_fnname_str2int(name)) < 0){
|
||||||
if ((cb = cbuf_new()) == NULL){
|
if ((cb = cbuf_new()) == NULL){
|
||||||
clicon_err(OE_XML, errno, "cbuf_new");
|
clicon_err(OE_XML, errno, "cbuf_new");
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -336,7 +340,6 @@ xp_nodetest_function(clixon_xpath_yacc *xpy,
|
||||||
clixon_xpath_parseerror(xpy, cbuf_get(cb));
|
clixon_xpath_parseerror(xpy, cbuf_get(cb));
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
fn = ret;
|
|
||||||
switch (fn){
|
switch (fn){
|
||||||
case XPATHFN_COMMENT: /* Group of not implemented node functions */
|
case XPATHFN_COMMENT: /* Group of not implemented node functions */
|
||||||
case XPATHFN_PROCESSING_INSTRUCTIONS:
|
case XPATHFN_PROCESSING_INSTRUCTIONS:
|
||||||
|
|
@ -363,16 +366,42 @@ xp_nodetest_function(clixon_xpath_yacc *xpy,
|
||||||
}
|
}
|
||||||
if (cb)
|
if (cb)
|
||||||
cbuf_free(cb);
|
cbuf_free(cb);
|
||||||
xtret = xp_new(XP_NODE_FN, fn, NULL, name, NULL, xpt, NULL);
|
xtret = xp_new(XP_NODE_FN, fn, NULL, name, NULL, NULL, NULL);
|
||||||
name = NULL; /* Consumed by xp_new */
|
|
||||||
done:
|
done:
|
||||||
if (cb)
|
if (cb)
|
||||||
cbuf_free(cb);
|
cbuf_free(cb);
|
||||||
if (name)
|
|
||||||
free(name);
|
|
||||||
return xtret;
|
return xtret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Axisname functions
|
||||||
|
*
|
||||||
|
* See rule [6] AxisName ::= 'ancestor',...
|
||||||
|
* in https://www.w3.org/TR/xpath-10/
|
||||||
|
* @param[in] xpy XPath parse handle
|
||||||
|
* @param[in] name Name of axisname function
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
xp_axisname_function(clixon_xpath_yacc *xpy,
|
||||||
|
char *name)
|
||||||
|
{
|
||||||
|
int fn = -1;
|
||||||
|
cbuf *cb = NULL;
|
||||||
|
|
||||||
|
if ((fn = axis_type_str2int(name)) < 0){
|
||||||
|
if ((cb = cbuf_new()) == NULL){
|
||||||
|
clicon_err(OE_XML, errno, "cbuf_new");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
cprintf(cb, "Unknown xpath axisname \"%s\"", name);
|
||||||
|
clixon_xpath_parseerror(xpy, cbuf_get(cb));
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
done:
|
||||||
|
if (cb)
|
||||||
|
cbuf_free(cb);
|
||||||
|
return fn;
|
||||||
|
}
|
||||||
|
|
||||||
%}
|
%}
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
@ -411,6 +440,7 @@ pathexpr : locationpath { $$=xp_new(XP_PATHEXPR,A_NAN,NULL,NULL,NULL,$1, NULL
|
||||||
| filterexpr DOUBLESLASH rellocpath { $$=xp_new(XP_PATHEXPR,A_NAN,NULL,strdup("//"),NULL,$1, $3);_XPY->xpy_top=$$;_PARSE_DEBUG("pathexpr-> filterexpr // rellocpath"); }
|
| filterexpr DOUBLESLASH rellocpath { $$=xp_new(XP_PATHEXPR,A_NAN,NULL,strdup("//"),NULL,$1, $3);_XPY->xpy_top=$$;_PARSE_DEBUG("pathexpr-> filterexpr // rellocpath"); }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
/* */
|
||||||
filterexpr : primaryexpr { $$=xp_new(XP_FILTEREXPR,A_NAN,NULL,NULL,NULL,$1, NULL);_PARSE_DEBUG("filterexpr-> primaryexpr"); }
|
filterexpr : primaryexpr { $$=xp_new(XP_FILTEREXPR,A_NAN,NULL,NULL,NULL,$1, NULL);_PARSE_DEBUG("filterexpr-> primaryexpr"); }
|
||||||
/* Filterexpr predicate */
|
/* Filterexpr predicate */
|
||||||
;
|
;
|
||||||
|
|
@ -431,21 +461,58 @@ rellocpath : step { $$=xp_new(XP_RELLOCPATH,A_NAN,NULL,NULL,NUL
|
||||||
| rellocpath DOUBLESLASH step { $$=xp_new(XP_RELLOCPATH,A_DESCENDANT_OR_SELF,NULL,NULL,NULL,$1, $3); _PARSE_DEBUG("rellocpath-> rellocpath // step"); }
|
| rellocpath DOUBLESLASH step { $$=xp_new(XP_RELLOCPATH,A_DESCENDANT_OR_SELF,NULL,NULL,NULL,$1, $3); _PARSE_DEBUG("rellocpath-> rellocpath // step"); }
|
||||||
;
|
;
|
||||||
|
|
||||||
step : axisspec nodetest predicates {$$=xp_new(XP_STEP,$1,NULL, NULL, NULL, $2, $3);_PARSE_DEBUG1("step->axisspec(%d) nodetest", $1); }
|
step : nodetest predicates
|
||||||
| '.' predicates { $$=xp_new(XP_STEP,A_SELF, NULL,NULL, NULL, NULL, $2); _PARSE_DEBUG("step-> ."); }
|
{ $$=xp_new(XP_STEP, A_CHILD, NULL, NULL, NULL, $1, $2);
|
||||||
|
_PARSE_DEBUG("step->nodetest predicates"); }
|
||||||
|
| axisspec nodetest predicates
|
||||||
|
{$$=xp_new(XP_STEP, $1, NULL, NULL, NULL, $2, $3);
|
||||||
|
_PARSE_DEBUG1("step->axisspec(%d) nodetest", $1); }
|
||||||
|
| abbreviatedstep { $$ = $1; }
|
||||||
|
;
|
||||||
|
|
||||||
|
abbreviatedstep : '.' predicates { $$=xp_new(XP_STEP,A_SELF, NULL,NULL, NULL, NULL, $2); _PARSE_DEBUG("step-> ."); }
|
||||||
| DOUBLEDOT predicates { $$=xp_new(XP_STEP, A_PARENT, NULL,NULL, NULL, NULL, $2); _PARSE_DEBUG("step-> .."); }
|
| DOUBLEDOT predicates { $$=xp_new(XP_STEP, A_PARENT, NULL,NULL, NULL, NULL, $2); _PARSE_DEBUG("step-> .."); }
|
||||||
;
|
;
|
||||||
|
|
||||||
axisspec : AXISNAME { _PARSE_DEBUG1("axisspec-> AXISNAME(%d) ::", $1); $$=$1;}
|
/* [5] AxisSpecifier::= AxisName '::'
|
||||||
| '@' { $$=A_ATTRIBUTE; _PARSE_DEBUG("axisspec-> @"); }
|
| AbbreviatedAxisSpecifier
|
||||||
| { _PARSE_DEBUG("axisspec-> "); $$=A_CHILD;}
|
*/
|
||||||
|
axisspec : NCNAME DOUBLECOLON
|
||||||
|
{ if (($$=xp_axisname_function(_XPY, $1)) < 0) YYERROR;
|
||||||
|
_PARSE_DEBUG2("axisspec-> AXISNAME(%s -> %d) ::", $1, $$);
|
||||||
|
}
|
||||||
|
| abbreviatedaxisspec
|
||||||
|
{ $$ = $1; }
|
||||||
;
|
;
|
||||||
|
|
||||||
nodetest : ADDOP { $$=xp_new(XP_NODE,A_NAN,NULL, NULL, strdup(clicon_int2str(xpopmap,$1)), NULL, NULL); _PARSE_DEBUG("nodetest-> *"); }
|
/* [13] AbbreviatedAxisSpecifier ::= '@'?
|
||||||
| NAME { $$=xp_new(XP_NODE,A_NAN,NULL, NULL, $1, NULL, NULL); _PARSE_DEBUG1("nodetest-> name(%s)",$1); }
|
* empty built into 2nd step rule
|
||||||
| NAME ':' NAME { $$=xp_new(XP_NODE,A_NAN,NULL, $1, $3, NULL, NULL);_PARSE_DEBUG2("nodetest-> name(%s) : name(%s)", $1, $3); }
|
*/
|
||||||
| NAME ':' '*' { $$=xp_new(XP_NODE,A_NAN,NULL, $1, NULL, NULL, NULL);_PARSE_DEBUG1("nodetest-> name(%s) : *", $1); }
|
abbreviatedaxisspec :'@' { $$=A_ATTRIBUTE; _PARSE_DEBUG("axisspec-> @"); }
|
||||||
| FUNCTIONNAME ')' { if (($$ = xp_nodetest_function(_XPY, $1, NULL)) == NULL) YYERROR;; _PARSE_DEBUG1("nodetest-> nodetype():%s", $1); }
|
;
|
||||||
|
|
||||||
|
nodetest : nametest { $$ = $1;
|
||||||
|
_PARSE_DEBUG("nodetest-> nametest");}
|
||||||
|
| NODETYPE ')'
|
||||||
|
{ if (($$ = xp_nodetest_function(_XPY, $1)) == NULL) YYERROR;
|
||||||
|
_PARSE_DEBUG1("nodetest-> nodetype(%s)", $1);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
nametest : ADDOP
|
||||||
|
{ char *str;
|
||||||
|
str = strdup(clicon_int2str(xpopmap,$1));
|
||||||
|
$$=xp_new(XP_NODE,A_NAN,NULL, NULL, str, NULL, NULL);
|
||||||
|
_PARSE_DEBUG("nametest-> *"); }
|
||||||
|
| NCNAME
|
||||||
|
{ $$=xp_new(XP_NODE,A_NAN,NULL, NULL, $1, NULL, NULL);
|
||||||
|
_PARSE_DEBUG1("nametest-> name[%s]",$1); }
|
||||||
|
| NCNAME ':' NCNAME
|
||||||
|
{ $$=xp_new(XP_NODE,A_NAN,NULL, $1, $3, NULL, NULL);
|
||||||
|
_PARSE_DEBUG2("nametest-> name[%s] : name[%s]", $1, $3); }
|
||||||
|
| NCNAME ':' '*'
|
||||||
|
{ $$=xp_new(XP_NODE,A_NAN,NULL, $1, NULL, NULL, NULL);
|
||||||
|
_PARSE_DEBUG1("nametest-> name[%s] : *", $1); }
|
||||||
;
|
;
|
||||||
|
|
||||||
/* evaluates to boolean */
|
/* evaluates to boolean */
|
||||||
|
|
@ -453,13 +520,9 @@ predicates : predicates '[' expr ']' { $$=xp_new(XP_PRED,A_NAN,NULL, NULL, NULL
|
||||||
| { $$=xp_new(XP_PRED,A_NAN,NULL, NULL, NULL, NULL, NULL); _PARSE_DEBUG("predicates->"); }
|
| { $$=xp_new(XP_PRED,A_NAN,NULL, NULL, NULL, NULL, NULL); _PARSE_DEBUG("predicates->"); }
|
||||||
;
|
;
|
||||||
primaryexpr : '(' expr ')' { $$=xp_new(XP_PRI0,A_NAN,NULL, NULL, NULL, $2, NULL); _PARSE_DEBUG("primaryexpr-> ( expr )"); }
|
primaryexpr : '(' expr ')' { $$=xp_new(XP_PRI0,A_NAN,NULL, NULL, NULL, $2, NULL); _PARSE_DEBUG("primaryexpr-> ( expr )"); }
|
||||||
|
| literal { $$ = $1; }
|
||||||
| NUMBER { $$=xp_new(XP_PRIME_NR,A_NAN, $1, NULL, NULL, NULL, NULL);_PARSE_DEBUG1("primaryexpr-> NUMBER(%s)", $1); /*XXX*/}
|
| NUMBER { $$=xp_new(XP_PRIME_NR,A_NAN, $1, NULL, NULL, NULL, NULL);_PARSE_DEBUG1("primaryexpr-> NUMBER(%s)", $1); /*XXX*/}
|
||||||
| QUOTE string QUOTE { $$=xp_new(XP_PRIME_STR,A_NAN,NULL, $2, NULL, NULL, NULL);_PARSE_DEBUG("primaryexpr-> \" string \""); }
|
| functioncall { $$ = $1; }
|
||||||
| QUOTE QUOTE { $$=xp_new(XP_PRIME_STR,A_NAN,NULL, strdup(""), NULL, NULL, NULL);_PARSE_DEBUG("primaryexpr-> \" \""); }
|
|
||||||
| APOST string APOST { $$=xp_new(XP_PRIME_STR,A_NAN,NULL, $2, NULL, NULL, NULL);_PARSE_DEBUG("primaryexpr-> ' string '"); }
|
|
||||||
| APOST APOST { $$=xp_new(XP_PRIME_STR,A_NAN,NULL, strdup(""), NULL, NULL, NULL);_PARSE_DEBUG("primaryexpr-> ' '"); }
|
|
||||||
| FUNCTIONNAME ')' { if (($$ = xp_primary_function(_XPY, $1, NULL)) == NULL) YYERROR; _PARSE_DEBUG("primaryexpr-> functionname ()"); }
|
|
||||||
| FUNCTIONNAME args ')' { if (($$ = xp_primary_function(_XPY, $1, $2)) == NULL) YYERROR; _PARSE_DEBUG("primaryexpr-> functionname (arguments)"); }
|
|
||||||
;
|
;
|
||||||
|
|
||||||
args : args ',' expr { $$=xp_new(XP_EXP,A_NAN,NULL,NULL,NULL,$1, $3);
|
args : args ',' expr { $$=xp_new(XP_EXP,A_NAN,NULL,NULL,NULL,$1, $3);
|
||||||
|
|
@ -468,6 +531,29 @@ args : args ',' expr { $$=xp_new(XP_EXP,A_NAN,NULL,NULL,NULL,$1, $3);
|
||||||
_PARSE_DEBUG("args -> expr "); }
|
_PARSE_DEBUG("args -> expr "); }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
literal : QUOTE string QUOTE
|
||||||
|
{ $$=xp_new(XP_PRIME_STR,A_NAN,NULL, $2, NULL, NULL, NULL);
|
||||||
|
_PARSE_DEBUG("literal-> \" string \""); }
|
||||||
|
| QUOTE QUOTE
|
||||||
|
{ $$=xp_new(XP_PRIME_STR,A_NAN,NULL, strdup(""), NULL, NULL, NULL);
|
||||||
|
_PARSE_DEBUG("primaryexpr-> \" \""); }
|
||||||
|
| APOST string APOST
|
||||||
|
{ $$=xp_new(XP_PRIME_STR,A_NAN,NULL, $2, NULL, NULL, NULL);
|
||||||
|
_PARSE_DEBUG("primaryexpr-> ' string '"); }
|
||||||
|
| APOST APOST
|
||||||
|
{ $$=xp_new(XP_PRIME_STR,A_NAN,NULL, strdup(""), NULL, NULL, NULL);
|
||||||
|
_PARSE_DEBUG("primaryexpr-> ' '"); }
|
||||||
|
;
|
||||||
|
|
||||||
|
functioncall : NCNAME '(' ')'
|
||||||
|
{ /* XXX warning: rule useless in parser due to conflicts */
|
||||||
|
if (($$ = xp_primary_function(_XPY, $1, NULL)) == NULL) YYERROR;
|
||||||
|
_PARSE_DEBUG("primaryexpr-> functionname ()"); }
|
||||||
|
| NCNAME '(' args ')'
|
||||||
|
{ if (($$ = xp_primary_function(_XPY, $1, $3)) == NULL) YYERROR;
|
||||||
|
_PARSE_DEBUG("primaryexpr-> functionname (arguments)"); }
|
||||||
|
;
|
||||||
|
|
||||||
string : string CHARS {
|
string : string CHARS {
|
||||||
int len = strlen($1);
|
int len = strlen($1);
|
||||||
$$ = realloc($1, len+strlen($2) + 1);
|
$$ = realloc($1, len+strlen($2) + 1);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,9 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# XPATH tests
|
# XPATH tests
|
||||||
|
# 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
|
||||||
|
|
||||||
# Magic line must be first in script (see README.md)
|
# Magic line must be first in script (see README.md)
|
||||||
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
||||||
|
|
@ -11,6 +15,7 @@ xml=$dir/xml.xml
|
||||||
xml2=$dir/xml2.xml
|
xml2=$dir/xml2.xml
|
||||||
xml3=$dir/xml3.xml
|
xml3=$dir/xml3.xml
|
||||||
xml4=$dir/xml4.xml
|
xml4=$dir/xml4.xml
|
||||||
|
xmlfn=$dir/xmlfn.xml
|
||||||
|
|
||||||
cat <<EOF > $xml
|
cat <<EOF > $xml
|
||||||
<aaa>
|
<aaa>
|
||||||
|
|
@ -94,173 +99,229 @@ cat <<EOF > $xml4
|
||||||
</root>
|
</root>
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
# XPath functions
|
||||||
|
cat <<EOF > $xmlfn
|
||||||
|
<root>
|
||||||
|
<ancestor>
|
||||||
|
<count>
|
||||||
|
<node>42</node>
|
||||||
|
</count>
|
||||||
|
</ancestor>
|
||||||
|
<count>
|
||||||
|
<node>
|
||||||
|
<ancestor>99</ancestor>
|
||||||
|
</node>
|
||||||
|
</count>
|
||||||
|
<node>
|
||||||
|
<ancestor>
|
||||||
|
<count>73</count>
|
||||||
|
</ancestor>
|
||||||
|
</node>
|
||||||
|
</root>
|
||||||
|
EOF
|
||||||
|
|
||||||
|
|
||||||
|
new "xpath not(aaa)"
|
||||||
|
expectpart "$($clixon_util_xpath -D $DBG -f $xml -p "not(aaa)")" 0 "bool:false"
|
||||||
|
|
||||||
|
new "xpath not (aaa) - delimiter"
|
||||||
|
expectpart "$($clixon_util_xpath -D $DBG -f $xml -p "not(aaa)")" 0 "bool:false"
|
||||||
|
|
||||||
|
new "xpath not(xyz)"
|
||||||
|
expectpart "$($clixon_util_xpath -D $DBG -f $xml -p "not(xyz)")" 0 "bool:true"
|
||||||
|
|
||||||
new "xpath /"
|
new "xpath /"
|
||||||
expecteof "$clixon_util_xpath -f $xml -p /" 0 "" "^nodeset:0:<aaa><bbb x=\"hello\"><ccc>42</ccc></bbb><bbb x=\"bye\"><ccc>99</ccc></bbb><ddd><ccc>22</ccc></ddd></aaa>$"
|
expectpart "$($clixon_util_xpath -D $DBG -f $xml -p /)" 0 "^nodeset:0:<aaa><bbb x=\"hello\"><ccc>42</ccc></bbb><bbb x=\"bye\"><ccc>99</ccc></bbb><ddd><ccc>22</ccc></ddd></aaa>$"
|
||||||
|
|
||||||
new "xpath /aaa"
|
new "xpath /aaa"
|
||||||
expecteof "$clixon_util_xpath -f $xml -p /aaa" 0 "" "^nodeset:0:<aaa><bbb x=\"hello\"><ccc>42</ccc></bbb><bbb x=\"bye\"><ccc>99</ccc></bbb><ddd><ccc>22</ccc></ddd></aaa>$"
|
expectpart "$($clixon_util_xpath -D $DBG -f $xml -p /aaa)" 0 "^nodeset:0:<aaa><bbb x=\"hello\"><ccc>42</ccc></bbb><bbb x=\"bye\"><ccc>99</ccc></bbb><ddd><ccc>22</ccc></ddd></aaa>$"
|
||||||
|
|
||||||
|
new "xpath aaa"
|
||||||
|
expectpart "$($clixon_util_xpath -D $DBG -f $xml -p aaa)" 0 "^nodeset:0:<aaa><bbb x=\"hello\"><ccc>42</ccc></bbb><bbb x=\"bye\"><ccc>99</ccc></bbb><ddd><ccc>22</ccc></ddd></aaa>$"
|
||||||
|
|
||||||
new "xpath /bbb"
|
new "xpath /bbb"
|
||||||
expecteof "$clixon_util_xpath -f $xml -p /bbb" 0 "" "^nodeset:$"
|
expectpart "$($clixon_util_xpath -D $DBG -f $xml -p /bbb)" 0 "^nodeset:$"
|
||||||
|
|
||||||
|
|
||||||
new "xpath /aaa/bbb"
|
new "xpath /aaa/bbb"
|
||||||
expecteof "$clixon_util_xpath -f $xml -p /aaa/bbb" 0 "" "^0:<bbb x=\"hello\"><ccc>42</ccc></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>$"
|
1:<bbb x=\"bye\"><ccc>99</ccc></bbb>$"
|
||||||
|
|
||||||
new "xpath /aaa/bbb union "
|
new "xpath /aaa/bbb union "
|
||||||
expecteof "$clixon_util_xpath -f $xml -p aaa/bbb[ccc=42]|aaa/ddd[ccc=22]" 0 "" '^nodeset:0:<bbb x="hello"><ccc>42</ccc></bbb>1:<ddd><ccc>22</ccc></ddd>$'
|
expectpart "$($clixon_util_xpath -D $DBG -f $xml -p "aaa/bbb[ccc=42]|aaa/ddd[ccc=22]")" 0 '^nodeset:0:<bbb x="hello"><ccc>42</ccc></bbb>1:<ddd><ccc>22</ccc></ddd>$'
|
||||||
|
|
||||||
new "xpath //bbb"
|
new "xpath //bbb"
|
||||||
expecteof "$clixon_util_xpath -f $xml -p //bbb" 0 "" "0:<bbb x=\"hello\"><ccc>42</ccc></bbb>
|
expectpart "$($clixon_util_xpath -D $DBG -f $xml -p //bbb)" 0 "0:<bbb x=\"hello\"><ccc>42</ccc></bbb>
|
||||||
1:<bbb x=\"bye\"><ccc>99</ccc></bbb>"
|
1:<bbb x=\"bye\"><ccc>99</ccc></bbb>"
|
||||||
|
|
||||||
new "xpath //b?b"
|
new "xpath //b?b"
|
||||||
#expecteof "$clixon_util_xpath -f $xml" 0 "//b?b" ""
|
#expecteof "$clixon_util_xpath -D $DBG -f $xml" 0 "//b?b" ""
|
||||||
|
|
||||||
|
# Clixon cant do //* things
|
||||||
new "xpath //b*"
|
new "xpath //b*"
|
||||||
#expecteof "$clixon_util_xpath -f $xml" 0 "//b*" ""
|
#expecteof "$clixon_util_xpath -D $DBG -f $xml" 0 "//b*" ""
|
||||||
|
|
||||||
new "xpath //b*/ccc"
|
new "xpath //b*/ccc"
|
||||||
#expecteof "$clixon_util_xpath -f $xml" 0 "//b*/ccc" ""
|
#expecteof "$clixon_util_xpath -D $DBG -f $xml" 0 "//b*/ccc" ""
|
||||||
|
|
||||||
new "xpath //bbb[0]"
|
new "xpath //bbb[0]"
|
||||||
expecteof "$clixon_util_xpath -f $xml -p //bbb[0]" 0 "" "^nodeset:0:<bbb x=\"hello\"><ccc>42</ccc></bbb>$"
|
expectpart "$($clixon_util_xpath -D $DBG -f $xml -p //bbb[0])" 0 "^nodeset:0:<bbb x=\"hello\"><ccc>42</ccc></bbb>$"
|
||||||
|
|
||||||
new "xpath //bbb[ccc=99]"
|
new "xpath //bbb[ccc=99]"
|
||||||
expecteof "$clixon_util_xpath -f $xml -p //bbb[ccc=99]" 0 "" "^nodeset:0:<bbb x=\"bye\"><ccc>99</ccc></bbb>$"
|
expectpart "$($clixon_util_xpath -D $DBG -f $xml -p //bbb[ccc=99])" 0 "^nodeset:0:<bbb x=\"bye\"><ccc>99</ccc></bbb>$"
|
||||||
|
|
||||||
new "xpath ../connection-type = 'responder-only'"
|
new "xpath ../connection-type = 'responder-only'"
|
||||||
expecteof "$clixon_util_xpath -f $xml2 -p ../connection-type='responder-only' -i /aaa/bbb/here" 0 "" "^bool:true$"
|
expectpart "$($clixon_util_xpath -D $DBG -f $xml2 -p "../connection-type='responder-only'" -i /aaa/bbb/here)" 0 "^bool:true$"
|
||||||
|
|
||||||
new "xpath ../connection-type = 'no-responder'"
|
new "xpath ../connection-type = 'no-responder'"
|
||||||
expecteof "$clixon_util_xpath -f $xml2 -p ../connection-type='no-responder' -i /aaa/bbb/here" 0 "" "^bool:false$"
|
expectpart "$($clixon_util_xpath -D $DBG -f $xml2 -p "../connection-type='no-responder'" -i /aaa/bbb/here)" 0 "^bool:false$"
|
||||||
|
|
||||||
new "xpath . <= 0.75 * ../max-rtr-adv-interval"
|
new "xpath . <= 0.75 * ../max-rtr-adv-interval"
|
||||||
expecteof "$clixon_util_xpath -f $xml2 -i /aaa/bbb/here" 0 ". <= 0.75 * ../max-rtr-adv-interval" "^bool:true$"
|
expecteof "$clixon_util_xpath -f $xml2 -i /aaa/bbb/here" 0 ". <= 0.75 * ../max-rtr-adv-interval" "^bool:true$"
|
||||||
|
|
||||||
new "xpath . > 0.75 * ../max-rtr-adv-interval"
|
new "xpath . > 0.75 * ../max-rtr-adv-interval"
|
||||||
expecteof "$clixon_util_xpath -f $xml2 -i /aaa/bbb/here" 0 ". > 0.75 * ../max-rtr-adv-interval" "^bool:false$"
|
expecteof "$clixon_util_xpath -D $DBG -f $xml2 -i /aaa/bbb/here" 0 ". > 0.75 * ../max-rtr-adv-interval" "^bool:false$"
|
||||||
|
|
||||||
new "xpath . <= ../valid-lifetime"
|
new "xpath . <= ../valid-lifetime"
|
||||||
expecteof "$clixon_util_xpath -f $xml2 -i /aaa/bbb/here" 0 ". <= ../valid-lifetime" "^bool:true$"
|
expecteof "$clixon_util_xpath -D $DBG -f $xml2 -i /aaa/bbb/here" 0 ". <= ../valid-lifetime" "^bool:true$"
|
||||||
|
|
||||||
new "xpath ../../rt:address-family = 'v6ur:ipv6-unicast'"
|
new "xpath ../../rt:address-family = 'v6ur:ipv6-unicast'"
|
||||||
expecteof "$clixon_util_xpath -f $xml2 -i /aaa/bbb/here" 0 "../../rt:address-family = 'v6ur:ipv6-unicast'" "^bool:true$"
|
expecteof "$clixon_util_xpath -D $DBG -f $xml2 -i /aaa/bbb/here" 0 "../../rt:address-family = 'v6ur:ipv6-unicast'" "^bool:true$"
|
||||||
|
|
||||||
new "xpath ../../../rt:address-family = 'v6ur:ipv6-unicast'"
|
new "xpath ../../../rt:address-family = 'v6ur:ipv6-unicast'"
|
||||||
expecteof "$clixon_util_xpath -f $xml2 -i /aaa/bbb/here2/here" 0 "../../../rt:address-family = 'v6ur:ipv6-unicast'" "^bool:true$"
|
expecteof "$clixon_util_xpath -D $DBG -f $xml2 -i /aaa/bbb/here2/here" 0 "../../../rt:address-family = 'v6ur:ipv6-unicast'" "^bool:true$"
|
||||||
|
|
||||||
new "xpath /if:interfaces/if:interface[if:name=current()/rt:name]/ip:ipv6/ip:enabled='true'"
|
new "xpath /if:interfaces/if:interface[if:name=current()/rt:name]/ip:ipv6/ip:enabled='true'"
|
||||||
expectpart "$($clixon_util_xpath -f $xml2 -p "/if:interfaces/if:interface[if:name=current()/rt:name]/ip:ipv6/ip:enabled='true'")" 0 "^bool:true$"
|
expectpart "$($clixon_util_xpath -D $DBG -f $xml2 -p "/if:interfaces/if:interface[if:name=current()/rt:name]/ip:ipv6/ip:enabled='true'")" 0 "^bool:true$"
|
||||||
|
|
||||||
new "xpath rt:address-family='v6ur:ipv6-unicast'"
|
new "xpath rt:address-family='v6ur:ipv6-unicast'"
|
||||||
expecteof "$clixon_util_xpath -f $xml2 -i /aaa" 0 "rt:address-family='v6ur:ipv6-unicast'" "^bool:true$"
|
expecteof "$clixon_util_xpath -D $DBG -f $xml2 -i /aaa" 0 "rt:address-family='v6ur:ipv6-unicast'" "^bool:true$"
|
||||||
|
|
||||||
new "xpath ../type='rt:static'"
|
new "xpath ../type='rt:static'"
|
||||||
expecteof "$clixon_util_xpath -f $xml2 -i /aaa/bbb/here" 0 "../type='rt:static'" "^bool:true$"
|
expecteof "$clixon_util_xpath -D $DBG -f $xml2 -i /aaa/bbb/here" 0 "../type='rt:static'" "^bool:true$"
|
||||||
|
|
||||||
new "xpath rib-name != ../../name"
|
new "xpath rib-name != ../../name"
|
||||||
expecteof "$clixon_util_xpath -f $xml2 -i /aaa/bbb" 0 "rib-name != ../name" "^bool:true$"
|
expecteof "$clixon_util_xpath -D $DBG -f $xml2 -i /aaa/bbb" 0 "rib-name != ../name" "^bool:true$"
|
||||||
|
|
||||||
new "xpath routing/ribs/rib[name=current()/rib-name]/address-family=../../address-family"
|
new "xpath routing/ribs/rib[name=current()/rib-name]/address-family=../../address-family"
|
||||||
expecteof "$clixon_util_xpath -f $xml2 -i /aaa/bbb" 0 "routing/ribs/rib[name=current()/rib-name]/address-family=../../address-family" "^bool:true$"
|
expecteof "$clixon_util_xpath -D $DBG -f $xml2 -i /aaa/bbb" 0 "routing/ribs/rib[name=current()/rib-name]/address-family=../../address-family" "^bool:true$"
|
||||||
|
|
||||||
new "xpath ifType = \"ethernet\" or ifMTU = 1500"
|
new "xpath ifType = \"ethernet\" or ifMTU = 1500"
|
||||||
expecteof "$clixon_util_xpath -f $xml2 -i /aaa/bbb" 0 "ifType = \"ethernet\" or ifMTU = 1500" "^bool:true$"
|
expecteof "$clixon_util_xpath -D $DBG -f $xml2 -i /aaa/bbb" 0 "ifType = \"ethernet\" or ifMTU = 1500" "^bool:true$"
|
||||||
|
|
||||||
new "xpath ifType != \"ethernet\" or ifMTU = 1500"
|
new "xpath ifType != \"ethernet\" or ifMTU = 1500"
|
||||||
expecteof "$clixon_util_xpath -f $xml2 -i /aaa/bbb" 0 "ifType != \"ethernet\" or ifMTU = 1500" "^bool:true$"
|
expecteof "$clixon_util_xpath -D $DBG -f $xml2 -i /aaa/bbb" 0 "ifType != \"ethernet\" or ifMTU = 1500" "^bool:true$"
|
||||||
|
|
||||||
new "xpath ifType = \"ethernet\" or ifMTU = 1400"
|
new "xpath ifType = \"ethernet\" or ifMTU = 1400"
|
||||||
expecteof "$clixon_util_xpath -f $xml2 -i /aaa/bbb" 0 "ifType = \"ethernet\" or ifMTU = 1400" "^bool:true$"
|
expecteof "$clixon_util_xpath -D $DBG -f $xml2 -i /aaa/bbb" 0 "ifType = \"ethernet\" or ifMTU = 1400" "^bool:true$"
|
||||||
|
|
||||||
new "xpath ifType != \"ethernet\" or ifMTU = 1400"
|
new "xpath ifType != \"ethernet\" or ifMTU = 1400"
|
||||||
expecteof "$clixon_util_xpath -f $xml2 -i /aaa/bbb" 0 "ifType != \"ethernet\" or ifMTU = 1400" "^bool:false$"
|
expecteof "$clixon_util_xpath -D $DBG -f $xml2 -i /aaa/bbb" 0 "ifType != \"ethernet\" or ifMTU = 1400" "^bool:false$"
|
||||||
|
|
||||||
new "xpath ifType = \"ethernet\" and ifMTU = 1500"
|
new "xpath ifType = \"ethernet\" and ifMTU = 1500"
|
||||||
expecteof "$clixon_util_xpath -f $xml2 -i /aaa/bbb" 0 "ifType = \"ethernet\" and ifMTU = 1500" "^bool:true$"
|
expecteof "$clixon_util_xpath -D $DBG -f $xml2 -i /aaa/bbb" 0 "ifType = \"ethernet\" and ifMTU = 1500" "^bool:true$"
|
||||||
|
|
||||||
new "xpath ifType != \"ethernet\" and ifMTU = 1500"
|
new "xpath ifType != \"ethernet\" and ifMTU = 1500"
|
||||||
expecteof "$clixon_util_xpath -f $xml2 -i /aaa/bbb" 0 "ifType != \"ethernet\" and ifMTU = 1500" "^bool:false$"
|
expecteof "$clixon_util_xpath -D $DBG -f $xml2 -i /aaa/bbb" 0 "ifType != \"ethernet\" and ifMTU = 1500" "^bool:false$"
|
||||||
|
|
||||||
new "xpath ifType = \"ethernet\" and ifMTU = 1400"
|
new "xpath ifType = \"ethernet\" and ifMTU = 1400"
|
||||||
expecteof "$clixon_util_xpath -f $xml2 -i /aaa/bbb" 0 "ifType = \"ethernet\" and ifMTU = 1400" "^bool:false$"
|
expecteof "$clixon_util_xpath -D $DBG -f $xml2 -i /aaa/bbb" 0 "ifType = \"ethernet\" and ifMTU = 1400" "^bool:false$"
|
||||||
|
|
||||||
new "xpath ifType != \"ethernet\" and ifMTU = 1400"
|
new "xpath ifType != \"ethernet\" and ifMTU = 1400"
|
||||||
expecteof "$clixon_util_xpath -f $xml2 -i /aaa/bbb" 0 "ifType != \"ethernet\" and ifMTU = 1400" "^bool:false$"
|
expecteof "$clixon_util_xpath -D $DBG -f $xml2 -i /aaa/bbb" 0 "ifType != \"ethernet\" and ifMTU = 1400" "^bool:false$"
|
||||||
|
|
||||||
new "xpath ifType != \"atm\" or (ifMTU <= 17966 and ifMTU >= 64)"
|
new "xpath ifType != \"atm\" or (ifMTU <= 17966 and ifMTU >= 64)"
|
||||||
expecteof "$clixon_util_xpath -f $xml2 -i /aaa/bbb" 0 "ifType != \"atm\" or (ifMTU <= 17966 and ifMTU >= 64)" "^bool:true$"
|
expecteof "$clixon_util_xpath -D $DBG -f $xml2 -i /aaa/bbb" 0 "ifType != \"atm\" or (ifMTU <= 17966 and ifMTU >= 64)" "^bool:true$"
|
||||||
|
|
||||||
new "xpath .[name='bar']"
|
new "xpath .[name='bar']"
|
||||||
expecteof "$clixon_util_xpath -f $xml2 -p .[name='bar'] -i /aaa/bbb/routing/ribs/rib" 0 "" "^nodeset:0:<rib><name>bar</name><address-family>myfamily</address-family></rib>$"
|
expecteof "$clixon_util_xpath -D $DBG -f $xml2 -p .[name='bar'] -i /aaa/bbb/routing/ribs/rib" 0 "^nodeset:0:<rib><name>bar</name><address-family>myfamily</address-family></rib>$"
|
||||||
|
|
||||||
new "xpath /aaa/bbb/namespace (namespace is xpath axisname)"
|
new "xpath /aaa/bbb/namespace (namespace is xpath axisname)"
|
||||||
expecteof "$clixon_util_xpath -f $xml2 -p /aaa/bbb/namespace" 0 "" "^nodeset:0:<namespace>urn:example:foo</namespace>$"
|
expectpart "$($clixon_util_xpath -D $DBG -f $xml2 -p /aaa/bbb/namespace)" 0 "^nodeset:0:<namespace>urn:example:foo</namespace>$"
|
||||||
|
|
||||||
# See https://github.com/clicon/clixon/issues/54
|
# See https://github.com/clicon/clixon/issues/54
|
||||||
# But it is not only axis names. There are also, for example, nodetype like this example:
|
# But it is not only axis names. There are also, for example, nodetype like this example:
|
||||||
#new "xpath /aaa/bbb/comment (comment is xpath nodetype)"
|
new "xpath /aaa/bbb/comment (comment is xpath nodetype)"
|
||||||
#expecteof "$clixon_util_xpath -f $xml2 -p /aaa/bbb/comment" 0 "" "^kalle$"
|
expectpart "$($clixon_util_xpath -D $DBG -f $xml2 -p /aaa/bbb/comment)" 0 "^nodeset:$"
|
||||||
|
|
||||||
new "Multiple entries"
|
new "Multiple entries"
|
||||||
new "xpath bbb[ccc='foo']"
|
new "xpath bbb[ccc='foo']"
|
||||||
expecteof "$clixon_util_xpath -f $xml3 -p bbb[ccc='foo']" 0 "" "^nodeset:0:<bbb x=\"hello\"><ccc>foo</ccc><ccc>42</ccc><ccc>bar</ccc></bbb>1:<bbb x=\"bye\"><ccc>99</ccc><ccc>foo</ccc></bbb>$"
|
expectpart "$($clixon_util_xpath -D $DBG -f $xml3 -p "bbb[ccc='foo']")" 0 "^nodeset:0:<bbb x=\"hello\"><ccc>foo</ccc><ccc>42</ccc><ccc>bar</ccc></bbb>1:<bbb x=\"bye\"><ccc>99</ccc><ccc>foo</ccc></bbb>$"
|
||||||
|
|
||||||
new "xpath bbb[ccc=\"foo\"]"
|
new "xpath bbb[ccc=\"foo\"]"
|
||||||
expecteof "$clixon_util_xpath -f $xml3 -p bbb[ccc=\"foo\"]" 0 "" "^nodeset:0:<bbb x=\"hello\"><ccc>foo</ccc><ccc>42</ccc><ccc>bar</ccc></bbb>1:<bbb x=\"bye\"><ccc>99</ccc><ccc>foo</ccc></bbb>$"
|
expectpart "$($clixon_util_xpath -D $DBG -f $xml3 -p "bbb[ccc=\"foo\"]")" 0 "^nodeset:0:<bbb x=\"hello\"><ccc>foo</ccc><ccc>42</ccc><ccc>bar</ccc></bbb>1:<bbb x=\"bye\"><ccc>99</ccc><ccc>foo</ccc></bbb>$"
|
||||||
|
|
||||||
new "xpath bbb[ccc='42']"
|
new "xpath bbb[ccc='42']"
|
||||||
expecteof "$clixon_util_xpath -f $xml3 -p bbb[ccc='42']" 0 "" "^nodeset:0:<bbb x=\"hello\"><ccc>foo</ccc><ccc>42</ccc><ccc>bar</ccc></bbb>$"
|
expectpart "$($clixon_util_xpath -D $DBG -f $xml3 -p bbb[ccc='42'])" 0 "^nodeset:0:<bbb x=\"hello\"><ccc>foo</ccc><ccc>42</ccc><ccc>bar</ccc></bbb>$"
|
||||||
|
|
||||||
new "xpath bbb[ccc=99] (number w/o quotes)"
|
new "xpath bbb[ccc=99] (number w/o quotes)"
|
||||||
expecteof "$clixon_util_xpath -f $xml3 -p bbb[ccc=99]" 0 "" "^nodeset:0:<bbb x=\"bye\"><ccc>99</ccc><ccc>foo</ccc></bbb>$"
|
expectpart "$($clixon_util_xpath -D $DBG -f $xml3 -p bbb[ccc=99])" 0 "^nodeset:0:<bbb x=\"bye\"><ccc>99</ccc><ccc>foo</ccc></bbb>$"
|
||||||
|
|
||||||
new "xpath bbb[ccc='bar']"
|
new "xpath bbb[ccc='bar']"
|
||||||
expecteof "$clixon_util_xpath -f $xml3 -p bbb[ccc='bar']" 0 "" "^nodeset:0:<bbb x=\"hello\"><ccc>foo</ccc><ccc>42</ccc><ccc>bar</ccc></bbb>$"
|
expectpart "$($clixon_util_xpath -D $DBG -f $xml3 -p "bbb[ccc='bar']")" 0 "^nodeset:0:<bbb x=\"hello\"><ccc>foo</ccc><ccc>42</ccc><ccc>bar</ccc></bbb>$"
|
||||||
|
|
||||||
new "xpath bbb[ccc='fie']"
|
new "xpath bbb[ccc='fie']"
|
||||||
expecteof "$clixon_util_xpath -f $xml3 -p bbb[ccc='fie']" 0 "" "^nodeset:$"
|
expectpart "$($clixon_util_xpath -D $DBG -f $xml3 -p "bbb[ccc='fie']")" 0 "^nodeset:$"
|
||||||
|
|
||||||
# Just syntax - no semantic meaning
|
# Just syntax - no semantic meaning
|
||||||
new "xpath derived-from 10.4.1"
|
new "xpath derived-from 10.4.1"
|
||||||
expectpart "$($clixon_util_xpath -f $xml3 -p 'derived-from(../../change-operation,"modify")')" 0 "bool:false"
|
expectpart "$($clixon_util_xpath -D $DBG -f $xml3 -p 'derived-from(../../change-operation,"modify")')" 0 "bool:false"
|
||||||
|
|
||||||
new "xpath derived-from-or-self"
|
new "xpath derived-from-or-self"
|
||||||
expectpart "$($clixon_util_xpath -f $xml3 -p 'derived-from-or-self(../../change-operation,"modify")')" 0 "bool:false"
|
expectpart "$($clixon_util_xpath -D $DBG -f $xml3 -p 'derived-from-or-self(../../change-operation,"modify")')" 0 "bool:false"
|
||||||
|
|
||||||
new "xpath contains"
|
new "xpath contains"
|
||||||
expectpart "$($clixon_util_xpath -f $xml3 -p "contains(../../objectClass,'BTSFunction') or contains(../../objectClass,'RNCFunction')")" 0 "bool:false"
|
expectpart "$($clixon_util_xpath -D $DBG -f $xml3 -p "contains(../../objectClass,'BTSFunction') or contains(../../objectClass,'RNCFunction')")" 0 "bool:false"
|
||||||
|
|
||||||
# Nodetests
|
# Nodetests
|
||||||
|
|
||||||
new "xpath nodetest: node"
|
new "xpath nodetest: node"
|
||||||
expectpart "$($clixon_util_xpath -f $xml3 -p "/bbb/ccc/self::node()")" 0 "nodeset:0:<ccc>foo</ccc>"
|
expectpart "$($clixon_util_xpath -D $DBG -f $xml3 -p "/bbb/ccc/self::node()")" 0 "nodeset:0:<ccc>foo</ccc>"
|
||||||
|
|
||||||
new "xpath nodetest: comment nyi"
|
new "xpath nodetest: comment nyi"
|
||||||
expectpart "$($clixon_util_xpath -f $xml3 -l o -p "/descendant-or-self::comment()")" 255 "XPATH function \"comment\" is not implemented"
|
expectpart "$($clixon_util_xpath -D $DBG -f $xml3 -l o -p "/descendant-or-self::comment()")" 255 "XPATH function \"comment\" is not implemented"
|
||||||
|
|
||||||
# Count
|
# Count
|
||||||
|
|
||||||
new "find bbb with 3 ccc children using count"
|
new "find bbb with 3 ccc children using count"
|
||||||
expectpart "$($clixon_util_xpath -f $xml3 -l o -p "(/bbb[count(ccc)=3])")" 0 "<bbb x=\"hello\"><ccc>foo</ccc><ccc>42</ccc><ccc>bar</ccc></bbb>"
|
expectpart "$($clixon_util_xpath -D $DBG -f $xml3 -l o -p "(/bbb[count(ccc)=3])")" 0 "<bbb x=\"hello\"><ccc>foo</ccc><ccc>42</ccc><ccc>bar</ccc></bbb>"
|
||||||
|
|
||||||
# Negative
|
# Negative
|
||||||
|
|
||||||
new "xpath dontexist"
|
new "xpath dontexist"
|
||||||
expectpart "$($clixon_util_xpath -f $xml3 -l o -p "dontexist()")" 255 "Unknown xpath function \"dontexist\""
|
expectpart "$($clixon_util_xpath -D $DBG -f $xml3 -l o -p "dontexist()")" 255 "Unknown xpath function \"dontexist\""
|
||||||
|
|
||||||
new "xpath enum-value nyi"
|
new "xpath enum-value nyi"
|
||||||
expectpart "$($clixon_util_xpath -f $xml3 -l o -p "enum-value()")" 255 "XPATH function \"enum-value\" is not implemented"
|
expectpart "$($clixon_util_xpath -D $DBG -f $xml3 -l o -p "enum-value()")" 255 "XPATH function \"enum-value\" is not implemented"
|
||||||
|
|
||||||
new "xpath /root/*/a"
|
new "xpath /root/*/a"
|
||||||
expecteof "$clixon_util_xpath -f $xml4 -p /root/*/a" 0 "" "nodeset:0:<a>111</a>1:<a>222</a>2:<a>111</a>"
|
expecteof "$clixon_util_xpath -D $DBG -f $xml4 -p /root/*/a" 0 "" "nodeset:0:<a>111</a>1:<a>222</a>2:<a>111</a>"
|
||||||
|
|
||||||
new "xpath /root/*/b"
|
new "xpath /root/*/b"
|
||||||
expecteof "$clixon_util_xpath -f $xml4 -p /root/*/b" 0 "" "nodeset:0:<b>111</b>"
|
expecteof "$clixon_util_xpath -D $DBG -f $xml4 -p /root/*/b" 0 "" "nodeset:0:<b>111</b>"
|
||||||
|
|
||||||
new "xpath /root/*/*[.='111']"
|
new "xpath /root/*/*[.='111']"
|
||||||
expecteof "$clixon_util_xpath -f $xml4 -p /root/*/*[.='111']" 0 "" "nodeset:0:<a>111</a>1:<b>111</b>2:<a>111</a>"
|
expecteof "$clixon_util_xpath -D $DBG -f $xml4 -p /root/*/*[.='111']" 0 "" "nodeset:0:<a>111</a>1:<b>111</b>2:<a>111</a>"
|
||||||
|
|
||||||
|
# Try functionnames in place of node nc-names
|
||||||
|
|
||||||
|
new "xpath nodetest: node"
|
||||||
|
expectpart "$($clixon_util_xpath -D $DBG -f $xmlfn -p "count(/root/count)")" 0 "number:1"
|
||||||
|
|
||||||
|
new "xpath nodetest: node"
|
||||||
|
expectpart "$($clixon_util_xpath -D $DBG -f $xmlfn -p "/root/node/self::node()")" 0 "<node><ancestor><count>73</count></ancestor></node>"
|
||||||
|
|
||||||
|
new "xpath functions as ncname: nodetype:node"
|
||||||
|
expectpart "$($clixon_util_xpath -D $DBG -f $xmlfn -p "root/ancestor/count/node")" 0 "<node>42</node>"
|
||||||
|
|
||||||
|
new "xpath functions as ncname: nodetype:node"
|
||||||
|
expectpart "$($clixon_util_xpath -D $DBG -f $xmlfn -p "root/ancestor/count[node=42]")" 0 "<count><node>42</node></count>"
|
||||||
|
|
||||||
|
new "xpath functions as ncname: axisname:ancestor"
|
||||||
|
expectpart "$($clixon_util_xpath -D $DBG -f $xmlfn -p "root/count/node[99=ancestor]")" 0 "<node><ancestor>99</ancestor></node>"
|
||||||
|
|
||||||
|
new "xpath functions as ncname: functioname:count"
|
||||||
|
expectpart "$($clixon_util_xpath -D $DBG -f $xmlfn -p "root/node/ancestor[73=count]")" 0 "<ancestor><count>73</count></ancestor>"
|
||||||
|
|
||||||
rm -rf $dir
|
rm -rf $dir
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,12 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# test xpath functions in YANG conditionals
|
# test xpath functions within YANG conditionals
|
||||||
# XPATH base https://www.w3.org/TR/xpath-10/
|
# XPATH base https://www.w3.org/TR/xpath-10/
|
||||||
# YANG XPATH functions: https://tools.ietf.org/html/rfc7950
|
# YANG XPATH functions: https://tools.ietf.org/html/rfc7950
|
||||||
# Tests:
|
# Test of xpath functions:
|
||||||
# - Contains
|
# - contains
|
||||||
|
# - derived-from
|
||||||
|
# - derived-from-or-self
|
||||||
|
# - bit-is-set
|
||||||
|
|
||||||
# Magic line must be first in script (see README.md)
|
# Magic line must be first in script (see README.md)
|
||||||
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
||||||
|
|
@ -102,6 +105,24 @@ module $APPNAME{
|
||||||
type uint32;
|
type uint32;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* Example derved from yangmodels ietf-mpls-ldp.yang */
|
||||||
|
container mustnot{
|
||||||
|
list mustlist{
|
||||||
|
key name;
|
||||||
|
leaf name{
|
||||||
|
type string;
|
||||||
|
}
|
||||||
|
container mycont{
|
||||||
|
must "not (../../ex:mustlist[ex:name!=current()/../ex:name])" {
|
||||||
|
description
|
||||||
|
"Only one list instance is allowed.";
|
||||||
|
}
|
||||||
|
leaf foo{
|
||||||
|
type string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
|
@ -120,7 +141,6 @@ fi
|
||||||
new "wait backend"
|
new "wait backend"
|
||||||
wait_backend
|
wait_backend
|
||||||
|
|
||||||
# contains
|
|
||||||
new "contains: Set site to foo that validates site OK"
|
new "contains: Set site to foo that validates site OK"
|
||||||
expecteof_netconf "$clixon_netconf -qf $cfg -D $DBG" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><edit-config><target><candidate/></target><config><top xmlns=\"urn:example:clixon\"><class>foo</class><mylist><id>12</id><site>42</site></mylist></top></config></edit-config></rpc>" "" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>"
|
expecteof_netconf "$clixon_netconf -qf $cfg -D $DBG" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><edit-config><target><candidate/></target><config><top xmlns=\"urn:example:clixon\"><class>foo</class><mylist><id>12</id><site>42</site></mylist></top></config></edit-config></rpc>" "" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,11 +45,6 @@ files=$(find ${YANG_STANDARD_DIR}/ietf/RFC -type f -name "*.yang")
|
||||||
for f in $files; do
|
for f in $files; do
|
||||||
if [ -n "$(head -1 $f|grep '^module')" ]; then
|
if [ -n "$(head -1 $f|grep '^module')" ]; then
|
||||||
# Mask old revision
|
# Mask old revision
|
||||||
if [ $f = ${YANG_STANDARD_DIR}/ietf/RFC/ietf-mpls-ldp@2022-03-14.yang -o $f = ${YANG_STANDARD_DIR}/ietf/RFC/ietf-mpls-ldp-extended@2022-03-14.yang ]; then
|
|
||||||
echo "FOOOOO"
|
|
||||||
# XXX xpath parse error: new (..)
|
|
||||||
continue;
|
|
||||||
fi
|
|
||||||
if [ $f = ${YANG_STANDARD_DIR}/ietf/RFC/ietf-yang-types@2010-09-24.yang ]; then
|
if [ $f = ${YANG_STANDARD_DIR}/ietf/RFC/ietf-yang-types@2010-09-24.yang ]; then
|
||||||
continue;
|
continue;
|
||||||
fi
|
fi
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue