Added support for XPATH functions:
* `contains`,
* `derived-from` and `derived-from-or-self`
* in particular in augment/when statements as shown in eg RFC 7950.
This commit is contained in:
parent
6d7b76550f
commit
c616aa1569
18 changed files with 800 additions and 48 deletions
295
lib/src/clixon_xpath_function.c
Normal file
295
lib/src/clixon_xpath_function.c
Normal file
|
|
@ -0,0 +1,295 @@
|
|||
/*
|
||||
*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright (C) 2009-2019 Olof Hagsand
|
||||
Copyright (C) 2020 Olof Hagsand and Rubicon Communications, LLC(Netgate)
|
||||
|
||||
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
|
||||
* and rfc 7950
|
||||
*
|
||||
*/
|
||||
#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 <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <syslog.h>
|
||||
#include <fcntl.h>
|
||||
#include <math.h> /* NaN */
|
||||
|
||||
/* 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_options.h"
|
||||
#include "clixon_yang.h"
|
||||
#include "clixon_yang_type.h"
|
||||
#include "clixon_xml.h"
|
||||
#include "clixon_xml_map.h"
|
||||
#include "clixon_yang_module.h"
|
||||
#include "clixon_validate.h"
|
||||
#include "clixon_xpath_ctx.h"
|
||||
#include "clixon_xpath.h"
|
||||
#include "clixon_xpath_eval.h"
|
||||
#include "clixon_xpath_function.h"
|
||||
|
||||
/*! Eval xpath function contains
|
||||
* @param[in] xc Incoming context
|
||||
* @param[in] xs XPATH node tree
|
||||
* @param[in] nsc XML Namespace context
|
||||
* @param[in] localonly Skip prefix and namespace tests (non-standard)
|
||||
* @param[out] xrp Resulting context
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @see https://www.w3.org/TR/xpath-10/#NT-FunctionName 4.2 String Functions
|
||||
*/
|
||||
int
|
||||
xp_function_contains(xp_ctx *xc,
|
||||
struct xpath_tree *xs,
|
||||
cvec *nsc,
|
||||
int localonly,
|
||||
xp_ctx **xrp)
|
||||
{
|
||||
int retval = -1;
|
||||
xp_ctx *xr0 = NULL;
|
||||
xp_ctx *xr1 = NULL;
|
||||
xp_ctx *xr = NULL;
|
||||
char *s0 = NULL;
|
||||
char *s1 = NULL;
|
||||
|
||||
/* contains two arguments in xs: boolean contains(string, string) */
|
||||
if (xp_eval(xc, xs->xs_c0, nsc, localonly, &xr0) < 0)
|
||||
goto done;
|
||||
if (ctx2string(xr0, &s0) < 0)
|
||||
goto done;
|
||||
if (xp_eval(xc, xs->xs_c1, nsc, localonly, &xr1) < 0)
|
||||
goto done;
|
||||
if (ctx2string(xr1, &s1) < 0)
|
||||
goto done;
|
||||
if ((xr = malloc(sizeof(*xr))) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "malloc");
|
||||
goto done;
|
||||
}
|
||||
memset(xr, 0, sizeof(*xr));
|
||||
xr->xc_type = XT_BOOL;
|
||||
xr->xc_bool = (strstr(s0, s1) != NULL);
|
||||
*xrp = xr;
|
||||
xr = NULL;
|
||||
retval = 0;
|
||||
done:
|
||||
if (xr0)
|
||||
ctx_free(xr0);
|
||||
if (xr1)
|
||||
ctx_free(xr1);
|
||||
if (s0)
|
||||
free(s0);
|
||||
if (s1)
|
||||
free(s1);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Helper function for derived-from(-and-self) - eval one node
|
||||
* @param[in] nsc XML Namespace context
|
||||
* @param[in] self If set, implements derived_from_or_self
|
||||
* @retval 1 OK and match
|
||||
* @retval 0 OK but not match
|
||||
* @retval -1 Error
|
||||
*/
|
||||
static int
|
||||
derived_from_one(char *baseidentity,
|
||||
cvec *nsc,
|
||||
cxobj *xleaf,
|
||||
int self)
|
||||
{
|
||||
int retval = -1;
|
||||
yang_stmt *yleaf;
|
||||
yang_stmt *ytype;
|
||||
yang_stmt *ybaseid;
|
||||
yang_stmt *ymod;
|
||||
cvec *idrefvec; /* Derived identityref list: (module:id)**/
|
||||
char *node = NULL;
|
||||
char *prefix = NULL;
|
||||
char *id = NULL;
|
||||
cbuf *cb = NULL;
|
||||
char *baseid = NULL;
|
||||
|
||||
/* Split baseidentity to get its id (w/o prefix) */
|
||||
if (nodeid_split(baseidentity, NULL, &baseid) < 0)
|
||||
goto done;
|
||||
if ((yleaf = xml_spec(xleaf)) == NULL)
|
||||
goto nomatch;
|
||||
if (yang_keyword_get(yleaf) != Y_LEAF && yang_keyword_get(yleaf) != Y_LEAF_LIST)
|
||||
goto nomatch;
|
||||
/* Node is of type identityref */
|
||||
if (yang_type_get(yleaf, NULL, &ytype, NULL, NULL, NULL, NULL, NULL) < 0)
|
||||
goto done;
|
||||
if (ytype == NULL || strcmp(yang_argument_get(ytype), "identityref"))
|
||||
goto nomatch;
|
||||
/* Find if the derivation chain is: identity ->...-> ytype
|
||||
* Example:
|
||||
* identity is ex:ethernet
|
||||
* xleaf <type>fast-ethernet</type>
|
||||
* yleaf type identityref{base interface-type;}
|
||||
*/
|
||||
/* Just get the object corresponding to the base identity */
|
||||
if ((ybaseid = yang_find_identity_nsc(ys_spec(yleaf), baseidentity, nsc)) == NULL)
|
||||
goto nomatch;
|
||||
/* Get its list of derived identities */
|
||||
idrefvec = yang_cvec_get(ybaseid);
|
||||
/* Get and split the leaf id reference */
|
||||
if ((node = xml_body(xleaf)) == NULL) /* It may not be empty */
|
||||
goto nomatch;
|
||||
if (nodeid_split(node, &prefix, &id) < 0)
|
||||
goto done;
|
||||
/* Get its module (prefixes are not used here) */
|
||||
if (prefix == NULL)
|
||||
ymod = ys_module(yleaf);
|
||||
else{ /* from prefix to name */
|
||||
#if 1 /* IDENTITYREF_KLUDGE */
|
||||
ymod = yang_find_module_by_prefix_yspec(ys_spec(yleaf), prefix);
|
||||
#endif
|
||||
}
|
||||
if (ymod == NULL)
|
||||
goto nomatch;
|
||||
/* self special case, ie that the xleaf has a ref to itself */
|
||||
if (self &&
|
||||
ymod == ys_module(ybaseid) &&
|
||||
strcmp(baseid, id) == 0){
|
||||
; /* match */
|
||||
}
|
||||
else {
|
||||
/* Allocate cbuf */
|
||||
if ((cb = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
cprintf(cb, "%s:%s", yang_argument_get(ymod), id);
|
||||
if (cvec_find(idrefvec, cbuf_get(cb)) == NULL)
|
||||
goto nomatch;
|
||||
}
|
||||
retval = 1;
|
||||
done:
|
||||
if (baseid)
|
||||
free(baseid);
|
||||
if (cb)
|
||||
cbuf_free(cb);
|
||||
if (id)
|
||||
free(id);
|
||||
if (prefix)
|
||||
free(prefix);
|
||||
return retval;
|
||||
nomatch:
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*! Eval xpath function derived-from(-and-self)
|
||||
* @param[in] xc Incoming context
|
||||
* @param[in] xs XPATH node tree
|
||||
* @param[in] nsc XML Namespace context
|
||||
* @param[in] localonly Skip prefix and namespace tests (non-standard)
|
||||
* @param[in] self If set, implements derived_from_or_self
|
||||
* @param[out] xrp Resulting context
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @see rfc7950 10.4.1
|
||||
* Returns "true" if any node in the argument "nodes" is a node of type "identityref" and its
|
||||
* value is an identity that is derived from (see Section 7.18.2) the identity "identity"
|
||||
* boolean derived-from(node-set nodes, string identity)
|
||||
* @see validate_identityref for similar code other usage
|
||||
*/
|
||||
int
|
||||
xp_function_derived_from(xp_ctx *xc,
|
||||
struct xpath_tree *xs,
|
||||
cvec *nsc,
|
||||
int localonly,
|
||||
int self,
|
||||
xp_ctx **xrp)
|
||||
{
|
||||
int retval = -1;
|
||||
xp_ctx *xr0 = NULL;
|
||||
xp_ctx *xr1 = NULL;
|
||||
xp_ctx *xr = NULL;
|
||||
char *identity = NULL;
|
||||
int i;
|
||||
int ret = 0;
|
||||
|
||||
/* contains two arguments in xs: boolean derived-from(node-set, string) */
|
||||
/* This evolves to a set of (identityref) nodes */
|
||||
if (xp_eval(xc, xs->xs_c0, nsc, localonly, &xr0) < 0)
|
||||
goto done;
|
||||
if (xr0->xc_type != XT_NODESET)
|
||||
goto done;
|
||||
/* This evolves to a string identity */
|
||||
if (xp_eval(xc, xs->xs_c1, nsc, localonly, &xr1) < 0)
|
||||
goto done;
|
||||
if (ctx2string(xr1, &identity) < 0)
|
||||
goto done;
|
||||
/* Allocate a return struct of type boolean */
|
||||
if ((xr = malloc(sizeof(*xr))) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "malloc");
|
||||
goto done;
|
||||
}
|
||||
memset(xr, 0, sizeof(*xr));
|
||||
xr->xc_type = XT_BOOL;
|
||||
/* ANY node is an identityref and its value an identity that is derived ... */
|
||||
for (i=0; i<xr0->xc_size; i++){
|
||||
if ((ret = derived_from_one(identity, nsc, xr0->xc_nodeset[i], self)) < 0)
|
||||
goto done;
|
||||
if (ret == 1)
|
||||
break;
|
||||
}
|
||||
xr->xc_bool = ret;
|
||||
*xrp = xr;
|
||||
xr = NULL;
|
||||
retval = 0;
|
||||
done:
|
||||
if (xr0)
|
||||
ctx_free(xr0);
|
||||
if (xr1)
|
||||
ctx_free(xr1);
|
||||
if (identity)
|
||||
free(identity);
|
||||
return retval;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue