* Full support of XPATH 1.0 according to https://www.w3.org/TR/xpath-10 using yacc/lex
* The previous XPATH imlementation was very restricted. * The only function implemented is the Yang extension "current()". No other functions are implemented (eg last(), count()).
This commit is contained in:
parent
60ce7b12bd
commit
bf728b37b8
26 changed files with 2856 additions and 481 deletions
|
|
@ -2,6 +2,9 @@
|
|||
|
||||
## 3.7.0 (Upcoming)
|
||||
### Major changes:
|
||||
* Full support of XPATH 1.0 according to https://www.w3.org/TR/xpath-10 using yacc/lex
|
||||
* The previous XPATH imlementation was very restricted.
|
||||
* The only function implemented is the Yang extension "current()". No other functions are implemented (eg last(), count()).
|
||||
* Support for YANG identity and identityref according to RFC 7950 Sec 7.18 and 9.10
|
||||
* Previous support did no validation of values.
|
||||
* Validation of types and CLI expansion
|
||||
|
|
@ -9,7 +12,7 @@
|
|||
* Applications which have not strictly enforced the identities may now have problems with validation and may need to be modified.
|
||||
|
||||
### Minor changes:
|
||||
* Dedicated xml,json,yang and xsl parser utility programs added
|
||||
* Dedicated xml,json,yang and xpath parser utility programs added
|
||||
* CDATA xml support (patch by David Cornejo, Netgate)
|
||||
* Encode and decode (parsing) support
|
||||
* Validation of yang bits type space-separated list value
|
||||
|
|
@ -47,7 +50,7 @@
|
|||
* See FAQ and example
|
||||
|
||||
### Corrected Bugs
|
||||
* Prefix of rpc was ignored
|
||||
* Prefix of rpc was ignored (thanks Dmitri at netgate)
|
||||
* https://github.com/clicon/clixon/issues/30
|
||||
* Added cli returna value also for single commands (eg -1)
|
||||
* Fixed JSON unbalanced braces resulting in assert.
|
||||
|
|
|
|||
|
|
@ -81,6 +81,8 @@
|
|||
#include <clixon/clixon_options.h>
|
||||
#include <clixon/clixon_xml_map.h>
|
||||
#include <clixon/clixon_xml_db.h>
|
||||
#include <clixon/clixon_xpath_ctx.h>
|
||||
#include <clixon/clixon_xpath.h>
|
||||
#include <clixon/clixon_xsl.h>
|
||||
#include <clixon/clixon_json.h>
|
||||
#include <clixon/clixon_netconf_lib.h>
|
||||
|
|
|
|||
|
|
@ -46,6 +46,8 @@ static const map_str2int atmap[] = {
|
|||
{NULL, -1}
|
||||
};
|
||||
* @endcode
|
||||
* @see clicon_int2str
|
||||
* @see clicon_str2int
|
||||
*/
|
||||
struct map_str2int{
|
||||
char *ms_str;
|
||||
|
|
|
|||
95
lib/clixon/clixon_xpath.h
Normal file
95
lib/clixon/clixon_xpath.h
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright (C) 2009-2018 Olof Hagsand and Benny Holmgren
|
||||
|
||||
This file is part of CLIXON.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Alternatively, the contents of this file may be used under the terms of
|
||||
the GNU General Public License Version 3 or later (the "GPL"),
|
||||
in which case the provisions of the GPL are applicable instead
|
||||
of those above. If you wish to allow use of your version of this file only
|
||||
under the terms of the GPL, and not to allow others to
|
||||
use your version of this file under the terms of Apache License version 2,
|
||||
indicate your decision by deleting the provisions above and replace them with
|
||||
the notice and other provisions required by the GPL. If you do not delete
|
||||
the provisions above, a recipient may use your version of this file under
|
||||
the terms of any one of the Apache License version 2 or the GPL.
|
||||
|
||||
***** END LICENSE BLOCK *****
|
||||
|
||||
* Clixon XML XPATH 1.0 according to https://www.w3.org/TR/xpath-10
|
||||
*/
|
||||
#ifndef _CLIXON_XPATH_H
|
||||
#define _CLIXON_XPATH_H
|
||||
|
||||
/*
|
||||
* Types
|
||||
*/
|
||||
enum xp_op{
|
||||
XO_AND,
|
||||
XO_OR,
|
||||
XO_DIV,
|
||||
XO_MOD,
|
||||
XO_ADD,
|
||||
XO_MULT,
|
||||
XO_SUB,
|
||||
XO_EQ,
|
||||
XO_NE,
|
||||
XO_GE,
|
||||
XO_LE,
|
||||
XO_LT,
|
||||
XO_GT,
|
||||
XO_UNION,
|
||||
};
|
||||
|
||||
/* Axis specifiers according to https://www.w3.org/TR/xpath-10/#NT-AxisName */
|
||||
enum axis_type{
|
||||
A_NAN = 0, /* Not set */
|
||||
A_ANCESTOR,
|
||||
A_ANCESTOR_OR_SELF,
|
||||
A_ATTRIBUTE,
|
||||
A_CHILD,
|
||||
A_DESCENDANT,
|
||||
A_DESCENDANT_OR_SELF,
|
||||
A_FOLLOWING,
|
||||
A_FOLLOWING_SIBLING,
|
||||
A_NAMESPACE,
|
||||
A_PARENT,
|
||||
A_PRECEEDING,
|
||||
A_PRECEEDING_SIBLING,
|
||||
A_SELF,
|
||||
A_ROOT /* XXX Not in https://www.w3.org/TR/xpath-10 */
|
||||
};
|
||||
|
||||
/*
|
||||
* Variables
|
||||
*/
|
||||
extern const map_str2int xpopmap[];
|
||||
|
||||
/*
|
||||
* Prototypes
|
||||
*/
|
||||
#if defined(__GNUC__) && __GNUC__ >= 3
|
||||
int xpath_vec_nodeset(cxobj *xcur, char *format, cxobj ***vec, size_t *veclen, ...) __attribute__ ((format (printf, 2, 5)));
|
||||
int xpath_vec_bool(cxobj *xcur, char *format, ...) __attribute__ ((format (printf, 2, 3)));
|
||||
#else
|
||||
int xpath_vec_nodeset(cxobj *xcur, char *format, cxobj ***vec, size_t *veclen, ...);
|
||||
int xpath_vec_bool(cxobj *xcur, char *format, ...);
|
||||
#endif
|
||||
int xpath_vec_ctx(cxobj *xcur, char *xpath, xp_ctx **xrp);
|
||||
|
||||
#endif /* _CLIXON_XPATH_H */
|
||||
103
lib/clixon/clixon_xpath_ctx.h
Normal file
103
lib/clixon/clixon_xpath_ctx.h
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright (C) 2009-2018 Olof Hagsand and Benny Holmgren
|
||||
|
||||
This file is part of CLIXON.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Alternatively, the contents of this file may be used under the terms of
|
||||
the GNU General Public License Version 3 or later (the "GPL"),
|
||||
in which case the provisions of the GPL are applicable instead
|
||||
of those above. If you wish to allow use of your version of this file only
|
||||
under the terms of the GPL, and not to allow others to
|
||||
use your version of this file under the terms of Apache License version 2,
|
||||
indicate your decision by deleting the provisions above and replace them with
|
||||
the notice and other provisions required by the GPL. If you do not delete
|
||||
the provisions above, a recipient may use your version of this file under
|
||||
the terms of any one of the Apache License version 2 or the GPL.
|
||||
|
||||
***** END LICENSE BLOCK *****
|
||||
|
||||
* Clixon XML XPATH 1.0 according to https://www.w3.org/TR/xpath-10
|
||||
* This file defines XPATH contexts using in traversing the XPATH parse tree.
|
||||
*/
|
||||
#ifndef _CLIXON_XPATH_CTX_H
|
||||
#define _CLIXON_XPATH_CTX_H
|
||||
|
||||
/*
|
||||
* Types
|
||||
*/
|
||||
|
||||
/*! XPATH expression type
|
||||
* An expression is evaluated to yield an object, which has one of the following four basic types:
|
||||
* node-set (an unordered collection of nodes without duplicates)
|
||||
* boolean (true or false)
|
||||
* number (a floating-point number)
|
||||
* string (a sequence of UCS characters)
|
||||
*/
|
||||
enum xp_objtype{
|
||||
XT_NODESET,
|
||||
XT_BOOL,
|
||||
XT_NUMBER,
|
||||
XT_STRING
|
||||
};
|
||||
|
||||
/* Expression evaluation occurs with respect to a context. XSLT and XPointer specify how the context is
|
||||
* determined for XPath expressions used in XSLT and XPointer respectively. The context consists of:
|
||||
* a node (the context node)
|
||||
* a pair of non-zero positive integers (the context position and the context size)
|
||||
* a set of variable bindings
|
||||
* a function library
|
||||
* the set of namespace declarations in scope for the expression
|
||||
|
||||
* For each node in the node-set to be filtered, the PredicateExpr is
|
||||
* evaluated with that node as the context node, with the number of nodes
|
||||
* in the node-set as the context size, and with the proximity position
|
||||
* of the node in the node-set with respect to the axis as the context
|
||||
* position; if PredicateExpr evaluates to true for that node, the node
|
||||
* is included in the new node-set; otherwise, it is not included.
|
||||
*/
|
||||
struct xp_ctx{
|
||||
enum xp_objtype xc_type;
|
||||
cxobj **xc_nodeset; /* if type XT_NODESET */
|
||||
size_t xc_size; /* Length of nodeset */
|
||||
int xc_bool; /* if xc_type XT_BOOL */
|
||||
double xc_number; /* if xc_type XT_NUMBER */
|
||||
char *xc_string; /* if xc_type XT_STRING */
|
||||
cxobj *xc_node; /* Node in nodeset XXX maybe not needed*/
|
||||
cxobj *xc_initial; /* RFC 7960 10.1.1 extension: for current() */
|
||||
int xc_descendant; /* // */
|
||||
/* NYI: a set of variable bindings, set of namespace declarations */
|
||||
};
|
||||
typedef struct xp_ctx xp_ctx;
|
||||
|
||||
/*
|
||||
* Variables
|
||||
*/
|
||||
extern const map_str2int ctxmap[];
|
||||
|
||||
/*
|
||||
* Prototypes
|
||||
*/
|
||||
int ctx_free(xp_ctx *xc);
|
||||
xp_ctx *ctx_dup(xp_ctx *xc);
|
||||
int ctx_nodeset_replace(xp_ctx *xc, cxobj **vec, size_t veclen);
|
||||
int ctx_print(cbuf *cb, int id, xp_ctx *xc, char *str);
|
||||
int ctx2boolean(xp_ctx *xc);
|
||||
int ctx2string(xp_ctx *xc, char **str0);
|
||||
int ctx2number(xp_ctx *xc, double *n0);
|
||||
|
||||
#endif /* _CLIXON_XPATH_CTX_H */
|
||||
|
|
@ -72,18 +72,19 @@ SRC = clixon_sig.c clixon_log.c clixon_err.c clixon_event.c \
|
|||
clixon_json.c clixon_yang.c clixon_yang_type.c \
|
||||
clixon_hash.c clixon_options.c clixon_plugin.c \
|
||||
clixon_proto.c clixon_proto_client.c \
|
||||
clixon_xsl.c clixon_sha1.c clixon_xml_db.c clixon_netconf_lib.c
|
||||
clixon_xsl.c clixon_xpath.c clixon_xpath_ctx.c clixon_sha1.c \
|
||||
clixon_xml_db.c clixon_netconf_lib.c
|
||||
|
||||
YACCOBJS := lex.clixon_xml_parse.o clixon_xml_parse.tab.o \
|
||||
lex.clixon_yang_parse.o clixon_yang_parse.tab.o \
|
||||
lex.clixon_json_parse.o clixon_json_parse.tab.o
|
||||
|
||||
lex.clixon_json_parse.o clixon_json_parse.tab.o \
|
||||
lex.clixon_xpath_parse.o clixon_xpath_parse.tab.o
|
||||
|
||||
# Extra applications. Utilities, unit testings. Not installed.
|
||||
APPSRC = clixon_util_xml.c
|
||||
APPSRC += clixon_util_json.c
|
||||
APPSRC += clixon_util_yang.c
|
||||
APPSRC += clixon_util_xsl.c
|
||||
APPSRC += clixon_util_xpath.c
|
||||
|
||||
APPS = $(APPSRC:.c=)
|
||||
|
||||
|
|
@ -107,9 +108,11 @@ clean:
|
|||
rm -f clixon_xml_parse.tab.[ch] clixon_xml_parse.yy.[co]
|
||||
rm -f clixon_yang_parse.tab.[ch] clixon_yang_parse.[co]
|
||||
rm -f clixon_json_parse.tab.[ch] clixon_json_parse.[co]
|
||||
rm -f clixon_xpath_parse.tab.[ch] clixon_xpath_parse.[co]
|
||||
rm -f lex.clixon_xml_parse.c
|
||||
rm -f lex.clixon_yang_parse.c
|
||||
rm -f lex.clixon_json_parse.c
|
||||
rm -f lex.clixon_xpath_parse.c
|
||||
|
||||
#############################################################################
|
||||
# Implicit rules for lex and yacc.
|
||||
|
|
@ -159,6 +162,18 @@ clixon_json_parse.tab.c clixon_json_parse.tab.h: clixon_json_parse.y
|
|||
lex.clixon_json_parse.o : lex.clixon_json_parse.c clixon_json_parse.tab.h
|
||||
$(CC) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) -Wno-error -c $<
|
||||
|
||||
# xpath parser
|
||||
lex.clixon_xpath_parse.c : clixon_xpath_parse.l clixon_xpath_parse.tab.h
|
||||
$(LEX) -Pclixon_xpath_parse clixon_xpath_parse.l # -d is debug
|
||||
|
||||
clixon_xpath_parse.tab.c clixon_xpath_parse.tab.h: clixon_xpath_parse.y
|
||||
$(YACC) -l -d -p clixon_xpath_parse clixon_xpath_parse.y # -t is debug
|
||||
mv y.tab.c clixon_xpath_parse.tab.c
|
||||
mv y.tab.h clixon_xpath_parse.tab.h
|
||||
|
||||
lex.clixon_xpath_parse.o : lex.clixon_xpath_parse.c clixon_xpath_parse.tab.h
|
||||
$(CC) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) -Wno-error -c $<
|
||||
|
||||
# APPS
|
||||
clixon_util_xml: clixon_util_xml.c $(MYLIB)
|
||||
$(CC) $(INCLUDES) $(CPPFLAGS) @CFLAGS@ $^ $(LIBS) -o $@
|
||||
|
|
@ -169,7 +184,7 @@ clixon_util_json: clixon_util_json.c $(MYLIB)
|
|||
clixon_util_yang: clixon_util_yang.c $(MYLIB)
|
||||
$(CC) $(INCLUDES) $(CPPFLAGS) @CFLAGS@ $^ $(LIBS) -o $@
|
||||
|
||||
clixon_util_xsl: clixon_util_xsl.c $(MYLIB)
|
||||
clixon_util_xpath: clixon_util_xpath.c $(MYLIB)
|
||||
$(CC) $(INCLUDES) $(CPPFLAGS) @CFLAGS@ $^ $(LIBS) -o $@
|
||||
|
||||
distclean: clean
|
||||
|
|
|
|||
231
lib/src/clixon_util_xpath.c
Normal file
231
lib/src/clixon_util_xpath.c
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
/*
|
||||
*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright (C) 2009-2018 Olof Hagsand and Benny Holmgren
|
||||
|
||||
This file is part of CLIXON.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Alternatively, the contents of this file may be used under the terms of
|
||||
the GNU General Public License Version 3 or later (the "GPL"),
|
||||
in which case the provisions of the GPL are applicable instead
|
||||
of those above. If you wish to allow use of your version of this file only
|
||||
under the terms of the GPL, and not to allow others to
|
||||
use your version of this file under the terms of Apache License version 2,
|
||||
indicate your decision by deleting the provisions above and replace them with
|
||||
the notice and other provisions required by the GPL. If you do not delete
|
||||
the provisions above, a recipient may use your version of this file under
|
||||
the terms of any one of the Apache License version 2 or the GPL.
|
||||
|
||||
***** END LICENSE BLOCK *****
|
||||
|
||||
See https://www.w3.org/TR/xpath/
|
||||
|
||||
* Turn this on to get an xpath test program
|
||||
* Usage: xpath [<xpath>]
|
||||
* read xpath on first line and xml on rest of lines from input
|
||||
* Example compile:
|
||||
gcc -g -o xpath -I. -I../clixon ./clixon_xsl.c -lclixon -lcligen
|
||||
* Example run:
|
||||
echo "a\n<a><b/></a>" | xpath
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "clixon_config.h" /* generated by config & autoconf */
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <fnmatch.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <syslog.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
/* cligen */
|
||||
#include <cligen/cligen.h>
|
||||
|
||||
/* clixon */
|
||||
#include <clixon/clixon.h>
|
||||
|
||||
static int
|
||||
usage(char *argv0)
|
||||
{
|
||||
fprintf(stderr, "usage:%s [options]\n"
|
||||
"where options are\n"
|
||||
"\t-h \t\tHelp\n"
|
||||
"\t-D <level> \tDebug\n"
|
||||
"\t-f <file> \tXML file\n"
|
||||
"\t-p <xpath> \tPrimary XPATH string\n"
|
||||
"\t-i <xpath0>\t(optional) Initial XPATH string\n"
|
||||
"and the following extra rules:\n"
|
||||
"\tif -f is not given, XML input is expected on stdin\n"
|
||||
"\tif -p is not given, <xpath> is expected as the first line on stdin\n"
|
||||
"This means that with no arguments, <xpath> and XML is expected on stadin.\n",
|
||||
argv0
|
||||
);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static int
|
||||
ctx_print2(cbuf *cb,
|
||||
xp_ctx *xc)
|
||||
{
|
||||
int i;
|
||||
|
||||
cprintf(cb, "%s:", (char*)clicon_int2str(ctxmap, xc->xc_type));
|
||||
switch (xc->xc_type){
|
||||
case XT_NODESET:
|
||||
for (i=0; i<xc->xc_size; i++){
|
||||
cprintf(cb, "%d:", i);
|
||||
clicon_xml2cbuf(cb, xc->xc_nodeset[i], 0, 0);
|
||||
}
|
||||
break;
|
||||
case XT_BOOL:
|
||||
cprintf(cb, "%s", xc->xc_bool?"true":"false");
|
||||
break;
|
||||
case XT_NUMBER:
|
||||
cprintf(cb, "%lf", xc->xc_number);
|
||||
break;
|
||||
case XT_STRING:
|
||||
cprintf(cb, "%s", xc->xc_string);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int retval = -1;
|
||||
char *argv0 = argv[0];
|
||||
int i;
|
||||
cxobj **xv = NULL;
|
||||
cxobj *x0 = NULL;
|
||||
cxobj *x;
|
||||
char c;
|
||||
int len;
|
||||
char *buf = NULL;
|
||||
int ret;
|
||||
int fd = 0; /* unless overriden by argv[1] */
|
||||
char *xpath = NULL;
|
||||
char *xpath0 = NULL;
|
||||
char *filename;
|
||||
xp_ctx *xc = NULL;
|
||||
cbuf *cb;
|
||||
|
||||
clicon_log_init("xpath", LOG_DEBUG, CLICON_LOG_STDERR);
|
||||
optind = 1;
|
||||
opterr = 0;
|
||||
while ((c = getopt(argc, argv, "hDf:p:i:")) != -1)
|
||||
switch (c) {
|
||||
case 'h':
|
||||
usage(argv0);
|
||||
break;
|
||||
case 'D':
|
||||
debug++;
|
||||
break;
|
||||
case 'f': /* XML file */
|
||||
filename = optarg;
|
||||
if ((fd = open(filename, O_RDONLY)) < 0){
|
||||
clicon_err(OE_UNIX, errno, "open(%s)", argv[1]);
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
case 'p': /* Primary XPATH string */
|
||||
xpath = optarg;
|
||||
break;
|
||||
case 'i': /* Optional initial XPATH string */
|
||||
xpath0 = optarg;
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
break;
|
||||
}
|
||||
if (xpath==NULL){
|
||||
/* First read xpath */
|
||||
len = 1024; /* any number is fine */
|
||||
if ((buf = malloc(len)) == NULL){
|
||||
perror("pt_file malloc");
|
||||
return -1;
|
||||
}
|
||||
memset(buf, 0, len);
|
||||
i = 0;
|
||||
while (1){
|
||||
if ((ret = read(0, &c, 1)) < 0){
|
||||
perror("read");
|
||||
goto done;
|
||||
}
|
||||
if (ret == 0)
|
||||
break;
|
||||
if (c == '\n')
|
||||
break;
|
||||
if (len==i){
|
||||
if ((buf = realloc(buf, 2*len)) == NULL){
|
||||
fprintf(stderr, "%s: realloc: %s\n", __FUNCTION__, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
memset(buf+len, 0, len);
|
||||
len *= 2;
|
||||
}
|
||||
buf[i++] = (char)(c&0xff);
|
||||
}
|
||||
xpath = buf;
|
||||
}
|
||||
/*
|
||||
* If fd=0, then continue reading from stdin (after CR)
|
||||
* If fd>0, reading from file opened as argv[1]
|
||||
*/
|
||||
if (xml_parse_file(fd, "</clicon>", NULL, &x0) < 0){
|
||||
fprintf(stderr, "Error: parsing: %s\n", clicon_err_reason);
|
||||
return -1;
|
||||
}
|
||||
/* If xpath0 given, position current x */
|
||||
if (xpath0){
|
||||
if ((x = xpath_first(x0, "%s", xpath0)) == NULL){
|
||||
fprintf(stderr, "Error: xpath0 returned NULL\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
x = x0;
|
||||
|
||||
/* Parse XML */
|
||||
if (xpath_vec_ctx(x, xpath, &xc) < 0)
|
||||
return -1;
|
||||
/* Print results */
|
||||
cb = cbuf_new();
|
||||
ctx_print2(cb, xc);
|
||||
fprintf(stdout, "%s\n", cbuf_get(cb));
|
||||
retval = 0;
|
||||
done:
|
||||
if (cb)
|
||||
cbuf_free(cb);
|
||||
if (xc)
|
||||
ctx_free(xc);
|
||||
if (xv)
|
||||
free(xv);
|
||||
if (buf)
|
||||
free(buf);
|
||||
if (x0)
|
||||
xml_free(x0);
|
||||
if (fd > 0)
|
||||
close(fd);
|
||||
return retval;
|
||||
}
|
||||
|
|
@ -1,141 +0,0 @@
|
|||
/*
|
||||
*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright (C) 2009-2018 Olof Hagsand and Benny Holmgren
|
||||
|
||||
This file is part of CLIXON.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Alternatively, the contents of this file may be used under the terms of
|
||||
the GNU General Public License Version 3 or later (the "GPL"),
|
||||
in which case the provisions of the GPL are applicable instead
|
||||
of those above. If you wish to allow use of your version of this file only
|
||||
under the terms of the GPL, and not to allow others to
|
||||
use your version of this file under the terms of Apache License version 2,
|
||||
indicate your decision by deleting the provisions above and replace them with
|
||||
the notice and other provisions required by the GPL. If you do not delete
|
||||
the provisions above, a recipient may use your version of this file under
|
||||
the terms of any one of the Apache License version 2 or the GPL.
|
||||
|
||||
***** END LICENSE BLOCK *****
|
||||
|
||||
See https://www.w3.org/TR/xpath/
|
||||
|
||||
* Turn this on to get an xpath test program
|
||||
* Usage: xpath [<xpath>]
|
||||
* read xpath on first line and xml on rest of lines from input
|
||||
* Example compile:
|
||||
gcc -g -o xpath -I. -I../clixon ./clixon_xsl.c -lclixon -lcligen
|
||||
* Example run:
|
||||
echo "a\n<a><b/></a>" | xpath
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "clixon_config.h" /* generated by config & autoconf */
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <fnmatch.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <syslog.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
/* cligen */
|
||||
#include <cligen/cligen.h>
|
||||
|
||||
/* clixon */
|
||||
#include <clixon/clixon.h>
|
||||
|
||||
|
||||
static int
|
||||
usage(char *argv0)
|
||||
{
|
||||
fprintf(stderr, "usage:%s <xpath>.\n\tInput on stdin\n", argv0);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int retval = -1;
|
||||
int i;
|
||||
cxobj **xv;
|
||||
cxobj *x;
|
||||
cxobj *xn;
|
||||
size_t xlen = 0;
|
||||
int c;
|
||||
int len;
|
||||
char *buf = NULL;
|
||||
int ret;
|
||||
|
||||
if (argc != 1){
|
||||
usage(argv[0]);
|
||||
return -1;
|
||||
}
|
||||
/* First read xpath */
|
||||
len = 1024; /* any number is fine */
|
||||
if ((buf = malloc(len)) == NULL){
|
||||
perror("pt_file malloc");
|
||||
return -1;
|
||||
}
|
||||
memset(buf, 0, len);
|
||||
i = 0;
|
||||
while (1){
|
||||
if ((ret = read(0, &c, 1)) < 0){
|
||||
perror("read");
|
||||
goto done;
|
||||
}
|
||||
if (ret == 0)
|
||||
break;
|
||||
if (c == '\n')
|
||||
break;
|
||||
if (len==i){
|
||||
if ((buf = realloc(buf, 2*len)) == NULL){
|
||||
fprintf(stderr, "%s: realloc: %s\n", __FUNCTION__, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
memset(buf+len, 0, len);
|
||||
len *= 2;
|
||||
}
|
||||
buf[i++] = (char)(c&0xff);
|
||||
}
|
||||
x = NULL;
|
||||
if (xml_parse_file(0, "</clicon>", NULL, &x) < 0){
|
||||
fprintf(stderr, "Error: parsing: %s\n", clicon_err_reason);
|
||||
return -1;
|
||||
}
|
||||
if (xpath_vec(x, "%s", &xv, &xlen, buf) < 0)
|
||||
return -1;
|
||||
if (xv){
|
||||
for (i=0; i<xlen; i++){
|
||||
xn = xv[i];
|
||||
fprintf(stdout, "%d:", i);
|
||||
clicon_xml2file(stdout, xn, 0, 0);
|
||||
fprintf(stdout, "\n");
|
||||
}
|
||||
free(xv);
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
if (x)
|
||||
xml_free(x);
|
||||
return retval;
|
||||
}
|
||||
|
|
@ -1487,8 +1487,6 @@ int
|
|||
xml_copy_one(cxobj *x0,
|
||||
cxobj *x1)
|
||||
{
|
||||
cg_var *cv1;
|
||||
|
||||
xml_type_set(x1, xml_type(x0));
|
||||
if (xml_value(x0)){ /* malloced string */
|
||||
if ((x1->x_value = strdup(x0->x_value)) == NULL){
|
||||
|
|
|
|||
|
|
@ -424,13 +424,15 @@ xml_yang_validate_all(cxobj *xt,
|
|||
void *arg)
|
||||
{
|
||||
int retval = -1;
|
||||
yang_stmt *ys;
|
||||
yang_stmt *ytype;
|
||||
yang_stmt *ys; /* yang node */
|
||||
yang_stmt *yc; /* yang child */
|
||||
char *xpath;
|
||||
|
||||
/* if not given by argument (overide) use default link
|
||||
and !Node has a config sub-statement and it is false */
|
||||
if ((ys = xml_spec(xt)) != NULL &&
|
||||
yang_config(ys) != 0){
|
||||
/* Node-specific validation */
|
||||
switch (ys->ys_keyword){
|
||||
case Y_LEAF:
|
||||
/* fall thru */
|
||||
|
|
@ -438,20 +440,29 @@ xml_yang_validate_all(cxobj *xt,
|
|||
/* Special case if leaf is leafref, then first check against
|
||||
current xml tree
|
||||
*/
|
||||
if ((ytype = yang_find((yang_node*)ys, Y_TYPE, NULL)) != NULL){
|
||||
if (strcmp(ytype->ys_argument, "leafref") == 0){
|
||||
if (validate_leafref(xt, ytype) < 0)
|
||||
if ((yc = yang_find((yang_node*)ys, Y_TYPE, NULL)) != NULL){
|
||||
if (strcmp(yc->ys_argument, "leafref") == 0){
|
||||
if (validate_leafref(xt, yc) < 0)
|
||||
goto done;
|
||||
}
|
||||
else if (strcmp(ytype->ys_argument, "identityref") == 0){
|
||||
if (validate_identityref(xt, ys, ytype) < 0)
|
||||
else if (strcmp(yc->ys_argument, "identityref") == 0){
|
||||
if (validate_identityref(xt, ys, yc) < 0)
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Y_MUST: /* RFC 7950 Sec 7.5.3 */
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
/* "when" sub-node RFC 7950 Sec 7.21.5 */
|
||||
if ((yc = yang_find((yang_node*)ys, Y_WHEN, NULL)) != NULL){
|
||||
xpath = yc->ys_argument; /* "when" has xpath argument */
|
||||
if (xpath_first(xt, "%s", xpath))
|
||||
;
|
||||
fprintf(stderr, "%s %s\n", __FUNCTION__, xpath);
|
||||
}
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
|
|
@ -1372,7 +1383,6 @@ xml_spec_populate(cxobj *x,
|
|||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*! Translate from restconf api-path in cvv form to xml xpath
|
||||
* eg a/b=c -> a/[b=c]
|
||||
* @param[in] yspec Yang spec
|
||||
|
|
|
|||
1183
lib/src/clixon_xpath.c
Normal file
1183
lib/src/clixon_xpath.c
Normal file
File diff suppressed because it is too large
Load diff
294
lib/src/clixon_xpath_ctx.c
Normal file
294
lib/src/clixon_xpath_ctx.c
Normal file
|
|
@ -0,0 +1,294 @@
|
|||
/*
|
||||
*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright (C) 2009-2018 Olof Hagsand and Benny Holmgren
|
||||
|
||||
This file is part of CLIXON.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Alternatively, the contents of this file may be used under the terms of
|
||||
the GNU General Public License Version 3 or later (the "GPL"),
|
||||
in which case the provisions of the GPL are applicable instead
|
||||
of those above. If you wish to allow use of your version of this file only
|
||||
under the terms of the GPL, and not to allow others to
|
||||
use your version of this file under the terms of Apache License version 2, indicate
|
||||
your decision by deleting the provisions above and replace them with the
|
||||
notice and other provisions required by the GPL. If you do not delete
|
||||
the provisions above, a recipient may use your version of this file under
|
||||
the terms of any one of the Apache License version 2 or the GPL.
|
||||
|
||||
***** END LICENSE BLOCK *****
|
||||
|
||||
* Clixon XML XPATH 1.0 according to https://www.w3.org/TR/xpath-10
|
||||
* This file defines XPATH contexts using in traversing the XPATH parse tree.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <fnmatch.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <syslog.h>
|
||||
#include <fcntl.h>
|
||||
#include <math.h>
|
||||
|
||||
/* cligen */
|
||||
#include <cligen/cligen.h>
|
||||
|
||||
/* clicon */
|
||||
#include "clixon_err.h"
|
||||
#include "clixon_log.h"
|
||||
#include "clixon_string.h"
|
||||
#include "clixon_queue.h"
|
||||
#include "clixon_hash.h"
|
||||
#include "clixon_handle.h"
|
||||
#include "clixon_yang.h"
|
||||
#include "clixon_xml.h"
|
||||
#include "clixon_xpath_parse.h"
|
||||
#include "clixon_xpath_ctx.h"
|
||||
|
||||
/*
|
||||
* Variables
|
||||
*/
|
||||
const map_str2int ctxmap[] = {
|
||||
{"nodeset", XT_NODESET},
|
||||
{"bool", XT_BOOL},
|
||||
{"number", XT_NUMBER},
|
||||
{"string", XT_STRING},
|
||||
{NULL, -1}
|
||||
};
|
||||
|
||||
/*! Free xpath context */
|
||||
int
|
||||
ctx_free(xp_ctx *xc)
|
||||
{
|
||||
if (xc->xc_nodeset)
|
||||
free(xc->xc_nodeset);
|
||||
if (xc->xc_string)
|
||||
free(xc->xc_string);
|
||||
free(xc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Duplicate xpath context */
|
||||
xp_ctx *
|
||||
ctx_dup(xp_ctx *xc0)
|
||||
{
|
||||
static xp_ctx *xc = NULL;
|
||||
|
||||
if ((xc = malloc(sizeof(*xc))) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "malloc");
|
||||
goto done;
|
||||
}
|
||||
memset(xc, 0, sizeof(*xc));
|
||||
*xc = *xc0;
|
||||
if (xc0->xc_size){
|
||||
if ((xc->xc_nodeset = calloc(xc0->xc_size, sizeof(cxobj*))) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "calloc");
|
||||
goto done;
|
||||
}
|
||||
memcpy(xc->xc_nodeset, xc0->xc_nodeset, xc->xc_size*sizeof(cxobj*));
|
||||
}
|
||||
if (xc0->xc_string)
|
||||
if ((xc->xc_string = strdup(xc0->xc_string)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "strdup");
|
||||
goto done;
|
||||
}
|
||||
done:
|
||||
return xc;
|
||||
}
|
||||
|
||||
/*! Print XPATH context */
|
||||
int
|
||||
ctx_print(cbuf *cb,
|
||||
int id,
|
||||
xp_ctx *xc,
|
||||
char *str)
|
||||
{
|
||||
static int ident = 0;
|
||||
int i;
|
||||
|
||||
if (id<0)
|
||||
ident += id;
|
||||
cprintf(cb, "%*s%s ", ident, "", str?str:"");
|
||||
if (id>0)
|
||||
ident += id;
|
||||
if (xc){
|
||||
cprintf(cb, "%s: ", (char*)clicon_int2str(ctxmap, xc->xc_type));
|
||||
switch (xc->xc_type){
|
||||
case XT_NODESET:
|
||||
for (i=0; i<xc->xc_size; i++)
|
||||
cprintf(cb, "%s ", xml_name(xc->xc_nodeset[i]));
|
||||
break;
|
||||
case XT_BOOL:
|
||||
cprintf(cb, "%s", xc->xc_bool?"true":"false");
|
||||
break;
|
||||
case XT_NUMBER:
|
||||
cprintf(cb, "%lf", xc->xc_number);
|
||||
break;
|
||||
case XT_STRING:
|
||||
cprintf(cb, "%s", xc->xc_string);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Convert xpath context to boolean according to boolean() function in XPATH spec
|
||||
* @param[in] xc XPATH context
|
||||
* @retval 0 False
|
||||
* @retval 1 True
|
||||
* a number is true if and only if it is neither positive or negative zero nor NaN
|
||||
* a node-set is true if and only if it is non-empty
|
||||
* a string is true if and only if its length is non-zero
|
||||
* an object of a type other than the four basic types is converted to a boolean
|
||||
* in a way that is dependent on that type
|
||||
*/
|
||||
int
|
||||
ctx2boolean(xp_ctx *xc)
|
||||
{
|
||||
int b;
|
||||
switch (xc->xc_type){
|
||||
case XT_NODESET:
|
||||
b = (xc->xc_size != 0);
|
||||
break;
|
||||
case XT_BOOL:
|
||||
b = xc->xc_bool;
|
||||
break;
|
||||
case XT_NUMBER:
|
||||
b = (xc->xc_number != 0.0 && xc->xc_number != NAN);
|
||||
break;
|
||||
case XT_STRING:
|
||||
b = (xc->xc_string && strlen(xc->xc_string));
|
||||
break;
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
/*! Convert xpath context to string according to string() function in XPATH spec
|
||||
* @param[in] xc XPATH context
|
||||
* @param[out] str0 Malloced result string
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @note string malloced.
|
||||
*/
|
||||
int
|
||||
ctx2string(xp_ctx *xc,
|
||||
char **str0)
|
||||
{
|
||||
int retval = -1;
|
||||
char *str = NULL;
|
||||
int len;
|
||||
char *b;
|
||||
|
||||
switch (xc->xc_type){
|
||||
case XT_NODESET:
|
||||
if (xc->xc_size && (b = xml_body(xc->xc_nodeset[0]))){
|
||||
if ((str = strdup(b)) == NULL){
|
||||
clicon_err(OE_XML, errno, "strdup");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
else
|
||||
if ((str = strdup("")) == NULL){
|
||||
clicon_err(OE_XML, errno, "strdup");
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
case XT_BOOL:
|
||||
if ((str = strdup(xc->xc_bool == 0?"false":"true")) == NULL){
|
||||
clicon_err(OE_XML, errno, "strdup");
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
case XT_NUMBER:
|
||||
len = snprintf(NULL, 0, "%0lf", xc->xc_number);
|
||||
len++;
|
||||
if ((str = malloc(len)) == NULL){
|
||||
clicon_err(OE_XML, errno, "malloc");
|
||||
goto done;
|
||||
}
|
||||
snprintf(str, len, "%0lf", xc->xc_number);
|
||||
break;
|
||||
case XT_STRING:
|
||||
if ((str = strdup(xc->xc_string)) == NULL){
|
||||
clicon_err(OE_XML, errno, "strdup");
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
}
|
||||
*str0 = str;
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Convert xpath context to number according to number() function in XPATH spec
|
||||
* @param[in] xc XPATH context
|
||||
* @param[out] n0 Floating point or NAN
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
int
|
||||
ctx2number(xp_ctx *xc,
|
||||
double *n0)
|
||||
{
|
||||
int retval = -1;
|
||||
char *str = NULL;
|
||||
double n;
|
||||
|
||||
switch (xc->xc_type){
|
||||
case XT_NODESET:
|
||||
if (ctx2string(xc, &str) < 0)
|
||||
goto done;
|
||||
if (sscanf(str, "%lf",&n) != 1)
|
||||
n = NAN;
|
||||
break;
|
||||
case XT_BOOL:
|
||||
n = (double)xc->xc_bool;
|
||||
break;
|
||||
case XT_NUMBER:
|
||||
n = xc->xc_number;
|
||||
break;
|
||||
case XT_STRING:
|
||||
if (sscanf(xc->xc_string, "%lf",&n) != 1)
|
||||
n = NAN;
|
||||
break;
|
||||
}
|
||||
*n0 = n;
|
||||
retval = 0;
|
||||
done:
|
||||
if (str)
|
||||
free(str);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Replace a nodeset of a XPATH context with a new nodeset
|
||||
*/
|
||||
int
|
||||
ctx_nodeset_replace(xp_ctx *xc,
|
||||
cxobj **vec,
|
||||
size_t veclen)
|
||||
{
|
||||
if (xc->xc_nodeset)
|
||||
free(xc->xc_nodeset);
|
||||
xc->xc_nodeset = vec;
|
||||
xc->xc_size = veclen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
101
lib/src/clixon_xpath_parse.h
Normal file
101
lib/src/clixon_xpath_parse.h
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright (C) 2009-2018 Olof Hagsand and Benny Holmgren
|
||||
|
||||
This file is part of CLIXON.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Alternatively, the contents of this file may be used under the terms of
|
||||
the GNU General Public License Version 3 or later (the "GPL"),
|
||||
in which case the provisions of the GPL are applicable instead
|
||||
of those above. If you wish to allow use of your version of this file only
|
||||
under the terms of the GPL, and not to allow others to
|
||||
use your version of this file under the terms of Apache License version 2,
|
||||
indicate your decision by deleting the provisions above and replace them with
|
||||
the notice and other provisions required by the GPL. If you do not delete
|
||||
the provisions above, a recipient may use your version of this file under
|
||||
the terms of any one of the Apache License version 2 or the GPL.
|
||||
|
||||
***** END LICENSE BLOCK *****
|
||||
|
||||
*/
|
||||
#ifndef _CLIXON_XPATH_PARSE_H_
|
||||
#define _CLIXON_XPATH_PARSE_H_
|
||||
|
||||
/*
|
||||
* Types
|
||||
*/
|
||||
/* used as non-terminal type in yacc rules */
|
||||
enum xp_type{
|
||||
XP_EXP,
|
||||
XP_AND,
|
||||
XP_RELEX,
|
||||
XP_ADD,
|
||||
XP_UNION,
|
||||
XP_PATHEXPR,
|
||||
XP_LOCPATH,
|
||||
XP_ABSPATH,
|
||||
XP_RELLOCPATH,
|
||||
XP_STEP,
|
||||
XP_NODE,
|
||||
XP_NODE_FN,
|
||||
XP_PRED,
|
||||
XP_PRI0,
|
||||
XP_PRIME_NR,
|
||||
XP_PRIME_STR,
|
||||
XP_PRIME_FN,
|
||||
};
|
||||
|
||||
/*! XPATH Parsing generates a tree of nodes that is later traversed
|
||||
*/
|
||||
struct xpath_tree{
|
||||
enum xp_type xs_type;
|
||||
int xs_int;
|
||||
double xs_double;
|
||||
char *xs_s0;
|
||||
char *xs_s1;
|
||||
struct xpath_tree *xs_c0; /* child 0 */
|
||||
struct xpath_tree *xs_c1; /* child 1 */
|
||||
};
|
||||
typedef struct xpath_tree xpath_tree;
|
||||
|
||||
struct clicon_xpath_yacc_arg{ /* XXX: mostly unrelevant */
|
||||
const char *xy_name; /* Name of syntax (for error string) */
|
||||
int xy_linenum; /* Number of \n in parsed buffer */
|
||||
char *xy_parse_string; /* original (copy of) parse string */
|
||||
void *xy_lexbuf; /* internal parse buffer from lex */
|
||||
xpath_tree *xy_top;
|
||||
};
|
||||
|
||||
/*
|
||||
* Variables
|
||||
*/
|
||||
extern char *clixon_xpath_parsetext;
|
||||
|
||||
/*
|
||||
* Prototypes
|
||||
*/
|
||||
int xpath_scan_init(struct clicon_xpath_yacc_arg *jy);
|
||||
int xpath_scan_exit(struct clicon_xpath_yacc_arg *jy);
|
||||
|
||||
int xpath_parse_init(struct clicon_xpath_yacc_arg *jy);
|
||||
int xpath_parse_exit(struct clicon_xpath_yacc_arg *jy);
|
||||
|
||||
int clixon_xpath_parselex(void *);
|
||||
int clixon_xpath_parseparse(void *);
|
||||
void clixon_xpath_parseerror(void *, char*);
|
||||
|
||||
#endif /* _CLIXON_XPATH_PARSE_H_ */
|
||||
174
lib/src/clixon_xpath_parse.l
Normal file
174
lib/src/clixon_xpath_parse.l
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright (C) 2009-2018 Olof Hagsand and Benny Holmgren
|
||||
|
||||
This file is part of CLIXON.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Alternatively, the contents of this file may be used under the terms of
|
||||
the GNU General Public License Version 3 or later (the "GPL"),
|
||||
in which case the provisions of the GPL are applicable instead
|
||||
of those above. If you wish to allow use of your version of this file only
|
||||
under the terms of the GPL, and not to allow others to
|
||||
use your version of this file under the terms of Apache License version 2,
|
||||
indicate your decision by deleting the provisions above and replace them with
|
||||
the notice and other provisions required by the GPL. If you do not delete
|
||||
the provisions above, a recipient may use your version of this file under
|
||||
the terms of any one of the Apache License version 2 or the GPL.
|
||||
|
||||
***** END LICENSE BLOCK *****
|
||||
|
||||
*/
|
||||
|
||||
%{
|
||||
|
||||
#include "clixon_config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "clixon_xpath_parse.tab.h" /* generated */
|
||||
|
||||
#include <cligen/cligen.h>
|
||||
|
||||
#include "clixon_queue.h"
|
||||
#include "clixon_hash.h"
|
||||
#include "clixon_handle.h"
|
||||
#include "clixon_yang.h"
|
||||
#include "clixon_log.h"
|
||||
#include "clixon_string.h"
|
||||
#include "clixon_xml.h"
|
||||
#include "clixon_xpath_ctx.h"
|
||||
#include "clixon_xpath.h"
|
||||
#include "clixon_xpath_parse.h"
|
||||
|
||||
/* Redefine main lex function so that you can send arguments to it: _yy is added to arg list */
|
||||
#define YY_DECL int clixon_xpath_parselex(void *_yy)
|
||||
|
||||
/* Dont use input function (use user-buffer) */
|
||||
#define YY_NO_INPUT
|
||||
|
||||
/* typecast macro */
|
||||
#define _XY ((struct clicon_xpath_yacc_arg *)_yy)
|
||||
|
||||
#define MAXBUF 4*4*64*1024
|
||||
|
||||
#undef clixon_xpath_parsewrap
|
||||
int
|
||||
clixon_xpath_parsewrap(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
%}
|
||||
|
||||
digit [0-9]
|
||||
integer {digit}+
|
||||
real ({digit}+[.]{digit}*)|({digit}*[.]{digit}+)
|
||||
|
||||
%x TOKEN
|
||||
%s QLITERAL
|
||||
%s ALITERAL
|
||||
|
||||
%%
|
||||
<TOKEN>[ \t]
|
||||
<TOKEN>\n { _XY->xy_linenum++; }
|
||||
<TOKEN>\r { }
|
||||
<TOKEN><<EOF>> { return X_EOF; }
|
||||
<TOKEN>".." { return DOUBLEDOT; }
|
||||
<TOKEN>[()\[\]\.@,/:|] { return *yytext; }
|
||||
<TOKEN>"::" { return DOUBLECOLON; }
|
||||
<TOKEN>and { clixon_xpath_parselval.intval = clicon_str2int(xpopmap, yytext); return LOGOP; }
|
||||
<TOKEN>or { clixon_xpath_parselval.intval = clicon_str2int(xpopmap, yytext); return LOGOP; }
|
||||
<TOKEN>div { clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext); return ADDOP; }
|
||||
<TOKEN>mod { clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext); return ADDOP; }
|
||||
<TOKEN>[+*\-] { clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext); return ADDOP; }
|
||||
<TOKEN>\? { return *yytext; }
|
||||
<TOKEN>"//" { return DOUBLESLASH; }
|
||||
<TOKEN>"!=" { clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext); return RELOP; }
|
||||
<TOKEN>">=" { clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext);return RELOP; }
|
||||
<TOKEN>"<=" { clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext);return RELOP; }
|
||||
<TOKEN>[<>=] { clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext);return RELOP; }
|
||||
<TOKEN>last { clixon_xpath_parselval.string = strdup(yytext); return FUNCTIONNAME; }
|
||||
<TOKEN>position { clixon_xpath_parselval.string = strdup(yytext); return FUNCTIONNAME; }
|
||||
<TOKEN>count { clixon_xpath_parselval.string = strdup(yytext); return FUNCTIONNAME; }
|
||||
<TOKEN>ancestor { clixon_xpath_parselval.intval = A_ANCESTOR; return AXISNAME; }
|
||||
<TOKEN>ancestor-or-self { clixon_xpath_parselval.intval = A_ANCESTOR_OR_SELF; return AXISNAME; }
|
||||
<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_PRECEEDING; return AXISNAME; }
|
||||
<TOKEN>preceding-sibling { clixon_xpath_parselval.intval = A_PRECEEDING_SIBLING; return AXISNAME; }
|
||||
<TOKEN>self { clixon_xpath_parselval.intval = A_SELF; return AXISNAME; }
|
||||
<TOKEN>current { clixon_xpath_parselval.string = strdup(yytext); return NODETYPE; }
|
||||
<TOKEN>comment { clixon_xpath_parselval.string = strdup(yytext); return NODETYPE; }
|
||||
<TOKEN>text { clixon_xpath_parselval.string = strdup(yytext); return NODETYPE; }
|
||||
<TOKEN>processing-instructions { clixon_xpath_parselval.string = strdup(yytext); return NODETYPE; }
|
||||
<TOKEN>node { clixon_xpath_parselval.string = strdup(yytext); return NODETYPE; }
|
||||
<TOKEN>\" { BEGIN(QLITERAL); return QUOTE; }
|
||||
<TOKEN>\' { BEGIN(ALITERAL); return APOST; }
|
||||
<TOKEN>\-?({integer}|{real}) { sscanf(yytext,"%lf",&clixon_xpath_parselval.dval); return NUMBER;}
|
||||
<TOKEN>[0-9A-Za-z_\-]+ { clixon_xpath_parselval.string = strdup(yytext);
|
||||
return NAME; /* rather be catch-all */
|
||||
}
|
||||
<TOKEN>. { fprintf(stderr,"LEXICAL ERROR\n"); return -1; }
|
||||
<QLITERAL>\" { BEGIN(TOKEN); return QUOTE; }
|
||||
<QLITERAL>. { clixon_xpath_parselval.string = strdup(yytext);
|
||||
return CHAR;}
|
||||
<ALITERAL>\' { BEGIN(TOKEN); return APOST; }
|
||||
<ALITERAL>. { clixon_xpath_parselval.string = strdup(yytext);
|
||||
return CHAR;}
|
||||
|
||||
%%
|
||||
|
||||
|
||||
/*! Initialize scanner.
|
||||
*/
|
||||
int
|
||||
xpath_scan_init(struct clicon_xpath_yacc_arg *xy)
|
||||
{
|
||||
BEGIN(TOKEN);
|
||||
xy->xy_lexbuf = yy_scan_string (xy->xy_parse_string);
|
||||
#if 1 /* XXX: just to use unput to avoid warning */
|
||||
if (0)
|
||||
yyunput(0, "");
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* free buffers
|
||||
* Even within Flex version 2.5 (this is assumed), freeing buffers is different.
|
||||
*/
|
||||
int
|
||||
xpath_scan_exit(struct clicon_xpath_yacc_arg *xy)
|
||||
{
|
||||
yy_delete_buffer(xy->xy_lexbuf);
|
||||
clixon_xpath_parselex_destroy(); /* modern */
|
||||
return 0;
|
||||
}
|
||||
|
||||
289
lib/src/clixon_xpath_parse.y
Normal file
289
lib/src/clixon_xpath_parse.y
Normal file
|
|
@ -0,0 +1,289 @@
|
|||
/*
|
||||
*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright (C) 2009-2018 Olof Hagsand and Benny Holmgren
|
||||
|
||||
This file is part of CLIXON.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Alternatively, the contents of this file may be used under the terms of
|
||||
the GNU General Public License Version 3 or later (the "GPL"),
|
||||
in which case the provisions of the GPL are applicable instead
|
||||
of those above. If you wish to allow use of your version of this file only
|
||||
under the terms of the GPL, and not to allow others to
|
||||
use your version of this file under the terms of Apache License version 2,
|
||||
indicate your decision by deleting the provisions above and replace them with
|
||||
the notice and other provisions required by the GPL. If you do not delete
|
||||
the provisions above, a recipient may use your version of this file under
|
||||
the terms of any one of the Apache License version 2 or the GPL.
|
||||
|
||||
***** END LICENSE BLOCK *****
|
||||
|
||||
* XPATH Parser
|
||||
* From https://www.w3.org/TR/xpath-10/
|
||||
* The primary syntactic construct in XPath is the expression.
|
||||
* An expression matches the production Expr
|
||||
* see https://www.w3.org/TR/xpath-10/#NT-Expr)
|
||||
* Lexical structure is defined by ExprToken, see
|
||||
* see https://www.w3.org/TR/xpath-10/#exprlex
|
||||
*/
|
||||
|
||||
%start start
|
||||
|
||||
%union {
|
||||
int intval;
|
||||
double dval;
|
||||
char *string;
|
||||
void *stack; /* xpath_tree */
|
||||
}
|
||||
|
||||
%token <intval> AXISNAME
|
||||
%token <intval> LOGOP
|
||||
%token <intval> ADDOP
|
||||
%token <intval> RELOP
|
||||
|
||||
%token <dval> NUMBER
|
||||
|
||||
%token <string> X_EOF
|
||||
%token <string> QUOTE
|
||||
%token <string> APOST
|
||||
%token <string> CHAR
|
||||
%token <string> NAME
|
||||
%token <string> NODETYPE
|
||||
%token <string> DOUBLEDOT
|
||||
%token <string> DOUBLECOLON
|
||||
%token <string> DOUBLESLASH
|
||||
%token <string> FUNCTIONNAME
|
||||
|
||||
%type <intval> axisspec
|
||||
|
||||
%type <string> string
|
||||
%type <stack> expr
|
||||
%type <stack> andexpr
|
||||
%type <stack> relexpr
|
||||
%type <stack> addexpr
|
||||
%type <stack> unionexpr
|
||||
%type <stack> pathexpr
|
||||
%type <stack> locationpath
|
||||
%type <stack> abslocpath
|
||||
%type <stack> rellocpath
|
||||
%type <stack> step
|
||||
%type <stack> nodetest
|
||||
%type <stack> predicates
|
||||
%type <stack> primaryexpr
|
||||
|
||||
%lex-param {void *_xy} /* Add this argument to parse() and lex() function */
|
||||
%parse-param {void *_xy}
|
||||
|
||||
%{
|
||||
/* Here starts user C-code */
|
||||
|
||||
/* typecast macro */
|
||||
#define _XY ((struct clicon_xpath_yacc_arg *)_xy)
|
||||
|
||||
#define _YYERROR(msg) {clicon_err(OE_XML, 0, "YYERROR %s '%s' %d", (msg), clixon_xpath_parsetext, _XY->xy_linenum); YYERROR;}
|
||||
|
||||
/* add _yy to error paramaters */
|
||||
#define YY_(msgid) msgid
|
||||
|
||||
#include "clixon_config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <fnmatch.h>
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#include <cligen/cligen.h>
|
||||
|
||||
#include "clixon_err.h"
|
||||
#include "clixon_log.h"
|
||||
#include "clixon_queue.h"
|
||||
#include "clixon_string.h"
|
||||
#include "clixon_hash.h"
|
||||
#include "clixon_handle.h"
|
||||
#include "clixon_yang.h"
|
||||
#include "clixon_xml.h"
|
||||
#include "clixon_xpath_ctx.h"
|
||||
#include "clixon_xpath.h"
|
||||
|
||||
#include "clixon_xpath_parse.h"
|
||||
|
||||
extern int clixon_xpath_parseget_lineno (void);
|
||||
|
||||
/*
|
||||
also called from yacc generated code *
|
||||
*/
|
||||
|
||||
void
|
||||
clixon_xpath_parseerror(void *_xy,
|
||||
char *s)
|
||||
{
|
||||
clicon_err(OE_XML, 0, "%s on line %d: %s at or before: '%s'",
|
||||
_XY->xy_name,
|
||||
_XY->xy_linenum ,
|
||||
s,
|
||||
clixon_xpath_parsetext);
|
||||
return;
|
||||
}
|
||||
|
||||
int
|
||||
xpath_parse_init(struct clicon_xpath_yacc_arg *xy)
|
||||
{
|
||||
// clicon_debug_init(2, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
xpath_parse_exit(struct clicon_xpath_yacc_arg *xy)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static xpath_tree *
|
||||
xp_new(enum xp_type type,
|
||||
int i0,
|
||||
double d0,
|
||||
char *s0,
|
||||
char *s1,
|
||||
xpath_tree *c0,
|
||||
xpath_tree *c1)
|
||||
{
|
||||
xpath_tree *xs = NULL;
|
||||
|
||||
if ((xs = malloc(sizeof(xpath_tree))) == NULL){
|
||||
clicon_err(OE_XML, errno, "malloc");
|
||||
goto done;
|
||||
}
|
||||
memset(xs, 0, sizeof(*xs));
|
||||
xs->xs_type = type;
|
||||
xs->xs_int = i0;
|
||||
xs->xs_double = d0;
|
||||
xs->xs_s0 = s0;
|
||||
xs->xs_s1 = s1;
|
||||
xs->xs_c0 = c0;
|
||||
xs->xs_c1 = c1;
|
||||
done:
|
||||
return xs;
|
||||
}
|
||||
|
||||
%}
|
||||
|
||||
%%
|
||||
|
||||
/*
|
||||
*/
|
||||
|
||||
start : expr X_EOF { _XY->xy_top=$1;clicon_debug(1,"start->expr"); YYACCEPT; }
|
||||
| locationpath X_EOF { _XY->xy_top=$1;clicon_debug(1,"start->locationpath"); YYACCEPT; }
|
||||
;
|
||||
|
||||
expr : expr LOGOP andexpr { $$=xp_new(XP_EXP,$2,0.0,NULL,NULL,$1, $3);clicon_debug(1,"expr->expr or andexpr"); }
|
||||
| andexpr { $$=xp_new(XP_EXP,A_NAN,0.0,NULL,NULL,$1, NULL);clicon_debug(1,"expr-> andexpr"); }
|
||||
;
|
||||
|
||||
andexpr : andexpr LOGOP relexpr { $$=xp_new(XP_AND,$2,0.0,NULL,NULL,$1, $3);clicon_debug(1,"andexpr-> andexpr and relexpr"); }
|
||||
| relexpr { $$=xp_new(XP_AND,A_NAN,0.0,NULL,NULL,$1, NULL);clicon_debug(1,"andexpr-> relexpr"); }
|
||||
;
|
||||
|
||||
relexpr : relexpr RELOP addexpr { $$=xp_new(XP_RELEX,$2,0.0,NULL,NULL,$1, $3);clicon_debug(1,"relexpr-> relexpr relop addexpr"); }
|
||||
| addexpr { $$=xp_new(XP_RELEX,A_NAN,0.0,NULL,NULL,$1, NULL);clicon_debug(1,"relexpr-> addexpr"); }
|
||||
;
|
||||
|
||||
addexpr : addexpr ADDOP unionexpr { $$=xp_new(XP_ADD,$2,0.0,NULL,NULL,$1, $3);clicon_debug(1,"addexpr-> addexpr ADDOP unionexpr"); }
|
||||
| unionexpr { $$=xp_new(XP_ADD,A_NAN,0.0,NULL,NULL,$1, NULL);clicon_debug(1,"addexpr-> unionexpr"); }
|
||||
;
|
||||
|
||||
/* node-set */
|
||||
unionexpr : unionexpr '|' pathexpr { $$=xp_new(XP_UNION,A_NAN,0.0,NULL,NULL,$1, $3);clicon_debug(1,"unionexpr-> unionexpr | pathexpr"); }
|
||||
| pathexpr { $$=xp_new(XP_UNION,A_NAN,0.0,NULL,NULL,$1, NULL);clicon_debug(1,"unionexpr-> pathexpr"); }
|
||||
;
|
||||
|
||||
pathexpr : locationpath { $$=xp_new(XP_PATHEXPR,A_NAN,0.0,NULL,NULL,$1, NULL);clicon_debug(1,"pathexpr-> locationpath"); }
|
||||
| primaryexpr { $$=xp_new(XP_PATHEXPR,A_NAN,0.0,NULL,NULL,$1, NULL);clicon_debug(1,"pathexpr-> primaryexpr"); }
|
||||
;
|
||||
|
||||
/* location path returns a node-set */
|
||||
locationpath : rellocpath { $$=xp_new(XP_LOCPATH,A_NAN,0.0,NULL,NULL,$1, NULL); clicon_debug(1,"locationpath-> rellocpath"); }
|
||||
| abslocpath { $$=xp_new(XP_LOCPATH,A_NAN,0.0,NULL,NULL,$1, NULL); clicon_debug(1,"locationpath-> abslocpath"); }
|
||||
;
|
||||
|
||||
abslocpath : '/' { $$=xp_new(XP_ABSPATH,A_ROOT,0.0,NULL,NULL,NULL, NULL);clicon_debug(1,"abslocpath-> /"); }
|
||||
| '/' rellocpath { $$=xp_new(XP_ABSPATH,A_ROOT,0.0,NULL,NULL,$2, NULL);clicon_debug(1,"abslocpath->/ rellocpath");}
|
||||
/* // is short for /descendant-or-self::node()/ */
|
||||
| DOUBLESLASH rellocpath {$$=xp_new(XP_ABSPATH,A_DESCENDANT_OR_SELF,0.0,NULL,NULL,$2, NULL); clicon_debug(1,"abslocpath-> // rellocpath"); }
|
||||
;
|
||||
|
||||
rellocpath : step { $$=xp_new(XP_RELLOCPATH,A_NAN,0.0,NULL,NULL,$1, NULL); clicon_debug(1,"rellocpath-> step"); }
|
||||
| rellocpath '/' step { $$=xp_new(XP_RELLOCPATH,A_NAN,0.0,NULL,NULL,$1, $3);clicon_debug(1,"rellocpath-> rellocpath / step"); }
|
||||
| rellocpath DOUBLESLASH step { $$=xp_new(XP_RELLOCPATH,A_DESCENDANT_OR_SELF,0.0,NULL,NULL,$1, $3); clicon_debug(1,"rellocpath-> rellocpath // step"); }
|
||||
;
|
||||
|
||||
step : axisspec nodetest predicates {$$=xp_new(XP_STEP,$1,0.0, NULL, NULL, $2, $3);clicon_debug(1,"step->axisspec(%d) nodetest", $1); }
|
||||
| '.' { $$=xp_new(XP_STEP,A_SELF, 0.0,NULL, NULL, NULL, NULL); clicon_debug(1,"step-> ."); }
|
||||
| DOUBLEDOT { $$=xp_new(XP_STEP, A_PARENT, 0.0,NULL, NULL, NULL, NULL); clicon_debug(1,"step-> .."); }
|
||||
;
|
||||
|
||||
axisspec : AXISNAME DOUBLECOLON { clicon_debug(1,"axisspec-> AXISNAME(%d) ::", $1); $$=$1;}
|
||||
| '@' { $$=A_ATTRIBUTE; clicon_debug(1,"axisspec-> @"); }
|
||||
| { clicon_debug(1,"axisspec-> "); $$=A_CHILD;}
|
||||
;
|
||||
|
||||
nodetest : '*' { $$=xp_new(XP_NODE,A_NAN,0.0, NULL, NULL, NULL, NULL); clicon_debug(1,"nodetest-> *"); }
|
||||
| NAME { $$=xp_new(XP_NODE,A_NAN,0.0, NULL, $1, NULL, NULL); clicon_debug(1,"nodetest-> name(%s)",$1); }
|
||||
| NAME ':' NAME { $$=xp_new(XP_NODE,A_NAN,0.0, $1, $3, NULL, NULL);clicon_debug(1,"nodetest-> name(%s) : name(%s)", $1, $3); }
|
||||
| NAME ':' '*' { $$=xp_new(XP_NODE,A_NAN,0.0, $1, NULL, NULL, NULL);clicon_debug(1,"nodetest-> name(%s) : *", $1); }
|
||||
| NODETYPE '(' ')' { $$=xp_new(XP_NODE_FN,A_NAN,0.0, $1, NULL, NULL, NULL); clicon_debug(1,"nodetest-> nodetype()"); }
|
||||
;
|
||||
|
||||
/* evaluates to boolean */
|
||||
predicates : predicates '[' expr ']' { $$=xp_new(XP_PRED,A_NAN,0.0, NULL, NULL, $1, $3); clicon_debug(1,"predicates-> [ expr ]"); }
|
||||
| { $$=xp_new(XP_PRED,A_NAN,0.0, NULL, NULL, NULL, NULL); clicon_debug(1,"predicates->"); }
|
||||
;
|
||||
|
||||
primaryexpr : '(' expr ')' { $$=xp_new(XP_PRI0,A_NAN,0.0, NULL, NULL, $2, NULL); clicon_debug(1,"primaryexpr-> ( expr )"); }
|
||||
| NUMBER { $$=xp_new(XP_PRIME_NR,A_NAN, $1, NULL, NULL, NULL, NULL);clicon_debug(1,"primaryexpr-> NUMBER(%lf)", $1); }
|
||||
| QUOTE string QUOTE { $$=xp_new(XP_PRIME_STR,A_NAN,0.0, $2, NULL, NULL, NULL);clicon_debug(1,"primaryexpr-> \" string \""); }
|
||||
| QUOTE QUOTE { $$=xp_new(XP_PRIME_STR,A_NAN,0.0, NULL, NULL, NULL, NULL);clicon_debug(1,"primaryexpr-> \" \""); }
|
||||
| APOST string APOST { $$=xp_new(XP_PRIME_STR,A_NAN,0.0, $2, NULL, NULL, NULL);clicon_debug(1,"primaryexpr-> ' string '"); }
|
||||
| APOST APOST { $$=xp_new(XP_PRIME_STR,A_NAN,0.0, NULL, NULL, NULL, NULL);clicon_debug(1,"primaryexpr-> ' '"); }
|
||||
| FUNCTIONNAME '(' ')' { $$=xp_new(XP_PRIME_FN,A_NAN,0.0, $1, NULL, NULL, NULL);clicon_debug(1,"primaryexpr-> functionname ( arguments )"); }
|
||||
;
|
||||
|
||||
/* XXX Adding this between FUNCTIONNAME() breaks parser,..
|
||||
arguments : arguments expr { clicon_debug(1,"arguments-> arguments expr"); }
|
||||
| { clicon_debug(1,"arguments-> "); }
|
||||
;
|
||||
*/
|
||||
string : string CHAR {
|
||||
int len = strlen($1);
|
||||
$$ = realloc($1, len+strlen($2) + 1);
|
||||
sprintf($$+len, "%s", $2);
|
||||
free($2);
|
||||
clicon_debug(1,"string-> string CHAR");
|
||||
}
|
||||
| CHAR { clicon_debug(1,"string-> "); }
|
||||
;
|
||||
|
||||
|
||||
%%
|
||||
|
||||
|
|
@ -35,54 +35,12 @@
|
|||
* NOTE: there is a main function at the end of this file where you can test out
|
||||
* different xpath expressions.
|
||||
* Look at the end of the file for a test unit program
|
||||
*/
|
||||
/*
|
||||
See https://www.w3.org/TR/xpath/
|
||||
|
||||
Implementation of a limited xslt xpath syntax. Some examples. Given the following
|
||||
xml tree:
|
||||
<aaa>
|
||||
<bbb x="hello"><ccc>42</ccc></bbb>
|
||||
<bbb x="bye"><ccc>99</ccc></bbb>
|
||||
<ddd><ccc>22</ccc></ddd>
|
||||
</aaa>
|
||||
|
||||
With the following xpath examples. There are some diffs and many limitations compared
|
||||
to the xml standards:
|
||||
/ whole tree <aaa>...</aaa>
|
||||
/bbb
|
||||
/aaa/bbb <bbb x="hello"><ccc>42</ccc></bbb>
|
||||
<bbb x="bye"><ccc>99</ccc></bbb>
|
||||
//bbb as above
|
||||
//b?b as above
|
||||
//b\* as above
|
||||
//b\*\/ccc <ccc>42</ccc>
|
||||
<ccc>99</ccc>
|
||||
//\*\/ccc <ccc>42</ccc>
|
||||
<ccc>99</ccc>
|
||||
<ccc>22</ccc>
|
||||
-- //bbb@x x="hello"
|
||||
//bbb[@x] <bbb x="hello"><ccc>42</ccc></bbb>
|
||||
<bbb x="bye"><ccc>99</ccc></bbb>
|
||||
//bbb[@x=hello] <bbb x="hello"><ccc>42</ccc></bbb>
|
||||
//bbb[@x="hello"] as above
|
||||
//bbb[0] <bbb x="hello"><ccc>42</ccc></bbb>
|
||||
//bbb[ccc=99] <bbb x="bye"><ccc>99</ccc></bbb>
|
||||
--- //\*\/[ccc=99] same as above
|
||||
'//bbb | //ddd' <bbb><ccc>42</ccc></bbb>
|
||||
<bbb x="hello"><ccc>99</ccc></bbb>
|
||||
<ddd><ccc>22</ccc></ddd> (NB spaces)
|
||||
etc
|
||||
For xpath v1.0 see http://www.w3.org/TR/xpath/
|
||||
record[name=c][time=d]
|
||||
in
|
||||
<record>
|
||||
<name>c</name>
|
||||
<time>d</time>
|
||||
<userid>45654df4-2292-45d3-9ca5-ee72452568a8</userid>
|
||||
</record>
|
||||
|
||||
The code is implemented according to XPATH 1.0:
|
||||
https://www.w3.org/TR/xpath-10/
|
||||
|
||||
The primary syntactic construct in XPath is the expression. An expression matches
|
||||
the production Expr (see https://www.w3.org/TR/xpath-10/#NT-Expr)
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
|
@ -95,6 +53,7 @@ in
|
|||
#include <assert.h>
|
||||
#include <syslog.h>
|
||||
#include <fcntl.h>
|
||||
#include <math.h>
|
||||
|
||||
/* cligen */
|
||||
#include <cligen/cligen.h>
|
||||
|
|
@ -108,14 +67,18 @@ in
|
|||
#include "clixon_handle.h"
|
||||
#include "clixon_yang.h"
|
||||
#include "clixon_xml.h"
|
||||
#include "clixon_xpath_ctx.h"
|
||||
#include "clixon_xpath.h"
|
||||
#include "clixon_xsl.h"
|
||||
|
||||
|
||||
/* Constants */
|
||||
#define XPATH_VEC_START 128
|
||||
|
||||
/*
|
||||
* Types
|
||||
*/
|
||||
|
||||
struct searchvec{
|
||||
cxobj **sv_v0; /* here is result */
|
||||
int sv_v0len;
|
||||
|
|
@ -127,13 +90,22 @@ typedef struct searchvec searchvec;
|
|||
|
||||
/* Local types
|
||||
*/
|
||||
enum axis_type{
|
||||
A_SELF,
|
||||
A_CHILD,
|
||||
A_PARENT,
|
||||
A_ROOT,
|
||||
A_ANCESTOR,
|
||||
A_DESCENDANT_OR_SELF, /* actually descendant-or-self */
|
||||
|
||||
struct xpath_predicate{
|
||||
struct xpath_predicate *xp_next;
|
||||
char *xp_expr;
|
||||
};
|
||||
|
||||
/* XPATH Axis according to https://www.w3.org/TR/xpath-10/#NT-Step
|
||||
* Axis ::= AxisSpecifier NodeTest Predicate*
|
||||
* Eg "child::
|
||||
*/
|
||||
struct xpath_element{
|
||||
struct xpath_element *xe_next;
|
||||
enum axis_type xe_type;
|
||||
char *xe_prefix; /* eg for namespaces */
|
||||
char *xe_str; /* eg for child */
|
||||
struct xpath_predicate *xe_predicate; /* eg within [] */
|
||||
};
|
||||
|
||||
/* Mapping between axis type string <--> int */
|
||||
|
|
@ -147,23 +119,12 @@ static const map_str2int axismap[] = {
|
|||
{NULL, -1}
|
||||
};
|
||||
|
||||
struct xpath_predicate{
|
||||
struct xpath_predicate *xp_next;
|
||||
char *xp_expr;
|
||||
};
|
||||
|
||||
struct xpath_element{
|
||||
struct xpath_element *xe_next;
|
||||
enum axis_type xe_type;
|
||||
char *xe_prefix; /* eg for namespaces */
|
||||
char *xe_str; /* eg for child */
|
||||
struct xpath_predicate *xe_predicate; /* eg within [] */
|
||||
};
|
||||
|
||||
static int xpath_split(char *xpathstr, char **pathexpr);
|
||||
|
||||
/*! Print xpath structure for debug */
|
||||
static int
|
||||
xpath_print(FILE *f, struct xpath_element *xplist)
|
||||
xpath_print(FILE *f,
|
||||
struct xpath_element *xplist)
|
||||
{
|
||||
struct xpath_element *xe;
|
||||
struct xpath_predicate *xp;
|
||||
|
|
@ -217,6 +178,11 @@ xpath_parse_predicate(struct xpath_element *xe,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! XPATH parse, create new child element
|
||||
* @param[in] atype Axis type, see https://www.w3.org/TR/xpath-10/#axes
|
||||
* @param[in] str
|
||||
* @param[out] xpnext
|
||||
*/
|
||||
static int
|
||||
xpath_element_new(enum axis_type atype,
|
||||
char *str,
|
||||
|
|
@ -309,8 +275,17 @@ xpath_free(struct xpath_element *xplist)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* // is short for /descendant-or-self::node()/
|
||||
/*! Parse xpath to xpath_element structure
|
||||
|
||||
*
|
||||
* [1] LocationPath ::= RelativeLocationPath
|
||||
* | AbsoluteLocationPath
|
||||
* [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
|
||||
* | AbbreviatedAbsoluteLocationPath
|
||||
* [3] RelativeLocationPath ::= Step
|
||||
| RelativeLocationPath '/' Step
|
||||
| AbbreviatedRelativeLocationPath
|
||||
* @see https://www.w3.org/TR/xpath-10/#NT-LocationPath
|
||||
*/
|
||||
static int
|
||||
xpath_parse(char *xpath,
|
||||
|
|
@ -355,6 +330,7 @@ xpath_parse(char *xpath,
|
|||
}
|
||||
s++;
|
||||
}
|
||||
/* Iterate through steps (s), see https://www.w3.org/TR/xpath-10/#NT-Step */
|
||||
s = s0;
|
||||
for (i=0; i<nvec; i++){
|
||||
if ((i==0 && strcmp(s,"")==0)) /* Initial / or // */
|
||||
|
|
@ -364,21 +340,10 @@ xpath_parse(char *xpath,
|
|||
else if (strncmp(s,"descendant-or-self::", strlen("descendant-or-self::"))==0){
|
||||
xpath_element_new(A_DESCENDANT_OR_SELF, s+strlen("descendant-or-self::"), &xpnext);
|
||||
}
|
||||
#if 1
|
||||
else if (strncmp(s,"..", strlen(".."))==0) /* abbreviatedstep */
|
||||
xpath_element_new(A_PARENT, s+strlen(".."), &xpnext);
|
||||
#else
|
||||
else if (strncmp(s,"..", strlen(s))==0) /* abbreviatedstep */
|
||||
xpath_element_new(A_PARENT, NULL, &xpnext);
|
||||
#endif
|
||||
#if 1 /* Problems with .[userid=1321] */
|
||||
else if (strncmp(s,".", strlen("."))==0)
|
||||
xpath_element_new(A_SELF, s+strlen("."), &xpnext);
|
||||
#else
|
||||
else if (strncmp(s,".", strlen(s))==0) /* abbreviatedstep */
|
||||
xpath_element_new(A_SELF, NULL, &xpnext);
|
||||
#endif
|
||||
|
||||
else if (strncmp(s,"self::", strlen("self::"))==0)
|
||||
xpath_element_new(A_SELF, s+strlen("self::"), &xpnext);
|
||||
|
||||
|
|
@ -406,17 +371,15 @@ xpath_parse(char *xpath,
|
|||
* The xv_* arguments are filled in nodes found earlier.
|
||||
* args:
|
||||
* @param[in] xn_parent Base XML object
|
||||
* @param[in] name shell wildcard pattern to match with node name
|
||||
* @param[in] pattern Shell wildcard pattern to match with node name
|
||||
* @param[in] node_type CX_ELMNT, CX_ATTR or CX_BODY
|
||||
* @param[in,out] vec1 internal buffers with results
|
||||
* @param[in,out] vec0 internal buffers with results
|
||||
* @param[in,out] vec_len internal buffers with length of vec0,vec1
|
||||
* @param[in,out] vec_max internal buffers with max of vec0,vec1
|
||||
* @param[in,out] vec0 Internal buffers with results
|
||||
* @param[in,out] vec0len Internal buffers with length of vec0
|
||||
* returns:
|
||||
* 0 on OK, -1 on error
|
||||
*/
|
||||
static int
|
||||
recursive_find(cxobj *xn,
|
||||
xpath_recursive_find(cxobj *xn,
|
||||
char *pattern,
|
||||
int node_type,
|
||||
uint16_t flags,
|
||||
|
|
@ -439,7 +402,7 @@ recursive_find(cxobj *xn,
|
|||
goto done;
|
||||
// continue; /* Dont go deeper */
|
||||
}
|
||||
if (recursive_find(xsub, pattern, node_type, flags, &vec, &veclen) < 0)
|
||||
if (xpath_recursive_find(xsub, pattern, node_type, flags, &vec, &veclen) < 0)
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
|
|
@ -695,7 +658,7 @@ xpath_find(cxobj *xcur,
|
|||
if (descendants0){
|
||||
for (i=0; i<vec0len; i++){
|
||||
xv = vec0[i];
|
||||
if (recursive_find(xv, xe->xe_str, CX_ELMNT, flags, &vec1, &vec1len) < 0)
|
||||
if (xpath_recursive_find(xv, xe->xe_str, CX_ELMNT, flags, &vec1, &vec1len) < 0)
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
|
@ -738,7 +701,6 @@ xpath_find(cxobj *xcur,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (xp = xe->xe_predicate; xp; xp = xp->xp_next){
|
||||
if (xpath_expr(xcur, xp->xp_expr, flags, &vec0, &vec0len) < 0)
|
||||
goto done;
|
||||
|
|
@ -798,6 +760,7 @@ xpath_split(char *xpathstr,
|
|||
* @param[in] flags if != 0, only match xml nodes matching flags
|
||||
* @param[out] vec2 Result XML node vector
|
||||
* @param[out] vec2len Length of result vector.
|
||||
* @see https://www.w3.org/TR/xpath-10/#NT-LocationPath
|
||||
*/
|
||||
static int
|
||||
xpath_exec(cxobj *xcur,
|
||||
|
|
@ -831,14 +794,20 @@ xpath_exec(cxobj *xcur,
|
|||
* @param[in] xcur xml-tree where to search
|
||||
* @param[in] xpath string with XPATH syntax
|
||||
* @param[in] flags if != 0, only match xml nodes matching flags
|
||||
* @param[in] vec1 vector of XML trees
|
||||
* @param[in] vec1len length of XML trees
|
||||
* @param[out] vec1 vector of XML trees
|
||||
* @param[out] vec1len length of XML trees
|
||||
* For example: xpath = //a | //b.
|
||||
* xpath_first+ splits xpath up in several subcalls
|
||||
* (eg xpath=//a and xpath=//b) and collects the results.
|
||||
* Note: if a match is found in both, two (or more) same results will be
|
||||
* returned.
|
||||
* Note, this could be 'folded' into xpath1 but I judged it too complex.
|
||||
* @see https://www.w3.org/TR/xpath-10/#NT-Expr
|
||||
* An 'Expr' is composed of compositions of and, or, =, +, -, down to:
|
||||
* PathExpr ::= LocationPath
|
||||
* | FilterExpr
|
||||
* | FilterExpr '/' RelativeLocationPath
|
||||
* | FilterExpr '//' RelativeLocationPath
|
||||
*/
|
||||
static int
|
||||
xpath_choice(cxobj *xcur,
|
||||
|
|
@ -848,7 +817,7 @@ xpath_choice(cxobj *xcur,
|
|||
size_t *vec1len)
|
||||
{
|
||||
int retval = -1;
|
||||
char *s0;
|
||||
char *s0 = NULL;
|
||||
char *s1;
|
||||
char *s2;
|
||||
char *xpath;
|
||||
|
|
@ -1020,7 +989,7 @@ xpath_each(cxobj *xcur,
|
|||
/*! A restricted xpath that returns a vector of matches
|
||||
*
|
||||
* See xpath1() on details for subset
|
||||
. * @param[in] xcur xml-tree where to search
|
||||
* @param[in] xcur xml-tree where to search
|
||||
* @param[in] xpath string with XPATH syntax
|
||||
* @param[out] vec vector of xml-trees. Vector must be free():d after use
|
||||
* @param[out] veclen returns length of vector in return value
|
||||
|
|
@ -1052,7 +1021,7 @@ xpath_vec(cxobj *xcur,
|
|||
int retval = -1;
|
||||
va_list ap;
|
||||
size_t len;
|
||||
char *xpath;
|
||||
char *xpath = NULL;
|
||||
|
||||
va_start(ap, veclen);
|
||||
len = vsnprintf(NULL, 0, format, ap);
|
||||
|
|
@ -1079,6 +1048,7 @@ xpath_vec(cxobj *xcur,
|
|||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/* A restricted xpath that returns a vector of matches (only nodes marked with flags)
|
||||
* @param[in] xcur xml-tree where to search
|
||||
* @param[in] xpath string with XPATH syntax
|
||||
|
|
@ -1140,96 +1110,3 @@ xpath_vec_flag(cxobj *xcur,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Turn this on to get an xpath test program
|
||||
* Usage: xpath [<xpath>]
|
||||
* read xpath on first line and xml on rest of lines from input
|
||||
* Example compile:
|
||||
gcc -g -o xpath -I. -I../clixon ./clixon_xsl.c -lclixon -lcligen
|
||||
* Example run:
|
||||
echo "a\n<a><b/></a>" | xpath
|
||||
*/
|
||||
#if 0 /* Test program */
|
||||
|
||||
|
||||
static int
|
||||
usage(char *argv0)
|
||||
{
|
||||
fprintf(stderr, "usage:%s <xml file name>.\n\tInput on stdin\n", argv0);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int retval = -1;
|
||||
int i;
|
||||
cxobj **xv;
|
||||
cxobj *x;
|
||||
cxobj *xn;
|
||||
size_t xlen = 0;
|
||||
int c;
|
||||
int len;
|
||||
char *buf = NULL;
|
||||
char *filename;
|
||||
int fd;
|
||||
|
||||
if (argc != 2){
|
||||
usage(argv[0]);
|
||||
goto done;
|
||||
}
|
||||
filename = argv[1];
|
||||
if ((fd = open(filename, O_RDONLY)) < 0){
|
||||
clicon_err(OE_UNIX, errno, "open(%s)", filename);
|
||||
goto done;
|
||||
}
|
||||
/* Read xpath */
|
||||
len = 1024; /* any number is fine */
|
||||
if ((buf = malloc(len)) == NULL){
|
||||
perror("pt_file malloc");
|
||||
return -1;
|
||||
}
|
||||
memset(buf, 0, len);
|
||||
i = 0;
|
||||
while (1){ /* read the whole file */
|
||||
if ((c = fgetc(stdin)) == EOF)
|
||||
return -1;
|
||||
if (c == '\n')
|
||||
break;
|
||||
if (len==i){
|
||||
if ((buf = realloc(buf, 2*len)) == NULL){
|
||||
fprintf(stderr, "%s: realloc: %s\n", __FUNCTION__, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
memset(buf+len, 0, len);
|
||||
len *= 2;
|
||||
}
|
||||
buf[i++] = (char)(c&0xff);
|
||||
}
|
||||
x = NULL;
|
||||
if (xml_parse_file(fd, "</clicon>", NULL, &x) < 0){
|
||||
fprintf(stderr, "Error: parsing: %s\n", clicon_err_reason);
|
||||
return -1;
|
||||
}
|
||||
close (fd);
|
||||
printf("\n");
|
||||
|
||||
if (xpath_vec(x, "%s", &xv, &xlen, buf) < 0)
|
||||
return -1;
|
||||
if (xv){
|
||||
for (i=0; i<xlen; i++){
|
||||
xn = xv[i];
|
||||
fprintf(stdout, "[%d]:\n", i);
|
||||
clicon_xml2file(stdout, xn, 0, 1);
|
||||
}
|
||||
free(xv);
|
||||
}
|
||||
if (x)
|
||||
xml_free(x);
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
#endif /* Test program */
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ err(){
|
|||
echo -e "\e[0m"
|
||||
echo "$ret"| od -t c > $dir/clixon-ret
|
||||
echo "$expect"| od -t c > $dir/clixon-expect
|
||||
diff $dir/clixon-ret $dir/clixon-expect
|
||||
diff $dir/clixon-expect $dir/clixon-ret
|
||||
|
||||
exit $testnr
|
||||
}
|
||||
|
|
|
|||
151
test/test_xpath.sh
Executable file
151
test/test_xpath.sh
Executable file
|
|
@ -0,0 +1,151 @@
|
|||
#!/bin/bash
|
||||
# Test: XPATH tests
|
||||
PROG=../lib/src/clixon_util_xpath
|
||||
|
||||
# include err() and new() functions and creates $dir
|
||||
. ./lib.sh
|
||||
|
||||
# XML file (alt provide it in stdin after xpath)
|
||||
xml=$dir/xml.xml
|
||||
xml2=$dir/xml2.xml
|
||||
|
||||
cat <<EOF > $xml
|
||||
<aaa>
|
||||
<bbb x="hello"><ccc>42</ccc></bbb>
|
||||
<bbb x="bye"><ccc>99</ccc></bbb>
|
||||
<ddd><ccc>22</ccc></ddd>
|
||||
</aaa>
|
||||
EOF
|
||||
|
||||
cat <<EOF > $xml2
|
||||
<if:interfaces>
|
||||
<if:interface>
|
||||
<if:name>e0</if:name>
|
||||
<ip:ipv6>
|
||||
<ip:enabled>true</ip:enabled>
|
||||
</ip:ipv6>
|
||||
</if:interface>
|
||||
</if:interfaces>
|
||||
<rt:name>e0</rt:name>
|
||||
<address-family>myfamily</address-family>
|
||||
<aaa>
|
||||
<rt:address-family>v6ur:ipv6-unicast</rt:address-family>
|
||||
<name>foo</name>
|
||||
<bbb>
|
||||
<routing>
|
||||
<ribs>
|
||||
<rib>
|
||||
<name>bar</name>
|
||||
<address-family>myfamily</address-family>
|
||||
</rib>
|
||||
</ribs>
|
||||
</routing>
|
||||
<max-rtr-adv-interval>22</max-rtr-adv-interval>
|
||||
<valid-lifetime>99</valid-lifetime>
|
||||
<connection-type>responder-only</connection-type>
|
||||
<type>rt:static</type>
|
||||
<rib-name>bar</rib-name>
|
||||
<here>0</here>
|
||||
<here2><here/></here2>
|
||||
<ifType>ethernet</ifType>
|
||||
<ifMTU>1500</ifMTU>
|
||||
</bbb>
|
||||
</aaa>
|
||||
EOF
|
||||
|
||||
new "xpath /"
|
||||
expecteof "$PROG -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"
|
||||
expecteof "$PROG -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"
|
||||
expecteof "$PROG -f $xml -p /bbb" 0 "" "^nodeset:$"
|
||||
|
||||
new "xpath /aaa/bbb"
|
||||
expecteof "$PROG -f $xml -p /aaa/bbb" 0 "" "^0:<bbb x=\"hello\"><ccc>42</ccc></bbb>
|
||||
1:<bbb x=\"bye\"><ccc>99</ccc></bbb>$"
|
||||
|
||||
new "xpath //bbb"
|
||||
expecteof "$PROG -f $xml -p //bbb" 0 "" "0:<bbb x=\"hello\"><ccc>42</ccc></bbb>
|
||||
1:<bbb x=\"bye\"><ccc>99</ccc></bbb>"
|
||||
|
||||
new "xpath //b?b"
|
||||
#expecteof "$PROG -f $xml" 0 "//b?b" ""
|
||||
|
||||
new "xpath //b*"
|
||||
#expecteof "$PROG -f $xml" 0 "//b*" ""
|
||||
|
||||
new "xpath //b*/ccc"
|
||||
#expecteof "$PROG -f $xml" 0 "//b*/ccc" ""
|
||||
|
||||
new "xpath //bbb[0]"
|
||||
expecteof "$PROG -f $xml -p //bbb[0]" 0 "" "^nodeset:0:<bbb x=\"hello\"><ccc>42</ccc></bbb>$"
|
||||
|
||||
new "xpath //bbb[ccc=99]"
|
||||
expecteof "$PROG -f $xml -p //bbb[ccc=99]" 0 "" "^nodeset:0:<bbb x=\"bye\"><ccc>99</ccc></bbb>$"
|
||||
|
||||
new "xpath ../connection-type = 'responder-only'"
|
||||
expecteof "$PROG -f $xml2 -p ../connection-type='responder-only' -i /aaa/bbb/here" 0 "" "^bool:true$"
|
||||
|
||||
new "xpath ../connection-type = 'no-responder'"
|
||||
expecteof "$PROG -f $xml2 -p ../connection-type='no-responder' -i /aaa/bbb/here" 0 "" "^bool:false$"
|
||||
|
||||
new "xpath . <= 0.75 * ../max-rtr-adv-interval"
|
||||
expecteof "$PROG -f $xml2 -i /aaa/bbb/here" 0 ". <= 0.75 * ../max-rtr-adv-interval" "^bool:true$"
|
||||
|
||||
new "xpath . > 0.75 * ../max-rtr-adv-interval"
|
||||
expecteof "$PROG -f $xml2 -i /aaa/bbb/here" 0 ". > 0.75 * ../max-rtr-adv-interval" "^bool:false$"
|
||||
|
||||
new "xpath . <= ../valid-lifetime"
|
||||
expecteof "$PROG -f $xml2 -i /aaa/bbb/here" 0 ". <= ../valid-lifetime" "^bool:true$"
|
||||
|
||||
new "xpath ../../rt:address-family = 'v6ur:ipv6-unicast'"
|
||||
expecteof "$PROG -f $xml2 -i /aaa/bbb/here" 0 "../../rt:address-family = 'v6ur:ipv6-unicast'" "^bool:true$"
|
||||
|
||||
new "xpath ../../../rt:address-family = 'v6ur:ipv6-unicast'"
|
||||
expecteof "$PROG -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'"
|
||||
expecteof "$PROG -f $xml2" 0 "/if:interfaces/if:interface[if:name=current()/rt:name]/ip:ipv6/ip:enabled='true'" "^bool:true$"
|
||||
|
||||
new "xpath rt:address-family='v6ur:ipv6-unicast'"
|
||||
expecteof "$PROG -f $xml2 -i /aaa" 0 "rt:address-family='v6ur:ipv6-unicast'" "^bool:true$"
|
||||
|
||||
new "xpath ../type='rt:static'"
|
||||
expecteof "$PROG -f $xml2 -i /aaa/bbb/here" 0 "../type='rt:static'" "^bool:true$"
|
||||
|
||||
new "xpath rib-name != ../../name"
|
||||
expecteof "$PROG -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 "$PROG -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 "$PROG -f $xml2 -i /aaa/bbb" 0 "ifType = \"ethernet\" or ifMTU = 1500" "^bool:true$"
|
||||
|
||||
new "xpath ifType != \"ethernet\" or ifMTU = 1500"
|
||||
expecteof "$PROG -f $xml2 -i /aaa/bbb" 0 "ifType != \"ethernet\" or ifMTU = 1500" "^bool:true$"
|
||||
|
||||
new "xpath ifType = \"ethernet\" or ifMTU = 1400"
|
||||
expecteof "$PROG -f $xml2 -i /aaa/bbb" 0 "ifType = \"ethernet\" or ifMTU = 1400" "^bool:true$"
|
||||
|
||||
new "xpath ifType != \"ethernet\" or ifMTU = 1400"
|
||||
expecteof "$PROG -f $xml2 -i /aaa/bbb" 0 "ifType != \"ethernet\" or ifMTU = 1400" "^bool:false$"
|
||||
|
||||
new "xpath ifType = \"ethernet\" and ifMTU = 1500"
|
||||
expecteof "$PROG -f $xml2 -i /aaa/bbb" 0 "ifType = \"ethernet\" and ifMTU = 1500" "^bool:true$"
|
||||
|
||||
new "xpath ifType != \"ethernet\" and ifMTU = 1500"
|
||||
expecteof "$PROG -f $xml2 -i /aaa/bbb" 0 "ifType != \"ethernet\" and ifMTU = 1500" "^bool:false$"
|
||||
|
||||
new "xpath ifType = \"ethernet\" and ifMTU = 1400"
|
||||
expecteof "$PROG -f $xml2 -i /aaa/bbb" 0 "ifType = \"ethernet\" and ifMTU = 1400" "^bool:false$"
|
||||
|
||||
new "xpath ifType != \"ethernet\" and ifMTU = 1400"
|
||||
expecteof "$PROG -f $xml2 -i /aaa/bbb" 0 "ifType != \"ethernet\" and ifMTU = 1400" "^bool:false$"
|
||||
|
||||
new "xpath ifType != \"atm\" or (ifMTU <= 17966 and ifMTU >= 64)"
|
||||
expecteof "$PROG -f $xml2 -i /aaa/bbb" 0 "ifType != \"atm\" or (ifMTU <= 17966 and ifMTU >= 64)" "^bool:true$"
|
||||
|
||||
rm -rf $dir
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
#!/bin/bash
|
||||
# Test: XSL tests
|
||||
PROG=../lib/src/clixon_util_xsl
|
||||
|
||||
# include err() and new() functions and creates $dir
|
||||
. ./lib.sh
|
||||
|
||||
new "xsl test"
|
||||
expecteof $PROG 0 "a
|
||||
<a><b/></a>" "^0:<a><b/></a>$"
|
||||
|
||||
rm -rf $dir
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
#!/bin/bash
|
||||
# Test4: Yang specifics: multi-keys and empty type
|
||||
# Yang specifics: multi-keys and empty type
|
||||
APPNAME=example
|
||||
# include err() and new() functions and creates $dir
|
||||
. ./lib.sh
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue