blob: f5afdfea087650445c92ff9d4c8641f3829bfa6f [file] [log] [blame]
Michal Vasko25895052015-09-21 11:41:12 +02001/**
2 * @file xpath.h
3 * @author Michal Vasko <mvasko@cesnet.cz>
4 * @brief YANG XPath evaluation functions header
5 *
6 * Copyright (c) 2015 CESNET, z.s.p.o.
7 *
Radek Krejci54f6fb32016-02-24 12:56:39 +01008 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
Michal Vasko8de098c2016-02-26 10:00:25 +010011 *
Radek Krejci54f6fb32016-02-24 12:56:39 +010012 * https://opensource.org/licenses/BSD-3-Clause
Michal Vasko25895052015-09-21 11:41:12 +020013 */
14
15#ifndef _XPATH_H
16#define _XPATH_H
17
18#include <stdint.h>
19
Michal Vaskofd76bd12015-09-24 15:49:57 +020020#include "tree_schema.h"
21#include "tree_data.h"
Michal Vasko25895052015-09-21 11:41:12 +020022
23/*
24 * XPath evaluator fully compliant with http://www.w3.org/TR/1999/REC-xpath-19991116/
25 * except the following restrictions in the grammar.
26 *
27 * PARSED GRAMMAR
28 *
29 * Full axes are not supported, abbreviated forms must be used,
Michal Vasko929756e2015-10-08 15:48:30 +020030 * variables are not supported, "id()" and "name(node-set?)"
31 * functions are not supported, and processing instruction and
32 * comment nodes are not supported, which is also reflected in
33 * the grammar. Undefined rules and constants are tokens.
Michal Vasko25895052015-09-21 11:41:12 +020034 *
35 * Modified full grammar:
36 *
37 * [1] LocationPath ::= RelativeLocationPath | AbsoluteLocationPath
Michal Vaskoca3f1dc2015-10-06 15:57:40 +020038 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath? | '//' RelativeLocationPath
Michal Vasko25895052015-09-21 11:41:12 +020039 * [3] RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | RelativeLocationPath '//' Step
40 * [4] Step ::= '@'? NodeTest Predicate* | '.' | '..'
41 * [5] NodeTest ::= NameTest | NodeType '(' ')'
42 * [6] Predicate ::= '[' Expr ']'
43 * [7] PrimaryExpr ::= '(' Expr ')' | Literal | Number | FunctionCall
44 * [8] FunctionCall ::= FunctionName '(' ( Expr ( ',' Expr )* )? ')'
45 * [9] PathExpr ::= LocationPath | PrimaryExpr Predicate*
46 * | PrimaryExpr Predicate* '/' RelativeLocationPath
47 * | PrimaryExpr Predicate* '//' RelativeLocationPath
48 * [10] Expr ::= AndExpr | Expr 'or' AndExpr
49 * [11] AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr
50 * [12] EqualityExpr ::= RelationalExpr | EqualityExpr '=' RelationalExpr
51 * | EqualityExpr '!=' RelationalExpr
52 * [13] RelationalExpr ::= AdditiveExpr
53 * | RelationalExpr '<' AdditiveExpr
54 * | RelationalExpr '>' AdditiveExpr
55 * | RelationalExpr '<=' AdditiveExpr
56 * | RelationalExpr '>=' AdditiveExpr
57 * [14] AdditiveExpr ::= MultiplicativeExpr
58 * | AdditiveExpr '+' MultiplicativeExpr
59 * | AdditiveExpr '-' MultiplicativeExpr
60 * [15] MultiplicativeExpr ::= UnaryExpr
61 * | MultiplicativeExpr '*' UnaryExpr
62 * | MultiplicativeExpr 'div' UnaryExpr
63 * | MultiplicativeExpr 'mod' UnaryExpr
64 * [16] UnaryExpr ::= UnionExpr | '-' UnaryExpr
65 * [17] UnionExpr ::= PathExpr | UnionExpr '|' PathExpr
66 */
67
68/* expression tokens allocation */
69#define LYXP_EXPR_SIZE_START 10
70#define LYXP_EXPR_SIZE_STEP 5
71
72/* XPath matches allocation */
73#define LYXP_SET_SIZE_START 2
74#define LYXP_SET_SIZE_STEP 2
75
76/* building string when casting */
77#define LYXP_STRING_CAST_SIZE_START 64
78#define LYXP_STRING_CAST_SIZE_STEP 16
79
80/**
81 * @brief Tokens that can be in an XPath expression.
82 */
83enum lyxp_token {
84 LYXP_TOKEN_NONE = 0,
85 LYXP_TOKEN_PAR1, /* '(' */
86 LYXP_TOKEN_PAR2, /* ')' */
87 LYXP_TOKEN_BRACK1, /* '[' */
88 LYXP_TOKEN_BRACK2, /* ']' */
89 LYXP_TOKEN_DOT, /* '.' */
90 LYXP_TOKEN_DDOT, /* '..' */
91 LYXP_TOKEN_AT, /* '@' */
92 LYXP_TOKEN_COMMA, /* ',' */
93 /* LYXP_TOKEN_DCOLON, * '::' * axes not supported */
94 LYXP_TOKEN_NAMETEST, /* NameTest */
95 LYXP_TOKEN_NODETYPE, /* NodeType */
96 LYXP_TOKEN_FUNCNAME, /* FunctionName */
97 LYXP_TOKEN_OPERATOR_LOG, /* Operator 'and', 'or' */
98 LYXP_TOKEN_OPERATOR_COMP, /* Operator '=', '!=', '<', '<=', '>', '>=' */
99 LYXP_TOKEN_OPERATOR_MATH, /* Operator '+', '-', '*', 'div', 'mod', '-' (unary) */
100 LYXP_TOKEN_OPERATOR_UNI, /* Operator '|' */
101 LYXP_TOKEN_OPERATOR_PATH, /* Operator '/', '//' */
102 /* LYXP_TOKEN_AXISNAME, * AxisName * axes not supported */
103 LYXP_TOKEN_LITERAL, /* Literal - with either single or double quote */
104 LYXP_TOKEN_NUMBER /* Number */
105};
106
107/**
108 * @brief Structure holding a parsed XPath expression.
109 */
110struct lyxp_expr {
111 enum lyxp_token *tokens; /* array of tokens */
112 uint16_t *expr_pos; /* array of pointers to the expression in expr (idx of the beginning) */
113 uint8_t *tok_len; /* array of token lengths in expr */
114 uint8_t **repeat; /* array of the operator token indices that succeed this expression ended with 0,
115 more in the comment after this declaration */
116 uint16_t used; /* used array items */
117 uint16_t size; /* allocated array items */
118
Michal Vasko2b84ea72016-05-05 17:56:58 +0200119 char *expr; /* the original XPath expression */
Michal Vasko25895052015-09-21 11:41:12 +0200120};
121
122/*
123 * lyxp_expr repeat
124 *
125 * This value is NULL for all the tokens that do not begin an
126 * expression which can be repeated. Otherwise it is an array
127 * of indices in the tokens array that are an operator for
128 * which the current expression is an operand. These values
129 * are used during evaluation to know whether we need to
130 * duplicate the current context or not. Examples:
131 *
132 * Expression: "/ *[key1 and key2 or key1 < key2]"
133 * Tokens: '/', '*', '[', NameTest, 'and', NameTest, 'or', NameTest, '<', NameTest, ']'
134 * Repeat: NULL, NULL, NULL, [4, 6, 0], NULL, NULL, NULL, [8, 0], NULL, NULL, NULL
135 *
136 * Expression: "//node[key and node2]/key | /cont"
137 * Tokens: '//', 'NameTest', '[', 'NameTest', 'and', 'NameTest', ']', '/', 'NameTest', '|', '/', 'NameTest'
138 * Repeat: [9, 0], NULL, NULL, [4, 0], NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
139 *
140 * Operators between expressions that are concerned:
141 * 'or', 'and', '=', '!=', '<', '>', '<=', '>=', '+', '-', '*', 'div', 'mod', '|'
142 */
143
144/**
145 * @brief Supported types of (partial) XPath results.
146 */
147enum lyxp_set_type {
148 LYXP_SET_EMPTY = 0,
149 LYXP_SET_NODE_SET,
Michal Vasko5b3492c2016-07-20 09:37:40 +0200150 LYXP_SET_SNODE_SET,
Michal Vasko25895052015-09-21 11:41:12 +0200151 LYXP_SET_BOOLEAN,
152 LYXP_SET_NUMBER,
153 LYXP_SET_STRING
154};
155
156/**
Michal Vasko8146d4c2016-05-09 15:50:29 +0200157 * @brief XPath set - (partial) result.
158 */
159struct lyxp_set {
160 enum lyxp_set_type type;
161 union {
162 struct lyxp_set_nodes {
163 struct lyd_node *node;
164 enum lyxp_node_type type;
165 uint32_t pos;
166 } *nodes;
Michal Vasko5b3492c2016-07-20 09:37:40 +0200167 struct lyxp_set_snodes {
168 struct lys_node *snode;
169 enum lyxp_node_type type;
170 /* 0 - snode was traversed, but not currently in the context,
171 * 1 - snode currently in context,
172 * 2 - snode in context and just added, so skip it for the current operation,
173 * >=3 - snode is not in context because we are in a predicate and this snode was used/will be used later */
174 uint32_t in_ctx;
175 } *snodes;
Michal Vasko8146d4c2016-05-09 15:50:29 +0200176 struct lyxp_set_attrs {
177 struct lyd_attr *attr;
178 enum lyxp_node_type type;
Michal Vasko5b3492c2016-07-20 09:37:40 +0200179 uint32_t pos; /* if node_type is LYXP_SET_NODE_ATTR, it is the parent node position */
Michal Vasko8146d4c2016-05-09 15:50:29 +0200180 } *attrs;
Michal Vasko40afe1a2016-08-22 14:20:43 +0200181 char *str;
Michal Vasko8146d4c2016-05-09 15:50:29 +0200182 long double num;
183 int bool;
184 } val;
185
Michal Vasko5b3492c2016-07-20 09:37:40 +0200186 /* this is valid only for type LYXP_SET_NODE_SET and LYXP_SET_SNODE_SET */
Michal Vasko8146d4c2016-05-09 15:50:29 +0200187 uint32_t used;
188 uint32_t size;
Michal Vasko5b3492c2016-07-20 09:37:40 +0200189 /* this is valid only for type LYXP_SET_NODE_SET */
Michal Vaskodb86ff42016-05-13 15:50:11 +0200190 uint32_t ctx_pos;
191 uint32_t ctx_size;
Michal Vasko8146d4c2016-05-09 15:50:29 +0200192};
193
Michal Vasko25895052015-09-21 11:41:12 +0200194/**
Michal Vasko6ed199c2016-02-04 12:07:19 +0100195 * @brief Evaluate the XPath expression \p expr on data. Be careful when using this function, the result can often
196 * be confusing without thorough understanding of XPath evaluation rules defined in RFC 6020.
Michal Vasko25895052015-09-21 11:41:12 +0200197 *
Michal Vasko30646e62015-10-09 14:02:09 +0200198 * @param[in] expr XPath expression to evaluate. Must be in JSON format (prefixes are model names).
Michal Vaskofdb73ae2016-08-24 16:02:12 +0200199 * @param[in] cur_node Current (context) data node. If the node has #LYD_VAL_INUSE flag, it is considered dummy (intended
200 * for but not restricted to evaluation with the LYXP_WHEN flag).
Michal Vaskob5157df2016-08-23 13:19:41 +0200201 * @param[in] cur_node_type Current (context) data node type. For every standard case use #LYXP_NODE_ELEM. But there are
202 * cases when the context node \p cur_node is actually supposed to be the XML root, there is no such data node. So, in
203 * this case just pass any top-level node into \p cur_node and use an enum value for this kind of root
204 * (#LYXP_NODE_ROOT_STATE if \p cur_node has config false and so on). #LYXP_NODE_TEXT and #LYXP_NODE_ATTR can also be used,
205 * but there are no use-cases in YANG.
Michal Vasko488590f2016-03-29 12:23:25 +0200206 * @param[out] set Result set. Must be valid and in the same libyang context as \p cur_node.
207 * To be safe, always either zero or cast the \p set to empty. After done using, either cast
208 * the \p set to empty (if allocated statically) or free it (if allocated dynamically) to
209 * prevent memory leaks.
Michal Vaskoa87d2582016-03-16 15:37:45 +0100210 * @param[in] options Whether to apply some evaluation restrictions.
Michal Vasko5b3492c2016-07-20 09:37:40 +0200211 * LYXP_MUST - apply must data tree access restrictions.
212 * LYXP_WHEN - apply when data tree access restrictions and consider LYD_WHEN flags in data nodes.
Michal Vasko25895052015-09-21 11:41:12 +0200213 *
Michal Vaskoa87d2582016-03-16 15:37:45 +0100214 * @return EXIT_SUCCESS on success, EXIT_FAILURE on unresolved when dependency, -1 on error.
Michal Vasko25895052015-09-21 11:41:12 +0200215 */
Michal Vaskoa59495d2016-08-22 09:18:58 +0200216int lyxp_eval(const char *expr, const struct lyd_node *cur_node, enum lyxp_node_type cur_node_type,
217 struct lyxp_set *set, int options);
Michal Vasko25895052015-09-21 11:41:12 +0200218
Michal Vasko5fb299e2015-10-06 15:44:55 +0200219/**
Michal Vasko5b3492c2016-07-20 09:37:40 +0200220 * @brief Get all the partial XPath nodes (atoms) that are required for \p expr to be evaluated.
221 *
222 * @param[in] expr XPath expression to be evaluated. Must be in JSON format (prefixes are model names).
223 * @param[in] cur_snode Current (context) schema node.
Michal Vasko508a50d2016-09-07 14:50:33 +0200224 * @param[in] cur_snode_type Current (context) schema node type.
Michal Vasko5b3492c2016-07-20 09:37:40 +0200225 * @param[out] set Result set. Must be valid and in the same libyang context as \p cur_snode.
226 * To be safe, always either zero or cast the \p set to empty. After done using, either cast
227 * the \p set to empty (if allocated statically) or free it (if allocated dynamically) to
228 * prevent memory leaks.
229 * @param[in] options Whether to apply some evaluation restrictions, one flag must always be used.
230 * LYXP_SNODE - no special data tree access modifiers.
231 * LYXP_SNODE_MUST - apply must data tree access restrictions.
232 * LYXP_SNODE_WHEN - apply when data tree access restrictions.
233 *
234 * @return EXIT_SUCCESS on success, -1 on error.
235 */
Michal Vasko508a50d2016-09-07 14:50:33 +0200236int lyxp_atomize(const char *expr, const struct lys_node *cur_snode, enum lyxp_node_type cur_snode_type,
237 struct lyxp_set *set, int options);
Michal Vasko5b3492c2016-07-20 09:37:40 +0200238
239/* these are used only internally */
240#define LYXP_SNODE 0x04
241#define LYXP_SNODE_MUST 0x08
242#define LYXP_SNODE_WHEN 0x10
243
244#define LYXP_SNODE_ALL 0x1C
245
246/**
Michal Vasko508a50d2016-09-07 14:50:33 +0200247 * @brief Works like lyxp_atomize(), but it is executed on all the when and must expressions
248 * which the node has.
Michal Vasko7e18c452015-10-07 09:34:36 +0200249 *
Michal Vasko508a50d2016-09-07 14:50:33 +0200250 * @param[in] node Node to examine.
251 * @param[in,out] set Resulting set of atoms merged from all the expressions.
252 * Will be cleared before use.
Michal Vasko7e18c452015-10-07 09:34:36 +0200253 *
Michal Vasko508a50d2016-09-07 14:50:33 +0200254 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko7e18c452015-10-07 09:34:36 +0200255 */
Michal Vasko508a50d2016-09-07 14:50:33 +0200256int lyxp_node_atomize(const struct lys_node *node, struct lyxp_set *set);
Michal Vasko7e18c452015-10-07 09:34:36 +0200257
258/**
Michal Vaskocf024702015-10-08 15:01:42 +0200259 * @brief Cast XPath set to another type.
260 * Indirectly context position aware.
261 *
262 * @param[in] set Set to cast.
263 * @param[in] target Target type to cast \p set into.
Michal Vasko488590f2016-03-29 12:23:25 +0200264 * @param[in] cur_node Current (context) data node. Cannot be NULL.
Michal Vaskoa87d2582016-03-16 15:37:45 +0100265 * @param[in] options Whether to apply some evaluation restrictions.
Michal Vaskofdb73ae2016-08-24 16:02:12 +0200266 *
267 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vaskocf024702015-10-08 15:01:42 +0200268 */
Michal Vaskofdb73ae2016-08-24 16:02:12 +0200269int lyxp_set_cast(struct lyxp_set *set, enum lyxp_set_type target, const struct lyd_node *cur_node, int options);
Michal Vasko04854892015-10-06 15:45:43 +0200270
271/**
Michal Vasko5fb299e2015-10-06 15:44:55 +0200272 * @brief Free contents of an XPath \p set.
273 *
274 * @param[in] set Set to free.
Michal Vasko5fb299e2015-10-06 15:44:55 +0200275 */
Michal Vasko40afe1a2016-08-22 14:20:43 +0200276void lyxp_set_free(struct lyxp_set *set);
Michal Vasko5fb299e2015-10-06 15:44:55 +0200277
Michal Vasko508a50d2016-09-07 14:50:33 +0200278void lyxp_set_snode_merge(struct lyxp_set *set1, struct lyxp_set *set2);
279
Michal Vasko25895052015-09-21 11:41:12 +0200280#endif /* _XPATH_H */