diff --git a/CHANGELOG.md b/CHANGELOG.md index e0cf2259..6a08b110 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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. * 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` +* 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) * [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` diff --git a/lib/clixon/clixon_xpath.h b/lib/clixon/clixon_xpath.h index 97c7e613..01e4a68d 100644 --- a/lib/clixon/clixon_xpath.h +++ b/lib/clixon/clixon_xpath.h @@ -124,6 +124,7 @@ typedef struct xpath_tree xpath_tree; * Prototypes */ char* axis_type_int2str(int axis_type); +int axis_type_str2int(char *name); char* xpath_tree_int2str(int nodetype); int xpath_tree_print_cb(cbuf *cb, xpath_tree *xs); int xpath_tree_print(FILE *f, xpath_tree *xs); diff --git a/lib/src/clixon_xpath.c b/lib/src/clixon_xpath.c index 3ba95a39..62d28e6f 100644 --- a/lib/src/clixon_xpath.c +++ b/lib/src/clixon_xpath.c @@ -160,6 +160,11 @@ axis_type_int2str(int 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 */ diff --git a/lib/src/clixon_xpath_parse.h b/lib/src/clixon_xpath_parse.h index bb87b26b..74ebdf96 100644 --- a/lib/src/clixon_xpath_parse.h +++ b/lib/src/clixon_xpath_parse.h @@ -44,6 +44,7 @@ struct clixon_xpath_yacc{ const char *xpy_name; /* Name of syntax (for error string) */ int xpy_linenum; /* Number of \n in parsed buffer */ 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 */ xpath_tree *xpy_top; }; diff --git a/lib/src/clixon_xpath_parse.l b/lib/src/clixon_xpath_parse.l index b0332d22..80e7adb0 100644 --- a/lib/src/clixon_xpath_parse.l +++ b/lib/src/clixon_xpath_parse.l @@ -32,6 +32,26 @@ ***** 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.h" #include "clixon_xpath_parse.h" +#include "clixon_xpath_function.h" #include "clixon_xpath_eval.h" /* 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; } -/* strip last char */ -void +/* strip last char: kludge to peek to next character */ +static void striplast(char *s) { s[strlen(s)-1] = 0; @@ -92,60 +113,83 @@ real ({digit}+[.]{digit}*)|({digit}*[.]{digit}+) namestart [A-Z_a-z] namechar [A-Z_a-z\-\.0-9] ncname {namestart}{namechar}* -fnname {ncname}\( -%x TOKEN +%s TOKEN0 +%s TOKEN2 %s QLITERAL %s ALITERAL %% -[ \t] -\n { _XPY->xpy_linenum++; } -\r { } -<> { return X_EOF; } -".." { return DOUBLEDOT; } -[()\[\]\.,/:|] { return *yytext; } -and { clixon_xpath_parselval.intval = clicon_str2int(xpopmap, yytext); return LOGOP; } -or { clixon_xpath_parselval.intval = clicon_str2int(xpopmap, yytext); return LOGOP; } -div { clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext); return ADDOP; } -mod { clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext); return ADDOP; } -[+*\-] { clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext); return ADDOP; } -\? { return *yytext; } -"//" { return DOUBLESLASH; } -"!=" { clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext); return RELOP; } -">=" { clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext);return RELOP; } -"<=" { clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext);return RELOP; } -[<>=] { clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext);return RELOP; } +[ \t] +\n { _XPY->xpy_linenum++; } +\r { } +<> { return X_EOF; } +".." { return DOUBLEDOT; } +:: { BEGIN(TOKEN2); return DOUBLECOLON; /* axisname */ } +[(\[] { BEGIN(TOKEN2); return *yytext; } +[)\]\.,/:|] { return *yytext; } +and { BEGIN(TOKEN2);clixon_xpath_parselval.intval = clicon_str2int(xpopmap, yytext); return LOGOP; } +or { BEGIN(TOKEN2);clixon_xpath_parselval.intval = clicon_str2int(xpopmap, yytext); return LOGOP; } +div { BEGIN(TOKEN2);clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext); return ADDOP; } +mod { BEGIN(TOKEN2);clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext); return ADDOP; } +[+*\-] { BEGIN(TOKEN2);clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext); return ADDOP; } +\? { return *yytext; } +"//" { BEGIN(TOKEN2);return DOUBLESLASH; } +"!=" { BEGIN(TOKEN2);clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext); return RELOP; } +">=" { BEGIN(TOKEN2);clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext);return RELOP; } +"<=" { BEGIN(TOKEN2);clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext);return RELOP; } +[<>=] { BEGIN(TOKEN2);clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext);return RELOP; } -{fnname} { clixon_xpath_parselval.string = strdup(yytext); striplast(clixon_xpath_parselval.string); return FUNCTIONNAME; } +@ { BEGIN(TOKEN2); return *yytext; } +\" { _XPY->xpy_lex_string_state = TOKEN0; BEGIN(QLITERAL); return QUOTE; } +\' { _XPY->xpy_lex_string_state = TOKEN0; BEGIN(ALITERAL); return APOST; } +\-?({integer}|{real}) { clixon_xpath_parselval.string = strdup(yytext); return NUMBER; } -@ { return *yytext; } -ancestor:: { clixon_xpath_parselval.intval = A_ANCESTOR; return AXISNAME; } -ancestor-or-self:: { clixon_xpath_parselval.intval = A_ANCESTOR_OR_SELF; return AXISNAME; } -attribute:: { clixon_xpath_parselval.intval = A_ATTRIBUTE; return AXISNAME; } -child:: { clixon_xpath_parselval.intval = A_CHILD; return AXISNAME; } -descendant:: { clixon_xpath_parselval.intval = A_DESCENDANT; return AXISNAME; } -descendant-or-self:: { clixon_xpath_parselval.intval = A_DESCENDANT_OR_SELF; return AXISNAME; } -following:: { clixon_xpath_parselval.intval = A_FOLLOWING; return AXISNAME; } -following-sibling:: { clixon_xpath_parselval.intval = A_FOLLOWING_SIBLING; return AXISNAME; } -namespace:: { clixon_xpath_parselval.intval = A_NAMESPACE; return AXISNAME; } -parent:: { clixon_xpath_parselval.intval = A_PARENT; return AXISNAME; } -preceding:: { clixon_xpath_parselval.intval = A_PRECEDING; return AXISNAME; } -preceding-sibling:: { clixon_xpath_parselval.intval = A_PRECEDING_SIBLING; return AXISNAME; } -self:: { clixon_xpath_parselval.intval = A_SELF; return AXISNAME; } +{ncname} { /* See lexical rules 2 and 3 in the file header */ + clixon_xpath_parselval.string = strdup(yytext); + return NCNAME; + } +. { fprintf(stderr,"LEXICAL ERROR\n"); return -1; } -\" { BEGIN(QLITERAL); return QUOTE; } -\' { BEGIN(ALITERAL); return APOST; } -\-?({integer}|{real}) { clixon_xpath_parselval.string = strdup(yytext); return NUMBER; } -{ncname} { clixon_xpath_parselval.string = strdup(yytext); - return NAME; /* rather be catch-all */ +[ \t] +\n { _XPY->xpy_linenum++; } +\r { } +<> { return X_EOF; } +".." { BEGIN(TOKEN0); return DOUBLEDOT; } +:: { BEGIN(TOKEN0); return DOUBLECOLON; /* axisname */ } +[()\[\]\.,/:|] { BEGIN(TOKEN0); return *yytext; } +and { BEGIN(TOKEN0); clixon_xpath_parselval.intval = clicon_str2int(xpopmap, yytext); return LOGOP; } +or { BEGIN(TOKEN0); clixon_xpath_parselval.intval = clicon_str2int(xpopmap, yytext); return LOGOP; } +div { BEGIN(TOKEN0); clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext); return ADDOP; } +mod { BEGIN(TOKEN0); clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext); return ADDOP; } +[+*\-] { BEGIN(TOKEN0); clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext); return ADDOP; } +\? { BEGIN(TOKEN0); return *yytext; } +"//" { BEGIN(TOKEN0); return DOUBLESLASH; } +"!=" { BEGIN(TOKEN0); clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext); return RELOP; } +">=" { BEGIN(TOKEN0); clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext);return RELOP; } +"<=" { BEGIN(TOKEN0); clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext);return RELOP; } +[<>=] { BEGIN(TOKEN0); clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext);return RELOP; } + +@ { BEGIN(TOKEN0); return *yytext; } +\" { BEGIN(TOKEN0); _XPY->xpy_lex_string_state=TOKEN2; BEGIN(QLITERAL); return QUOTE; } +\' { BEGIN(TOKEN0); _XPY->xpy_lex_string_state=TOKEN2; BEGIN(ALITERAL); return APOST; } +\-?({integer}|{real}) { BEGIN(TOKEN0); clixon_xpath_parselval.string = strdup(yytext); return NUMBER; } + +comment\( { BEGIN(TOKEN0); clixon_xpath_parselval.string = strdup(yytext); striplast(clixon_xpath_parselval.string); return NODETYPE; } +text\( { BEGIN(TOKEN0); clixon_xpath_parselval.string = strdup(yytext); striplast(clixon_xpath_parselval.string); return NODETYPE; } +processing-instructions\( { BEGIN(TOKEN0); clixon_xpath_parselval.string = strdup(yytext); striplast(clixon_xpath_parselval.string); return NODETYPE; } +node\( { BEGIN(TOKEN0); clixon_xpath_parselval.string = strdup(yytext); striplast(clixon_xpath_parselval.string); return NODETYPE; } +{ncname} { /* See lexical rules 2 and 3 in the file header */ + BEGIN(TOKEN0); + clixon_xpath_parselval.string = strdup(yytext); + return NCNAME; } -. { fprintf(stderr,"LEXICAL ERROR\n"); return -1; } +. { fprintf(stderr,"LEXICAL ERROR\n"); return -1; } -\" { BEGIN(TOKEN); return QUOTE; } +\" { BEGIN(_XPY->xpy_lex_string_state); return QUOTE; } [^"]+ { clixon_xpath_parselval.string = strdup(yytext); return CHARS;} -\' { BEGIN(TOKEN); return APOST; } +\' { BEGIN(_XPY->xpy_lex_string_state); return APOST; } [^']+ { clixon_xpath_parselval.string = strdup(yytext); return CHARS;} @@ -157,7 +201,7 @@ fnname {ncname}\( int xpath_scan_init(clixon_xpath_yacc *xpy) { - BEGIN(TOKEN); + BEGIN(TOKEN0); xpy->xpy_lexbuf = yy_scan_string (xpy->xpy_parse_string); #if 1 /* XXX: just to use unput to avoid warning */ if (0) diff --git a/lib/src/clixon_xpath_parse.y b/lib/src/clixon_xpath_parse.y index 1d090ab1..2b76472a 100644 --- a/lib/src/clixon_xpath_parse.y +++ b/lib/src/clixon_xpath_parse.y @@ -49,7 +49,6 @@ void *stack; /* xpath_tree */ } -%token AXISNAME %token LOGOP %token ADDOP %token RELOP @@ -59,12 +58,15 @@ %token QUOTE %token APOST %token CHARS -%token NAME +%token NCNAME +%token NODETYPE %token DOUBLEDOT +%token DOUBLECOLON %token DOUBLESLASH %token FUNCTIONNAME %type axisspec +%type abbreviatedaxisspec %type string %type args @@ -79,9 +81,13 @@ %type abslocpath %type rellocpath %type step +%type abbreviatedstep %type nodetest +%type nametest %type predicates %type primaryexpr +%type literal +%type functioncall %lex-param {void *_xpy} /* Add this argument to parse() and lex() function */ %parse-param {void *_xpy} @@ -319,15 +325,13 @@ xp_primary_function(clixon_xpath_yacc *xpy, */ static xpath_tree * xp_nodetest_function(clixon_xpath_yacc *xpy, - char *name, - xpath_tree *xpt) + char *name) { xpath_tree *xtret = NULL; - enum clixon_xpath_function fn; cbuf *cb = NULL; - int ret; - - if ((ret = xp_fnname_str2int(name)) < 0){ + enum clixon_xpath_function fn; + + if ((fn = xp_fnname_str2int(name)) < 0){ if ((cb = cbuf_new()) == NULL){ clicon_err(OE_XML, errno, "cbuf_new"); goto done; @@ -336,7 +340,6 @@ xp_nodetest_function(clixon_xpath_yacc *xpy, clixon_xpath_parseerror(xpy, cbuf_get(cb)); goto done; } - fn = ret; switch (fn){ case XPATHFN_COMMENT: /* Group of not implemented node functions */ case XPATHFN_PROCESSING_INSTRUCTIONS: @@ -363,16 +366,42 @@ xp_nodetest_function(clixon_xpath_yacc *xpy, } if (cb) cbuf_free(cb); - xtret = xp_new(XP_NODE_FN, fn, NULL, name, NULL, xpt, NULL); - name = NULL; /* Consumed by xp_new */ + xtret = xp_new(XP_NODE_FN, fn, NULL, name, NULL, NULL, NULL); done: if (cb) cbuf_free(cb); - if (name) - free(name); 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 : primaryexpr { $$=xp_new(XP_FILTEREXPR,A_NAN,NULL,NULL,NULL,$1, NULL);_PARSE_DEBUG("filterexpr-> primaryexpr"); } /* 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"); } ; -step : axisspec nodetest predicates {$$=xp_new(XP_STEP,$1,NULL, NULL, NULL, $2, $3);_PARSE_DEBUG1("step->axisspec(%d) nodetest", $1); } - | '.' 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-> .."); } +step : nodetest predicates + { $$=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-> .."); } + ; + +/* [5] AxisSpecifier::= AxisName '::' + | AbbreviatedAxisSpecifier +*/ +axisspec : NCNAME DOUBLECOLON + { if (($$=xp_axisname_function(_XPY, $1)) < 0) YYERROR; + _PARSE_DEBUG2("axisspec-> AXISNAME(%s -> %d) ::", $1, $$); + } + | abbreviatedaxisspec + { $$ = $1; } ; -axisspec : AXISNAME { _PARSE_DEBUG1("axisspec-> AXISNAME(%d) ::", $1); $$=$1;} - | '@' { $$=A_ATTRIBUTE; _PARSE_DEBUG("axisspec-> @"); } - | { _PARSE_DEBUG("axisspec-> "); $$=A_CHILD;} - ; +/* [13] AbbreviatedAxisSpecifier ::= '@'? + * empty built into 2nd step rule + */ +abbreviatedaxisspec :'@' { $$=A_ATTRIBUTE; _PARSE_DEBUG("axisspec-> @"); } + ; -nodetest : ADDOP { $$=xp_new(XP_NODE,A_NAN,NULL, NULL, strdup(clicon_int2str(xpopmap,$1)), NULL, NULL); _PARSE_DEBUG("nodetest-> *"); } - | NAME { $$=xp_new(XP_NODE,A_NAN,NULL, NULL, $1, NULL, NULL); _PARSE_DEBUG1("nodetest-> name(%s)",$1); } - | 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); } - | 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 */ @@ -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->"); } ; primaryexpr : '(' expr ')' { $$=xp_new(XP_PRI0,A_NAN,NULL, NULL, NULL, $2, NULL); _PARSE_DEBUG("primaryexpr-> ( expr )"); } - | 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 \""); } - | 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)"); } + | literal { $$ = $1; } + | NUMBER { $$=xp_new(XP_PRIME_NR,A_NAN, $1, NULL, NULL, NULL, NULL);_PARSE_DEBUG1("primaryexpr-> NUMBER(%s)", $1); /*XXX*/} + | functioncall { $$ = $1; } ; 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 "); } ; +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 { int len = strlen($1); $$ = realloc($1, len+strlen($2) + 1); diff --git a/test/test_xpath.sh b/test/test_xpath.sh index 0b1d5f7c..efc2b129 100755 --- a/test/test_xpath.sh +++ b/test/test_xpath.sh @@ -1,5 +1,9 @@ #!/usr/bin/env bash # 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) 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 xml3=$dir/xml3.xml xml4=$dir/xml4.xml +xmlfn=$dir/xmlfn.xml cat < $xml @@ -94,173 +99,229 @@ cat < $xml4 EOF +# XPath functions +cat < $xmlfn + + + + 42 + + + + + 99 + + + + + 73 + + + +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 /" -expecteof "$clixon_util_xpath -f $xml -p /" 0 "" "^nodeset:0:429922$" +expectpart "$($clixon_util_xpath -D $DBG -f $xml -p /)" 0 "^nodeset:0:429922$" new "xpath /aaa" -expecteof "$clixon_util_xpath -f $xml -p /aaa" 0 "" "^nodeset:0:429922$" +expectpart "$($clixon_util_xpath -D $DBG -f $xml -p /aaa)" 0 "^nodeset:0:429922$" + +new "xpath aaa" +expectpart "$($clixon_util_xpath -D $DBG -f $xml -p aaa)" 0 "^nodeset:0:429922$" 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" -expecteof "$clixon_util_xpath -f $xml -p /aaa/bbb" 0 "" "^0:42 +expectpart "$($clixon_util_xpath -D $DBG -f $xml -p /aaa/bbb)" 0 "^0:42 1:99$" new "xpath /aaa/bbb union " -expecteof "$clixon_util_xpath -f $xml -p aaa/bbb[ccc=42]|aaa/ddd[ccc=22]" 0 "" '^nodeset:0:421:22$' +expectpart "$($clixon_util_xpath -D $DBG -f $xml -p "aaa/bbb[ccc=42]|aaa/ddd[ccc=22]")" 0 '^nodeset:0:421:22$' new "xpath //bbb" -expecteof "$clixon_util_xpath -f $xml -p //bbb" 0 "" "0:42 +expectpart "$($clixon_util_xpath -D $DBG -f $xml -p //bbb)" 0 "0:42 1:99" 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*" -#expecteof "$clixon_util_xpath -f $xml" 0 "//b*" "" +#expecteof "$clixon_util_xpath -D $DBG -f $xml" 0 "//b*" "" 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]" -expecteof "$clixon_util_xpath -f $xml -p //bbb[0]" 0 "" "^nodeset:0:42$" +expectpart "$($clixon_util_xpath -D $DBG -f $xml -p //bbb[0])" 0 "^nodeset:0:42$" new "xpath //bbb[ccc=99]" -expecteof "$clixon_util_xpath -f $xml -p //bbb[ccc=99]" 0 "" "^nodeset:0:99$" +expectpart "$($clixon_util_xpath -D $DBG -f $xml -p //bbb[ccc=99])" 0 "^nodeset:0:99$" 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'" -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" 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" -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" -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'" -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'" -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'" -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'" -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'" -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" -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" -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" -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" -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" -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" -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" -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" -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" -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" -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)" -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']" -expecteof "$clixon_util_xpath -f $xml2 -p .[name='bar'] -i /aaa/bbb/routing/ribs/rib" 0 "" "^nodeset:0:barmyfamily$" +expecteof "$clixon_util_xpath -D $DBG -f $xml2 -p .[name='bar'] -i /aaa/bbb/routing/ribs/rib" 0 "^nodeset:0:barmyfamily$" new "xpath /aaa/bbb/namespace (namespace is xpath axisname)" -expecteof "$clixon_util_xpath -f $xml2 -p /aaa/bbb/namespace" 0 "" "^nodeset:0:urn:example:foo$" +expectpart "$($clixon_util_xpath -D $DBG -f $xml2 -p /aaa/bbb/namespace)" 0 "^nodeset:0:urn:example:foo$" # See https://github.com/clicon/clixon/issues/54 # 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)" -#expecteof "$clixon_util_xpath -f $xml2 -p /aaa/bbb/comment" 0 "" "^kalle$" +new "xpath /aaa/bbb/comment (comment is xpath nodetype)" +expectpart "$($clixon_util_xpath -D $DBG -f $xml2 -p /aaa/bbb/comment)" 0 "^nodeset:$" new "Multiple entries" new "xpath bbb[ccc='foo']" -expecteof "$clixon_util_xpath -f $xml3 -p bbb[ccc='foo']" 0 "" "^nodeset:0:foo42bar1:99foo$" +expectpart "$($clixon_util_xpath -D $DBG -f $xml3 -p "bbb[ccc='foo']")" 0 "^nodeset:0:foo42bar1:99foo$" new "xpath bbb[ccc=\"foo\"]" -expecteof "$clixon_util_xpath -f $xml3 -p bbb[ccc=\"foo\"]" 0 "" "^nodeset:0:foo42bar1:99foo$" +expectpart "$($clixon_util_xpath -D $DBG -f $xml3 -p "bbb[ccc=\"foo\"]")" 0 "^nodeset:0:foo42bar1:99foo$" new "xpath bbb[ccc='42']" -expecteof "$clixon_util_xpath -f $xml3 -p bbb[ccc='42']" 0 "" "^nodeset:0:foo42bar$" +expectpart "$($clixon_util_xpath -D $DBG -f $xml3 -p bbb[ccc='42'])" 0 "^nodeset:0:foo42bar$" new "xpath bbb[ccc=99] (number w/o quotes)" -expecteof "$clixon_util_xpath -f $xml3 -p bbb[ccc=99]" 0 "" "^nodeset:0:99foo$" +expectpart "$($clixon_util_xpath -D $DBG -f $xml3 -p bbb[ccc=99])" 0 "^nodeset:0:99foo$" new "xpath bbb[ccc='bar']" -expecteof "$clixon_util_xpath -f $xml3 -p bbb[ccc='bar']" 0 "" "^nodeset:0:foo42bar$" +expectpart "$($clixon_util_xpath -D $DBG -f $xml3 -p "bbb[ccc='bar']")" 0 "^nodeset:0:foo42bar$" 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 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" -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" -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 new "xpath nodetest: node" -expectpart "$($clixon_util_xpath -f $xml3 -p "/bbb/ccc/self::node()")" 0 "nodeset:0:foo" +expectpart "$($clixon_util_xpath -D $DBG -f $xml3 -p "/bbb/ccc/self::node()")" 0 "nodeset:0:foo" 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 new "find bbb with 3 ccc children using count" -expectpart "$($clixon_util_xpath -f $xml3 -l o -p "(/bbb[count(ccc)=3])")" 0 "foo42bar" +expectpart "$($clixon_util_xpath -D $DBG -f $xml3 -l o -p "(/bbb[count(ccc)=3])")" 0 "foo42bar" # Negative 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" -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" -expecteof "$clixon_util_xpath -f $xml4 -p /root/*/a" 0 "" "nodeset:0:1111:2222:111" +expecteof "$clixon_util_xpath -D $DBG -f $xml4 -p /root/*/a" 0 "" "nodeset:0:1111:2222:111" new "xpath /root/*/b" -expecteof "$clixon_util_xpath -f $xml4 -p /root/*/b" 0 "" "nodeset:0:111" +expecteof "$clixon_util_xpath -D $DBG -f $xml4 -p /root/*/b" 0 "" "nodeset:0:111" new "xpath /root/*/*[.='111']" -expecteof "$clixon_util_xpath -f $xml4 -p /root/*/*[.='111']" 0 "" "nodeset:0:1111:1112:111" +expecteof "$clixon_util_xpath -D $DBG -f $xml4 -p /root/*/*[.='111']" 0 "" "nodeset:0:1111:1112:111" + +# 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 "73" + +new "xpath functions as ncname: nodetype:node" +expectpart "$($clixon_util_xpath -D $DBG -f $xmlfn -p "root/ancestor/count/node")" 0 "42" + +new "xpath functions as ncname: nodetype:node" +expectpart "$($clixon_util_xpath -D $DBG -f $xmlfn -p "root/ancestor/count[node=42]")" 0 "42" + +new "xpath functions as ncname: axisname:ancestor" +expectpart "$($clixon_util_xpath -D $DBG -f $xmlfn -p "root/count/node[99=ancestor]")" 0 "99" + +new "xpath functions as ncname: functioname:count" +expectpart "$($clixon_util_xpath -D $DBG -f $xmlfn -p "root/node/ancestor[73=count]")" 0 "73" rm -rf $dir diff --git a/test/test_xpath_functions.sh b/test/test_xpath_functions.sh index a6b4cba5..5eb90748 100755 --- a/test/test_xpath_functions.sh +++ b/test/test_xpath_functions.sh @@ -1,9 +1,12 @@ #!/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/ # YANG XPATH functions: https://tools.ietf.org/html/rfc7950 -# Tests: -# - Contains +# Test of xpath functions: +# - contains +# - derived-from +# - derived-from-or-self +# - bit-is-set # Magic line must be first in script (see README.md) s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi @@ -102,6 +105,24 @@ module $APPNAME{ 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 @@ -120,7 +141,6 @@ fi new "wait backend" wait_backend -# contains new "contains: Set site to foo that validates site OK" expecteof_netconf "$clixon_netconf -qf $cfg -D $DBG" 0 "$DEFAULTHELLO" "foo1242" "" "" diff --git a/test/test_yang_models_ietf.sh b/test/test_yang_models_ietf.sh index 4d9c07cd..32e8805a 100755 --- a/test/test_yang_models_ietf.sh +++ b/test/test_yang_models_ietf.sh @@ -45,11 +45,6 @@ files=$(find ${YANG_STANDARD_DIR}/ietf/RFC -type f -name "*.yang") for f in $files; do if [ -n "$(head -1 $f|grep '^module')" ]; then # 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 continue; fi