blob: f61d6e60b1a77bac13797486a4a06d9e0058668f [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"
Michal Vaskocde73ac2019-11-14 16:10:27 +010030#include "validation.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 */
Michal Vaskoecd62de2019-11-13 12:35:11 +010050 struct ly_set when_check; /**< set of nodes with "when" conditions */
Radek Krejcie7b95092019-05-15 11:03:07 +020051};
52
53/**
Radek Krejciaca74032019-06-04 08:53:06 +020054 * @brief XML-parser's implementation of ly_type_resolve_prefix() callback to provide mapping between prefixes used in the values to the schema
55 * via XML namespaces.
56 */
57static const struct lys_module *
58lydxml_resolve_prefix(struct ly_ctx *ctx, const char *prefix, size_t prefix_len, void *parser)
59{
60 const struct lyxml_ns *ns;
61 struct lyxml_context *xmlctx = (struct lyxml_context*)parser;
62
63 ns = lyxml_ns_get(xmlctx, prefix, prefix_len);
64 if (!ns) {
65 return NULL;
66 }
67
68 return ly_ctx_get_module_implemented_ns(ctx, ns->uri);
69}
70
Radek Krejci28681fa2019-09-06 13:08:45 +020071struct attr_data_s {
72 const char *prefix;
73 const char *name;
74 char *value;
75 size_t prefix_len;
76 size_t name_len;
77 size_t value_len;
78 int dynamic;
79};
80
Radek Krejciaca74032019-06-04 08:53:06 +020081/**
Radek Krejcie7b95092019-05-15 11:03:07 +020082 * @brief Parse XML attributes of the XML element of YANG data.
83 *
84 * @param[in] ctx XML YANG data parser context.
Radek Krejcie7b95092019-05-15 11:03:07 +020085 * @param[in,out] data Pointer to the XML string representation of the YANG data to parse.
86 * @param[out] attributes Resulting list of the parsed attributes. XML namespace definitions are not parsed
87 * as attributes, they are stored internally in the parser context.
88 * @reutn LY_ERR value.
89 */
90static LY_ERR
Radek Krejci28681fa2019-09-06 13:08:45 +020091lydxml_attributes_parse(struct lyd_xml_ctx *ctx, const char **data, struct ly_set *attrs_data)
Radek Krejcie7b95092019-05-15 11:03:07 +020092{
93 LY_ERR ret = LY_SUCCESS;
Radek Krejci28681fa2019-09-06 13:08:45 +020094 unsigned int u;
Radek Krejcie7b95092019-05-15 11:03:07 +020095 const char *prefix, *name;
96 size_t prefix_len, name_len;
Radek Krejci28681fa2019-09-06 13:08:45 +020097 struct attr_data_s *attr_data;
Radek Krejcie7b95092019-05-15 11:03:07 +020098
99 while(ctx->status == LYXML_ATTRIBUTE &&
100 lyxml_get_attribute((struct lyxml_context*)ctx, data, &prefix, &prefix_len, &name, &name_len) == LY_SUCCESS) {
Radek Krejci38d85362019-09-05 16:26:38 +0200101 char *buffer = NULL;
102 size_t buffer_size = 0;
Radek Krejcie7b95092019-05-15 11:03:07 +0200103
Radek Krejci17a78d82019-05-15 15:49:55 +0200104 if (!name) {
105 /* seems like all the attrributes were internally processed as namespace definitions */
106 continue;
Radek Krejcie7b95092019-05-15 11:03:07 +0200107 }
Radek Krejci17a78d82019-05-15 15:49:55 +0200108
Radek Krejci38d85362019-09-05 16:26:38 +0200109 /* auxiliary store the prefix information and value string, because we have to wait with resolving prefix
110 * to the time when all the namespaces, defined in this element, are parsed. With the prefix we can find the
111 * annotation definition for the attribute and correctly process the value */
112 attr_data = malloc(sizeof *attr_data);
113 attr_data->prefix = prefix;
Radek Krejci28681fa2019-09-06 13:08:45 +0200114 attr_data->name = name;
Radek Krejci38d85362019-09-05 16:26:38 +0200115 attr_data->prefix_len = prefix_len;
Radek Krejci28681fa2019-09-06 13:08:45 +0200116 attr_data->name_len = name_len;
Radek Krejci38d85362019-09-05 16:26:38 +0200117 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 +0200118 LY_CHECK_ERR_GOTO(ret, free(attr_data), error);
119 ly_set_add(attrs_data, attr_data, LY_SET_OPT_USEASLIST);
120 }
121
122 return LY_SUCCESS;
123
124error:
125 for (u = 0; u < attrs_data->count; ++u) {
126 if (((struct attr_data_s*)attrs_data->objs[u])->dynamic) {
127 free(((struct attr_data_s*)attrs_data->objs[u])->value);
128 }
129 }
130 ly_set_erase(attrs_data, free);
131 return ret;
132}
133
134static LY_ERR
135lydxml_attributes(struct lyd_xml_ctx *ctx, struct ly_set *attrs_data, struct lyd_node *parent)
136{
137 LY_ERR ret = LY_EVALID, rc;
Michal Vasko90932a92020-02-12 14:33:03 +0100138 struct lyd_attr *attr = NULL;
Radek Krejci28681fa2019-09-06 13:08:45 +0200139 const struct lyxml_ns *ns;
140 struct lys_module *mod;
141
142 for (unsigned int u = 0; u < attrs_data->count; ++u) {
Radek Krejci28681fa2019-09-06 13:08:45 +0200143 struct attr_data_s *attr_data = (struct attr_data_s*)attrs_data->objs[u];
144
145 if (!attr_data->prefix_len) {
146 /* in XML, all attributes must be prefixed
147 * TODO exception for NETCONF filters which are supposed to map to the ietf-netconf without prefix */
148 if (ctx->options & LYD_OPT_STRICT) {
149 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Missing mandatory prefix for XML attribute \"%.*s\".",
150 attr_data->name_len, attr_data->name);
151 }
152skip_attr:
153 if (attr_data->dynamic) {
154 free(attr_data->value);
155 attr_data->dynamic = 0;
156 }
157 continue;
158 }
159
160 /* get namespace of the attribute to find its annotation definition */
161 ns = lyxml_ns_get((struct lyxml_context *)ctx, attr_data->prefix, attr_data->prefix_len);
162 if (!ns) {
163 /* unknown namespace, ignore the attribute */
164 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", attr_data->prefix_len, attr_data->prefix);
165 goto cleanup;
166 }
167 mod = ly_ctx_get_module_implemented_ns(ctx->ctx, ns->uri);
168 if (!mod) {
169 /* module is not implemented or not present in the schema */
170 if (ctx->options & LYD_OPT_STRICT) {
171 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE,
172 "Unknown (or not implemented) YANG module with namespace \"%s\" for attribute \"%.*s%s%.*s\".",
Michal Vasko90932a92020-02-12 14:33:03 +0100173 ns, attr_data->prefix_len, attr_data->prefix, attr_data->prefix_len ? ":" : "", attr_data->name_len,
174 attr_data->name);
Radek Krejci28681fa2019-09-06 13:08:45 +0200175 }
176 goto skip_attr;
177 }
178
Michal Vasko90932a92020-02-12 14:33:03 +0100179 rc = lyd_create_attr(parent, mod, attr_data->name, attr_data->name_len, attr_data->value, attr_data->value_len,
180 &attr_data->dynamic, lydxml_resolve_prefix, ctx, LYD_XML, &attr);
Radek Krejci28681fa2019-09-06 13:08:45 +0200181 if (rc == LY_EINCOMPLETE) {
182 ly_set_add(&ctx->incomplete_type_validation_attrs, attr, LY_SET_OPT_USEASLIST);
183 } else if (rc) {
184 ret = rc;
Radek Krejci28681fa2019-09-06 13:08:45 +0200185 goto cleanup;
186 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200187 }
Radek Krejci28681fa2019-09-06 13:08:45 +0200188 ret = LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200189
190cleanup:
191
Radek Krejci28681fa2019-09-06 13:08:45 +0200192 for (unsigned int u = 0; u < attrs_data->count; ++u) {
193 if (((struct attr_data_s*)attrs_data->objs[u])->dynamic) {
194 free(((struct attr_data_s*)attrs_data->objs[u])->value);
Radek Krejci38d85362019-09-05 16:26:38 +0200195 }
196 }
Radek Krejci28681fa2019-09-06 13:08:45 +0200197 ly_set_erase(attrs_data, free);
198
Radek Krejcie7b95092019-05-15 11:03:07 +0200199 return ret;
200}
201
202/**
203 * @brief Parse XML elements as children YANG data node of the specified parent node.
204 *
205 * @param[in] ctx XML YANG data parser context.
206 * @param[in] parent Parent node where the children are inserted. NULL in case of parsing top-level elements.
207 * @param[in,out] data Pointer to the XML string representation of the YANG data to parse.
208 * @param[out] node Resulting list of the parsed nodes.
209 * @reutn LY_ERR value.
210 */
211static LY_ERR
212lydxml_nodes(struct lyd_xml_ctx *ctx, struct lyd_node_inner *parent, const char **data, struct lyd_node **node)
213{
214 LY_ERR ret = LY_SUCCESS;
215 const char *prefix, *name;
Radek Krejcie7b95092019-05-15 11:03:07 +0200216 size_t prefix_len, name_len;
Radek Krejci28681fa2019-09-06 13:08:45 +0200217 struct ly_set attrs_data = {0};
Radek Krejcie7b95092019-05-15 11:03:07 +0200218 const struct lyxml_ns *ns;
219 const struct lysc_node *snode;
220 struct lys_module *mod;
221 unsigned int parents_count = ctx->elements.count;
Michal Vasko90932a92020-02-12 14:33:03 +0100222 struct lyd_node *cur = NULL, *key_anchor;
223 int dynamic = 0;
224 char *buffer = NULL, *value;
225 size_t buffer_size = 0, value_len;
Radek Krejcie7b95092019-05-15 11:03:07 +0200226
Michal Vasko14654712020-02-06 08:35:21 +0100227 while (ctx->status == LYXML_ELEMENT) {
Radek Krejcie7b95092019-05-15 11:03:07 +0200228 ret = lyxml_get_element((struct lyxml_context *)ctx, data, &prefix, &prefix_len, &name, &name_len);
229 LY_CHECK_GOTO(ret, cleanup);
230 if (!name) {
231 /* closing previous element */
Radek Krejcie7b95092019-05-15 11:03:07 +0200232 if (ctx->elements.count < parents_count) {
233 /* all siblings parsed */
234 break;
235 } else {
236 continue;
237 }
238 }
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200239 if (ctx->status == LYXML_ATTRIBUTE) {
Michal Vasko90932a92020-02-12 14:33:03 +0100240 if (lydxml_attributes_parse(ctx, data, &attrs_data) != LY_SUCCESS) {
241 ret = LY_EVALID;
242 goto cleanup;
243 }
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200244 }
245
Radek Krejcie7b95092019-05-15 11:03:07 +0200246 ns = lyxml_ns_get((struct lyxml_context *)ctx, prefix, prefix_len);
247 if (!ns) {
Radek Krejci28681fa2019-09-06 13:08:45 +0200248 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", prefix_len, prefix);
Michal Vasko90932a92020-02-12 14:33:03 +0100249 ret = LY_EVALID;
250 goto cleanup;
Radek Krejcie7b95092019-05-15 11:03:07 +0200251 }
252 mod = ly_ctx_get_module_implemented_ns(ctx->ctx, ns->uri);
253 if (!mod) {
254 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "No module with namespace \"%s\" in the context.", ns->uri);
Michal Vasko90932a92020-02-12 14:33:03 +0100255 ret = LY_EVALID;
256 goto cleanup;
Radek Krejcie7b95092019-05-15 11:03:07 +0200257 }
Michal Vaskoe444f752020-02-10 12:20:06 +0100258 snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, 0);
Radek Krejcie7b95092019-05-15 11:03:07 +0200259 if (!snode) {
Michal Vasko90932a92020-02-12 14:33:03 +0100260 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Element \"%.*s\" not found in the \"%s\" module.",
261 name_len, name, mod->name);
262 ret = LY_EVALID;
Radek Krejcie7b95092019-05-15 11:03:07 +0200263 goto cleanup;
264 }
Radek Krejci710226d2019-07-24 17:24:59 +0200265
Michal Vasko90932a92020-02-12 14:33:03 +0100266 if (snode->nodetype & (LYS_ACTION | LYS_NOTIF)) {
267 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_DATA, "Unexpected %s element \"%.*s\".",
268 snode->nodetype == LYS_ACTION ? "RPC/action" : "notification", name_len, name);
269 ret = LY_EVALID;
270 goto cleanup;
Radek Krejcie7b95092019-05-15 11:03:07 +0200271 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200272
273 if (snode->nodetype & LYD_NODE_TERM) {
Radek Krejcie7b95092019-05-15 11:03:07 +0200274 if (ctx->status == LYXML_ELEM_CONTENT) {
275 /* get the value */
Radek Krejci11702142019-07-24 17:46:04 +0200276 ret = lyxml_get_string((struct lyxml_context *)ctx, data, &buffer, &buffer_size, &value, &value_len, &dynamic);
Michal Vasko14654712020-02-06 08:35:21 +0100277 if (ret != LY_SUCCESS) {
278 if (ret == LY_EINVAL) {
279 /* just indentation of a child element found */
Michal Vasko90932a92020-02-12 14:33:03 +0100280 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX, "Child element inside terminal node \"%s\" found.",
281 snode->name);
Michal Vasko14654712020-02-06 08:35:21 +0100282 }
Radek Krejci339e2de2019-05-17 14:28:24 +0200283 goto cleanup;
284 }
Radek Krejcie92210c2019-05-17 15:53:35 +0200285 } else {
286 /* no content - validate empty value */
287 value = "";
288 value_len = 0;
Michal Vasko90932a92020-02-12 14:33:03 +0100289 dynamic = 0;
Radek Krejcie7b95092019-05-15 11:03:07 +0200290 }
Michal Vasko90932a92020-02-12 14:33:03 +0100291
292 /* create node */
293 ret = lyd_create_term(snode, value, value_len, &dynamic, lydxml_resolve_prefix, ctx, LYD_XML, &cur);
294 /* buffer spent */
295 buffer = NULL;
Radek Krejcie553e6d2019-06-07 15:33:18 +0200296 if (ret == LY_EINCOMPLETE) {
297 ly_set_add(&ctx->incomplete_type_validation, cur, LY_SET_OPT_USEASLIST);
298 } else if (ret) {
Radek Krejcie553e6d2019-06-07 15:33:18 +0200299 goto cleanup;
300 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200301 } else if (snode->nodetype & LYD_NODE_INNER) {
Radek Krejcie7b95092019-05-15 11:03:07 +0200302 if (ctx->status == LYXML_ELEM_CONTENT) {
303 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 +0200304 if (r != LY_EINVAL && (r != LY_SUCCESS || value_len != 0)) {
Radek Krejcie7b95092019-05-15 11:03:07 +0200305 LOGINT(ctx->ctx);
Radek Krejci11702142019-07-24 17:46:04 +0200306 ret = LY_EINT;
Radek Krejcie7b95092019-05-15 11:03:07 +0200307 goto cleanup;
308 }
309 }
Michal Vasko90932a92020-02-12 14:33:03 +0100310
311 /* create node */
312 ret = lyd_create_inner(snode, &cur);
313 LY_CHECK_GOTO(ret, cleanup);
314
Radek Krejciee4cab22019-07-17 17:07:47 +0200315 /* process children */
Radek Krejcie553e6d2019-06-07 15:33:18 +0200316 if (ctx->status == LYXML_ELEMENT && parents_count != ctx->elements.count) {
Michal Vasko14654712020-02-06 08:35:21 +0100317 ret = lydxml_nodes(ctx, (struct lyd_node_inner *)cur, data, lyd_node_children_p(cur));
Radek Krejcie92210c2019-05-17 15:53:35 +0200318 LY_CHECK_GOTO(ret, cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200319 }
Radek Krejciee4cab22019-07-17 17:07:47 +0200320 } else if (snode->nodetype & LYD_NODE_ANY) {
321 unsigned int cur_element_index = ctx->elements.count;
322 const char *start = *data, *stop;
323 const char *p, *n;
324 size_t p_len, n_len;
325
326 /* skip children data and store them as a string */
Radek Krejci26a5dfb2019-07-26 14:51:06 +0200327 while (ctx->status != LYXML_END && cur_element_index <= ctx->elements.count) {
Radek Krejciee4cab22019-07-17 17:07:47 +0200328 switch (ctx->status) {
329 case LYXML_ELEMENT:
330 ret = lyxml_get_element((struct lyxml_context *)ctx, data, &p, &p_len, &n, &n_len);
Michal Vasko90932a92020-02-12 14:33:03 +0100331 LY_CHECK_GOTO(ret, cleanup);
Radek Krejciee4cab22019-07-17 17:07:47 +0200332 break;
333 case LYXML_ATTRIBUTE:
Michal Vasko14654712020-02-06 08:35:21 +0100334 lyxml_get_attribute((struct lyxml_context *)ctx, data, &p, &p_len, &n, &n_len);
Radek Krejciee4cab22019-07-17 17:07:47 +0200335 break;
336 case LYXML_ELEM_CONTENT:
337 case LYXML_ATTR_CONTENT:
338 ret = lyxml_get_string((struct lyxml_context *)ctx, data, NULL, NULL, NULL, NULL, NULL);
Michal Vasko90932a92020-02-12 14:33:03 +0100339 /* not an error, just incorrect XML parser status */
340 if (ret && (ret != LY_EINVAL)) {
341 goto cleanup;
Radek Krejciee4cab22019-07-17 17:07:47 +0200342 }
343 break;
344 case LYXML_END:
Radek Krejci26a5dfb2019-07-26 14:51:06 +0200345 /* end of data */
Radek Krejciee4cab22019-07-17 17:07:47 +0200346 LOGINT(ctx->ctx);
Radek Krejci11702142019-07-24 17:46:04 +0200347 ret = LY_EINT;
Radek Krejciee4cab22019-07-17 17:07:47 +0200348 goto cleanup;
349 }
Radek Krejciee4cab22019-07-17 17:07:47 +0200350 }
Michal Vasko90932a92020-02-12 14:33:03 +0100351
352 /* get value */
Radek Krejci26a5dfb2019-07-26 14:51:06 +0200353 if (start != *data) {
354 /* data now points after the anydata's closing element tag, we need just end of its content */
355 for (stop = *data - 1; *stop != '<'; --stop);
Michal Vasko90932a92020-02-12 14:33:03 +0100356 start = lydict_insert(ctx->ctx, start, stop - start);
357 } else {
358 start = NULL;
359 }
360
361 /* create node */
362 ret = lyd_create_any(snode, start, LYD_ANYDATA_XML, &cur);
363 if (ret) {
364 lydict_remove(ctx->ctx, start);
365 goto cleanup;
Radek Krejci26a5dfb2019-07-26 14:51:06 +0200366 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200367 }
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200368
Michal Vasko90932a92020-02-12 14:33:03 +0100369 /* add attributes */
370 LY_CHECK_GOTO(ret = lydxml_attributes(ctx, &attrs_data, cur), cleanup);
371
Michal Vaskocde73ac2019-11-14 16:10:27 +0100372 /* remember we need to evaluate this node's when */
373 if (!(snode->nodetype & (LYS_ACTION | LYS_NOTIF)) && snode->when) {
374 ly_set_add(&ctx->when_check, cur, LY_SET_OPT_USEASLIST);
375 }
376
Michal Vasko90932a92020-02-12 14:33:03 +0100377 /* hash */
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200378 lyd_hash(cur);
Radek Krejcib6f7ae52019-07-19 10:31:42 +0200379
Michal Vasko90932a92020-02-12 14:33:03 +0100380 /* insert */
381 if (parent) {
382 if (cur->schema->flags & LYS_KEY) {
383 /* check the key order, the anchor must always be the last child */
384 key_anchor = lyd_get_prev_key_anchor(parent->child, cur->schema);
385 if ((!key_anchor && parent->child) || (key_anchor && key_anchor->next)) {
386 if (ctx->options & LYD_OPT_STRICT) {
387 LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_DATA, "Invalid position of the key \"%s\" in a list.",
388 cur->schema->name);
389 ret = LY_EVALID;
390 goto cleanup;
391 } else {
392 LOGWRN(ctx->ctx, "Invalid position of the key \"%s\" in a list.", cur->schema->name);
393 }
394 }
395 }
396 lyd_insert_node((struct lyd_node *)parent, NULL, cur);
397 } else if (*node) {
398 lyd_insert_node(NULL, *node, cur);
399 } else {
400 (*node) = cur;
Radek Krejcib6f7ae52019-07-19 10:31:42 +0200401 }
Michal Vasko90932a92020-02-12 14:33:03 +0100402
403 cur = NULL;
Radek Krejcie7b95092019-05-15 11:03:07 +0200404 }
405
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200406 /* TODO add missing siblings default elements */
407
Michal Vasko90932a92020-02-12 14:33:03 +0100408 /* success */
409 ret = LY_SUCCESS;
410
Radek Krejcie7b95092019-05-15 11:03:07 +0200411cleanup:
Michal Vasko90932a92020-02-12 14:33:03 +0100412 free(buffer);
413 lyd_free_tree(cur);
Radek Krejci28681fa2019-09-06 13:08:45 +0200414 for (unsigned int u = 0; u < attrs_data.count; ++u) {
415 if (((struct attr_data_s*)attrs_data.objs[u])->dynamic) {
416 free(((struct attr_data_s*)attrs_data.objs[u])->value);
417 }
418 }
419 ly_set_erase(&attrs_data, free);
Michal Vasko90932a92020-02-12 14:33:03 +0100420 if (ret && *node) {
421 lyd_free_withsiblings(*node);
422 *node = NULL;
423 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200424 return ret;
425}
426
427LY_ERR
Michal Vaskoa3881362020-01-21 15:57:35 +0100428lyd_parse_xml(struct ly_ctx *ctx, const char *data, int options, struct lyd_node **result)
Radek Krejcie7b95092019-05-15 11:03:07 +0200429{
Radek Krejci18a57d92019-07-25 14:01:42 +0200430 LY_ERR ret = LY_SUCCESS;
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200431 struct lyd_node_inner *parent = NULL;
Michal Vaskocde73ac2019-11-14 16:10:27 +0100432 const struct lyd_node **result_trees = NULL;
Radek Krejcie7b95092019-05-15 11:03:07 +0200433 struct lyd_xml_ctx xmlctx = {0};
434
435 xmlctx.options = options;
436 xmlctx.ctx = ctx;
437 xmlctx.line = 1;
438
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200439 /* init */
440 *result = NULL;
441
Michal Vaskoa3881362020-01-21 15:57:35 +0100442#if 0
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200443 if (options & LYD_OPT_RPCREPLY) {
Radek Krejci3c1046e2019-07-26 13:06:53 +0200444 /* prepare container for RPC reply, for which we need RPC
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200445 * - prepare *result as top-level node
446 * - prepare parent as the RPC/action node */
Radek Krejci3c1046e2019-07-26 13:06:53 +0200447 const struct lyd_node *action;
448 for (action = trees[0]; action && action->schema->nodetype != LYS_ACTION; action = lyd_node_children(action)) {
449 /* skip list's keys */
Radek Krejci26a5dfb2019-07-26 14:51:06 +0200450 for ( ;action && action->schema->nodetype == LYS_LEAF; action = action->next);
451 if (action && action->schema->nodetype == LYS_ACTION) {
452 break;
453 }
Radek Krejci3c1046e2019-07-26 13:06:53 +0200454 }
455 if (!action) {
456 LOGERR(ctx, LY_EINVAL, "Data parser invalid argument trees - the first item in the array must be the RPC/action request when parsing %s.",
457 lyd_parse_options_type2str(options));
458 return LY_EINVAL;
459 }
460 parent = (struct lyd_node_inner*)lyd_dup(action, NULL, LYD_DUP_WITH_PARENTS);
461 LY_CHECK_ERR_RET(!parent, LOGERR(ctx, ly_errcode(ctx), "Unable to duplicate RPC/action container for RPC/action reply."), ly_errcode(ctx));
462 for (*result = (struct lyd_node*)parent; (*result)->parent; *result = (struct lyd_node*)(*result)->parent);
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200463 }
Michal Vaskoa3881362020-01-21 15:57:35 +0100464#endif
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200465
Radek Krejci26a5dfb2019-07-26 14:51:06 +0200466 if (!data || !data[0]) {
Michal Vaskocde73ac2019-11-14 16:10:27 +0100467 /* no data - just check for missing mandatory nodes */
468 goto validation;
Radek Krejci26a5dfb2019-07-26 14:51:06 +0200469 }
470
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200471 ret = lydxml_nodes(&xmlctx, parent, &data, *result ? &parent->child : result);
Michal Vaskocde73ac2019-11-14 16:10:27 +0100472 LY_CHECK_GOTO(ret, cleanup);
473
474 /* prepare sized array for validator */
475 if (*result) {
476 result_trees = lyd_trees_new(1, *result);
477 }
478
479 /* finish incompletely validated terminal values/attributes and when conditions */
480 ret = lyd_validate_unres(&xmlctx.incomplete_type_validation, &xmlctx.incomplete_type_validation_attrs,
481 &xmlctx.when_check, LYD_XML, lydxml_resolve_prefix, ctx, result_trees);
482 LY_CHECK_GOTO(ret, cleanup);
483
484validation:
Michal Vaskoa3881362020-01-21 15:57:35 +0100485#if 0
Michal Vaskocde73ac2019-11-14 16:10:27 +0100486 if ((!(*result) || (parent && !parent->child)) && (options & (LYD_OPT_RPC | LYD_OPT_NOTIF))) {
487 /* error, missing top level node identify RPC and Notification */
488 LOGERR(ctx, LY_EINVAL, "Invalid input data of data parser - expected %s which cannot be empty.",
489 lyd_parse_options_type2str(options));
490 ret = LY_EINVAL;
491 goto cleanup;
492 }
Michal Vaskoa3881362020-01-21 15:57:35 +0100493#endif
Michal Vaskocde73ac2019-11-14 16:10:27 +0100494
495 /* context node and other validation tasks that depend on other data nodes */
Michal Vaskoacd83e72020-02-04 14:12:01 +0100496 ret = lyd_validate_data(result_trees, NULL, 0, ctx, options);
Michal Vaskocde73ac2019-11-14 16:10:27 +0100497 LY_CHECK_GOTO(result, cleanup);
498
499cleanup:
500 ly_set_erase(&xmlctx.incomplete_type_validation, NULL);
501 ly_set_erase(&xmlctx.incomplete_type_validation_attrs, NULL);
502 ly_set_erase(&xmlctx.when_check, NULL);
503 lyxml_context_clear((struct lyxml_context*)&xmlctx);
504 lyd_trees_free(result_trees, 0);
Radek Krejcie92210c2019-05-17 15:53:35 +0200505 if (ret) {
506 lyd_free_all(*result);
507 *result = NULL;
508 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200509 return ret;
510}