blob: a3c8acf69fdf0a83e2cb0c12ff654850c91fb099 [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
Radek Krejcie7b95092019-05-15 11:03:07 +020015#include <stdint.h>
16#include <stdlib.h>
17#include <string.h>
Michal Vasko9b368d32020-02-14 13:53:31 +010018#include <assert.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020019
Radek Krejci535ea9f2020-05-29 16:01:05 +020020#include "common.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020021#include "context.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020022#include "log.h"
Radek Krejci7931b192020-06-25 17:05:03 +020023#include "parser_data.h"
24#include "parser_internal.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020025#include "set.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020026#include "tree.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020027#include "tree_data_internal.h"
28#include "tree_schema.h"
Michal Vaskocde73ac2019-11-14 16:10:27 +010029#include "validation.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020030#include "xml.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020031
32/**
Michal Vaskob36053d2020-03-26 15:49:30 +010033 * @brief Internal context for XML YANG data parser.
Radek Krejcie7b95092019-05-15 11:03:07 +020034 */
35struct lyd_xml_ctx {
Michal Vaskob36053d2020-03-26 15:49:30 +010036 struct lyxml_ctx *xmlctx; /**< XML context */
Radek Krejcie7b95092019-05-15 11:03:07 +020037
Michal Vasko52927e22020-03-16 17:26:14 +010038 uint32_t options; /**< various @ref dataparseroptions. */
Michal Vasko1bf09392020-03-27 12:38:10 +010039 uint32_t int_opts; /**< internal data parser options */
Michal Vasko52927e22020-03-16 17:26:14 +010040 uint32_t path_len; /**< used bytes in the path buffer */
Radek Krejcie7b95092019-05-15 11:03:07 +020041#define LYD_PARSER_BUFSIZE 4078
42 char path[LYD_PARSER_BUFSIZE]; /**< buffer for the generated path */
Michal Vasko52927e22020-03-16 17:26:14 +010043 struct ly_set unres_node_type; /**< set of nodes validated with LY_EINCOMPLETE result */
44 struct ly_set unres_meta_type; /**< set of metadata validated with LY_EINCOMPLETE result */
Michal Vaskoecd62de2019-11-13 12:35:11 +010045 struct ly_set when_check; /**< set of nodes with "when" conditions */
Michal Vasko1bf09392020-03-27 12:38:10 +010046 struct lyd_node *op_ntf; /**< if an RPC/action/notification is being parsed, store the pointer to it */
Radek Krejcie7b95092019-05-15 11:03:07 +020047};
48
49/**
Michal Vaskob36053d2020-03-26 15:49:30 +010050 * @brief XML-parser's implementation of ly_type_resolve_prefix() callback to provide mapping between prefixes used
51 * in the values to the schema via XML namespaces.
Radek Krejciaca74032019-06-04 08:53:06 +020052 */
53static const struct lys_module *
Michal Vasko52927e22020-03-16 17:26:14 +010054lydxml_resolve_prefix(const struct ly_ctx *ctx, const char *prefix, size_t prefix_len, void *parser)
Radek Krejciaca74032019-06-04 08:53:06 +020055{
56 const struct lyxml_ns *ns;
Michal Vaskob36053d2020-03-26 15:49:30 +010057 struct lyxml_ctx *xmlctx = (struct lyxml_ctx *)parser;
Radek Krejciaca74032019-06-04 08:53:06 +020058
59 ns = lyxml_ns_get(xmlctx, prefix, prefix_len);
60 if (!ns) {
61 return NULL;
62 }
63
64 return ly_ctx_get_module_implemented_ns(ctx, ns->uri);
65}
66
Radek Krejcie7b95092019-05-15 11:03:07 +020067static LY_ERR
Michal Vasko60ea6352020-06-29 13:39:39 +020068lydxml_metadata(struct lyxml_ctx *xmlctx, const struct lysc_node *sparent, int strict, struct ly_set *unres_meta_type,
Michal Vaskob36053d2020-03-26 15:49:30 +010069 struct lyd_meta **meta)
Radek Krejcie7b95092019-05-15 11:03:07 +020070{
Michal Vaskob36053d2020-03-26 15:49:30 +010071 LY_ERR ret = LY_EVALID;
Radek Krejci28681fa2019-09-06 13:08:45 +020072 const struct lyxml_ns *ns;
73 struct lys_module *mod;
Michal Vaskob36053d2020-03-26 15:49:30 +010074 const char *name;
75 size_t name_len;
Radek Krejci28681fa2019-09-06 13:08:45 +020076
Michal Vaskob36053d2020-03-26 15:49:30 +010077 *meta = NULL;
Radek Krejci28681fa2019-09-06 13:08:45 +020078
Michal Vaskob36053d2020-03-26 15:49:30 +010079 while (xmlctx->status == LYXML_ATTRIBUTE) {
80 if (!xmlctx->prefix_len) {
Radek Krejci28681fa2019-09-06 13:08:45 +020081 /* in XML, all attributes must be prefixed
82 * TODO exception for NETCONF filters which are supposed to map to the ietf-netconf without prefix */
Michal Vasko52927e22020-03-16 17:26:14 +010083 if (strict) {
84 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Missing mandatory prefix for XML metadata \"%.*s\".",
Michal Vaskob36053d2020-03-26 15:49:30 +010085 xmlctx->name_len, xmlctx->name);
86 goto cleanup;
Radek Krejci28681fa2019-09-06 13:08:45 +020087 }
Michal Vaskob36053d2020-03-26 15:49:30 +010088
Radek Krejci28681fa2019-09-06 13:08:45 +020089skip_attr:
Michal Vaskob36053d2020-03-26 15:49:30 +010090 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
91 assert(xmlctx->status == LYXML_ATTR_CONTENT);
92 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejci28681fa2019-09-06 13:08:45 +020093 continue;
94 }
95
96 /* get namespace of the attribute to find its annotation definition */
Michal Vaskob36053d2020-03-26 15:49:30 +010097 ns = lyxml_ns_get(xmlctx, xmlctx->prefix, xmlctx->prefix_len);
Radek Krejci28681fa2019-09-06 13:08:45 +020098 if (!ns) {
Michal Vasko52927e22020-03-16 17:26:14 +010099 /* unknown namespace, XML error */
100 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
Michal Vaskob36053d2020-03-26 15:49:30 +0100101 xmlctx->prefix_len, xmlctx->prefix);
Radek Krejci28681fa2019-09-06 13:08:45 +0200102 goto cleanup;
103 }
Michal Vasko52927e22020-03-16 17:26:14 +0100104 mod = ly_ctx_get_module_implemented_ns(xmlctx->ctx, ns->uri);
Radek Krejci28681fa2019-09-06 13:08:45 +0200105 if (!mod) {
106 /* module is not implemented or not present in the schema */
Michal Vasko52927e22020-03-16 17:26:14 +0100107 if (strict) {
108 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE,
Michal Vasko9f96a052020-03-10 09:41:45 +0100109 "Unknown (or not implemented) YANG module with namespace \"%s\" for metadata \"%.*s%s%.*s\".",
Michal Vaskob36053d2020-03-26 15:49:30 +0100110 ns->uri, xmlctx->prefix_len, xmlctx->prefix, xmlctx->prefix_len ? ":" : "", xmlctx->name_len,
111 xmlctx->name);
112 goto cleanup;
Radek Krejci28681fa2019-09-06 13:08:45 +0200113 }
114 goto skip_attr;
115 }
116
Michal Vasko60ea6352020-06-29 13:39:39 +0200117 /* remember meta name and get its content */
Michal Vaskob36053d2020-03-26 15:49:30 +0100118 name = xmlctx->name;
119 name_len = xmlctx->name_len;
120 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
121 assert(xmlctx->status == LYXML_ATTR_CONTENT);
122
123 /* create metadata */
124 ret = lyd_create_meta(NULL, meta, mod, name, name_len, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic,
125 lydxml_resolve_prefix, xmlctx, LYD_XML, sparent);
126 if (ret == LY_EINCOMPLETE) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200127 if (unres_meta_type) {
128 ly_set_add(unres_meta_type, *meta, LY_SET_OPT_USEASLIST);
Michal Vasko52927e22020-03-16 17:26:14 +0100129 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100130 } else if (ret) {
Radek Krejci28681fa2019-09-06 13:08:45 +0200131 goto cleanup;
132 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100133
134 /* next attribute */
135 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200136 }
Michal Vasko52927e22020-03-16 17:26:14 +0100137
Radek Krejci28681fa2019-09-06 13:08:45 +0200138 ret = LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200139
140cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100141 if (ret) {
Michal Vasko3a41dff2020-07-15 14:30:28 +0200142 lyd_free_meta_siblings(*meta);
Michal Vaskob36053d2020-03-26 15:49:30 +0100143 *meta = NULL;
Radek Krejci38d85362019-09-05 16:26:38 +0200144 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200145 return ret;
146}
147
Michal Vasko52927e22020-03-16 17:26:14 +0100148static LY_ERR
Michal Vaskob36053d2020-03-26 15:49:30 +0100149lydxml_attrs(struct lyxml_ctx *xmlctx, struct ly_attr **attr)
Michal Vasko52927e22020-03-16 17:26:14 +0100150{
151 LY_ERR ret = LY_SUCCESS;
152 const struct lyxml_ns *ns;
153 struct ly_prefix *val_prefs;
154 struct ly_attr *attr2;
Michal Vaskob36053d2020-03-26 15:49:30 +0100155 const char *name, *prefix;
156 size_t name_len, prefix_len;
Michal Vasko52927e22020-03-16 17:26:14 +0100157
158 assert(attr);
Michal Vaskob36053d2020-03-26 15:49:30 +0100159 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100160
Michal Vaskob36053d2020-03-26 15:49:30 +0100161 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vasko52927e22020-03-16 17:26:14 +0100162 ns = NULL;
Michal Vaskob36053d2020-03-26 15:49:30 +0100163 if (xmlctx->prefix_len) {
Michal Vasko52927e22020-03-16 17:26:14 +0100164 /* get namespace of the attribute */
Michal Vaskob36053d2020-03-26 15:49:30 +0100165 ns = lyxml_ns_get(xmlctx, xmlctx->prefix, xmlctx->prefix_len);
Michal Vasko52927e22020-03-16 17:26:14 +0100166 if (!ns) {
167 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
Michal Vaskob36053d2020-03-26 15:49:30 +0100168 xmlctx->prefix_len, xmlctx->prefix);
Michal Vasko52927e22020-03-16 17:26:14 +0100169 ret = LY_EVALID;
170 goto cleanup;
171 }
172 }
173
174 if (*attr) {
175 attr2 = *attr;
176 } else {
177 attr2 = NULL;
178 }
179
Michal Vaskob36053d2020-03-26 15:49:30 +0100180 /* remember attr prefix, name, and get its content */
181 prefix = xmlctx->prefix;
182 prefix_len = xmlctx->prefix_len;
183 name = xmlctx->name;
184 name_len = xmlctx->name_len;
185 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
186 assert(xmlctx->status == LYXML_ATTR_CONTENT);
187
Michal Vasko52927e22020-03-16 17:26:14 +0100188 /* get value prefixes */
Michal Vaskob36053d2020-03-26 15:49:30 +0100189 LY_CHECK_GOTO(ret = lyxml_get_prefixes(xmlctx, xmlctx->value, xmlctx->value_len, &val_prefs), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100190
191 /* attr2 is always changed to the created attribute */
Michal Vaskob36053d2020-03-26 15:49:30 +0100192 ret = ly_create_attr(NULL, &attr2, xmlctx->ctx, name, name_len, xmlctx->value, xmlctx->value_len,
193 &xmlctx->dynamic, LYD_XML, val_prefs, prefix, prefix_len, ns ? ns->uri : NULL);
Michal Vasko52927e22020-03-16 17:26:14 +0100194 LY_CHECK_GOTO(ret, cleanup);
195
196 if (!*attr) {
197 *attr = attr2;
198 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100199
200 /* next attribute */
201 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100202 }
203
204cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100205 if (ret) {
Michal Vasko3a41dff2020-07-15 14:30:28 +0200206 ly_free_attr_siblings(xmlctx->ctx, *attr);
Michal Vaskob36053d2020-03-26 15:49:30 +0100207 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100208 }
Michal Vasko52927e22020-03-16 17:26:14 +0100209 return ret;
210}
211
Michal Vasko44685da2020-03-17 15:38:06 +0100212static LY_ERR
Michal Vaskob36053d2020-03-26 15:49:30 +0100213lydxml_check_list(struct lyxml_ctx *xmlctx, const struct lysc_node *list)
Michal Vasko44685da2020-03-17 15:38:06 +0100214{
Michal Vaskob36053d2020-03-26 15:49:30 +0100215 LY_ERR ret = LY_SUCCESS, r;
216 enum LYXML_PARSER_STATUS next;
Michal Vasko44685da2020-03-17 15:38:06 +0100217 struct ly_set key_set = {0};
218 const struct lysc_node *snode;
Michal Vaskob36053d2020-03-26 15:49:30 +0100219 uint32_t i, parents_count;
Michal Vasko44685da2020-03-17 15:38:06 +0100220
221 assert(list && (list->nodetype == LYS_LIST));
222
223 /* get all keys into a set (keys do not have if-features or anything) */
224 snode = NULL;
225 while ((snode = lys_getnext(snode, list, NULL, LYS_GETNEXT_NOSTATECHECK)) && (snode->flags & LYS_KEY)) {
226 ly_set_add(&key_set, (void *)snode, LY_SET_OPT_USEASLIST);
227 }
228
Michal Vaskob36053d2020-03-26 15:49:30 +0100229 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vasko44685da2020-03-17 15:38:06 +0100230 /* find key definition */
231 for (i = 0; i < key_set.count; ++i) {
232 snode = (const struct lysc_node *)key_set.objs[i];
Michal Vaskob36053d2020-03-26 15:49:30 +0100233 if (!ly_strncmp(snode->name, xmlctx->name, xmlctx->name_len)) {
Michal Vasko44685da2020-03-17 15:38:06 +0100234 break;
235 }
236 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100237 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100238
239 /* skip attributes */
240 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100241 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
242 assert(xmlctx->status == LYXML_ATTR_CONTENT);
243 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100244 }
245
Michal Vaskob36053d2020-03-26 15:49:30 +0100246 assert(xmlctx->status == LYXML_ELEM_CONTENT);
247 if (i < key_set.count) {
248 /* validate the value */
Michal Vaskof937cfe2020-08-03 16:07:12 +0200249 r = _lys_value_validate(NULL, snode, xmlctx->value, xmlctx->value_len, lydxml_resolve_prefix, xmlctx, LYD_XML);
Michal Vaskob36053d2020-03-26 15:49:30 +0100250 if (!r) {
251 /* key with a valid value, remove from the set */
252 ly_set_rm_index(&key_set, i, NULL);
Michal Vasko44685da2020-03-17 15:38:06 +0100253 }
254 }
255
Michal Vaskob36053d2020-03-26 15:49:30 +0100256 /* parser next */
257 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100258
Michal Vaskob36053d2020-03-26 15:49:30 +0100259 /* skip any children, resursively */
260 parents_count = xmlctx->elements.count;
261 while ((parents_count < xmlctx->elements.count) || (xmlctx->status == LYXML_ELEMENT)) {
262 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
263 }
264
265 /* parser next, but do not parse closing element of the list because it would remove its namespaces */
266 assert(xmlctx->status == LYXML_ELEM_CLOSE);
267 LY_CHECK_GOTO(ret = lyxml_ctx_peek(xmlctx, &next), cleanup);
268 if (next != LYXML_ELEM_CLOSE) {
269 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
270 }
Michal Vasko44685da2020-03-17 15:38:06 +0100271 }
272
273 if (key_set.count) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100274 /* some keys are missing/did not validate */
Michal Vasko44685da2020-03-17 15:38:06 +0100275 ret = LY_ENOT;
Michal Vasko44685da2020-03-17 15:38:06 +0100276 }
277
278cleanup:
279 ly_set_erase(&key_set, NULL);
280 return ret;
281}
282
Michal Vasko1bf09392020-03-27 12:38:10 +0100283static LY_ERR
284lydxml_data_skip(struct lyxml_ctx *xmlctx)
285{
286 uint32_t parents_count;
287
288 /* remember current number of parents */
289 parents_count = xmlctx->elements.count;
290
291 /* skip after the content */
292 while (xmlctx->status != LYXML_ELEM_CONTENT) {
293 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
294 }
295 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
296
297 /* skip all children elements, recursively, if any */
298 while (parents_count < xmlctx->elements.count) {
299 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
300 }
301
302 /* close element */
303 assert(xmlctx->status == LYXML_ELEM_CLOSE);
304 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
305
306 return LY_SUCCESS;
307}
308
309static LY_ERR
310lydxml_data_check_schema(struct lyd_xml_ctx *lydctx, const struct lysc_node **snode)
311{
312 LY_ERR ret = LY_SUCCESS;
313 enum LYXML_PARSER_STATUS prev_status;
Michal Vasko63f3d842020-07-08 10:10:14 +0200314 const char *prev_current, *pname, *pprefix;
Michal Vasko1bf09392020-03-27 12:38:10 +0100315 size_t pprefix_len, pname_len;
316 struct lyxml_ctx *xmlctx = lydctx->xmlctx;
317
Radek Krejci7931b192020-06-25 17:05:03 +0200318 if ((lydctx->options & LYD_PARSE_NO_STATE) && ((*snode)->flags & LYS_CONFIG_R)) {
Michal Vaskocb7526d2020-03-30 15:08:26 +0200319 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LY_VCODE_INNODE, "state", (*snode)->name);
Michal Vasko1bf09392020-03-27 12:38:10 +0100320 return LY_EVALID;
321 }
322
323 if ((*snode)->nodetype & (LYS_RPC | LYS_ACTION)) {
324 if (lydctx->int_opts & LYD_INTOPT_RPC) {
325 if (lydctx->op_ntf) {
326 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_DATA, "Unexpected %s element \"%s\", %s \"%s\" already parsed.",
327 lys_nodetype2str((*snode)->nodetype), (*snode)->name,
328 lys_nodetype2str(lydctx->op_ntf->schema->nodetype), lydctx->op_ntf->schema->name);
329 return LY_EVALID;
330 }
331 } else {
332 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_DATA, "Unexpected %s element \"%s\".",
333 lys_nodetype2str((*snode)->nodetype), (*snode)->name);
334 return LY_EVALID;
335 }
336 } else if ((*snode)->nodetype == LYS_NOTIF) {
337 if (lydctx->int_opts & LYD_INTOPT_NOTIF) {
338 if (lydctx->op_ntf) {
339 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_DATA, "Unexpected %s element \"%s\", %s \"%s\" already parsed.",
340 lys_nodetype2str((*snode)->nodetype), (*snode)->name,
341 lys_nodetype2str(lydctx->op_ntf->schema->nodetype), lydctx->op_ntf->schema->name);
342 return LY_EVALID;
343 }
344 } else {
345 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_DATA, "Unexpected %s element \"%s\".",
346 lys_nodetype2str((*snode)->nodetype), (*snode)->name);
347 return LY_EVALID;
348 }
349 }
350
Radek Krejci7931b192020-06-25 17:05:03 +0200351 if ((lydctx->options & LYD_PARSE_OPAQ) && ((*snode)->nodetype & (LYD_NODE_TERM | LYS_LIST))) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100352 /* backup parser */
353 prev_status = xmlctx->status;
354 pprefix = xmlctx->prefix;
355 pprefix_len = xmlctx->prefix_len;
356 pname = xmlctx->name;
357 pname_len = xmlctx->name_len;
Michal Vasko63f3d842020-07-08 10:10:14 +0200358 prev_current = xmlctx->in->current;
Michal Vasko1bf09392020-03-27 12:38:10 +0100359 if ((xmlctx->status == LYXML_ELEM_CONTENT) && xmlctx->dynamic) {
360 /* it was backed up, do not free */
361 xmlctx->dynamic = 0;
362 }
363
364 /* skip attributes */
365 while (xmlctx->status == LYXML_ATTRIBUTE) {
366 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
367 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
368 }
369
370 if ((*snode)->nodetype & LYD_NODE_TERM) {
371 /* value may not be valid in which case we parse it as an opaque node */
Michal Vaskof937cfe2020-08-03 16:07:12 +0200372 if (_lys_value_validate(NULL, *snode, xmlctx->value, xmlctx->value_len, lydxml_resolve_prefix, xmlctx, LYD_XML)) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100373 *snode = NULL;
374 }
375 } else {
376 /* skip content */
377 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
378
379 if (lydxml_check_list(xmlctx, *snode)) {
380 /* invalid list, parse as opaque if it missing/has invalid some keys */
381 *snode = NULL;
382 }
383 }
384
385restore:
386 /* restore parser */
387 if (xmlctx->dynamic) {
388 free((char *)xmlctx->value);
389 }
390 xmlctx->status = prev_status;
391 xmlctx->prefix = pprefix;
392 xmlctx->prefix_len = pprefix_len;
393 xmlctx->name = pname;
394 xmlctx->name_len = pname_len;
Michal Vasko63f3d842020-07-08 10:10:14 +0200395 xmlctx->in->current = prev_current;
Michal Vasko1bf09392020-03-27 12:38:10 +0100396 }
397
398 return ret;
399}
400
Radek Krejcie7b95092019-05-15 11:03:07 +0200401/**
Michal Vasko9f96a052020-03-10 09:41:45 +0100402 * @brief Parse XML elements as YANG data node children the specified parent node.
Radek Krejcie7b95092019-05-15 11:03:07 +0200403 *
Michal Vaskob36053d2020-03-26 15:49:30 +0100404 * @param[in] lydctx XML YANG data parser context.
Radek Krejcie7b95092019-05-15 11:03:07 +0200405 * @param[in] parent Parent node where the children are inserted. NULL in case of parsing top-level elements.
Radek Krejcie7b95092019-05-15 11:03:07 +0200406 * @param[out] node Resulting list of the parsed nodes.
Michal Vasko9b368d32020-02-14 13:53:31 +0100407 * @return LY_ERR value.
Radek Krejcie7b95092019-05-15 11:03:07 +0200408 */
409static LY_ERR
Michal Vasko1bf09392020-03-27 12:38:10 +0100410lydxml_data_r(struct lyd_xml_ctx *lydctx, struct lyd_node_inner *parent, struct lyd_node **first)
Radek Krejcie7b95092019-05-15 11:03:07 +0200411{
Michal Vaskob36053d2020-03-26 15:49:30 +0100412 LY_ERR ret = LY_SUCCESS;
Michal Vasko1bf09392020-03-27 12:38:10 +0100413 const char *prefix, *name;
414 size_t prefix_len, name_len;
Michal Vaskob36053d2020-03-26 15:49:30 +0100415 struct lyxml_ctx *xmlctx;
416 const struct ly_ctx *ctx;
Radek Krejcie7b95092019-05-15 11:03:07 +0200417 const struct lyxml_ns *ns;
Michal Vasko5ab0d5c2020-06-29 11:48:05 +0200418 struct lyd_meta *meta = NULL, *m;
419 struct ly_attr *attr = NULL, *a;
Radek Krejcie7b95092019-05-15 11:03:07 +0200420 const struct lysc_node *snode;
421 struct lys_module *mod;
Michal Vasko1bf09392020-03-27 12:38:10 +0100422 uint32_t prev_opts;
Michal Vasko52927e22020-03-16 17:26:14 +0100423 struct lyd_node *cur = NULL, *anchor;
424 struct ly_prefix *val_prefs;
Michal Vasko1ce933a2020-03-30 12:38:22 +0200425 int getnext_opts;
Radek Krejcie7b95092019-05-15 11:03:07 +0200426
Michal Vaskob36053d2020-03-26 15:49:30 +0100427 xmlctx = lydctx->xmlctx;
428 ctx = xmlctx->ctx;
Michal Vasko1ce933a2020-03-30 12:38:22 +0200429 /* leave if-feature check for validation */
430 getnext_opts = LYS_GETNEXT_NOSTATECHECK | (lydctx->int_opts & LYD_INTOPT_REPLY ? LYS_GETNEXT_OUTPUT : 0);
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100431
Michal Vaskob36053d2020-03-26 15:49:30 +0100432 while (xmlctx->status == LYXML_ELEMENT) {
433 /* remember element prefix and name */
434 prefix = xmlctx->prefix;
435 prefix_len = xmlctx->prefix_len;
436 name = xmlctx->name;
437 name_len = xmlctx->name_len;
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200438
Michal Vaskob36053d2020-03-26 15:49:30 +0100439 /* get the element module */
440 ns = lyxml_ns_get(xmlctx, prefix, prefix_len);
Radek Krejcie7b95092019-05-15 11:03:07 +0200441 if (!ns) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100442 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
443 prefix_len, prefix);
Michal Vasko90932a92020-02-12 14:33:03 +0100444 ret = LY_EVALID;
445 goto cleanup;
Radek Krejcie7b95092019-05-15 11:03:07 +0200446 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100447 mod = ly_ctx_get_module_implemented_ns(ctx, ns->uri);
Michal Vaskoaa7f4fa2020-06-22 10:03:53 +0200448 if (!mod) {
Radek Krejci7931b192020-06-25 17:05:03 +0200449 if (lydctx->options & LYD_PARSE_STRICT) {
Michal Vaskoaa7f4fa2020-06-22 10:03:53 +0200450 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "No module with namespace \"%s\" in the context.",
451 ns->uri);
452 ret = LY_EVALID;
453 goto cleanup;
454 }
Radek Krejci7931b192020-06-25 17:05:03 +0200455 if (!(lydctx->options & LYD_PARSE_OPAQ)) {
Michal Vasko2acb5a62020-06-23 13:23:53 +0200456 /* skip element with children */
457 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), cleanup);
458 continue;
459 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200460 }
Michal Vasko52927e22020-03-16 17:26:14 +0100461
Michal Vasko1bf09392020-03-27 12:38:10 +0100462 /* parser next */
463 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
464
Michal Vaskob36053d2020-03-26 15:49:30 +0100465 /* get the schema node */
Michal Vasko52927e22020-03-16 17:26:14 +0100466 snode = NULL;
467 if (mod && (!parent || parent->schema)) {
Michal Vasko1ce933a2020-03-30 12:38:22 +0200468 snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
Michal Vaskob36053d2020-03-26 15:49:30 +0100469 if (!snode) {
Radek Krejci7931b192020-06-25 17:05:03 +0200470 if (lydctx->options & LYD_PARSE_STRICT) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100471 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Element \"%.*s\" not found in the \"%s\" module.",
472 name_len, name, mod->name);
473 ret = LY_EVALID;
474 goto cleanup;
Radek Krejci7931b192020-06-25 17:05:03 +0200475 } else if (!(lydctx->options & LYD_PARSE_OPAQ)) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100476 /* skip element with children */
477 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), cleanup);
Michal Vaskob36053d2020-03-26 15:49:30 +0100478 continue;
479 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100480 } else {
Michal Vasko1bf09392020-03-27 12:38:10 +0100481 /* check that schema node is valid and can be used */
482 LY_CHECK_GOTO(ret = lydxml_data_check_schema(lydctx, &snode), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100483 }
484 }
485
Michal Vaskob36053d2020-03-26 15:49:30 +0100486 /* create metadata/attributes */
487 if (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vasko52927e22020-03-16 17:26:14 +0100488 if (snode) {
Radek Krejci7931b192020-06-25 17:05:03 +0200489 ret = lydxml_metadata(xmlctx, snode, lydctx->options & LYD_PARSE_STRICT, &lydctx->unres_meta_type, &meta);
Michal Vasko52927e22020-03-16 17:26:14 +0100490 LY_CHECK_GOTO(ret, cleanup);
491 } else {
Radek Krejci7931b192020-06-25 17:05:03 +0200492 assert(lydctx->options & LYD_PARSE_OPAQ);
Michal Vaskob36053d2020-03-26 15:49:30 +0100493 ret = lydxml_attrs(xmlctx, &attr);
494 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100495 }
Michal Vasko8d544252020-03-02 10:19:52 +0100496 }
497
Michal Vaskob36053d2020-03-26 15:49:30 +0100498 assert(xmlctx->status == LYXML_ELEM_CONTENT);
Michal Vasko52927e22020-03-16 17:26:14 +0100499 if (!snode) {
Radek Krejci7931b192020-06-25 17:05:03 +0200500 assert(lydctx->options & LYD_PARSE_OPAQ);
Michal Vasko52927e22020-03-16 17:26:14 +0100501
Michal Vaskob36053d2020-03-26 15:49:30 +0100502 if (xmlctx->ws_only) {
503 /* ignore WS-only value */
504 xmlctx->value_len = 0;
505 val_prefs = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100506 } else {
Michal Vaskob36053d2020-03-26 15:49:30 +0100507 /* get value prefixes */
508 ret = lyxml_get_prefixes(xmlctx, xmlctx->value, xmlctx->value_len, &val_prefs);
Michal Vasko52927e22020-03-16 17:26:14 +0100509 LY_CHECK_GOTO(ret, cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200510 }
Michal Vasko90932a92020-02-12 14:33:03 +0100511
512 /* create node */
Michal Vaskob36053d2020-03-26 15:49:30 +0100513 ret = lyd_create_opaq(ctx, name, name_len, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic, LYD_XML,
514 val_prefs, prefix, prefix_len, ns->uri, &cur);
515 LY_CHECK_GOTO(ret, cleanup);
516
517 /* parser next */
518 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
519
520 /* process children */
521 if (xmlctx->status == LYXML_ELEMENT) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100522 ret = lydxml_data_r(lydctx, (struct lyd_node_inner *)cur, lyd_node_children_p(cur));
Michal Vaskob36053d2020-03-26 15:49:30 +0100523 LY_CHECK_GOTO(ret, cleanup);
524 }
525 } else if (snode->nodetype & LYD_NODE_TERM) {
526 /* create node */
527 ret = lyd_create_term(snode, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic, lydxml_resolve_prefix,
528 xmlctx, LYD_XML, &cur);
Radek Krejcie553e6d2019-06-07 15:33:18 +0200529 if (ret == LY_EINCOMPLETE) {
Radek Krejci7931b192020-06-25 17:05:03 +0200530 if (!(lydctx->options & LYD_PARSE_ONLY)) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100531 ly_set_add(&lydctx->unres_node_type, cur, LY_SET_OPT_USEASLIST);
Michal Vasko9b368d32020-02-14 13:53:31 +0100532 }
Radek Krejcie553e6d2019-06-07 15:33:18 +0200533 } else if (ret) {
Radek Krejcie553e6d2019-06-07 15:33:18 +0200534 goto cleanup;
535 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100536
537 if (parent && (cur->schema->flags & LYS_KEY)) {
Michal Vaskob104f112020-07-17 09:54:54 +0200538 /* check the key order, the anchor must never be a key */
539 anchor = lyd_insert_get_next_anchor(parent->child, cur);
540 if (anchor && (anchor->schema->flags & LYS_KEY)) {
Radek Krejci7931b192020-06-25 17:05:03 +0200541 if (lydctx->options & LYD_PARSE_STRICT) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100542 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_DATA, "Invalid position of the key \"%s\" in a list.",
Michal Vasko9b368d32020-02-14 13:53:31 +0100543 cur->schema->name);
544 ret = LY_EVALID;
545 goto cleanup;
546 } else {
Michal Vaskob36053d2020-03-26 15:49:30 +0100547 LOGWRN(ctx, "Invalid position of the key \"%s\" in a list.", cur->schema->name);
Michal Vasko9b368d32020-02-14 13:53:31 +0100548 }
549 }
550 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100551
552 /* parser next */
553 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
554
555 /* no children expected */
556 if (xmlctx->status == LYXML_ELEMENT) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100557 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Child element \"%.*s\" inside a terminal node \"%s\" found.",
558 xmlctx->name_len, xmlctx->name, snode->name);
Michal Vasko44685da2020-03-17 15:38:06 +0100559 ret = LY_EVALID;
560 goto cleanup;
Michal Vaskob36053d2020-03-26 15:49:30 +0100561 }
562 } else if (snode->nodetype & LYD_NODE_INNER) {
563 if (!xmlctx->ws_only) {
564 /* value in inner node */
Michal Vasko1bf09392020-03-27 12:38:10 +0100565 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Text value \"%.*s\" inside an inner node \"%s\" found.",
566 xmlctx->value_len, xmlctx->value, snode->name);
Michal Vaskob36053d2020-03-26 15:49:30 +0100567 ret = LY_EVALID;
568 goto cleanup;
Radek Krejcie7b95092019-05-15 11:03:07 +0200569 }
Michal Vasko90932a92020-02-12 14:33:03 +0100570
571 /* create node */
572 ret = lyd_create_inner(snode, &cur);
573 LY_CHECK_GOTO(ret, cleanup);
574
Michal Vaskob36053d2020-03-26 15:49:30 +0100575 /* parser next */
576 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
577
Radek Krejciee4cab22019-07-17 17:07:47 +0200578 /* process children */
Michal Vaskob36053d2020-03-26 15:49:30 +0100579 if (xmlctx->status == LYXML_ELEMENT) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100580 ret = lydxml_data_r(lydctx, (struct lyd_node_inner *)cur, lyd_node_children_p(cur));
Michal Vasko9f96a052020-03-10 09:41:45 +0100581 LY_CHECK_GOTO(ret, cleanup);
582 }
583
584 if (snode->nodetype == LYS_LIST) {
585 /* check all keys exist */
Michal Vasko44685da2020-03-17 15:38:06 +0100586 LY_CHECK_GOTO(ret = lyd_parse_check_keys(cur), cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200587 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100588
Radek Krejci7931b192020-06-25 17:05:03 +0200589 if (!(lydctx->options & LYD_PARSE_ONLY)) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100590 /* new node validation, autodelete CANNOT occur, all nodes are new */
Michal Vasko8104fd42020-07-13 11:09:51 +0200591 ret = lyd_validate_new(lyd_node_children_p(cur), snode, NULL, NULL);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100592 LY_CHECK_GOTO(ret, cleanup);
593
Michal Vasko9b368d32020-02-14 13:53:31 +0100594 /* add any missing default children */
Michal Vaskoa6669ba2020-08-06 16:14:26 +0200595 ret = lyd_new_implicit_r(cur, lyd_node_children_p(cur), NULL, NULL, &lydctx->unres_node_type,
596 &lydctx->when_check, (lydctx->options & LYD_VALIDATE_NO_STATE)
597 ? LYD_IMPLICIT_NO_STATE : 0, NULL);
Michal Vasko9b368d32020-02-14 13:53:31 +0100598 LY_CHECK_GOTO(ret, cleanup);
599 }
600
Michal Vasko751cb4d2020-07-14 12:25:28 +0200601 if (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100602 /* rememeber the RPC/action/notification */
603 lydctx->op_ntf = cur;
Michal Vasko9b368d32020-02-14 13:53:31 +0100604 }
Radek Krejciee4cab22019-07-17 17:07:47 +0200605 } else if (snode->nodetype & LYD_NODE_ANY) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100606 if (!xmlctx->ws_only) {
607 /* value in inner node */
Michal Vasko1bf09392020-03-27 12:38:10 +0100608 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Text value \"%.*s\" inside an any node \"%s\" found.",
609 xmlctx->value_len, xmlctx->value, snode->name);
Michal Vaskob36053d2020-03-26 15:49:30 +0100610 ret = LY_EVALID;
611 goto cleanup;
Radek Krejciee4cab22019-07-17 17:07:47 +0200612 }
Michal Vasko90932a92020-02-12 14:33:03 +0100613
Michal Vaskob36053d2020-03-26 15:49:30 +0100614 /* parser next */
615 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
616
Michal Vasko52927e22020-03-16 17:26:14 +0100617 /* parse any data tree with correct options */
Michal Vaskob36053d2020-03-26 15:49:30 +0100618 prev_opts = lydctx->options;
Radek Krejci7931b192020-06-25 17:05:03 +0200619 lydctx->options &= ~LYD_PARSE_STRICT;
620 lydctx->options |= LYD_PARSE_OPAQ;
Michal Vasko52927e22020-03-16 17:26:14 +0100621 anchor = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100622 ret = lydxml_data_r(lydctx, NULL, &anchor);
Michal Vaskob36053d2020-03-26 15:49:30 +0100623 lydctx->options = prev_opts;
Michal Vasko52927e22020-03-16 17:26:14 +0100624 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko90932a92020-02-12 14:33:03 +0100625
626 /* create node */
Michal Vasko52927e22020-03-16 17:26:14 +0100627 ret = lyd_create_any(snode, anchor, LYD_ANYDATA_DATATREE, &cur);
628 LY_CHECK_GOTO(ret, cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200629 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100630 assert(cur);
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200631
Michal Vasko1bf09392020-03-27 12:38:10 +0100632 /* add/correct flags */
Michal Vasko52927e22020-03-16 17:26:14 +0100633 if (snode) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200634 lyd_parse_set_data_flags(cur, &lydctx->when_check, &meta, lydctx->options);
Michal Vasko8d544252020-03-02 10:19:52 +0100635 }
636
Michal Vasko52927e22020-03-16 17:26:14 +0100637 /* add metadata/attributes */
638 if (snode) {
Michal Vasko5ab0d5c2020-06-29 11:48:05 +0200639 LY_LIST_FOR(meta, m) {
640 m->parent = cur;
641 }
Michal Vasko52927e22020-03-16 17:26:14 +0100642 cur->meta = meta;
643 meta = NULL;
644 } else {
645 assert(!cur->schema);
Michal Vasko5ab0d5c2020-06-29 11:48:05 +0200646 LY_LIST_FOR(attr, a) {
647 a->parent = (struct lyd_node_opaq *)cur;
648 }
Michal Vasko52927e22020-03-16 17:26:14 +0100649 ((struct lyd_node_opaq *)cur)->attr = attr;
650 attr = NULL;
651 }
Radek Krejcib6f7ae52019-07-19 10:31:42 +0200652
Michal Vaskob104f112020-07-17 09:54:54 +0200653 /* insert, keep first pointer correct */
Michal Vaskob1b5c262020-03-05 14:29:47 +0100654 lyd_insert_node((struct lyd_node *)parent, first, cur);
Michal Vaskob104f112020-07-17 09:54:54 +0200655 while (!parent && (*first)->prev->next) {
656 *first = (*first)->prev;
657 }
Michal Vasko90932a92020-02-12 14:33:03 +0100658 cur = NULL;
Michal Vaskob36053d2020-03-26 15:49:30 +0100659
660 /* parser next */
661 assert(xmlctx->status == LYXML_ELEM_CLOSE);
662 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200663 }
664
Michal Vasko90932a92020-02-12 14:33:03 +0100665 /* success */
666 ret = LY_SUCCESS;
667
Radek Krejcie7b95092019-05-15 11:03:07 +0200668cleanup:
Michal Vasko3a41dff2020-07-15 14:30:28 +0200669 lyd_free_meta_siblings(meta);
670 ly_free_attr_siblings(ctx, attr);
Michal Vasko90932a92020-02-12 14:33:03 +0100671 lyd_free_tree(cur);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100672 if (ret && *first) {
673 lyd_free_siblings(*first);
674 *first = NULL;
Michal Vasko90932a92020-02-12 14:33:03 +0100675 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200676 return ret;
677}
678
679LY_ERR
Michal Vasko63f3d842020-07-08 10:10:14 +0200680lyd_parse_xml_data(const struct ly_ctx *ctx, struct ly_in *in, int parse_options, int validate_options, struct lyd_node **tree)
Radek Krejcie7b95092019-05-15 11:03:07 +0200681{
Radek Krejci18a57d92019-07-25 14:01:42 +0200682 LY_ERR ret = LY_SUCCESS;
Michal Vaskob36053d2020-03-26 15:49:30 +0100683 struct lyd_xml_ctx lydctx = {0};
Michal Vaskob1b5c262020-03-05 14:29:47 +0100684 uint32_t i = 0;
685 const struct lys_module *mod;
686 struct lyd_node *first, *next, **first2;
Radek Krejcie7b95092019-05-15 11:03:07 +0200687
Radek Krejci7931b192020-06-25 17:05:03 +0200688 assert(!(parse_options & ~LYD_PARSE_OPTS_MASK));
689 assert(!(validate_options & ~LYD_VALIDATE_OPTS_MASK));
690
Michal Vaskob36053d2020-03-26 15:49:30 +0100691 /* init context and tree */
Michal Vasko63f3d842020-07-08 10:10:14 +0200692 LY_CHECK_GOTO(ret = lyxml_ctx_new(ctx, in, &lydctx.xmlctx), cleanup);
Radek Krejci7931b192020-06-25 17:05:03 +0200693 lydctx.options = parse_options;
Michal Vaskob1b5c262020-03-05 14:29:47 +0100694 *tree = NULL;
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200695
Michal Vaskob1b5c262020-03-05 14:29:47 +0100696 /* parse XML data */
Michal Vasko1bf09392020-03-27 12:38:10 +0100697 LY_CHECK_GOTO(ret = lydxml_data_r(&lydctx, NULL, tree), cleanup);
Michal Vaskocde73ac2019-11-14 16:10:27 +0100698
Radek Krejci7931b192020-06-25 17:05:03 +0200699 if (!(parse_options & LYD_PARSE_ONLY)) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100700 next = *tree;
701 while (1) {
Radek Krejci7931b192020-06-25 17:05:03 +0200702 if (validate_options & LYD_VALIDATE_PRESENT) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100703 mod = lyd_data_next_module(&next, &first);
704 } else {
Michal Vasko26e80012020-07-08 10:55:46 +0200705 mod = lyd_mod_next_module(next, NULL, ctx, &i, &first);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100706 }
707 if (!mod) {
708 break;
709 }
710 if (first == *tree) {
711 /* make sure first2 changes are carried to tree */
712 first2 = tree;
713 } else {
714 first2 = &first;
715 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100716
Michal Vaskob1b5c262020-03-05 14:29:47 +0100717 /* validate new top-level nodes, autodelete CANNOT occur, all nodes are new */
Michal Vasko8104fd42020-07-13 11:09:51 +0200718 LY_CHECK_GOTO(ret = lyd_validate_new(first2, NULL, mod, NULL), cleanup);
Michal Vasko9b368d32020-02-14 13:53:31 +0100719
Michal Vaskob1b5c262020-03-05 14:29:47 +0100720 /* add all top-level defaults for this module */
Michal Vaskoa6669ba2020-08-06 16:14:26 +0200721 ret = lyd_new_implicit_r(NULL, first2, NULL, mod, &lydctx.unres_node_type, &lydctx.when_check,
722 validate_options & LYD_VALIDATE_NO_STATE ? LYD_IMPLICIT_NO_STATE : 0, NULL);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100723 LY_CHECK_GOTO(ret, cleanup);
724
725 /* finish incompletely validated terminal values/attributes and when conditions */
Michal Vaskob36053d2020-03-26 15:49:30 +0100726 ret = lyd_validate_unres(tree, &lydctx.when_check, &lydctx.unres_node_type, &lydctx.unres_meta_type, LYD_XML,
Michal Vasko8104fd42020-07-13 11:09:51 +0200727 lydxml_resolve_prefix, lydctx.xmlctx, NULL);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100728 LY_CHECK_GOTO(ret, cleanup);
729
730 /* perform final validation that assumes the data tree is final */
Radek Krejci7931b192020-06-25 17:05:03 +0200731 LY_CHECK_GOTO(ret = lyd_validate_final_r(*first2, NULL, mod, validate_options, 0), cleanup);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100732 }
Michal Vaskocde73ac2019-11-14 16:10:27 +0100733 }
734
Michal Vaskocde73ac2019-11-14 16:10:27 +0100735cleanup:
Michal Vasko9b368d32020-02-14 13:53:31 +0100736 /* there should be no unresolved types stored */
Radek Krejci7931b192020-06-25 17:05:03 +0200737 assert(!(parse_options & LYD_PARSE_ONLY) || (!lydctx.unres_node_type.count && !lydctx.unres_meta_type.count
Michal Vaskob36053d2020-03-26 15:49:30 +0100738 && !lydctx.when_check.count));
Michal Vasko9b368d32020-02-14 13:53:31 +0100739
Michal Vaskob36053d2020-03-26 15:49:30 +0100740 ly_set_erase(&lydctx.unres_node_type, NULL);
741 ly_set_erase(&lydctx.unres_meta_type, NULL);
742 ly_set_erase(&lydctx.when_check, NULL);
743 lyxml_ctx_free(lydctx.xmlctx);
Michal Vasko9f96a052020-03-10 09:41:45 +0100744 if (ret) {
745 lyd_free_all(*tree);
746 *tree = NULL;
747 }
748 return ret;
749}
Michal Vasko1bf09392020-03-27 12:38:10 +0100750
751static LY_ERR
752lydxml_envelope(struct lyxml_ctx *xmlctx, const char *name, const char *uri, struct lyd_node **envp)
753{
754 LY_ERR ret = LY_SUCCESS;
755 const struct lyxml_ns *ns = NULL;
756 struct ly_attr *attr = NULL;
757 const char *prefix;
758 size_t prefix_len;
759
760 *envp = NULL;
761
762 assert(xmlctx->status == LYXML_ELEMENT);
763 if (ly_strncmp(name, xmlctx->name, xmlctx->name_len)) {
764 /* not the expected element */
765 return LY_SUCCESS;
766 }
767
768 prefix = xmlctx->prefix;
769 prefix_len = xmlctx->prefix_len;
770 ns = lyxml_ns_get(xmlctx, prefix, prefix_len);
771 if (!ns) {
772 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
773 prefix_len, prefix);
774 return LY_EVALID;
775 } else if (strcmp(ns->uri, uri)) {
776 /* different namespace */
777 return LY_SUCCESS;
778 }
779
780 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
781
782 /* create attributes */
783 if (xmlctx->status == LYXML_ATTRIBUTE) {
784 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
785 }
786
787 if (!xmlctx->ws_only) {
788 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Unexpected value \"%.*s\" in the \"%s\" element.",
789 xmlctx->value_len, xmlctx->value, name);
790 ret = LY_EVALID;
791 goto cleanup;
792 }
793
794 /* parser next element */
795 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
796
797 /* create node */
798 ret = lyd_create_opaq(xmlctx->ctx, name, strlen(name), "", 0, NULL, LYD_XML, NULL, prefix, prefix_len, uri, envp);
799 LY_CHECK_GOTO(ret, cleanup);
800
801 /* assign atributes */
802 ((struct lyd_node_opaq *)(*envp))->attr = attr;
803 attr = NULL;
804
805cleanup:
Michal Vasko3a41dff2020-07-15 14:30:28 +0200806 ly_free_attr_siblings(xmlctx->ctx, attr);
Michal Vasko1bf09392020-03-27 12:38:10 +0100807 return ret;
808}
809
810LY_ERR
Michal Vasko63f3d842020-07-08 10:10:14 +0200811lyd_parse_xml_rpc(const struct ly_ctx *ctx, struct ly_in *in, struct lyd_node **tree, struct lyd_node **op)
Michal Vasko1bf09392020-03-27 12:38:10 +0100812{
813 LY_ERR ret = LY_SUCCESS;
814 struct lyd_xml_ctx lydctx = {0};
815 struct lyd_node *rpc_e = NULL, *act_e = NULL;
816
817 /* init */
Michal Vasko63f3d842020-07-08 10:10:14 +0200818 LY_CHECK_GOTO(ret = lyxml_ctx_new(ctx, in, &lydctx.xmlctx), cleanup);
Radek Krejci7931b192020-06-25 17:05:03 +0200819 lydctx.options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
Michal Vasko1bf09392020-03-27 12:38:10 +0100820 lydctx.int_opts = LYD_INTOPT_RPC;
821 *tree = NULL;
Michal Vaskocc048b22020-03-27 15:52:38 +0100822 if (op) {
823 *op = NULL;
824 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100825
826 /* parse "rpc", if any */
827 LY_CHECK_GOTO(ret = lydxml_envelope(lydctx.xmlctx, "rpc", "urn:ietf:params:xml:ns:netconf:base:1.0", &rpc_e), cleanup);
828
829 if (rpc_e) {
830 /* parse "action", if any */
831 LY_CHECK_GOTO(ret = lydxml_envelope(lydctx.xmlctx, "action", "urn:ietf:params:xml:ns:yang:1", &act_e), cleanup);
832 }
833
834 /* parse the rest of data normally */
835 LY_CHECK_GOTO(ret = lydxml_data_r(&lydctx, NULL, tree), cleanup);
836
837 /* make sure we have parsed some operation */
838 if (!lydctx.op_ntf) {
839 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_DATA, "Missing the \"rpc\"/\"action\" node.");
840 ret = LY_EVALID;
841 goto cleanup;
842 }
843
844 /* finish XML parsing and check operation type */
845 if (act_e) {
846 if (lydctx.xmlctx->status != LYXML_ELEM_CLOSE) {
847 assert(lydctx.xmlctx->status == LYXML_ELEMENT);
848 LOGVAL(ctx, LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"action\".",
849 lydctx.xmlctx->name_len, lydctx.xmlctx->name);
850 ret = LY_EVALID;
851 goto cleanup;
852 } else if (lydctx.op_ntf->schema->nodetype != LYS_ACTION) {
853 LOGVAL(ctx, LY_VLOG_LYD, lydctx.op_ntf, LYVE_DATA, "Unexpected %s element, an \"action\" expected.",
854 lys_nodetype2str(lydctx.op_ntf->schema->nodetype));
855 ret = LY_EVALID;
856 goto cleanup;
857 }
858 LY_CHECK_GOTO(ret = lyxml_ctx_next(lydctx.xmlctx), cleanup);
859 }
860 if (rpc_e) {
861 if (lydctx.xmlctx->status != LYXML_ELEM_CLOSE) {
862 assert(lydctx.xmlctx->status == LYXML_ELEMENT);
863 LOGVAL(ctx, LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"rpc\".",
864 lydctx.xmlctx->name_len, lydctx.xmlctx->name);
865 ret = LY_EVALID;
866 goto cleanup;
867 } else if (!act_e && (lydctx.op_ntf->schema->nodetype != LYS_RPC)) {
868 LOGVAL(ctx, LY_VLOG_LYD, lydctx.op_ntf, LYVE_DATA, "Unexpected %s element, an \"rpc\" expected.",
869 lys_nodetype2str(lydctx.op_ntf->schema->nodetype));
870 ret = LY_EVALID;
871 goto cleanup;
872 }
873 LY_CHECK_GOTO(ret = lyxml_ctx_next(lydctx.xmlctx), cleanup);
874 }
875
Michal Vaskocc048b22020-03-27 15:52:38 +0100876 if (op) {
877 *op = lydctx.op_ntf;
878 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100879 assert(*tree);
880 if (act_e) {
881 /* connect to the action */
882 lyd_insert_node(act_e, NULL, *tree);
883 *tree = act_e;
884 }
885 if (rpc_e) {
886 /* connect to the rpc */
887 lyd_insert_node(rpc_e, NULL, *tree);
888 *tree = rpc_e;
889 }
890
891cleanup:
892 /* we have used parse_only flag */
893 assert(!lydctx.unres_node_type.count && !lydctx.unres_meta_type.count && !lydctx.when_check.count);
894 lyxml_ctx_free(lydctx.xmlctx);
895 if (ret) {
896 lyd_free_all(*tree);
897 lyd_free_tree(act_e);
898 lyd_free_tree(rpc_e);
899 *tree = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100900 }
901 return ret;
902}
Michal Vaskoa8edff02020-03-27 14:47:01 +0100903
904static LY_ERR
905lydxml_notif_envelope(struct lyxml_ctx *xmlctx, struct lyd_node **envp)
906{
907 LY_ERR ret = LY_SUCCESS;
908 const struct lyxml_ns *ns = NULL;
909 struct ly_attr *attr = NULL;
910 struct lyd_node *et;
911 const char *prefix;
912 size_t prefix_len;
913
914 *envp = NULL;
915
916 /* container envelope */
917 LY_CHECK_GOTO(ret = lydxml_envelope(xmlctx, "notification", "urn:ietf:params:xml:ns:netconf:notification:1.0",
918 envp), cleanup);
919
920 /* no envelope, fine */
921 if (!*envp) {
922 goto cleanup;
923 }
924
925 /* child "eventTime" */
926 if ((xmlctx->status != LYXML_ELEMENT) || ly_strncmp("eventTime", xmlctx->name, xmlctx->name_len)) {
927 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Missing the \"eventTime\" element.");
928 ret = LY_EVALID;
929 goto cleanup;
930 }
931
932 prefix = xmlctx->prefix;
933 prefix_len = xmlctx->prefix_len;
934 ns = lyxml_ns_get(xmlctx, prefix, prefix_len);
935 if (!ns) {
936 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
937 prefix_len, prefix);
938 ret = LY_EVALID;
939 goto cleanup;
940 } else if (strcmp(ns->uri, "urn:ietf:params:xml:ns:netconf:notification:1.0")) {
941 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Invalid namespace \"%s\" of \"eventTime\".",
942 ns->uri);
943 ret = LY_EVALID;
944 goto cleanup;
945 }
946
947 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
948
949 /* create attributes */
950 if (xmlctx->status == LYXML_ATTRIBUTE) {
951 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
952 }
953
954 /* validate value */
955 /* TODO */
956 /*if (!xmlctx->ws_only) {
957 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Unexpected value \"%.*s\" in the \"%s\" element.",
958 xmlctx->value_len, xmlctx->value, name);
959 ret = LY_EVALID;
960 goto cleanup;
961 }*/
962
963 /* create node */
964 ret = lyd_create_opaq(xmlctx->ctx, "eventTime", 9, xmlctx->value, xmlctx->value_len, NULL, LYD_XML, NULL,
965 prefix, prefix_len, ns->uri, &et);
966 LY_CHECK_GOTO(ret, cleanup);
967
968 /* assign atributes */
969 ((struct lyd_node_opaq *)et)->attr = attr;
970 attr = NULL;
971
972 /* insert */
973 lyd_insert_node(*envp, NULL, et);
974
975 /* finish parsing */
976 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
977 if (xmlctx->status != LYXML_ELEM_CLOSE) {
978 assert(xmlctx->status == LYXML_ELEMENT);
979 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"eventTime\".",
980 xmlctx->name_len, xmlctx->name);
981 ret = LY_EVALID;
982 goto cleanup;
983 }
984 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
985
986cleanup:
987 if (ret) {
988 lyd_free_tree(*envp);
Michal Vasko3a41dff2020-07-15 14:30:28 +0200989 ly_free_attr_siblings(xmlctx->ctx, attr);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100990 }
991 return ret;
992}
993
994LY_ERR
Michal Vasko63f3d842020-07-08 10:10:14 +0200995lyd_parse_xml_notif(const struct ly_ctx *ctx, struct ly_in *in, struct lyd_node **tree, struct lyd_node **ntf)
Michal Vaskoa8edff02020-03-27 14:47:01 +0100996{
997 LY_ERR ret = LY_SUCCESS;
998 struct lyd_xml_ctx lydctx = {0};
999 struct lyd_node *ntf_e = NULL;
1000
1001 /* init */
Michal Vasko63f3d842020-07-08 10:10:14 +02001002 LY_CHECK_GOTO(ret = lyxml_ctx_new(ctx, in, &lydctx.xmlctx), cleanup);
Radek Krejci7931b192020-06-25 17:05:03 +02001003 lydctx.options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001004 lydctx.int_opts = LYD_INTOPT_NOTIF;
1005 *tree = NULL;
Michal Vaskocc048b22020-03-27 15:52:38 +01001006 if (ntf) {
1007 *ntf = NULL;
1008 }
Michal Vaskoa8edff02020-03-27 14:47:01 +01001009
1010 /* parse "notification" and "eventTime", if present */
1011 LY_CHECK_GOTO(ret = lydxml_notif_envelope(lydctx.xmlctx, &ntf_e), cleanup);
1012
1013 /* parse the rest of data normally */
1014 LY_CHECK_GOTO(ret = lydxml_data_r(&lydctx, NULL, tree), cleanup);
1015
1016 /* make sure we have parsed some notification */
1017 if (!lydctx.op_ntf) {
1018 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_DATA, "Missing the \"notification\" node.");
1019 ret = LY_EVALID;
1020 goto cleanup;
1021 }
1022
1023 /* finish XML parsing */
1024 if (ntf_e) {
1025 if (lydctx.xmlctx->status != LYXML_ELEM_CLOSE) {
1026 assert(lydctx.xmlctx->status == LYXML_ELEMENT);
1027 LOGVAL(ctx, LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"notification\".",
1028 lydctx.xmlctx->name_len, lydctx.xmlctx->name);
1029 ret = LY_EVALID;
1030 goto cleanup;
1031 }
1032 LY_CHECK_GOTO(ret = lyxml_ctx_next(lydctx.xmlctx), cleanup);
1033 }
1034
Michal Vaskocc048b22020-03-27 15:52:38 +01001035 if (ntf) {
1036 *ntf = lydctx.op_ntf;
1037 }
Michal Vaskoa8edff02020-03-27 14:47:01 +01001038 assert(*tree);
1039 if (ntf_e) {
1040 /* connect to the notification */
1041 lyd_insert_node(ntf_e, NULL, *tree);
1042 *tree = ntf_e;
1043 }
1044
1045cleanup:
1046 /* we have used parse_only flag */
1047 assert(!lydctx.unres_node_type.count && !lydctx.unres_meta_type.count && !lydctx.when_check.count);
1048 lyxml_ctx_free(lydctx.xmlctx);
1049 if (ret) {
1050 lyd_free_all(*tree);
1051 lyd_free_tree(ntf_e);
1052 *tree = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001053 }
1054 return ret;
1055}
Michal Vasko1ce933a2020-03-30 12:38:22 +02001056
1057LY_ERR
Michal Vasko63f3d842020-07-08 10:10:14 +02001058lyd_parse_xml_reply(const struct lyd_node *request, struct ly_in *in, struct lyd_node **tree, struct lyd_node **op)
Michal Vasko1ce933a2020-03-30 12:38:22 +02001059{
1060 LY_ERR ret = LY_SUCCESS;
1061 struct lyd_xml_ctx lydctx = {0};
Radek Krejcib1247842020-07-02 16:22:38 +02001062 struct lyd_node *rpcr_e = NULL, *iter, *req_op, *rep_op = NULL;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001063
1064 /* init */
Michal Vasko63f3d842020-07-08 10:10:14 +02001065 LY_CHECK_GOTO(ret = lyxml_ctx_new(LYD_NODE_CTX(request), in, &lydctx.xmlctx), cleanup);
Radek Krejci7931b192020-06-25 17:05:03 +02001066 lydctx.options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001067 lydctx.int_opts = LYD_INTOPT_REPLY;
1068 *tree = NULL;
1069 if (op) {
1070 *op = NULL;
1071 }
1072
1073 /* find request OP */
Michal Vasko56daf732020-08-10 10:57:18 +02001074 LYD_TREE_DFS_BEGIN((struct lyd_node *)request, req_op) {
Michal Vasko1ce933a2020-03-30 12:38:22 +02001075 if (req_op->schema->nodetype & (LYS_RPC | LYS_ACTION)) {
1076 break;
1077 }
Michal Vasko56daf732020-08-10 10:57:18 +02001078 LYD_TREE_DFS_END(request, req_op);
Michal Vasko1ce933a2020-03-30 12:38:22 +02001079 }
1080 if (!(req_op->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
1081 LOGERR(LYD_NODE_CTX(request), LY_EINVAL, "No RPC/action in the request found.");
1082 ret = LY_EINVAL;
1083 goto cleanup;
1084 }
1085
1086 /* duplicate request OP with parents */
Michal Vasko3a41dff2020-07-15 14:30:28 +02001087 LY_CHECK_GOTO(ret = lyd_dup_single(req_op, NULL, LYD_DUP_WITH_PARENTS, &rep_op), cleanup);
Michal Vasko1ce933a2020-03-30 12:38:22 +02001088
1089 /* parse "rpc-reply", if any */
Michal Vasko3a41dff2020-07-15 14:30:28 +02001090 LY_CHECK_GOTO(ret = lydxml_envelope(lydctx.xmlctx, "rpc-reply", "urn:ietf:params:xml:ns:netconf:base:1.0", &rpcr_e),
1091 cleanup);
Michal Vasko1ce933a2020-03-30 12:38:22 +02001092
1093 /* parse the rest of data normally but connect them to the duplicated operation */
1094 LY_CHECK_GOTO(ret = lydxml_data_r(&lydctx, (struct lyd_node_inner *)rep_op, lyd_node_children_p(rep_op)), cleanup);
1095
1096 /* finish XML parsing and check operation type */
1097 if (rpcr_e) {
1098 if (lydctx.xmlctx->status != LYXML_ELEM_CLOSE) {
1099 assert(lydctx.xmlctx->status == LYXML_ELEMENT);
1100 LOGVAL(LYD_NODE_CTX(request), LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX,
1101 "Unexpected sibling element \"%.*s\" of \"rpc-reply\".", lydctx.xmlctx->name_len, lydctx.xmlctx->name);
1102 ret = LY_EVALID;
1103 goto cleanup;
1104 }
1105 LY_CHECK_GOTO(ret = lyxml_ctx_next(lydctx.xmlctx), cleanup);
1106 }
1107
1108 if (op) {
1109 *op = rep_op;
1110 }
1111 for (iter = rep_op; iter->parent; iter = (struct lyd_node *)iter->parent);
1112 *tree = iter;
1113 if (rpcr_e) {
1114 /* connect to the operation */
1115 lyd_insert_node(rpcr_e, NULL, *tree);
1116 *tree = rpcr_e;
1117 }
1118
1119cleanup:
1120 /* we have used parse_only flag */
1121 assert(!lydctx.unres_node_type.count && !lydctx.unres_meta_type.count && !lydctx.when_check.count);
1122 lyxml_ctx_free(lydctx.xmlctx);
1123 if (ret) {
1124 lyd_free_all(rep_op);
1125 lyd_free_tree(rpcr_e);
1126 }
1127 return ret;
1128}