blob: d967fe978c540cc642f717c14d45b1cf3e0b76ca [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
Radek Krejci28681fa2019-09-06 13:08:45 +020070struct attr_data_s {
71 const char *prefix;
72 const char *name;
73 char *value;
74 size_t prefix_len;
75 size_t name_len;
76 size_t value_len;
77 int dynamic;
78};
79
Radek Krejciaca74032019-06-04 08:53:06 +020080/**
Radek Krejcie7b95092019-05-15 11:03:07 +020081 * @brief Parse XML attributes of the XML element of YANG data.
82 *
83 * @param[in] ctx XML YANG data parser context.
Radek Krejcie7b95092019-05-15 11:03:07 +020084 * @param[in,out] data Pointer to the XML string representation of the YANG data to parse.
85 * @param[out] attributes Resulting list of the parsed attributes. XML namespace definitions are not parsed
86 * as attributes, they are stored internally in the parser context.
87 * @reutn LY_ERR value.
88 */
89static LY_ERR
Radek Krejci28681fa2019-09-06 13:08:45 +020090lydxml_attributes_parse(struct lyd_xml_ctx *ctx, const char **data, struct ly_set *attrs_data)
Radek Krejcie7b95092019-05-15 11:03:07 +020091{
92 LY_ERR ret = LY_SUCCESS;
Radek Krejci28681fa2019-09-06 13:08:45 +020093 unsigned int u;
Radek Krejcie7b95092019-05-15 11:03:07 +020094 const char *prefix, *name;
95 size_t prefix_len, name_len;
Radek Krejci28681fa2019-09-06 13:08:45 +020096 struct attr_data_s *attr_data;
Radek Krejcie7b95092019-05-15 11:03:07 +020097
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;
Radek Krejci28681fa2019-09-06 13:08:45 +0200113 attr_data->name = name;
Radek Krejci38d85362019-09-05 16:26:38 +0200114 attr_data->prefix_len = prefix_len;
Radek Krejci28681fa2019-09-06 13:08:45 +0200115 attr_data->name_len = name_len;
Radek Krejci38d85362019-09-05 16:26:38 +0200116 ret = lyxml_get_string((struct lyxml_context *)ctx, data, &buffer, &buffer_size, &attr_data->value, &attr_data->value_len, &attr_data->dynamic);
Radek Krejci28681fa2019-09-06 13:08:45 +0200117 LY_CHECK_ERR_GOTO(ret, free(attr_data), error);
118 ly_set_add(attrs_data, attr_data, LY_SET_OPT_USEASLIST);
119 }
120
121 return LY_SUCCESS;
122
123error:
124 for (u = 0; u < attrs_data->count; ++u) {
125 if (((struct attr_data_s*)attrs_data->objs[u])->dynamic) {
126 free(((struct attr_data_s*)attrs_data->objs[u])->value);
127 }
128 }
129 ly_set_erase(attrs_data, free);
130 return ret;
131}
132
133static LY_ERR
134lydxml_attributes(struct lyd_xml_ctx *ctx, struct ly_set *attrs_data, struct lyd_node *parent)
135{
136 LY_ERR ret = LY_EVALID, rc;
137 struct lyd_attr *attr = NULL, *last = NULL;
138 const struct lyxml_ns *ns;
139 struct lys_module *mod;
140
141 for (unsigned int u = 0; u < attrs_data->count; ++u) {
142 unsigned int v;
143 struct lysc_ext_instance *ant = NULL;
144 struct attr_data_s *attr_data = (struct attr_data_s*)attrs_data->objs[u];
145
146 if (!attr_data->prefix_len) {
147 /* in XML, all attributes must be prefixed
148 * TODO exception for NETCONF filters which are supposed to map to the ietf-netconf without prefix */
149 if (ctx->options & LYD_OPT_STRICT) {
150 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Missing mandatory prefix for XML attribute \"%.*s\".",
151 attr_data->name_len, attr_data->name);
152 }
153skip_attr:
154 if (attr_data->dynamic) {
155 free(attr_data->value);
156 attr_data->dynamic = 0;
157 }
158 continue;
159 }
160
161 /* get namespace of the attribute to find its annotation definition */
162 ns = lyxml_ns_get((struct lyxml_context *)ctx, attr_data->prefix, attr_data->prefix_len);
163 if (!ns) {
164 /* unknown namespace, ignore the attribute */
165 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", attr_data->prefix_len, attr_data->prefix);
166 goto cleanup;
167 }
168 mod = ly_ctx_get_module_implemented_ns(ctx->ctx, ns->uri);
169 if (!mod) {
170 /* module is not implemented or not present in the schema */
171 if (ctx->options & LYD_OPT_STRICT) {
172 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE,
173 "Unknown (or not implemented) YANG module with namespace \"%s\" for attribute \"%.*s%s%.*s\".",
174 ns, attr_data->prefix_len, attr_data->prefix, attr_data->prefix_len ? ":" : "", attr_data->name_len, attr_data->name);
175 }
176 goto skip_attr;
177 }
178
179 LY_ARRAY_FOR(mod->compiled->exts, v) {
180 if (mod->compiled->exts[v].def->plugin == lyext_plugins_internal[LYEXT_PLUGIN_INTERNAL_ANNOTATION].plugin &&
181 !strncmp(mod->compiled->exts[v].argument, attr_data->name, attr_data->name_len) && !mod->compiled->exts[v].argument[attr_data->name_len]) {
182 /* we have the annotation definition */
183 ant = &mod->compiled->exts[v];
184 break;
185 }
186 }
187 if (!ant) {
188 /* attribute is not defined as a metadata annotation (RFC 7952) */
189 if (ctx->options & LYD_OPT_STRICT) {
190 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Annotation definition for attribute \"%s:%.*s\" not found.",
191 mod->name, attr_data->name_len, attr_data->name);
192 }
193 goto skip_attr;
194 }
Radek Krejci17a78d82019-05-15 15:49:55 +0200195
196 attr = calloc(1, sizeof *attr);
197 LY_CHECK_ERR_GOTO(!attr, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
Radek Krejci28681fa2019-09-06 13:08:45 +0200198 attr->parent = parent;
199 attr->annotation = ant;
200 rc = lyd_value_parse_attr(attr, attr_data->value, attr_data->value_len, attr_data->dynamic, 0, lydxml_resolve_prefix, ctx, LYD_XML, NULL);
201 if (rc == LY_EINCOMPLETE) {
202 ly_set_add(&ctx->incomplete_type_validation_attrs, attr, LY_SET_OPT_USEASLIST);
203 } else if (rc) {
204 ret = rc;
205 free(attr);
206 goto cleanup;
207 }
208 attr_data->dynamic = 0; /* value eaten by lyd_value_parse_attr() */
209 attr->name = lydict_insert(ctx->ctx, attr_data->name, attr_data->name_len);
Radek Krejci17a78d82019-05-15 15:49:55 +0200210
211 if (last) {
212 last->next = attr;
213 } else {
Radek Krejci28681fa2019-09-06 13:08:45 +0200214 parent->attr = attr;
Radek Krejci17a78d82019-05-15 15:49:55 +0200215 }
216 last = attr;
Radek Krejcie7b95092019-05-15 11:03:07 +0200217 }
Radek Krejci28681fa2019-09-06 13:08:45 +0200218 ret = LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200219
220cleanup:
221
Radek Krejci28681fa2019-09-06 13:08:45 +0200222 for (unsigned int u = 0; u < attrs_data->count; ++u) {
223 if (((struct attr_data_s*)attrs_data->objs[u])->dynamic) {
224 free(((struct attr_data_s*)attrs_data->objs[u])->value);
Radek Krejci38d85362019-09-05 16:26:38 +0200225 }
226 }
Radek Krejci28681fa2019-09-06 13:08:45 +0200227 ly_set_erase(attrs_data, free);
228
Radek Krejcie7b95092019-05-15 11:03:07 +0200229 return ret;
230}
231
232/**
233 * @brief Parse XML elements as children YANG data node of the specified parent node.
234 *
235 * @param[in] ctx XML YANG data parser context.
236 * @param[in] parent Parent node where the children are inserted. NULL in case of parsing top-level elements.
237 * @param[in,out] data Pointer to the XML string representation of the YANG data to parse.
238 * @param[out] node Resulting list of the parsed nodes.
239 * @reutn LY_ERR value.
240 */
241static LY_ERR
242lydxml_nodes(struct lyd_xml_ctx *ctx, struct lyd_node_inner *parent, const char **data, struct lyd_node **node)
243{
244 LY_ERR ret = LY_SUCCESS;
245 const char *prefix, *name;
Radek Krejcie7b95092019-05-15 11:03:07 +0200246 size_t prefix_len, name_len;
Radek Krejci28681fa2019-09-06 13:08:45 +0200247 struct ly_set attrs_data = {0};
Radek Krejcie7b95092019-05-15 11:03:07 +0200248 const struct lyxml_ns *ns;
249 const struct lysc_node *snode;
250 struct lys_module *mod;
251 unsigned int parents_count = ctx->elements.count;
Radek Krejci710226d2019-07-24 17:24:59 +0200252 struct lyd_node *cur = NULL, *prev = NULL, *last = NULL;
Radek Krejcie7b95092019-05-15 11:03:07 +0200253
254 (*node) = NULL;
255
256 while(ctx->status == LYXML_ELEMENT) {
257 ret = lyxml_get_element((struct lyxml_context *)ctx, data, &prefix, &prefix_len, &name, &name_len);
258 LY_CHECK_GOTO(ret, cleanup);
259 if (!name) {
260 /* closing previous element */
Radek Krejcie7b95092019-05-15 11:03:07 +0200261 if (ctx->elements.count < parents_count) {
262 /* all siblings parsed */
263 break;
264 } else {
265 continue;
266 }
267 }
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200268 if (ctx->status == LYXML_ATTRIBUTE) {
Radek Krejci28681fa2019-09-06 13:08:45 +0200269 LY_CHECK_GOTO(lydxml_attributes_parse(ctx, data, &attrs_data), error);
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200270 }
271
Radek Krejcie7b95092019-05-15 11:03:07 +0200272 ns = lyxml_ns_get((struct lyxml_context *)ctx, prefix, prefix_len);
273 if (!ns) {
Radek Krejci28681fa2019-09-06 13:08:45 +0200274 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", prefix_len, prefix);
Radek Krejci11702142019-07-24 17:46:04 +0200275 goto error;
Radek Krejcie7b95092019-05-15 11:03:07 +0200276 }
277 mod = ly_ctx_get_module_implemented_ns(ctx->ctx, ns->uri);
278 if (!mod) {
279 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 +0200280 goto error;
Radek Krejcie7b95092019-05-15 11:03:07 +0200281 }
282 snode = lys_child(parent ? parent->schema : NULL, mod, name, name_len, 0, (ctx->options & LYD_OPT_RPCREPLY) ? LYS_GETNEXT_OUTPUT : 0);
283 if (!snode) {
284 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 +0200285 goto error;
Radek Krejcie7b95092019-05-15 11:03:07 +0200286 }
287
288 /* allocate new node */
289 switch (snode->nodetype) {
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200290 case LYS_ACTION:
291 if ((ctx->options & LYD_OPT_TYPEMASK) != LYD_OPT_RPC) {
292 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_RESTRICTION, "Unexpected RPC/action element \"%.*s\" in %s data set.",
293 name_len, name, lyd_parse_options_type2str(ctx->options & LYD_OPT_TYPEMASK));
Radek Krejci11702142019-07-24 17:46:04 +0200294 goto error;
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200295 }
296 cur = calloc(1, sizeof(struct lyd_node_inner));
297 break;
298 case LYS_NOTIF:
299 if ((ctx->options & LYD_OPT_TYPEMASK) != LYD_OPT_RPC) {
300 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_RESTRICTION, "Unexpected Notification element \"%.*s\" in %s data set.",
301 name_len, name, lyd_parse_options_type2str(ctx->options));
Radek Krejci11702142019-07-24 17:46:04 +0200302 goto error;
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200303 }
304 cur = calloc(1, sizeof(struct lyd_node_inner));
305 break;
Radek Krejcie7b95092019-05-15 11:03:07 +0200306 case LYS_CONTAINER:
307 case LYS_LIST:
308 cur = calloc(1, sizeof(struct lyd_node_inner));
309 break;
310 case LYS_LEAF:
311 case LYS_LEAFLIST:
312 cur = calloc(1, sizeof(struct lyd_node_term));
313 break;
314 case LYS_ANYDATA:
315 case LYS_ANYXML:
316 cur = calloc(1, sizeof(struct lyd_node_any));
317 break;
Radek Krejcie7b95092019-05-15 11:03:07 +0200318 default:
319 LOGINT(ctx->ctx);
Radek Krejci11702142019-07-24 17:46:04 +0200320 ret = LY_EINT;
Radek Krejcie7b95092019-05-15 11:03:07 +0200321 goto cleanup;
322 }
323 if (!(*node)) {
324 (*node) = cur;
325 }
Radek Krejci710226d2019-07-24 17:24:59 +0200326 last = cur;
Radek Krejcie7b95092019-05-15 11:03:07 +0200327 cur->schema = snode;
Radek Krejci710226d2019-07-24 17:24:59 +0200328 cur->prev = cur;
Radek Krejcie7b95092019-05-15 11:03:07 +0200329 cur->parent = parent;
Radek Krejcie92210c2019-05-17 15:53:35 +0200330 if (parent) {
Radek Krejci710226d2019-07-24 17:24:59 +0200331 if (prev && cur->schema->nodetype == LYS_LEAF && (cur->schema->flags & LYS_KEY)) {
332 /* it is key and we need to insert it into a correct place */
Radek Krejci0fe9b512019-07-26 17:51:05 +0200333 struct lysc_node *key_s;
Radek Krejci710226d2019-07-24 17:24:59 +0200334 unsigned int cur_index, key_index;
335 struct lyd_node *key;
336
Radek Krejci0fe9b512019-07-26 17:51:05 +0200337 for (cur_index = 0, key_s = ((struct lysc_node_list*)parent->schema)->child;
338 key_s && key_s != cur->schema;
339 ++cur_index, key_s = key_s->next);
340 for (key = prev;
341 !(key->schema->flags & LYS_KEY) && key->prev != prev;
342 key = key->prev);
Radek Krejci710226d2019-07-24 17:24:59 +0200343 for (; key->schema->flags & LYS_KEY; key = key->prev) {
Radek Krejci0fe9b512019-07-26 17:51:05 +0200344 for (key_index = 0, key_s = ((struct lysc_node_list*)parent->schema)->child;
345 key_s && key_s != key->schema;
346 ++key_index, key_s = key_s->next);
Radek Krejci710226d2019-07-24 17:24:59 +0200347 if (key_index < cur_index) {
348 /* cur key is supposed to be placed after the key */
349 cur->next = key->next;
350 cur->prev = key;
351 key->next = cur;
352 if (cur->next) {
353 cur->next->prev = cur;
354 } else {
355 parent->child->prev = cur;
356 }
357 break;
358 }
359 if (key->prev == prev) {
360 /* current key is supposed to be the first child from the current children */
361 key = NULL;
362 break;
363 }
364 }
365 if (!key || !(key->schema->flags & LYS_KEY)) {
366 /* current key is supposed to be the first child from the current children */
367 cur->next = parent->child;
368 cur->prev = parent->child->prev;
369 parent->child->prev = cur;
370 parent->child = cur;
371 }
372 if (cur->next) {
373 last = prev;
374 if (ctx->options & LYD_OPT_STRICT) {
375 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_RESTRICTION, "Invalid position of the key \"%.*s\" in a list.",
376 name_len, name);
Radek Krejci11702142019-07-24 17:46:04 +0200377 goto error;
Radek Krejci710226d2019-07-24 17:24:59 +0200378 } else {
379 LOGWRN(ctx->ctx, "Invalid position of the key \"%.*s\" in a list.", name_len, name);
380 }
381 }
382 } else {
383 /* last child of the parent */
384 if (prev) {
385 parent->child->prev = cur;
386 prev->next = cur;
387 cur->prev = prev;
388 }
389 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200390 } else {
Radek Krejci710226d2019-07-24 17:24:59 +0200391 /* top level */
392 if (prev) {
393 /* last top level node */
394 struct lyd_node *iter;
395 for (iter = prev; iter->prev->next; iter = iter->prev);
396 iter->prev = cur;
397 prev->next = cur;
398 cur->prev = prev;
399 } /* first top level node - nothing more to do */
Radek Krejcie7b95092019-05-15 11:03:07 +0200400 }
Radek Krejci710226d2019-07-24 17:24:59 +0200401 prev = last;
Radek Krejci28681fa2019-09-06 13:08:45 +0200402 LY_CHECK_GOTO(ret = lydxml_attributes(ctx, &attrs_data, cur), cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200403
404 if (snode->nodetype & LYD_NODE_TERM) {
405 int dynamic = 0;
406 char *buffer = NULL, *value;
407 size_t buffer_size = 0, value_len;
408
409 if (ctx->status == LYXML_ELEM_CONTENT) {
410 /* get the value */
Radek Krejci11702142019-07-24 17:46:04 +0200411 ret = lyxml_get_string((struct lyxml_context *)ctx, data, &buffer, &buffer_size, &value, &value_len, &dynamic);
412 if (ret == LY_EINVAL) {
Radek Krejci339e2de2019-05-17 14:28:24 +0200413 /* just indentation of a child element found */
414 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX, "Child element inside terminal node \"%s\" found.", cur->schema->name);
415 goto cleanup;
416 }
Radek Krejci11702142019-07-24 17:46:04 +0200417 ret = LY_SUCCESS;
Radek Krejcie92210c2019-05-17 15:53:35 +0200418 } else {
419 /* no content - validate empty value */
420 value = "";
421 value_len = 0;
Radek Krejcie7b95092019-05-15 11:03:07 +0200422 }
Radek Krejci3c9758d2019-07-11 16:49:10 +0200423 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 +0200424 if (ret == LY_EINCOMPLETE) {
425 ly_set_add(&ctx->incomplete_type_validation, cur, LY_SET_OPT_USEASLIST);
426 } else if (ret) {
427 if (dynamic){
428 free(value);
429 }
430 goto cleanup;
431 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200432 } else if (snode->nodetype & LYD_NODE_INNER) {
433 int dynamic = 0;
434 char *buffer = NULL, *value;
435 size_t buffer_size = 0, value_len;
436
437 if (ctx->status == LYXML_ELEM_CONTENT) {
438 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 +0200439 if (r != LY_EINVAL && (r != LY_SUCCESS || value_len != 0)) {
Radek Krejcie7b95092019-05-15 11:03:07 +0200440 LOGINT(ctx->ctx);
Radek Krejci11702142019-07-24 17:46:04 +0200441 ret = LY_EINT;
Radek Krejcie7b95092019-05-15 11:03:07 +0200442 goto cleanup;
443 }
444 }
Radek Krejciee4cab22019-07-17 17:07:47 +0200445 /* process children */
Radek Krejcie553e6d2019-06-07 15:33:18 +0200446 if (ctx->status == LYXML_ELEMENT && parents_count != ctx->elements.count) {
Radek Krejcie7b95092019-05-15 11:03:07 +0200447 ret = lydxml_nodes(ctx, (struct lyd_node_inner*)cur, data, lyd_node_children_p(cur));
Radek Krejcie92210c2019-05-17 15:53:35 +0200448 LY_CHECK_GOTO(ret, cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200449 }
Radek Krejciee4cab22019-07-17 17:07:47 +0200450 } else if (snode->nodetype & LYD_NODE_ANY) {
451 unsigned int cur_element_index = ctx->elements.count;
452 const char *start = *data, *stop;
453 const char *p, *n;
454 size_t p_len, n_len;
455
456 /* skip children data and store them as a string */
Radek Krejci26a5dfb2019-07-26 14:51:06 +0200457 while (ctx->status != LYXML_END && cur_element_index <= ctx->elements.count) {
Radek Krejciee4cab22019-07-17 17:07:47 +0200458 switch (ctx->status) {
459 case LYXML_ELEMENT:
460 ret = lyxml_get_element((struct lyxml_context *)ctx, data, &p, &p_len, &n, &n_len);
461 break;
462 case LYXML_ATTRIBUTE:
463 lyxml_get_attribute((struct lyxml_context*)ctx, data, &p, &p_len, &n, &n_len);
464 break;
465 case LYXML_ELEM_CONTENT:
466 case LYXML_ATTR_CONTENT:
467 ret = lyxml_get_string((struct lyxml_context *)ctx, data, NULL, NULL, NULL, NULL, NULL);
468 if (ret == LY_EINVAL) {
469 /* not an error, just incorrect XML parser status */
470 ret = LY_SUCCESS;
471 }
472 break;
473 case LYXML_END:
Radek Krejci26a5dfb2019-07-26 14:51:06 +0200474 /* end of data */
Radek Krejciee4cab22019-07-17 17:07:47 +0200475 LOGINT(ctx->ctx);
Radek Krejci11702142019-07-24 17:46:04 +0200476 ret = LY_EINT;
Radek Krejciee4cab22019-07-17 17:07:47 +0200477 goto cleanup;
478 }
479 LY_CHECK_GOTO(ret, cleanup);
480 }
Radek Krejciee4cab22019-07-17 17:07:47 +0200481 ((struct lyd_node_any*)cur)->value_type = LYD_ANYDATA_XML;
Radek Krejci26a5dfb2019-07-26 14:51:06 +0200482 if (start != *data) {
483 /* data now points after the anydata's closing element tag, we need just end of its content */
484 for (stop = *data - 1; *stop != '<'; --stop);
485 ((struct lyd_node_any*)cur)->value.xml = lydict_insert(ctx->ctx, start, stop - start);
486 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200487 }
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200488
489 /* calculate the hash and insert it into parent (list with keys is handled when its keys are inserted) */
490 lyd_hash(cur);
491 lyd_insert_hash(cur);
Radek Krejcib6f7ae52019-07-19 10:31:42 +0200492
493 /* if we have empty non-presence container, we keep it, but mark it as default */
494 if (cur->schema->nodetype == LYS_CONTAINER && !((struct lyd_node_inner*)cur)->child &&
495 !cur->attr && !(((struct lysc_node_container*)cur->schema)->flags & LYS_PRESENCE)) {
496 cur->flags |= LYD_DEFAULT;
497 }
498
499 /* TODO context validation */
Radek Krejcie7b95092019-05-15 11:03:07 +0200500 }
501
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200502 /* TODO add missing siblings default elements */
503
Radek Krejcie7b95092019-05-15 11:03:07 +0200504cleanup:
Radek Krejci28681fa2019-09-06 13:08:45 +0200505 for (unsigned int u = 0; u < attrs_data.count; ++u) {
506 if (((struct attr_data_s*)attrs_data.objs[u])->dynamic) {
507 free(((struct attr_data_s*)attrs_data.objs[u])->value);
508 }
509 }
510 ly_set_erase(&attrs_data, free);
Radek Krejcie7b95092019-05-15 11:03:07 +0200511 return ret;
Radek Krejci11702142019-07-24 17:46:04 +0200512
513error:
514 ret = LY_EVALID;
515 goto cleanup;
Radek Krejcie7b95092019-05-15 11:03:07 +0200516}
517
518LY_ERR
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200519lyd_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 +0200520{
Radek Krejci18a57d92019-07-25 14:01:42 +0200521 LY_ERR ret = LY_SUCCESS;
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200522 struct lyd_node_inner *parent = NULL;
Radek Krejcie7b95092019-05-15 11:03:07 +0200523 struct lyd_xml_ctx xmlctx = {0};
524
525 xmlctx.options = options;
526 xmlctx.ctx = ctx;
527 xmlctx.line = 1;
528
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200529 /* init */
530 *result = NULL;
531
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200532 if (options & LYD_OPT_RPCREPLY) {
Radek Krejci3c1046e2019-07-26 13:06:53 +0200533 /* prepare container for RPC reply, for which we need RPC
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200534 * - prepare *result as top-level node
535 * - prepare parent as the RPC/action node */
Radek Krejci3c1046e2019-07-26 13:06:53 +0200536 const struct lyd_node *action;
537 for (action = trees[0]; action && action->schema->nodetype != LYS_ACTION; action = lyd_node_children(action)) {
538 /* skip list's keys */
Radek Krejci26a5dfb2019-07-26 14:51:06 +0200539 for ( ;action && action->schema->nodetype == LYS_LEAF; action = action->next);
540 if (action && action->schema->nodetype == LYS_ACTION) {
541 break;
542 }
Radek Krejci3c1046e2019-07-26 13:06:53 +0200543 }
544 if (!action) {
545 LOGERR(ctx, LY_EINVAL, "Data parser invalid argument trees - the first item in the array must be the RPC/action request when parsing %s.",
546 lyd_parse_options_type2str(options));
547 return LY_EINVAL;
548 }
549 parent = (struct lyd_node_inner*)lyd_dup(action, NULL, LYD_DUP_WITH_PARENTS);
550 LY_CHECK_ERR_RET(!parent, LOGERR(ctx, ly_errcode(ctx), "Unable to duplicate RPC/action container for RPC/action reply."), ly_errcode(ctx));
551 for (*result = (struct lyd_node*)parent; (*result)->parent; *result = (struct lyd_node*)(*result)->parent);
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200552 }
553
Radek Krejci26a5dfb2019-07-26 14:51:06 +0200554 if (!data || !data[0]) {
555 goto no_data;
556 }
557
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200558 ret = lydxml_nodes(&xmlctx, parent, &data, *result ? &parent->child : result);
Radek Krejcie92210c2019-05-17 15:53:35 +0200559 if (ret) {
560 lyd_free_all(*result);
561 *result = NULL;
Radek Krejcie553e6d2019-06-07 15:33:18 +0200562 } else {
563 /* finish incompletely validated terminal values */
564 for (unsigned int u = 0; u < xmlctx.incomplete_type_validation.count; u++) {
565 struct lyd_node_term *node = (struct lyd_node_term*)xmlctx.incomplete_type_validation.objs[u];
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200566 const struct lyd_node **result_trees = NULL;
Radek Krejcie72c0432019-06-10 10:17:03 +0200567
568 /* prepare sized array for validator */
569 if (*result) {
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200570 result_trees = lyd_trees_new(1, *result);
Radek Krejcie553e6d2019-06-07 15:33:18 +0200571 }
Radek Krejcie72c0432019-06-10 10:17:03 +0200572 /* validate and store the value of the node */
Radek Krejci3c9758d2019-07-11 16:49:10 +0200573 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 +0200574 lydxml_resolve_prefix, ctx, LYD_XML, result_trees);
575 lyd_trees_free(result_trees, 0);
Radek Krejcie553e6d2019-06-07 15:33:18 +0200576 if (ret) {
577 lyd_free_all(*result);
578 *result = NULL;
579 break;
580 }
581 }
Radek Krejci38d85362019-09-05 16:26:38 +0200582 /* ... and attribute values */
583 for (unsigned int u = 0; u < xmlctx.incomplete_type_validation_attrs.count; u++) {
584 struct lyd_attr *attr = (struct lyd_attr*)xmlctx.incomplete_type_validation_attrs.objs[u];
585 const struct lyd_node **result_trees = NULL;
586
587 /* prepare sized array for validator */
588 if (*result) {
589 result_trees = lyd_trees_new(1, *result);
590 }
591 /* validate and store the value of the node */
592 ret = lyd_value_parse_attr(attr, attr->value.canonized, attr->value.canonized ? strlen(attr->value.canonized) : 0, 0, 1,
593 lydxml_resolve_prefix, ctx, LYD_XML, result_trees);
594 lyd_trees_free(result_trees, 0);
595 if (ret) {
596 lyd_free_all(*result);
597 *result = NULL;
598 break;
599 }
600 }
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200601
Radek Krejci3c1046e2019-07-26 13:06:53 +0200602 if (!(*result) || (parent && !parent->child)) {
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200603no_data:
604 /* no data */
605 if (options & (LYD_OPT_RPC | LYD_OPT_NOTIF)) {
Radek Krejci3c1046e2019-07-26 13:06:53 +0200606 /* error, missing top level node identify RPC and Notification */
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200607 LOGERR(ctx, LY_EINVAL, "Invalid input data of data parser - expected %s which cannot be empty.",
608 lyd_parse_options_type2str(options));
609 } else {
610 /* others - no work is needed, just check for missing mandatory nodes */
Radek Krejci3c1046e2019-07-26 13:06:53 +0200611 /* TODO lyd_validate(&result, options, ctx);
612 * - according to the data tree type */
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200613 }
614 }
Radek Krejcie92210c2019-05-17 15:53:35 +0200615 }
Radek Krejcie553e6d2019-06-07 15:33:18 +0200616
617 ly_set_erase(&xmlctx.incomplete_type_validation, NULL);
Radek Krejci38d85362019-09-05 16:26:38 +0200618 ly_set_erase(&xmlctx.incomplete_type_validation_attrs, NULL);
Radek Krejcie7b95092019-05-15 11:03:07 +0200619 lyxml_context_clear((struct lyxml_context*)&xmlctx);
620 return ret;
621}