blob: 6685e8b103de55f9eccde87b78884c495d49ed85 [file] [log] [blame]
Radek Krejcie7b95092019-05-15 11:03:07 +02001/**
2 * @file parser_xml.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief XML data parser for libyang
5 *
6 * Copyright (c) 2019 CESNET, z.s.p.o.
7 *
8 * 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
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
14
15#include "common.h"
16
17#include <stdint.h>
18#include <stdlib.h>
19#include <string.h>
20
21#include "context.h"
22#include "dict.h"
23#include "log.h"
24#include "plugins_types.h"
25#include "set.h"
26#include "tree_data.h"
27#include "tree_data_internal.h"
28#include "tree_schema.h"
29#include "xml.h"
Radek Krejci38d85362019-09-05 16:26:38 +020030#include "plugins_exts_internal.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020031
32/**
33 * @brief internal context for XML YANG data parser.
34 *
35 * The leading part is compatible with the struct lyxml_context
36 */
37struct lyd_xml_ctx {
38 struct ly_ctx *ctx; /**< libyang context */
39 uint64_t line; /**< number of the line being currently processed */
40 enum LYXML_PARSER_STATUS status; /**< status providing information about the next expected object in input data */
41 struct ly_set elements; /**< list of not-yet-closed elements */
42 struct ly_set ns; /**< handled with LY_SET_OPT_USEASLIST */
43
44 uint16_t options; /**< various @ref dataparseroptions. */
45 uint16_t path_len; /**< used bytes in the path buffer */
46#define LYD_PARSER_BUFSIZE 4078
47 char path[LYD_PARSER_BUFSIZE]; /**< buffer for the generated path */
Radek Krejcie553e6d2019-06-07 15:33:18 +020048 struct ly_set incomplete_type_validation; /**< set of nodes validated with LY_EINCOMPLETE result */
Radek Krejci38d85362019-09-05 16:26:38 +020049 struct ly_set incomplete_type_validation_attrs; /**< set of attributes validated with LY_EINCOMPLETE result */
Radek Krejcie7b95092019-05-15 11:03:07 +020050};
51
52/**
Radek Krejciaca74032019-06-04 08:53:06 +020053 * @brief XML-parser's implementation of ly_type_resolve_prefix() callback to provide mapping between prefixes used in the values to the schema
54 * via XML namespaces.
55 */
56static const struct lys_module *
57lydxml_resolve_prefix(struct ly_ctx *ctx, const char *prefix, size_t prefix_len, void *parser)
58{
59 const struct lyxml_ns *ns;
60 struct lyxml_context *xmlctx = (struct lyxml_context*)parser;
61
62 ns = lyxml_ns_get(xmlctx, prefix, prefix_len);
63 if (!ns) {
64 return NULL;
65 }
66
67 return ly_ctx_get_module_implemented_ns(ctx, ns->uri);
68}
69
70/**
Radek Krejcie7b95092019-05-15 11:03:07 +020071 * @brief Parse XML attributes of the XML element of YANG data.
72 *
73 * @param[in] ctx XML YANG data parser context.
Radek Krejcie7b95092019-05-15 11:03:07 +020074 * @param[in,out] data Pointer to the XML string representation of the YANG data to parse.
75 * @param[out] attributes Resulting list of the parsed attributes. XML namespace definitions are not parsed
76 * as attributes, they are stored internally in the parser context.
77 * @reutn LY_ERR value.
78 */
79static LY_ERR
Radek Krejci17a78d82019-05-15 15:49:55 +020080lydxml_attributes(struct lyd_xml_ctx *ctx, const char **data, struct lyd_attr **attributes)
Radek Krejcie7b95092019-05-15 11:03:07 +020081{
82 LY_ERR ret = LY_SUCCESS;
Radek Krejci38d85362019-09-05 16:26:38 +020083 unsigned int u, v;
Radek Krejcie7b95092019-05-15 11:03:07 +020084 const char *prefix, *name;
85 size_t prefix_len, name_len;
86 struct lyd_attr *attr = NULL, *last = NULL;
87 const struct lyxml_ns *ns;
Radek Krejci38d85362019-09-05 16:26:38 +020088 struct ly_set attr_datas = {0};
89 struct attr_data_s {
Radek Krejcie7b95092019-05-15 11:03:07 +020090 const char *prefix;
Radek Krejci38d85362019-09-05 16:26:38 +020091 char *value;
Radek Krejcie7b95092019-05-15 11:03:07 +020092 size_t prefix_len;
Radek Krejci38d85362019-09-05 16:26:38 +020093 size_t value_len;
94 int dynamic;
95 } *attr_data;
Radek Krejcie7b95092019-05-15 11:03:07 +020096 struct lys_module *mod;
97
98 while(ctx->status == LYXML_ATTRIBUTE &&
99 lyxml_get_attribute((struct lyxml_context*)ctx, data, &prefix, &prefix_len, &name, &name_len) == LY_SUCCESS) {
Radek Krejci38d85362019-09-05 16:26:38 +0200100 char *buffer = NULL;
101 size_t buffer_size = 0;
Radek Krejcie7b95092019-05-15 11:03:07 +0200102
Radek Krejci17a78d82019-05-15 15:49:55 +0200103 if (!name) {
104 /* seems like all the attrributes were internally processed as namespace definitions */
105 continue;
Radek Krejcie7b95092019-05-15 11:03:07 +0200106 }
Radek Krejci17a78d82019-05-15 15:49:55 +0200107
Radek Krejci38d85362019-09-05 16:26:38 +0200108 /* auxiliary store the prefix information and value string, because we have to wait with resolving prefix
109 * to the time when all the namespaces, defined in this element, are parsed. With the prefix we can find the
110 * annotation definition for the attribute and correctly process the value */
111 attr_data = malloc(sizeof *attr_data);
112 attr_data->prefix = prefix;
113 attr_data->prefix_len = prefix_len;
114 ret = lyxml_get_string((struct lyxml_context *)ctx, data, &buffer, &buffer_size, &attr_data->value, &attr_data->value_len, &attr_data->dynamic);
115 LY_CHECK_ERR_GOTO(ret, free(attr_data), cleanup);
116 ly_set_add(&attr_datas, attr_data, LY_SET_OPT_USEASLIST);
Radek Krejci17a78d82019-05-15 15:49:55 +0200117
118 attr = calloc(1, sizeof *attr);
119 LY_CHECK_ERR_GOTO(!attr, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
Radek Krejci17a78d82019-05-15 15:49:55 +0200120 attr->name = lydict_insert(ctx->ctx, name, name_len);
Radek Krejci17a78d82019-05-15 15:49:55 +0200121
122 if (last) {
123 last->next = attr;
124 } else {
125 (*attributes) = attr;
126 }
127 last = attr;
Radek Krejcie7b95092019-05-15 11:03:07 +0200128 }
129
Radek Krejci38d85362019-09-05 16:26:38 +0200130 /* resolve annotation pointers in all the attributes and process the attribute's values */
131 for (last = *attributes, u = 0; u < attr_datas.count && last; u++, last = last->next) {
132 attr_data = (struct attr_data_s*)attr_datas.objs[u];
133 ns = lyxml_ns_get((struct lyxml_context *)ctx, attr_data->prefix, attr_data->prefix_len);
Radek Krejcie7b95092019-05-15 11:03:07 +0200134 mod = ly_ctx_get_module_implemented_ns(ctx->ctx, ns->uri);
135
Radek Krejci38d85362019-09-05 16:26:38 +0200136 LY_ARRAY_FOR(mod->compiled->exts, v) {
137 if (mod->compiled->exts[v].def->plugin == lyext_plugins_internal[LYEXT_PLUGIN_INTERNAL_ANNOTATION].plugin &&
138 !strcmp(mod->compiled->exts[v].argument, last->name)) {
139 /* we have the annotation definition */
140 last->annotation = &mod->compiled->exts[v];
141 break;
142 }
143 }
144
145 if (!last->annotation) {
146 /* attribute is not defined as a metadata annotation (RFC 7952) */
147
148 }
149
150 ret = lyd_value_parse_attr(attr, attr_data->value, attr_data->value_len, attr_data->dynamic, 0, lydxml_resolve_prefix, ctx, LYD_XML, NULL);
151 if (ret == LY_EINCOMPLETE) {
152 ly_set_add(&ctx->incomplete_type_validation_attrs, attr, LY_SET_OPT_USEASLIST);
153 } else if (ret) {
154 goto cleanup;
155 }
156 attr_data->dynamic = 0; /* value eaten by lyd_value_parse_attr() */
Radek Krejcie7b95092019-05-15 11:03:07 +0200157 }
158
159cleanup:
160
Radek Krejci38d85362019-09-05 16:26:38 +0200161 for (u = 0; u < attr_datas.count; ++u) {
162 if (((struct attr_data_s*)attr_datas.objs[u])->dynamic) {
163 free(((struct attr_data_s*)attr_datas.objs[u])->value);
164 }
165 }
166 ly_set_erase(&attr_datas, free);
Radek Krejcie7b95092019-05-15 11:03:07 +0200167 return ret;
168}
169
170/**
171 * @brief Parse XML elements as children YANG data node of the specified parent node.
172 *
173 * @param[in] ctx XML YANG data parser context.
174 * @param[in] parent Parent node where the children are inserted. NULL in case of parsing top-level elements.
175 * @param[in,out] data Pointer to the XML string representation of the YANG data to parse.
176 * @param[out] node Resulting list of the parsed nodes.
177 * @reutn LY_ERR value.
178 */
179static LY_ERR
180lydxml_nodes(struct lyd_xml_ctx *ctx, struct lyd_node_inner *parent, const char **data, struct lyd_node **node)
181{
182 LY_ERR ret = LY_SUCCESS;
183 const char *prefix, *name;
Radek Krejcie7b95092019-05-15 11:03:07 +0200184 size_t prefix_len, name_len;
185 struct lyd_attr *attributes = NULL;
186 const struct lyxml_ns *ns;
187 const struct lysc_node *snode;
188 struct lys_module *mod;
189 unsigned int parents_count = ctx->elements.count;
Radek Krejci710226d2019-07-24 17:24:59 +0200190 struct lyd_node *cur = NULL, *prev = NULL, *last = NULL;
Radek Krejcie7b95092019-05-15 11:03:07 +0200191
192 (*node) = NULL;
193
194 while(ctx->status == LYXML_ELEMENT) {
195 ret = lyxml_get_element((struct lyxml_context *)ctx, data, &prefix, &prefix_len, &name, &name_len);
196 LY_CHECK_GOTO(ret, cleanup);
197 if (!name) {
198 /* closing previous element */
Radek Krejcie7b95092019-05-15 11:03:07 +0200199 if (ctx->elements.count < parents_count) {
200 /* all siblings parsed */
201 break;
202 } else {
203 continue;
204 }
205 }
206 attributes = NULL;
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200207 if (ctx->status == LYXML_ATTRIBUTE) {
Radek Krejci11702142019-07-24 17:46:04 +0200208 LY_CHECK_GOTO(lydxml_attributes(ctx, data, &attributes), error);
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200209 }
210
Radek Krejcie7b95092019-05-15 11:03:07 +0200211 ns = lyxml_ns_get((struct lyxml_context *)ctx, prefix, prefix_len);
212 if (!ns) {
213 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%*.s\".", prefix_len, prefix);
Radek Krejci11702142019-07-24 17:46:04 +0200214 goto error;
Radek Krejcie7b95092019-05-15 11:03:07 +0200215 }
216 mod = ly_ctx_get_module_implemented_ns(ctx->ctx, ns->uri);
217 if (!mod) {
218 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "No module with namespace \"%s\" in the context.", ns->uri);
Radek Krejci11702142019-07-24 17:46:04 +0200219 goto error;
Radek Krejcie7b95092019-05-15 11:03:07 +0200220 }
221 snode = lys_child(parent ? parent->schema : NULL, mod, name, name_len, 0, (ctx->options & LYD_OPT_RPCREPLY) ? LYS_GETNEXT_OUTPUT : 0);
222 if (!snode) {
223 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Element \"%.*s\" not found in the \"%s\" module.", name_len, name, mod->name);
Radek Krejci11702142019-07-24 17:46:04 +0200224 goto error;
Radek Krejcie7b95092019-05-15 11:03:07 +0200225 }
226
227 /* allocate new node */
228 switch (snode->nodetype) {
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200229 case LYS_ACTION:
230 if ((ctx->options & LYD_OPT_TYPEMASK) != LYD_OPT_RPC) {
231 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_RESTRICTION, "Unexpected RPC/action element \"%.*s\" in %s data set.",
232 name_len, name, lyd_parse_options_type2str(ctx->options & LYD_OPT_TYPEMASK));
Radek Krejci11702142019-07-24 17:46:04 +0200233 goto error;
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200234 }
235 cur = calloc(1, sizeof(struct lyd_node_inner));
236 break;
237 case LYS_NOTIF:
238 if ((ctx->options & LYD_OPT_TYPEMASK) != LYD_OPT_RPC) {
239 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_RESTRICTION, "Unexpected Notification element \"%.*s\" in %s data set.",
240 name_len, name, lyd_parse_options_type2str(ctx->options));
Radek Krejci11702142019-07-24 17:46:04 +0200241 goto error;
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200242 }
243 cur = calloc(1, sizeof(struct lyd_node_inner));
244 break;
Radek Krejcie7b95092019-05-15 11:03:07 +0200245 case LYS_CONTAINER:
246 case LYS_LIST:
247 cur = calloc(1, sizeof(struct lyd_node_inner));
248 break;
249 case LYS_LEAF:
250 case LYS_LEAFLIST:
251 cur = calloc(1, sizeof(struct lyd_node_term));
252 break;
253 case LYS_ANYDATA:
254 case LYS_ANYXML:
255 cur = calloc(1, sizeof(struct lyd_node_any));
256 break;
Radek Krejcie7b95092019-05-15 11:03:07 +0200257 default:
258 LOGINT(ctx->ctx);
Radek Krejci11702142019-07-24 17:46:04 +0200259 ret = LY_EINT;
Radek Krejcie7b95092019-05-15 11:03:07 +0200260 goto cleanup;
261 }
262 if (!(*node)) {
263 (*node) = cur;
264 }
Radek Krejci710226d2019-07-24 17:24:59 +0200265 last = cur;
Radek Krejcie7b95092019-05-15 11:03:07 +0200266 cur->schema = snode;
Radek Krejci710226d2019-07-24 17:24:59 +0200267 cur->prev = cur;
Radek Krejcie7b95092019-05-15 11:03:07 +0200268 cur->parent = parent;
Radek Krejcie92210c2019-05-17 15:53:35 +0200269 if (parent) {
Radek Krejci710226d2019-07-24 17:24:59 +0200270 if (prev && cur->schema->nodetype == LYS_LEAF && (cur->schema->flags & LYS_KEY)) {
271 /* it is key and we need to insert it into a correct place */
Radek Krejci0fe9b512019-07-26 17:51:05 +0200272 struct lysc_node *key_s;
Radek Krejci710226d2019-07-24 17:24:59 +0200273 unsigned int cur_index, key_index;
274 struct lyd_node *key;
275
Radek Krejci0fe9b512019-07-26 17:51:05 +0200276 for (cur_index = 0, key_s = ((struct lysc_node_list*)parent->schema)->child;
277 key_s && key_s != cur->schema;
278 ++cur_index, key_s = key_s->next);
279 for (key = prev;
280 !(key->schema->flags & LYS_KEY) && key->prev != prev;
281 key = key->prev);
Radek Krejci710226d2019-07-24 17:24:59 +0200282 for (; key->schema->flags & LYS_KEY; key = key->prev) {
Radek Krejci0fe9b512019-07-26 17:51:05 +0200283 for (key_index = 0, key_s = ((struct lysc_node_list*)parent->schema)->child;
284 key_s && key_s != key->schema;
285 ++key_index, key_s = key_s->next);
Radek Krejci710226d2019-07-24 17:24:59 +0200286 if (key_index < cur_index) {
287 /* cur key is supposed to be placed after the key */
288 cur->next = key->next;
289 cur->prev = key;
290 key->next = cur;
291 if (cur->next) {
292 cur->next->prev = cur;
293 } else {
294 parent->child->prev = cur;
295 }
296 break;
297 }
298 if (key->prev == prev) {
299 /* current key is supposed to be the first child from the current children */
300 key = NULL;
301 break;
302 }
303 }
304 if (!key || !(key->schema->flags & LYS_KEY)) {
305 /* current key is supposed to be the first child from the current children */
306 cur->next = parent->child;
307 cur->prev = parent->child->prev;
308 parent->child->prev = cur;
309 parent->child = cur;
310 }
311 if (cur->next) {
312 last = prev;
313 if (ctx->options & LYD_OPT_STRICT) {
314 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_RESTRICTION, "Invalid position of the key \"%.*s\" in a list.",
315 name_len, name);
Radek Krejci11702142019-07-24 17:46:04 +0200316 goto error;
Radek Krejci710226d2019-07-24 17:24:59 +0200317 } else {
318 LOGWRN(ctx->ctx, "Invalid position of the key \"%.*s\" in a list.", name_len, name);
319 }
320 }
321 } else {
322 /* last child of the parent */
323 if (prev) {
324 parent->child->prev = cur;
325 prev->next = cur;
326 cur->prev = prev;
327 }
328 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200329 } else {
Radek Krejci710226d2019-07-24 17:24:59 +0200330 /* top level */
331 if (prev) {
332 /* last top level node */
333 struct lyd_node *iter;
334 for (iter = prev; iter->prev->next; iter = iter->prev);
335 iter->prev = cur;
336 prev->next = cur;
337 cur->prev = prev;
338 } /* first top level node - nothing more to do */
Radek Krejcie7b95092019-05-15 11:03:07 +0200339 }
Radek Krejci710226d2019-07-24 17:24:59 +0200340 prev = last;
Radek Krejcie7b95092019-05-15 11:03:07 +0200341 cur->attr = attributes;
342 attributes = NULL;
343
344 if (snode->nodetype & LYD_NODE_TERM) {
345 int dynamic = 0;
346 char *buffer = NULL, *value;
347 size_t buffer_size = 0, value_len;
348
349 if (ctx->status == LYXML_ELEM_CONTENT) {
350 /* get the value */
Radek Krejci11702142019-07-24 17:46:04 +0200351 ret = lyxml_get_string((struct lyxml_context *)ctx, data, &buffer, &buffer_size, &value, &value_len, &dynamic);
352 if (ret == LY_EINVAL) {
Radek Krejci339e2de2019-05-17 14:28:24 +0200353 /* just indentation of a child element found */
354 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX, "Child element inside terminal node \"%s\" found.", cur->schema->name);
355 goto cleanup;
356 }
Radek Krejci11702142019-07-24 17:46:04 +0200357 ret = LY_SUCCESS;
Radek Krejcie92210c2019-05-17 15:53:35 +0200358 } else {
359 /* no content - validate empty value */
360 value = "";
361 value_len = 0;
Radek Krejcie7b95092019-05-15 11:03:07 +0200362 }
Radek Krejci3c9758d2019-07-11 16:49:10 +0200363 ret = lyd_value_parse((struct lyd_node_term*)cur, value, value_len, dynamic, 0, lydxml_resolve_prefix, ctx, LYD_XML, NULL);
Radek Krejcie553e6d2019-06-07 15:33:18 +0200364 if (ret == LY_EINCOMPLETE) {
365 ly_set_add(&ctx->incomplete_type_validation, cur, LY_SET_OPT_USEASLIST);
366 } else if (ret) {
367 if (dynamic){
368 free(value);
369 }
370 goto cleanup;
371 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200372 } else if (snode->nodetype & LYD_NODE_INNER) {
373 int dynamic = 0;
374 char *buffer = NULL, *value;
375 size_t buffer_size = 0, value_len;
376
377 if (ctx->status == LYXML_ELEM_CONTENT) {
378 LY_ERR r = lyxml_get_string((struct lyxml_context *)ctx, data, &buffer, &buffer_size, &value, &value_len, &dynamic);
Radek Krejcie553e6d2019-06-07 15:33:18 +0200379 if (r != LY_EINVAL && (r != LY_SUCCESS || value_len != 0)) {
Radek Krejcie7b95092019-05-15 11:03:07 +0200380 LOGINT(ctx->ctx);
Radek Krejci11702142019-07-24 17:46:04 +0200381 ret = LY_EINT;
Radek Krejcie7b95092019-05-15 11:03:07 +0200382 goto cleanup;
383 }
384 }
Radek Krejciee4cab22019-07-17 17:07:47 +0200385 /* process children */
Radek Krejcie553e6d2019-06-07 15:33:18 +0200386 if (ctx->status == LYXML_ELEMENT && parents_count != ctx->elements.count) {
Radek Krejcie7b95092019-05-15 11:03:07 +0200387 ret = lydxml_nodes(ctx, (struct lyd_node_inner*)cur, data, lyd_node_children_p(cur));
Radek Krejcie92210c2019-05-17 15:53:35 +0200388 LY_CHECK_GOTO(ret, cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200389 }
Radek Krejciee4cab22019-07-17 17:07:47 +0200390 } else if (snode->nodetype & LYD_NODE_ANY) {
391 unsigned int cur_element_index = ctx->elements.count;
392 const char *start = *data, *stop;
393 const char *p, *n;
394 size_t p_len, n_len;
395
396 /* skip children data and store them as a string */
Radek Krejci26a5dfb2019-07-26 14:51:06 +0200397 while (ctx->status != LYXML_END && cur_element_index <= ctx->elements.count) {
Radek Krejciee4cab22019-07-17 17:07:47 +0200398 switch (ctx->status) {
399 case LYXML_ELEMENT:
400 ret = lyxml_get_element((struct lyxml_context *)ctx, data, &p, &p_len, &n, &n_len);
401 break;
402 case LYXML_ATTRIBUTE:
403 lyxml_get_attribute((struct lyxml_context*)ctx, data, &p, &p_len, &n, &n_len);
404 break;
405 case LYXML_ELEM_CONTENT:
406 case LYXML_ATTR_CONTENT:
407 ret = lyxml_get_string((struct lyxml_context *)ctx, data, NULL, NULL, NULL, NULL, NULL);
408 if (ret == LY_EINVAL) {
409 /* not an error, just incorrect XML parser status */
410 ret = LY_SUCCESS;
411 }
412 break;
413 case LYXML_END:
Radek Krejci26a5dfb2019-07-26 14:51:06 +0200414 /* end of data */
Radek Krejciee4cab22019-07-17 17:07:47 +0200415 LOGINT(ctx->ctx);
Radek Krejci11702142019-07-24 17:46:04 +0200416 ret = LY_EINT;
Radek Krejciee4cab22019-07-17 17:07:47 +0200417 goto cleanup;
418 }
419 LY_CHECK_GOTO(ret, cleanup);
420 }
Radek Krejciee4cab22019-07-17 17:07:47 +0200421 ((struct lyd_node_any*)cur)->value_type = LYD_ANYDATA_XML;
Radek Krejci26a5dfb2019-07-26 14:51:06 +0200422 if (start != *data) {
423 /* data now points after the anydata's closing element tag, we need just end of its content */
424 for (stop = *data - 1; *stop != '<'; --stop);
425 ((struct lyd_node_any*)cur)->value.xml = lydict_insert(ctx->ctx, start, stop - start);
426 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200427 }
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200428
429 /* calculate the hash and insert it into parent (list with keys is handled when its keys are inserted) */
430 lyd_hash(cur);
431 lyd_insert_hash(cur);
Radek Krejcib6f7ae52019-07-19 10:31:42 +0200432
433 /* if we have empty non-presence container, we keep it, but mark it as default */
434 if (cur->schema->nodetype == LYS_CONTAINER && !((struct lyd_node_inner*)cur)->child &&
435 !cur->attr && !(((struct lysc_node_container*)cur->schema)->flags & LYS_PRESENCE)) {
436 cur->flags |= LYD_DEFAULT;
437 }
438
439 /* TODO context validation */
Radek Krejcie7b95092019-05-15 11:03:07 +0200440 }
441
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200442 /* TODO add missing siblings default elements */
443
Radek Krejcie7b95092019-05-15 11:03:07 +0200444cleanup:
Radek Krejcie7b95092019-05-15 11:03:07 +0200445 lyd_free_attr(ctx->ctx, attributes, 1);
Radek Krejcie7b95092019-05-15 11:03:07 +0200446 return ret;
Radek Krejci11702142019-07-24 17:46:04 +0200447
448error:
449 ret = LY_EVALID;
450 goto cleanup;
Radek Krejcie7b95092019-05-15 11:03:07 +0200451}
452
453LY_ERR
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200454lyd_parse_xml(struct ly_ctx *ctx, const char *data, int options, const struct lyd_node **trees, struct lyd_node **result)
Radek Krejcie7b95092019-05-15 11:03:07 +0200455{
Radek Krejci18a57d92019-07-25 14:01:42 +0200456 LY_ERR ret = LY_SUCCESS;
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200457 struct lyd_node_inner *parent = NULL;
Radek Krejcie7b95092019-05-15 11:03:07 +0200458 struct lyd_xml_ctx xmlctx = {0};
459
460 xmlctx.options = options;
461 xmlctx.ctx = ctx;
462 xmlctx.line = 1;
463
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200464 /* init */
465 *result = NULL;
466
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200467 if (options & LYD_OPT_RPCREPLY) {
Radek Krejci3c1046e2019-07-26 13:06:53 +0200468 /* prepare container for RPC reply, for which we need RPC
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200469 * - prepare *result as top-level node
470 * - prepare parent as the RPC/action node */
Radek Krejci3c1046e2019-07-26 13:06:53 +0200471 const struct lyd_node *action;
472 for (action = trees[0]; action && action->schema->nodetype != LYS_ACTION; action = lyd_node_children(action)) {
473 /* skip list's keys */
Radek Krejci26a5dfb2019-07-26 14:51:06 +0200474 for ( ;action && action->schema->nodetype == LYS_LEAF; action = action->next);
475 if (action && action->schema->nodetype == LYS_ACTION) {
476 break;
477 }
Radek Krejci3c1046e2019-07-26 13:06:53 +0200478 }
479 if (!action) {
480 LOGERR(ctx, LY_EINVAL, "Data parser invalid argument trees - the first item in the array must be the RPC/action request when parsing %s.",
481 lyd_parse_options_type2str(options));
482 return LY_EINVAL;
483 }
484 parent = (struct lyd_node_inner*)lyd_dup(action, NULL, LYD_DUP_WITH_PARENTS);
485 LY_CHECK_ERR_RET(!parent, LOGERR(ctx, ly_errcode(ctx), "Unable to duplicate RPC/action container for RPC/action reply."), ly_errcode(ctx));
486 for (*result = (struct lyd_node*)parent; (*result)->parent; *result = (struct lyd_node*)(*result)->parent);
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200487 }
488
Radek Krejci26a5dfb2019-07-26 14:51:06 +0200489 if (!data || !data[0]) {
490 goto no_data;
491 }
492
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200493 ret = lydxml_nodes(&xmlctx, parent, &data, *result ? &parent->child : result);
Radek Krejcie92210c2019-05-17 15:53:35 +0200494 if (ret) {
495 lyd_free_all(*result);
496 *result = NULL;
Radek Krejcie553e6d2019-06-07 15:33:18 +0200497 } else {
498 /* finish incompletely validated terminal values */
499 for (unsigned int u = 0; u < xmlctx.incomplete_type_validation.count; u++) {
500 struct lyd_node_term *node = (struct lyd_node_term*)xmlctx.incomplete_type_validation.objs[u];
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200501 const struct lyd_node **result_trees = NULL;
Radek Krejcie72c0432019-06-10 10:17:03 +0200502
503 /* prepare sized array for validator */
504 if (*result) {
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200505 result_trees = lyd_trees_new(1, *result);
Radek Krejcie553e6d2019-06-07 15:33:18 +0200506 }
Radek Krejcie72c0432019-06-10 10:17:03 +0200507 /* validate and store the value of the node */
Radek Krejci3c9758d2019-07-11 16:49:10 +0200508 ret = lyd_value_parse(node, node->value.canonized, node->value.canonized ? strlen(node->value.canonized) : 0, 0, 1,
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200509 lydxml_resolve_prefix, ctx, LYD_XML, result_trees);
510 lyd_trees_free(result_trees, 0);
Radek Krejcie553e6d2019-06-07 15:33:18 +0200511 if (ret) {
512 lyd_free_all(*result);
513 *result = NULL;
514 break;
515 }
516 }
Radek Krejci38d85362019-09-05 16:26:38 +0200517 /* ... and attribute values */
518 for (unsigned int u = 0; u < xmlctx.incomplete_type_validation_attrs.count; u++) {
519 struct lyd_attr *attr = (struct lyd_attr*)xmlctx.incomplete_type_validation_attrs.objs[u];
520 const struct lyd_node **result_trees = NULL;
521
522 /* prepare sized array for validator */
523 if (*result) {
524 result_trees = lyd_trees_new(1, *result);
525 }
526 /* validate and store the value of the node */
527 ret = lyd_value_parse_attr(attr, attr->value.canonized, attr->value.canonized ? strlen(attr->value.canonized) : 0, 0, 1,
528 lydxml_resolve_prefix, ctx, LYD_XML, result_trees);
529 lyd_trees_free(result_trees, 0);
530 if (ret) {
531 lyd_free_all(*result);
532 *result = NULL;
533 break;
534 }
535 }
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200536
Radek Krejci3c1046e2019-07-26 13:06:53 +0200537 if (!(*result) || (parent && !parent->child)) {
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200538no_data:
539 /* no data */
540 if (options & (LYD_OPT_RPC | LYD_OPT_NOTIF)) {
Radek Krejci3c1046e2019-07-26 13:06:53 +0200541 /* error, missing top level node identify RPC and Notification */
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200542 LOGERR(ctx, LY_EINVAL, "Invalid input data of data parser - expected %s which cannot be empty.",
543 lyd_parse_options_type2str(options));
544 } else {
545 /* others - no work is needed, just check for missing mandatory nodes */
Radek Krejci3c1046e2019-07-26 13:06:53 +0200546 /* TODO lyd_validate(&result, options, ctx);
547 * - according to the data tree type */
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200548 }
549 }
Radek Krejcie92210c2019-05-17 15:53:35 +0200550 }
Radek Krejcie553e6d2019-06-07 15:33:18 +0200551
552 ly_set_erase(&xmlctx.incomplete_type_validation, NULL);
Radek Krejci38d85362019-09-05 16:26:38 +0200553 ly_set_erase(&xmlctx.incomplete_type_validation_attrs, NULL);
Radek Krejcie7b95092019-05-15 11:03:07 +0200554 lyxml_context_clear((struct lyxml_context*)&xmlctx);
555 return ret;
556}