blob: 634957a5891de9ae421286503ab2d6a9afbdf008 [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 Vasko93909772016-10-26 10:32:10 +020030 * variables are not supported, "id()" function is not supported,
31 * and processing instruction and comment nodes are not supported,
32 * which is also reflected in the grammar. Undefined rules and
33 * 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 *
Michal Vasko56d082c2016-10-25 14:00:42 +0200140 * Operators between expressions which this concerns:
Michal Vasko25895052015-09-21 11:41:12 +0200141 * '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
Michal Vaskob94a5e42016-09-08 14:01:56 +0200203 * this case just pass the first top-level node into \p cur_node and use an enum value for this kind of root
204 * (#LYXP_NODE_ROOT_CONFIG if \p cur_node has config true, otherwise #LYXP_NODE_ROOT). #LYXP_NODE_TEXT and #LYXP_NODE_ATTR can also be used,
Michal Vaskob5157df2016-08-23 13:19:41 +0200205 * but there are no use-cases in YANG.
Michal Vaskoe3886bb2017-01-02 11:33:28 +0100206 * @param[in] local_mod Local module relative to the \p expr. Used only to determine the internal canonical value for identities.
Michal Vasko488590f2016-03-29 12:23:25 +0200207 * @param[out] set Result set. Must be valid and in the same libyang context as \p cur_node.
208 * To be safe, always either zero or cast the \p set to empty. After done using, either cast
209 * the \p set to empty (if allocated statically) or free it (if allocated dynamically) to
210 * prevent memory leaks.
Michal Vaskoa87d2582016-03-16 15:37:45 +0100211 * @param[in] options Whether to apply some evaluation restrictions.
Michal Vasko5b3492c2016-07-20 09:37:40 +0200212 * LYXP_MUST - apply must data tree access restrictions.
213 * LYXP_WHEN - apply when data tree access restrictions and consider LYD_WHEN flags in data nodes.
Michal Vasko25895052015-09-21 11:41:12 +0200214 *
Michal Vaskoa87d2582016-03-16 15:37:45 +0100215 * @return EXIT_SUCCESS on success, EXIT_FAILURE on unresolved when dependency, -1 on error.
Michal Vasko25895052015-09-21 11:41:12 +0200216 */
Michal Vaskoa59495d2016-08-22 09:18:58 +0200217int lyxp_eval(const char *expr, const struct lyd_node *cur_node, enum lyxp_node_type cur_node_type,
Michal Vaskoe3886bb2017-01-02 11:33:28 +0100218 const struct lys_module *local_mod, struct lyxp_set *set, int options);
Michal Vasko25895052015-09-21 11:41:12 +0200219
Michal Vasko5fb299e2015-10-06 15:44:55 +0200220/**
Michal Vasko5b3492c2016-07-20 09:37:40 +0200221 * @brief Get all the partial XPath nodes (atoms) that are required for \p expr to be evaluated.
222 *
223 * @param[in] expr XPath expression to be evaluated. Must be in JSON format (prefixes are model names).
224 * @param[in] cur_snode Current (context) schema node.
Michal Vasko508a50d2016-09-07 14:50:33 +0200225 * @param[in] cur_snode_type Current (context) schema node type.
Michal Vasko5b3492c2016-07-20 09:37:40 +0200226 * @param[out] set Result set. Must be valid and in the same libyang context as \p cur_snode.
227 * To be safe, always either zero or cast the \p set to empty. After done using, either cast
228 * the \p set to empty (if allocated statically) or free it (if allocated dynamically) to
229 * prevent memory leaks.
230 * @param[in] options Whether to apply some evaluation restrictions, one flag must always be used.
231 * LYXP_SNODE - no special data tree access modifiers.
232 * LYXP_SNODE_MUST - apply must data tree access restrictions.
233 * LYXP_SNODE_WHEN - apply when data tree access restrictions.
Michal Vaskob94a5e42016-09-08 14:01:56 +0200234 * LYXP_SNODE_OUTPUT - search RPC/action output instead input
Michal Vasko5b3492c2016-07-20 09:37:40 +0200235 *
236 * @return EXIT_SUCCESS on success, -1 on error.
237 */
Michal Vasko508a50d2016-09-07 14:50:33 +0200238int lyxp_atomize(const char *expr, const struct lys_node *cur_snode, enum lyxp_node_type cur_snode_type,
239 struct lyxp_set *set, int options);
Michal Vasko5b3492c2016-07-20 09:37:40 +0200240
241/* these are used only internally */
242#define LYXP_SNODE 0x04
243#define LYXP_SNODE_MUST 0x08
244#define LYXP_SNODE_WHEN 0x10
Michal Vaskodb1da032016-09-08 10:07:38 +0200245#define LYXP_SNODE_OUTPUT 0x20
Michal Vasko5b3492c2016-07-20 09:37:40 +0200246
247#define LYXP_SNODE_ALL 0x1C
248
249/**
Michal Vasko508a50d2016-09-07 14:50:33 +0200250 * @brief Works like lyxp_atomize(), but it is executed on all the when and must expressions
251 * which the node has.
Michal Vasko7e18c452015-10-07 09:34:36 +0200252 *
Michal Vasko508a50d2016-09-07 14:50:33 +0200253 * @param[in] node Node to examine.
254 * @param[in,out] set Resulting set of atoms merged from all the expressions.
255 * Will be cleared before use.
Michal Vasko769f8032017-01-24 13:11:55 +0100256 * @param[in] warn_on_fwd_ref Setting this flag causes no errors to be printed and
257 * only warning is printed on forward reference paths (addressing a non-existing node).
Michal Vasko7e18c452015-10-07 09:34:36 +0200258 *
Michal Vasko508a50d2016-09-07 14:50:33 +0200259 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko7e18c452015-10-07 09:34:36 +0200260 */
Michal Vasko769f8032017-01-24 13:11:55 +0100261int lyxp_node_atomize(const struct lys_node *node, struct lyxp_set *set, int warn_on_fwd_ref);
Michal Vasko7e18c452015-10-07 09:34:36 +0200262
263/**
Michal Vaskocf024702015-10-08 15:01:42 +0200264 * @brief Cast XPath set to another type.
265 * Indirectly context position aware.
266 *
267 * @param[in] set Set to cast.
268 * @param[in] target Target type to cast \p set into.
Michal Vasko488590f2016-03-29 12:23:25 +0200269 * @param[in] cur_node Current (context) data node. Cannot be NULL.
Michal Vaskoe3886bb2017-01-02 11:33:28 +0100270 * @param[in] local_mod Local expression module.
Michal Vaskoa87d2582016-03-16 15:37:45 +0100271 * @param[in] options Whether to apply some evaluation restrictions.
Michal Vaskofdb73ae2016-08-24 16:02:12 +0200272 *
273 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vaskocf024702015-10-08 15:01:42 +0200274 */
Michal Vaskoe3886bb2017-01-02 11:33:28 +0100275int lyxp_set_cast(struct lyxp_set *set, enum lyxp_set_type target, const struct lyd_node *cur_node,
276 const struct lys_module *local_mod, int options);
Michal Vasko04854892015-10-06 15:45:43 +0200277
278/**
Michal Vasko5fb299e2015-10-06 15:44:55 +0200279 * @brief Free contents of an XPath \p set.
280 *
281 * @param[in] set Set to free.
Michal Vasko5fb299e2015-10-06 15:44:55 +0200282 */
Michal Vasko40afe1a2016-08-22 14:20:43 +0200283void lyxp_set_free(struct lyxp_set *set);
Michal Vasko5fb299e2015-10-06 15:44:55 +0200284
Michal Vasko56d082c2016-10-25 14:00:42 +0200285/**
286 * @brief Parse an XPath expression into a structure of tokens.
287 * Logs directly.
288 *
289 * http://www.w3.org/TR/1999/REC-xpath-19991116/ section 3.7
290 *
291 * @param[in] expr XPath expression to parse. It is duplicated.
292 *
293 * @return Filled expression structure or NULL on error.
294 */
295struct lyxp_expr *lyxp_parse_expr(const char *expr);
296
297/**
Michal Vasko89afc112017-03-16 13:57:28 +0100298 * @brief Reparse (perform additional syntax checks) an XPath
299 * expression structure.
Michal Vasko56d082c2016-10-25 14:00:42 +0200300 *
Michal Vasko89afc112017-03-16 13:57:28 +0100301 * @param[in] exp Parsed expression structure.
302 * @param[in,out] exp_idx Current index in \p exp. Set to 0 on first call, param just for recursion.
303 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko56d082c2016-10-25 14:00:42 +0200304 */
Michal Vasko89afc112017-03-16 13:57:28 +0100305int lyxp_reparse_expr(struct lyxp_expr *exp, uint16_t *exp_idx);
306
307/**
308 * @brief Frees a parsed XPath expression. \p expr should not be used afterwards.
309 *
310 * @param[in] expr Expression to free.
311 */
312void lyxp_expr_free(struct lyxp_expr *expr);
Michal Vasko56d082c2016-10-25 14:00:42 +0200313
Michal Vasko25895052015-09-21 11:41:12 +0200314#endif /* _XPATH_H */