blob: 224b3c340eef710d10712900bc751940837a6388 [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
Michal Vasko69730152020-10-09 16:30:07 +020015#include <assert.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020016#include <stdint.h>
17#include <stdlib.h>
18#include <string.h>
19
Radek Krejci535ea9f2020-05-29 16:01:05 +020020#include "common.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020021#include "context.h"
Radek Krejci77114102021-03-10 15:21:57 +010022#include "dict.h"
Michal Vaskoafac7822020-10-20 14:22:26 +020023#include "in_internal.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020024#include "log.h"
Radek Krejci7931b192020-06-25 17:05:03 +020025#include "parser_data.h"
26#include "parser_internal.h"
tadeas-vintrlikbf8aa6e2021-11-03 13:07:34 +010027#include "plugins_exts.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020028#include "set.h"
Radek Krejci77114102021-03-10 15:21:57 +010029#include "tree.h"
Radek Krejci47fab892020-11-05 17:02:41 +010030#include "tree_data.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020031#include "tree_data_internal.h"
32#include "tree_schema.h"
Radek Krejci77114102021-03-10 15:21:57 +010033#include "tree_schema_internal.h"
Michal Vaskocde73ac2019-11-14 16:10:27 +010034#include "validation.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020035#include "xml.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020036
Radek Krejci1798aae2020-07-14 13:26:06 +020037void
38lyd_xml_ctx_free(struct lyd_ctx *lydctx)
39{
40 struct lyd_xml_ctx *ctx = (struct lyd_xml_ctx *)lydctx;
41
42 lyd_ctx_free(lydctx);
43 lyxml_ctx_free(ctx->xmlctx);
44 free(ctx);
45}
46
Michal Vasko45791ad2021-06-17 08:45:03 +020047/**
48 * @brief Parse and create XML metadata.
49 *
50 * @param[in] lydctx XML data parser context.
Michal Vaskoaac267d2022-01-17 13:34:48 +010051 * @param[in] sparent Schema node of the parent.
Michal Vasko45791ad2021-06-17 08:45:03 +020052 * @param[out] meta List of created metadata instances.
53 * @return LY_ERR value.
54 */
Radek Krejcie7b95092019-05-15 11:03:07 +020055static LY_ERR
Michal Vaskoaac267d2022-01-17 13:34:48 +010056lydxml_metadata(struct lyd_xml_ctx *lydctx, const struct lysc_node *sparent, struct lyd_meta **meta)
Radek Krejcie7b95092019-05-15 11:03:07 +020057{
aPiecek1c4da362021-04-29 14:26:34 +020058 LY_ERR ret = LY_SUCCESS;
Radek Krejci28681fa2019-09-06 13:08:45 +020059 const struct lyxml_ns *ns;
60 struct lys_module *mod;
Michal Vaskob36053d2020-03-26 15:49:30 +010061 const char *name;
62 size_t name_len;
Michal Vasko45791ad2021-06-17 08:45:03 +020063 LY_ARRAY_COUNT_TYPE u;
64 ly_bool filter_attrs = 0;
Radek Krejci1798aae2020-07-14 13:26:06 +020065 struct lyxml_ctx *xmlctx = lydctx->xmlctx;
Radek Krejci28681fa2019-09-06 13:08:45 +020066
Michal Vaskob36053d2020-03-26 15:49:30 +010067 *meta = NULL;
Radek Krejci28681fa2019-09-06 13:08:45 +020068
Michal Vasko45791ad2021-06-17 08:45:03 +020069 /* check for NETCONF filter unqualified attributes */
Michal Vaskoaac267d2022-01-17 13:34:48 +010070 LY_ARRAY_FOR(sparent->exts, u) {
71 if (!strcmp(sparent->exts[u].def->name, "get-filter-element-attributes") &&
72 !strcmp(sparent->exts[u].def->module->name, "ietf-netconf")) {
Michal Vasko45791ad2021-06-17 08:45:03 +020073 filter_attrs = 1;
74 break;
75 }
76 }
77
Michal Vaskob36053d2020-03-26 15:49:30 +010078 while (xmlctx->status == LYXML_ATTRIBUTE) {
79 if (!xmlctx->prefix_len) {
Michal Vasko45791ad2021-06-17 08:45:03 +020080 /* in XML all attributes must be prefixed except NETCONF filter ones marked by an extension */
81 if (filter_attrs && (!ly_strncmp("type", xmlctx->name, xmlctx->name_len) ||
82 !ly_strncmp("select", xmlctx->name, xmlctx->name_len))) {
83 mod = ly_ctx_get_module_implemented(xmlctx->ctx, "ietf-netconf");
84 if (!mod) {
85 LOGVAL(xmlctx->ctx, LYVE_REFERENCE,
86 "Missing (or not implemented) YANG module \"ietf-netconf\" for special filter attributes.");
87 ret = LY_ENOTFOUND;
88 goto cleanup;
89 }
90 goto create_meta;
91 }
92
Michal Vaskoe0665742021-02-11 11:08:44 +010093 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +010094 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Missing mandatory prefix for XML metadata \"%.*s\".",
Radek Krejci422afb12021-03-04 16:38:16 +010095 (int)xmlctx->name_len, xmlctx->name);
Michal Vasko45791ad2021-06-17 08:45:03 +020096 ret = LY_EVALID;
Michal Vaskob36053d2020-03-26 15:49:30 +010097 goto cleanup;
Radek Krejci28681fa2019-09-06 13:08:45 +020098 }
Michal Vaskob36053d2020-03-26 15:49:30 +010099
Michal Vasko45791ad2021-06-17 08:45:03 +0200100 /* skip attr */
Michal Vaskob36053d2020-03-26 15:49:30 +0100101 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
102 assert(xmlctx->status == LYXML_ATTR_CONTENT);
103 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejci28681fa2019-09-06 13:08:45 +0200104 continue;
105 }
106
107 /* get namespace of the attribute to find its annotation definition */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200108 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
Radek Krejci28681fa2019-09-06 13:08:45 +0200109 if (!ns) {
Michal Vasko52927e22020-03-16 17:26:14 +0100110 /* unknown namespace, XML error */
Radek Krejci422afb12021-03-04 16:38:16 +0100111 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)xmlctx->prefix_len, xmlctx->prefix);
Michal Vasko45791ad2021-06-17 08:45:03 +0200112 ret = LY_ENOTFOUND;
Radek Krejci28681fa2019-09-06 13:08:45 +0200113 goto cleanup;
114 }
Michal Vasko45791ad2021-06-17 08:45:03 +0200115
116 /* get the module with metadata definition */
Michal Vasko52927e22020-03-16 17:26:14 +0100117 mod = ly_ctx_get_module_implemented_ns(xmlctx->ctx, ns->uri);
Radek Krejci28681fa2019-09-06 13:08:45 +0200118 if (!mod) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100119 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100120 LOGVAL(xmlctx->ctx, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +0200121 "Unknown (or not implemented) YANG module with namespace \"%s\" for metadata \"%.*s%s%.*s\".",
Radek Krejci422afb12021-03-04 16:38:16 +0100122 ns->uri, (int)xmlctx->prefix_len, xmlctx->prefix, xmlctx->prefix_len ? ":" : "",
123 (int)xmlctx->name_len, xmlctx->name);
Michal Vasko45791ad2021-06-17 08:45:03 +0200124 ret = LY_ENOTFOUND;
Michal Vaskob36053d2020-03-26 15:49:30 +0100125 goto cleanup;
Radek Krejci28681fa2019-09-06 13:08:45 +0200126 }
Michal Vasko45791ad2021-06-17 08:45:03 +0200127
128 /* skip attr */
129 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
130 assert(xmlctx->status == LYXML_ATTR_CONTENT);
131 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
132 continue;
Radek Krejci28681fa2019-09-06 13:08:45 +0200133 }
134
Michal Vasko45791ad2021-06-17 08:45:03 +0200135create_meta:
Michal Vasko60ea6352020-06-29 13:39:39 +0200136 /* remember meta name and get its content */
Michal Vaskob36053d2020-03-26 15:49:30 +0100137 name = xmlctx->name;
138 name_len = xmlctx->name_len;
139 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
140 assert(xmlctx->status == LYXML_ATTR_CONTENT);
141
142 /* create metadata */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200143 ret = lyd_parser_create_meta((struct lyd_ctx *)lydctx, NULL, meta, mod, name, name_len, xmlctx->value,
Michal Vaskoaac267d2022-01-17 13:34:48 +0100144 xmlctx->value_len, &xmlctx->dynamic, LY_VALUE_XML, &xmlctx->ns, LYD_HINT_DATA, sparent);
Radek Krejci1798aae2020-07-14 13:26:06 +0200145 LY_CHECK_GOTO(ret, cleanup);
Michal Vaskob36053d2020-03-26 15:49:30 +0100146
147 /* next attribute */
148 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200149 }
Michal Vasko52927e22020-03-16 17:26:14 +0100150
Radek Krejcie7b95092019-05-15 11:03:07 +0200151cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100152 if (ret) {
Michal Vasko3a41dff2020-07-15 14:30:28 +0200153 lyd_free_meta_siblings(*meta);
Michal Vaskob36053d2020-03-26 15:49:30 +0100154 *meta = NULL;
Radek Krejci38d85362019-09-05 16:26:38 +0200155 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200156 return ret;
157}
158
Michal Vasko52927e22020-03-16 17:26:14 +0100159static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200160lydxml_attrs(struct lyxml_ctx *xmlctx, struct lyd_attr **attr)
Michal Vasko52927e22020-03-16 17:26:14 +0100161{
162 LY_ERR ret = LY_SUCCESS;
163 const struct lyxml_ns *ns;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100164 void *val_prefix_data;
Radek Krejci8df109d2021-04-23 12:19:08 +0200165 LY_VALUE_FORMAT format;
Radek Krejci1798aae2020-07-14 13:26:06 +0200166 struct lyd_attr *attr2;
Michal Vaskob36053d2020-03-26 15:49:30 +0100167 const char *name, *prefix;
168 size_t name_len, prefix_len;
Michal Vasko52927e22020-03-16 17:26:14 +0100169
170 assert(attr);
Michal Vaskob36053d2020-03-26 15:49:30 +0100171 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100172
Michal Vaskob36053d2020-03-26 15:49:30 +0100173 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vasko52927e22020-03-16 17:26:14 +0100174 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 Vaskoe137fc42021-07-22 11:53:13 +0200188 /* handle special "xml" attribute prefix */
189 if ((prefix_len == 3) && !strncmp(prefix, "xml", 3)) {
190 name = prefix;
191 name_len += 1 + prefix_len;
192 prefix = NULL;
193 prefix_len = 0;
194 }
195
196 /* find namespace of the attribute, if any */
197 ns = NULL;
198 if (prefix_len) {
199 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
200 if (!ns) {
201 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
202 ret = LY_EVALID;
203 goto cleanup;
204 }
205 }
206
Michal Vasko52927e22020-03-16 17:26:14 +0100207 /* get value prefixes */
Michal Vaskofc2cd072021-02-24 13:17:17 +0100208 val_prefix_data = NULL;
Radek Krejci8df109d2021-04-23 12:19:08 +0200209 LY_CHECK_GOTO(ret = ly_store_prefix_data(xmlctx->ctx, xmlctx->value, xmlctx->value_len, LY_VALUE_XML,
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100210 &xmlctx->ns, &format, &val_prefix_data), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100211
212 /* attr2 is always changed to the created attribute */
Michal Vasko501af032020-11-11 20:27:44 +0100213 ret = lyd_create_attr(NULL, &attr2, xmlctx->ctx, name, name_len, prefix, prefix_len, ns ? ns->uri : NULL,
Michal Vasko8589d0a2022-02-01 13:15:08 +0100214 ns ? strlen(ns->uri) : 0, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic, format, val_prefix_data,
215 LYD_HINT_DATA);
Michal Vasko52927e22020-03-16 17:26:14 +0100216 LY_CHECK_GOTO(ret, cleanup);
217
218 if (!*attr) {
219 *attr = attr2;
220 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100221
222 /* next attribute */
223 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100224 }
225
226cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100227 if (ret) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200228 lyd_free_attr_siblings(xmlctx->ctx, *attr);
Michal Vaskob36053d2020-03-26 15:49:30 +0100229 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100230 }
Michal Vasko52927e22020-03-16 17:26:14 +0100231 return ret;
232}
233
Michal Vasko44685da2020-03-17 15:38:06 +0100234static LY_ERR
Michal Vaskob36053d2020-03-26 15:49:30 +0100235lydxml_check_list(struct lyxml_ctx *xmlctx, const struct lysc_node *list)
Michal Vasko44685da2020-03-17 15:38:06 +0100236{
Michal Vaskob36053d2020-03-26 15:49:30 +0100237 LY_ERR ret = LY_SUCCESS, r;
238 enum LYXML_PARSER_STATUS next;
Michal Vasko44685da2020-03-17 15:38:06 +0100239 struct ly_set key_set = {0};
240 const struct lysc_node *snode;
Michal Vaskob36053d2020-03-26 15:49:30 +0100241 uint32_t i, parents_count;
Michal Vasko44685da2020-03-17 15:38:06 +0100242
243 assert(list && (list->nodetype == LYS_LIST));
244
245 /* get all keys into a set (keys do not have if-features or anything) */
246 snode = NULL;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100247 while ((snode = lys_getnext(snode, list, NULL, 0)) && (snode->flags & LYS_KEY)) {
Radek Krejci3d92e442020-10-12 12:48:13 +0200248 ret = ly_set_add(&key_set, (void *)snode, 1, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200249 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100250 }
251
Michal Vasko12d809c2021-03-03 16:34:32 +0100252 /* remember parent count */
253 parents_count = xmlctx->elements.count;
254
Michal Vaskob36053d2020-03-26 15:49:30 +0100255 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vasko44685da2020-03-17 15:38:06 +0100256 /* find key definition */
257 for (i = 0; i < key_set.count; ++i) {
258 snode = (const struct lysc_node *)key_set.objs[i];
Michal Vaskob36053d2020-03-26 15:49:30 +0100259 if (!ly_strncmp(snode->name, xmlctx->name, xmlctx->name_len)) {
Michal Vasko44685da2020-03-17 15:38:06 +0100260 break;
261 }
262 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100263 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100264
265 /* skip attributes */
266 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100267 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
268 assert(xmlctx->status == LYXML_ATTR_CONTENT);
269 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100270 }
271
Michal Vaskob36053d2020-03-26 15:49:30 +0100272 assert(xmlctx->status == LYXML_ELEM_CONTENT);
273 if (i < key_set.count) {
274 /* validate the value */
Radek Krejci8df109d2021-04-23 12:19:08 +0200275 r = lys_value_validate(NULL, snode, xmlctx->value, xmlctx->value_len, LY_VALUE_XML, &xmlctx->ns);
Michal Vaskob36053d2020-03-26 15:49:30 +0100276 if (!r) {
277 /* key with a valid value, remove from the set */
278 ly_set_rm_index(&key_set, i, NULL);
Michal Vasko44685da2020-03-17 15:38:06 +0100279 }
280 }
281
Michal Vaskob36053d2020-03-26 15:49:30 +0100282 /* parser next */
283 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100284
Michal Vaskob36053d2020-03-26 15:49:30 +0100285 /* skip any children, resursively */
Michal Vasko12d809c2021-03-03 16:34:32 +0100286 while (xmlctx->status == LYXML_ELEMENT) {
287 while (parents_count < xmlctx->elements.count) {
288 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
289 }
290 assert(xmlctx->status == LYXML_ELEM_CLOSE);
Michal Vaskob36053d2020-03-26 15:49:30 +0100291 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
292 }
293
294 /* parser next, but do not parse closing element of the list because it would remove its namespaces */
295 assert(xmlctx->status == LYXML_ELEM_CLOSE);
296 LY_CHECK_GOTO(ret = lyxml_ctx_peek(xmlctx, &next), cleanup);
297 if (next != LYXML_ELEM_CLOSE) {
298 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
299 }
Michal Vasko44685da2020-03-17 15:38:06 +0100300 }
301
302 if (key_set.count) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100303 /* some keys are missing/did not validate */
Michal Vasko44685da2020-03-17 15:38:06 +0100304 ret = LY_ENOT;
Michal Vasko44685da2020-03-17 15:38:06 +0100305 }
306
307cleanup:
308 ly_set_erase(&key_set, NULL);
309 return ret;
310}
311
Michal Vasko5c24ed12021-06-09 09:27:32 +0200312/**
313 * @brief Skip an element with all its descendants.
314 *
315 * @param[in] xmlctx XML parser context.
316 * @return LY_ERR value.
317 */
Michal Vasko1bf09392020-03-27 12:38:10 +0100318static LY_ERR
319lydxml_data_skip(struct lyxml_ctx *xmlctx)
320{
321 uint32_t parents_count;
322
323 /* remember current number of parents */
324 parents_count = xmlctx->elements.count;
aPiecek9cdb9e62021-05-18 09:46:20 +0200325 assert(parents_count);
Michal Vasko1bf09392020-03-27 12:38:10 +0100326
327 /* skip after the content */
328 while (xmlctx->status != LYXML_ELEM_CONTENT) {
329 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
330 }
331 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
332
333 /* skip all children elements, recursively, if any */
aPiecek9cdb9e62021-05-18 09:46:20 +0200334 while (parents_count <= xmlctx->elements.count) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100335 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
336 }
337
338 /* close element */
339 assert(xmlctx->status == LYXML_ELEM_CLOSE);
340 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
341
342 return LY_SUCCESS;
343}
344
Michal Vasko5c24ed12021-06-09 09:27:32 +0200345/**
346 * @brief Check that the current element can be parsed as a data node.
347 *
348 * @param[in] lydctx XML data parser context.
349 * @param[in,out] snode Found schema node, set to NULL if data node cannot be created.
350 * @return LY_ERR value.
351 */
Michal Vasko1bf09392020-03-27 12:38:10 +0100352static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200353lydxml_data_check_opaq(struct lyd_xml_ctx *lydctx, const struct lysc_node **snode)
Michal Vasko1bf09392020-03-27 12:38:10 +0100354{
355 LY_ERR ret = LY_SUCCESS;
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200356 struct lyxml_ctx *xmlctx = lydctx->xmlctx, pxmlctx;
Michal Vasko1bf09392020-03-27 12:38:10 +0100357
Radek IÅ¡a3930fd72021-03-08 10:48:40 +0100358 if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
359 /* only checks specific to opaque nodes */
360 return LY_SUCCESS;
361 }
362
Michal Vasko13854662021-06-09 09:27:50 +0200363 if (!((*snode)->nodetype & (LYD_NODE_TERM | LYD_NODE_INNER))) {
364 /* nothing to check */
365 return LY_SUCCESS;
366 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100367
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200368 assert(xmlctx->elements.count);
369
Michal Vasko13854662021-06-09 09:27:50 +0200370 /* backup parser */
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200371 LY_CHECK_RET(lyxml_ctx_backup(xmlctx, &pxmlctx));
Michal Vasko1bf09392020-03-27 12:38:10 +0100372
Michal Vasko13854662021-06-09 09:27:50 +0200373 /* skip attributes */
374 while (xmlctx->status == LYXML_ATTRIBUTE) {
375 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
376 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
377 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100378
Michal Vasko13854662021-06-09 09:27:50 +0200379 if ((*snode)->nodetype & LYD_NODE_TERM) {
380 /* value may not be valid in which case we parse it as an opaque node */
381 if (lys_value_validate(NULL, *snode, xmlctx->value, xmlctx->value_len, LY_VALUE_XML, &xmlctx->ns)) {
Michal Vaskod0237d42021-07-12 14:49:46 +0200382 LOGVRB("Parsing opaque term node \"%s\" with invalid value \"%.*s\".", (*snode)->name, xmlctx->value_len,
383 xmlctx->value);
Michal Vasko13854662021-06-09 09:27:50 +0200384 *snode = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100385 }
Michal Vasko13854662021-06-09 09:27:50 +0200386 } else if ((*snode)->nodetype == LYS_LIST) {
387 /* skip content */
388 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
Michal Vasko1bf09392020-03-27 12:38:10 +0100389
Michal Vasko13854662021-06-09 09:27:50 +0200390 if (lydxml_check_list(xmlctx, *snode)) {
391 /* invalid list, parse as opaque if it missing/has invalid some keys */
Michal Vaskod0237d42021-07-12 14:49:46 +0200392 LOGVRB("Parsing opaque list node \"%s\" with missing/invalid keys.", (*snode)->name);
Michal Vasko13854662021-06-09 09:27:50 +0200393 *snode = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100394 }
Michal Vasko13854662021-06-09 09:27:50 +0200395 } else {
Radek IÅ¡a3930fd72021-03-08 10:48:40 +0100396 /* if there is a non-WS value, it cannot be parsed as an inner node */
397 assert(xmlctx->status == LYXML_ELEM_CONTENT);
398 if (!xmlctx->ws_only) {
399 *snode = NULL;
400 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100401 }
402
Michal Vasko13854662021-06-09 09:27:50 +0200403restore:
404 /* restore parser */
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200405 lyxml_ctx_restore(xmlctx, &pxmlctx);
Michal Vasko1bf09392020-03-27 12:38:10 +0100406 return ret;
407}
408
Radek Krejcie7b95092019-05-15 11:03:07 +0200409/**
Michal Vaskoaac267d2022-01-17 13:34:48 +0100410 * @brief Try to parse data with a parent based on an extension instance.
411 *
412 * @param[in] lydctx XML data parser context.
413 * @param[in,out] parent Parent node where the children are inserted.
414 * @return LY_SUCCESS on success;
415 * @return LY_ENOT if no extension instance parsed the data;
416 * @return LY_ERR on error.
417 */
418static LY_ERR
419lydxml_nested_ext(struct lyd_xml_ctx *lydctx, struct lyd_node *parent)
420{
421 LY_ERR r;
422 struct ly_in in_bck, in_start, in_ext;
423 LY_ARRAY_COUNT_TYPE u;
424 struct lysc_ext_instance *nested_exts = NULL;
425 lyplg_ext_data_parse_clb ext_parse_cb;
426 struct lyd_ctx_ext_val *ext_val;
427
428 /* backup current input */
429 in_bck = *lydctx->xmlctx->in;
430
431 /* go back in the input for extension parsing */
432 in_start = *lydctx->xmlctx->in;
433 if (lydctx->xmlctx->status != LYXML_ELEM_CONTENT) {
434 assert((lydctx->xmlctx->status == LYXML_ELEMENT) || (lydctx->xmlctx->status == LYXML_ATTRIBUTE));
435 in_start.current = lydctx->xmlctx->prefix ? lydctx->xmlctx->prefix : lydctx->xmlctx->name;
436 }
437 do {
438 --in_start.current;
439 } while (in_start.current[0] != '<');
440
441 /* check if there are any nested extension instances */
442 if (parent && parent->schema) {
443 nested_exts = parent->schema->exts;
444 }
445 LY_ARRAY_FOR(nested_exts, u) {
446 /* prepare the input and try to parse this extension data */
447 in_ext = in_start;
448 ext_parse_cb = nested_exts[u].def->plugin->parse;
449 r = ext_parse_cb(&in_ext, LYD_XML, &nested_exts[u], parent, lydctx->parse_opts | LYD_PARSE_ONLY);
450 if (!r) {
451 /* data successfully parsed, remember for validation */
452 if (!(lydctx->parse_opts & LYD_PARSE_ONLY)) {
453 ext_val = malloc(sizeof *ext_val);
454 LY_CHECK_ERR_RET(!ext_val, LOGMEM(lydctx->xmlctx->ctx), LY_EMEM);
455 ext_val->ext = &nested_exts[u];
Michal Vaskoc08b9d22022-02-10 15:48:39 +0100456 ext_val->sibling = lyd_child_no_keys(parent);
Michal Vaskoaac267d2022-01-17 13:34:48 +0100457 LY_CHECK_RET(ly_set_add(&lydctx->ext_val, ext_val, 1, NULL));
458 }
459
460 /* adjust the xmlctx accordingly */
461 *lydctx->xmlctx->in = in_ext;
462 lydctx->xmlctx->status = LYXML_ELEM_CONTENT;
463 lydctx->xmlctx->dynamic = 0;
464 ly_set_rm_index(&lydctx->xmlctx->elements, lydctx->xmlctx->elements.count - 1, free);
465 lyxml_ns_rm(lydctx->xmlctx);
466 LY_CHECK_RET(lyxml_ctx_next(lydctx->xmlctx));
467 return LY_SUCCESS;
468 } else if (r != LY_ENOT) {
469 /* fatal error */
470 return r;
471 }
472 /* data was not from this module, continue */
473 }
474
475 /* no extensions or none matched, restore input */
476 *lydctx->xmlctx->in = in_bck;
477 return LY_ENOT;
478}
479
480/**
Michal Vaskoa5da3292020-08-12 13:10:50 +0200481 * @brief Parse XML subtree.
Radek Krejcie7b95092019-05-15 11:03:07 +0200482 *
Michal Vaskob36053d2020-03-26 15:49:30 +0100483 * @param[in] lydctx XML YANG data parser context.
Michal Vaskoe0665742021-02-11 11:08:44 +0100484 * @param[in,out] parent Parent node where the children are inserted. NULL in case of parsing top-level elements.
485 * @param[in,out] first_p Pointer to the first (@p parent or top-level) child. In case there were already some siblings,
486 * this may point to a previously existing node.
487 * @param[in,out] parsed Optional set to add all the parsed siblings into.
Michal Vasko9b368d32020-02-14 13:53:31 +0100488 * @return LY_ERR value.
Radek Krejcie7b95092019-05-15 11:03:07 +0200489 */
490static LY_ERR
Michal Vaskoe0665742021-02-11 11:08:44 +0100491lydxml_subtree_r(struct lyd_xml_ctx *lydctx, struct lyd_node *parent, struct lyd_node **first_p, struct ly_set *parsed)
Radek Krejcie7b95092019-05-15 11:03:07 +0200492{
tadeas-vintrlikbf8aa6e2021-11-03 13:07:34 +0100493 LY_ERR ret = LY_SUCCESS, r;
Michal Vasko27c4dce2021-03-04 15:50:50 +0100494 const char *prefix, *name, *val;
Michal Vasko1bf09392020-03-27 12:38:10 +0100495 size_t prefix_len, name_len;
Michal Vaskob36053d2020-03-26 15:49:30 +0100496 struct lyxml_ctx *xmlctx;
497 const struct ly_ctx *ctx;
Radek Krejcie7b95092019-05-15 11:03:07 +0200498 const struct lyxml_ns *ns;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200499 struct lyd_meta *meta = NULL;
500 struct lyd_attr *attr = NULL;
Radek Krejcie7b95092019-05-15 11:03:07 +0200501 const struct lysc_node *snode;
502 struct lys_module *mod;
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200503 uint32_t prev_parse_opts, prev_int_opts;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200504 struct lyd_node *node = NULL, *anchor;
Michal Vaskofc2cd072021-02-24 13:17:17 +0100505 void *val_prefix_data = NULL;
Radek Krejci8df109d2021-04-23 12:19:08 +0200506 LY_VALUE_FORMAT format;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200507 uint32_t getnext_opts;
Michal Vaskoaac267d2022-01-17 13:34:48 +0100508 ly_bool parse_subtree;
Radek Krejcie7b95092019-05-15 11:03:07 +0200509
Michal Vaskoe0665742021-02-11 11:08:44 +0100510 assert(parent || first_p);
511
Michal Vaskob36053d2020-03-26 15:49:30 +0100512 xmlctx = lydctx->xmlctx;
513 ctx = xmlctx->ctx;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100514 getnext_opts = lydctx->int_opts & LYD_INTOPT_REPLY ? LYS_GETNEXT_OUTPUT : 0;
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100515
Michal Vaskoaac267d2022-01-17 13:34:48 +0100516 parse_subtree = lydctx->parse_opts & LYD_PARSE_SUBTREE ? 1 : 0;
517 /* all descendants should be parsed */
518 lydctx->parse_opts &= ~LYD_PARSE_SUBTREE;
519
Michal Vaskoa5da3292020-08-12 13:10:50 +0200520 assert(xmlctx->status == LYXML_ELEMENT);
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200521
Michal Vaskoa5da3292020-08-12 13:10:50 +0200522 /* remember element prefix and name */
523 prefix = xmlctx->prefix;
524 prefix_len = xmlctx->prefix_len;
525 name = xmlctx->name;
526 name_len = xmlctx->name_len;
527
528 /* get the element module */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200529 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200530 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100531 LOGVAL(ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200532 ret = LY_EVALID;
533 goto error;
534 }
535 mod = ly_ctx_get_module_implemented_ns(ctx, ns->uri);
536 if (!mod) {
Michal Vaskoaac267d2022-01-17 13:34:48 +0100537 /* check for extension data */
538 r = lydxml_nested_ext(lydctx, parent);
539 if (!r) {
540 /* successfully parsed */
541 return r;
542 } else if (r != LY_ENOT) {
543 /* error */
544 ret = r;
545 goto error;
546 }
547
548 /* unknown module */
Michal Vaskoe0665742021-02-11 11:08:44 +0100549 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100550 LOGVAL(ctx, LYVE_REFERENCE, "No module with namespace \"%s\" in the context.", ns->uri);
Michal Vasko90932a92020-02-12 14:33:03 +0100551 ret = LY_EVALID;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200552 goto error;
Radek Krejcie7b95092019-05-15 11:03:07 +0200553 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100554 if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
Michal Vaskoa5da3292020-08-12 13:10:50 +0200555 /* skip element with children */
556 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
557 return LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200558 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200559 }
560
Michal Vaskoa5da3292020-08-12 13:10:50 +0200561 /* parser next */
562 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
Michal Vasko90932a92020-02-12 14:33:03 +0100563
Michal Vaskoa5da3292020-08-12 13:10:50 +0200564 /* get the schema node */
565 snode = NULL;
Michal Vasko81008a52021-07-21 16:06:12 +0200566 if (mod) {
Radek Krejcif16e2542021-02-17 15:39:23 +0100567 if (!parent && lydctx->ext) {
Radek Krejciba05eab2021-03-10 13:19:29 +0100568 snode = lysc_ext_find_node(lydctx->ext, mod, name, name_len, 0, getnext_opts);
Radek Krejcif16e2542021-02-17 15:39:23 +0100569 } else {
570 snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
571 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200572 if (!snode) {
Michal Vaskoaac267d2022-01-17 13:34:48 +0100573 /* check for extension data */
574 r = lydxml_nested_ext(lydctx, parent);
575 if (!r) {
576 /* successfully parsed */
577 return r;
578 } else if (r != LY_ENOT) {
579 /* error */
580 ret = r;
581 goto error;
tadeas-vintrlikbf8aa6e2021-11-03 13:07:34 +0100582 }
Michal Vaskoaac267d2022-01-17 13:34:48 +0100583
584 /* unknown data node */
Michal Vaskoe0665742021-02-11 11:08:44 +0100585 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
586 if (parent) {
Radek Krejci422afb12021-03-04 16:38:16 +0100587 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found as a child of \"%s\" node.",
Michal Vaskoc08b9d22022-02-10 15:48:39 +0100588 (int)name_len, name, LYD_NAME(parent));
Radek Krejcif16e2542021-02-17 15:39:23 +0100589 } else if (lydctx->ext) {
590 if (lydctx->ext->argument) {
Radek Krejci422afb12021-03-04 16:38:16 +0100591 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" %s extension instance.",
592 (int)name_len, name, lydctx->ext->argument, lydctx->ext->def->name);
Radek Krejcif16e2542021-02-17 15:39:23 +0100593 } else {
Radek Krejci422afb12021-03-04 16:38:16 +0100594 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the %s extension instance.",
595 (int)name_len, name, lydctx->ext->def->name);
Radek Krejcif16e2542021-02-17 15:39:23 +0100596 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100597 } else {
Radek Krejci422afb12021-03-04 16:38:16 +0100598 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" module.",
599 (int)name_len, name, mod->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100600 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200601 ret = LY_EVALID;
602 goto error;
Michal Vaskoe0665742021-02-11 11:08:44 +0100603 } else if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
Michal Vaskod4f82492022-01-05 12:06:51 +0100604 LOGVRB("Skipping parsing of unknown node \"%.*s\".", name_len, name);
Michal Vaskod0237d42021-07-12 14:49:46 +0200605
Michal Vaskoa5da3292020-08-12 13:10:50 +0200606 /* skip element with children */
607 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
608 return LY_SUCCESS;
609 }
610 } else {
611 /* check that schema node is valid and can be used */
612 LY_CHECK_GOTO(ret = lyd_parser_check_schema((struct lyd_ctx *)lydctx, snode), error);
613 LY_CHECK_GOTO(ret = lydxml_data_check_opaq(lydctx, &snode), error);
614 }
615 }
616
617 /* create metadata/attributes */
618 if (xmlctx->status == LYXML_ATTRIBUTE) {
619 if (snode) {
Michal Vaskoaac267d2022-01-17 13:34:48 +0100620 ret = lydxml_metadata(lydctx, snode, &meta);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200621 LY_CHECK_GOTO(ret, error);
622 } else {
Michal Vaskoe0665742021-02-11 11:08:44 +0100623 assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200624 ret = lydxml_attrs(xmlctx, &attr);
625 LY_CHECK_GOTO(ret, error);
626 }
627 }
628
629 assert(xmlctx->status == LYXML_ELEM_CONTENT);
630 if (!snode) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100631 assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200632
633 if (xmlctx->ws_only) {
634 /* ignore WS-only value */
Radek IÅ¡a017270d2021-02-16 10:26:15 +0100635 if (xmlctx->dynamic) {
636 free((char *) xmlctx->value);
637 }
638 xmlctx->dynamic = 0;
639 xmlctx->value = "";
Michal Vaskoa5da3292020-08-12 13:10:50 +0200640 xmlctx->value_len = 0;
Radek Krejci8df109d2021-04-23 12:19:08 +0200641 format = LY_VALUE_XML;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200642 } else {
643 /* get value prefixes */
Radek Krejci8df109d2021-04-23 12:19:08 +0200644 ret = ly_store_prefix_data(xmlctx->ctx, xmlctx->value, xmlctx->value_len, LY_VALUE_XML,
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100645 &xmlctx->ns, &format, &val_prefix_data);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200646 LY_CHECK_GOTO(ret, error);
647 }
648
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200649 /* get NS again, it may have been backed up and restored */
650 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
651 assert(ns);
652
Michal Vaskoa5da3292020-08-12 13:10:50 +0200653 /* create node */
Michal Vasko501af032020-11-11 20:27:44 +0100654 ret = lyd_create_opaq(ctx, name, name_len, prefix, prefix_len, ns->uri, strlen(ns->uri), xmlctx->value,
655 xmlctx->value_len, &xmlctx->dynamic, format, val_prefix_data, LYD_HINT_DATA, &node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200656 LY_CHECK_GOTO(ret, error);
657
658 /* parser next */
659 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
660
661 /* process children */
662 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100663 ret = lydxml_subtree_r(lydctx, node, lyd_node_child_p(node), NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200664 LY_CHECK_GOTO(ret, error);
665 }
666 } else if (snode->nodetype & LYD_NODE_TERM) {
667 /* create node */
Michal Vasko22df3f02020-08-24 13:29:22 +0200668 LY_CHECK_GOTO(ret = lyd_parser_create_term((struct lyd_ctx *)lydctx, snode, xmlctx->value, xmlctx->value_len,
Radek Krejci8df109d2021-04-23 12:19:08 +0200669 &xmlctx->dynamic, LY_VALUE_XML, &xmlctx->ns, LYD_HINT_DATA, &node), error);
Radek Krejciddace2c2021-01-08 11:30:56 +0100670 LOG_LOCSET(snode, node, NULL, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200671
672 if (parent && (node->schema->flags & LYS_KEY)) {
673 /* check the key order, the anchor must never be a key */
Michal Vaskoe0665742021-02-11 11:08:44 +0100674 anchor = lyd_insert_get_next_anchor(lyd_child(parent), node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200675 if (anchor && (anchor->schema->flags & LYS_KEY)) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100676 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100677 LOGVAL(ctx, LYVE_DATA, "Invalid position of the key \"%s\" in a list.", node->schema->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200678 ret = LY_EVALID;
679 goto error;
680 } else {
681 LOGWRN(ctx, "Invalid position of the key \"%s\" in a list.", node->schema->name);
682 }
683 }
684 }
685
686 /* parser next */
687 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
688
689 /* no children expected */
690 if (xmlctx->status == LYXML_ELEMENT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100691 LOGVAL(ctx, LYVE_SYNTAX, "Child element \"%.*s\" inside a terminal node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100692 (int)xmlctx->name_len, xmlctx->name, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200693 ret = LY_EVALID;
694 goto error;
695 }
696 } else if (snode->nodetype & LYD_NODE_INNER) {
697 if (!xmlctx->ws_only) {
698 /* value in inner node */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100699 LOGVAL(ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an inner node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100700 (int)xmlctx->value_len, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200701 ret = LY_EVALID;
702 goto error;
703 }
704
705 /* create node */
706 ret = lyd_create_inner(snode, &node);
707 LY_CHECK_GOTO(ret, error);
708
Radek Krejciddace2c2021-01-08 11:30:56 +0100709 LOG_LOCSET(snode, node, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100710
Michal Vaskoa5da3292020-08-12 13:10:50 +0200711 /* parser next */
712 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
713
714 /* process children */
715 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100716 ret = lydxml_subtree_r(lydctx, node, lyd_node_child_p(node), NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200717 LY_CHECK_GOTO(ret, error);
718 }
719
720 if (snode->nodetype == LYS_LIST) {
721 /* check all keys exist */
722 LY_CHECK_GOTO(ret = lyd_parse_check_keys(node), error);
723 }
724
Michal Vaskoe0665742021-02-11 11:08:44 +0100725 if (!(lydctx->parse_opts & LYD_PARSE_ONLY)) {
Michal Vaskoa5da3292020-08-12 13:10:50 +0200726 /* new node validation, autodelete CANNOT occur, all nodes are new */
Michal Vaskoe0665742021-02-11 11:08:44 +0100727 ret = lyd_validate_new(lyd_node_child_p(node), snode, NULL, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200728 LY_CHECK_GOTO(ret, error);
729
730 /* add any missing default children */
Michal Vaskoaac267d2022-01-17 13:34:48 +0100731 ret = lyd_new_implicit_r(node, lyd_node_child_p(node), NULL, NULL, &lydctx->node_when, &lydctx->node_types,
732 (lydctx->val_opts & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200733 LY_CHECK_GOTO(ret, error);
734 }
735
736 if (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
737 /* rememeber the RPC/action/notification */
738 lydctx->op_node = node;
739 }
740 } else if (snode->nodetype & LYD_NODE_ANY) {
Michal Vasko27c4dce2021-03-04 15:50:50 +0100741 if ((snode->nodetype == LYS_ANYDATA) && !xmlctx->ws_only) {
742 /* value in anydata node, we expect a tree */
743 LOGVAL(ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an anydata node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100744 (int)xmlctx->value_len < 20 ? xmlctx->value_len : 20, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200745 ret = LY_EVALID;
746 goto error;
747 }
748
Michal Vasko27c4dce2021-03-04 15:50:50 +0100749 if (!xmlctx->ws_only) {
750 /* use an arbitrary text value for anyxml */
751 lydict_insert(xmlctx->ctx, xmlctx->value, xmlctx->value_len, &val);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200752
Michal Vasko27c4dce2021-03-04 15:50:50 +0100753 /* parser next */
754 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
755
756 /* create node */
757 ret = lyd_create_any(snode, val, LYD_ANYDATA_STRING, 1, &node);
758 LY_CHECK_GOTO(ret, error);
759 } else {
760 /* parser next */
761 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
762
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200763 /* update options so that generic data can be parsed */
764 prev_parse_opts = lydctx->parse_opts;
Michal Vasko27c4dce2021-03-04 15:50:50 +0100765 lydctx->parse_opts &= ~LYD_PARSE_STRICT;
766 lydctx->parse_opts |= LYD_PARSE_OPAQ;
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200767 prev_int_opts = lydctx->int_opts;
Michal Vasko02ed9d82021-07-15 14:58:04 +0200768 lydctx->int_opts |= LYD_INTOPT_ANY | LYD_INTOPT_WITH_SIBLINGS;
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200769
770 /* parse any data tree */
Michal Vasko27c4dce2021-03-04 15:50:50 +0100771 anchor = NULL;
772 while (xmlctx->status == LYXML_ELEMENT) {
773 ret = lydxml_subtree_r(lydctx, NULL, &anchor, NULL);
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200774 if (ret) {
775 break;
776 }
Michal Vasko27c4dce2021-03-04 15:50:50 +0100777 }
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200778
779 /* restore options */
780 lydctx->parse_opts = prev_parse_opts;
781 lydctx->int_opts = prev_int_opts;
782
783 LY_CHECK_GOTO(ret, error);
Michal Vasko27c4dce2021-03-04 15:50:50 +0100784
785 /* create node */
786 ret = lyd_create_any(snode, anchor, LYD_ANYDATA_DATATREE, 1, &node);
787 LY_CHECK_GOTO(ret, error);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200788 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200789 }
790 assert(node);
791
792 /* add/correct flags */
793 if (snode) {
Michal Vaskoaac267d2022-01-17 13:34:48 +0100794 lyd_parse_set_data_flags(node, &lydctx->node_when, &meta, lydctx->parse_opts);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200795 }
796
797 /* parser next */
798 assert(xmlctx->status == LYXML_ELEM_CLOSE);
Michal Vaskoaac267d2022-01-17 13:34:48 +0100799 if (!parse_subtree) {
800 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
801 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200802
803 /* add metadata/attributes */
804 if (snode) {
Michal Vasko871a0252020-11-11 18:35:24 +0100805 lyd_insert_meta(node, meta, 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200806 } else {
807 lyd_insert_attr(node, attr);
808 }
809
810 /* insert, keep first pointer correct */
Michal Vasko6ee6f432021-07-16 09:49:14 +0200811 lyd_insert_node(parent, first_p, node, lydctx->parse_opts & LYD_PARSE_ORDERED ? 1 : 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200812 while (!parent && (*first_p)->prev->next) {
813 *first_p = (*first_p)->prev;
814 }
815
Michal Vaskoe0665742021-02-11 11:08:44 +0100816 /* rememeber a successfully parsed node */
817 if (parsed) {
818 ly_set_add(parsed, node, 1, NULL);
819 }
820
Radek Krejciddace2c2021-01-08 11:30:56 +0100821 LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200822 return LY_SUCCESS;
823
824error:
Radek Krejciddace2c2021-01-08 11:30:56 +0100825 LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
Michal Vasko3a41dff2020-07-15 14:30:28 +0200826 lyd_free_meta_siblings(meta);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200827 lyd_free_attr_siblings(ctx, attr);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200828 lyd_free_tree(node);
Radek Krejcie7b95092019-05-15 11:03:07 +0200829 return ret;
830}
831
Michal Vaskoe0665742021-02-11 11:08:44 +0100832/**
833 * @brief Parse a specific XML element into an opaque node.
834 *
835 * @param[in] xmlctx XML parser context.
836 * @param[in] name Name of the element.
837 * @param[in] uri URI of the element.
838 * @param[in] value Whether a value is expected in the element.
839 * @param[out] evnp Parsed envelope (opaque node).
840 * @return LY_SUCCESS on success.
841 * @return LY_ENOT if the specified element did not match.
842 * @return LY_ERR value on error.
843 */
Michal Vasko1bf09392020-03-27 12:38:10 +0100844static LY_ERR
Michal Vaskoe0665742021-02-11 11:08:44 +0100845lydxml_envelope(struct lyxml_ctx *xmlctx, const char *name, const char *uri, ly_bool value, struct lyd_node **envp)
Michal Vasko1bf09392020-03-27 12:38:10 +0100846{
Michal Vaskoe0665742021-02-11 11:08:44 +0100847 LY_ERR rc = LY_SUCCESS;
848 const struct lyxml_ns *ns;
Radek Krejci1798aae2020-07-14 13:26:06 +0200849 struct lyd_attr *attr = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100850 const char *prefix;
851 size_t prefix_len;
852
Michal Vasko1bf09392020-03-27 12:38:10 +0100853 assert(xmlctx->status == LYXML_ELEMENT);
854 if (ly_strncmp(name, xmlctx->name, xmlctx->name_len)) {
855 /* not the expected element */
Michal Vaskoe0665742021-02-11 11:08:44 +0100856 return LY_ENOT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100857 }
858
859 prefix = xmlctx->prefix;
860 prefix_len = xmlctx->prefix_len;
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200861 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100862 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100863 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +0100864 return LY_EVALID;
865 } else if (strcmp(ns->uri, uri)) {
866 /* different namespace */
867 return LY_ENOT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100868 }
869
870 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
871
872 /* create attributes */
873 if (xmlctx->status == LYXML_ATTRIBUTE) {
874 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
875 }
876
Michal Vaskoe0665742021-02-11 11:08:44 +0100877 assert(xmlctx->status == LYXML_ELEM_CONTENT);
878 if (!value && !xmlctx->ws_only) {
879 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected value \"%.*s\" in the \"%s\" element.",
Radek Krejci422afb12021-03-04 16:38:16 +0100880 (int)xmlctx->value_len, xmlctx->value, name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100881 rc = LY_EVALID;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100882 goto cleanup;
Michal Vaskoe0665742021-02-11 11:08:44 +0100883 }
Michal Vaskoa8edff02020-03-27 14:47:01 +0100884
885 /* create node */
Michal Vaskoe0665742021-02-11 11:08:44 +0100886 rc = lyd_create_opaq(xmlctx->ctx, name, strlen(name), prefix, prefix_len, uri, strlen(uri), xmlctx->value,
Radek Krejci8df109d2021-04-23 12:19:08 +0200887 xmlctx->ws_only ? 0 : xmlctx->value_len, NULL, LY_VALUE_XML, NULL, 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100888 LY_CHECK_GOTO(rc, cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100889
890 /* assign atributes */
Michal Vaskoe0665742021-02-11 11:08:44 +0100891 ((struct lyd_node_opaq *)(*envp))->attr = attr;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100892 attr = NULL;
893
Michal Vaskoe0665742021-02-11 11:08:44 +0100894 /* parser next element */
895 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100896
Michal Vaskoe0665742021-02-11 11:08:44 +0100897cleanup:
898 lyd_free_attr_siblings(xmlctx->ctx, attr);
899 if (rc) {
900 lyd_free_tree(*envp);
901 *envp = NULL;
902 }
903 return rc;
904}
905
906/**
907 * @brief Parse all expected non-data XML elements of a NETCONF rpc message.
908 *
909 * @param[in] xmlctx XML parser context.
910 * @param[out] evnp Parsed envelope(s) (opaque node).
911 * @param[out] int_opts Internal options for parsing the rest of YANG data.
912 * @param[out] close_elem Number of parsed opened elements that need to be closed.
913 * @return LY_SUCCESS on success.
914 * @return LY_ERR value on error.
915 */
916static LY_ERR
917lydxml_env_netconf_rpc(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
918{
919 LY_ERR rc = LY_SUCCESS, r;
920 struct lyd_node *child;
921
922 assert(envp && !*envp);
923
924 /* parse "rpc" */
925 r = lydxml_envelope(xmlctx, "rpc", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100926 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
927
928 /* parse "action", if any */
929 r = lydxml_envelope(xmlctx, "action", "urn:ietf:params:xml:ns:yang:1", 0, &child);
930 if (r == LY_SUCCESS) {
931 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +0200932 lyd_insert_node(*envp, NULL, child, 0);
Michal Vaskoe0665742021-02-11 11:08:44 +0100933
934 /* NETCONF action */
935 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_ACTION;
936 *close_elem = 2;
937 } else if (r == LY_ENOT) {
938 /* NETCONF RPC */
939 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_RPC;
940 *close_elem = 1;
941 } else {
942 rc = r;
943 goto cleanup;
944 }
945
946cleanup:
947 if (rc) {
948 lyd_free_tree(*envp);
949 *envp = NULL;
950 }
951 return rc;
952}
953
954/**
955 * @brief Parse all expected non-data XML elements of a NETCONF notification message.
956 *
957 * @param[in] xmlctx XML parser context.
958 * @param[out] evnp Parsed envelope(s) (opaque node).
959 * @param[out] int_opts Internal options for parsing the rest of YANG data.
960 * @param[out] close_elem Number of parsed opened elements that need to be closed.
961 * @return LY_SUCCESS on success.
962 * @return LY_ERR value on error.
963 */
964static LY_ERR
965lydxml_env_netconf_notif(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
966{
967 LY_ERR rc = LY_SUCCESS, r;
968 struct lyd_node *child;
969
970 assert(envp && !*envp);
971
972 /* parse "notification" */
973 r = lydxml_envelope(xmlctx, "notification", "urn:ietf:params:xml:ns:netconf:notification:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100974 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
975
976 /* parse "eventTime" */
977 r = lydxml_envelope(xmlctx, "eventTime", "urn:ietf:params:xml:ns:netconf:notification:1.0", 1, &child);
978 if (r == LY_ENOT) {
Radek Krejci422afb12021-03-04 16:38:16 +0100979 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unexpected element \"%.*s\" instead of \"eventTime\".",
980 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100981 r = LY_EVALID;
982 }
983 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
984
985 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +0200986 lyd_insert_node(*envp, NULL, child, 0);
Michal Vaskoe0665742021-02-11 11:08:44 +0100987
988 /* validate value */
989 /* TODO validate child->value as yang:date-and-time */
990
991 /* finish child parsing */
Michal Vaskoa8edff02020-03-27 14:47:01 +0100992 if (xmlctx->status != LYXML_ELEM_CLOSE) {
993 assert(xmlctx->status == LYXML_ELEMENT);
Michal Vaskoe0665742021-02-11 11:08:44 +0100994 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"eventTime\".",
Radek Krejci422afb12021-03-04 16:38:16 +0100995 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100996 rc = LY_EVALID;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100997 goto cleanup;
998 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100999 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1000
1001 /* NETCONF notification */
1002 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_NOTIF;
1003 *close_elem = 1;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001004
1005cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +01001006 if (rc) {
Michal Vaskoa8edff02020-03-27 14:47:01 +01001007 lyd_free_tree(*envp);
Michal Vaskoe0665742021-02-11 11:08:44 +01001008 *envp = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001009 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001010 return rc;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001011}
Michal Vasko79135ae2020-12-16 10:08:35 +01001012
Michal Vaskoe0665742021-02-11 11:08:44 +01001013/**
1014 * @brief Parse an XML element as an opaque node subtree.
1015 *
1016 * @param[in] xmlctx XML parser context.
1017 * @param[in] parent Parent to append nodes to.
1018 * @return LY_ERR value.
1019 */
1020static LY_ERR
1021lydxml_opaq_r(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
Michal Vaskoa8edff02020-03-27 14:47:01 +01001022{
Michal Vaskoe0665742021-02-11 11:08:44 +01001023 LY_ERR rc = LY_SUCCESS;
1024 const struct lyxml_ns *ns;
1025 struct lyd_attr *attr = NULL;
1026 struct lyd_node *child = NULL;
1027 const char *name, *prefix;
1028 size_t name_len, prefix_len;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001029
Michal Vaskoe0665742021-02-11 11:08:44 +01001030 assert(xmlctx->status == LYXML_ELEMENT);
Michal Vaskoa8edff02020-03-27 14:47:01 +01001031
Michal Vaskoe0665742021-02-11 11:08:44 +01001032 name = xmlctx->name;
1033 name_len = xmlctx->name_len;
1034 prefix = xmlctx->prefix;
1035 prefix_len = xmlctx->prefix_len;
1036 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
1037 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +01001038 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +01001039 return LY_EVALID;
1040 }
Michal Vaskoa8edff02020-03-27 14:47:01 +01001041
Michal Vaskoe0665742021-02-11 11:08:44 +01001042 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
Michal Vaskoa8edff02020-03-27 14:47:01 +01001043
Michal Vaskoe0665742021-02-11 11:08:44 +01001044 /* create attributes */
1045 if (xmlctx->status == LYXML_ATTRIBUTE) {
1046 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
1047 }
1048
1049 /* create node */
1050 assert(xmlctx->status == LYXML_ELEM_CONTENT);
1051 rc = lyd_create_opaq(xmlctx->ctx, name, name_len, prefix, prefix_len, ns->uri, strlen(ns->uri), xmlctx->value,
Radek Krejci8df109d2021-04-23 12:19:08 +02001052 xmlctx->ws_only ? 0 : xmlctx->value_len, NULL, LY_VALUE_XML, NULL, 0, &child);
Michal Vaskoe0665742021-02-11 11:08:44 +01001053 LY_CHECK_GOTO(rc, cleanup);
1054
1055 /* assign atributes */
1056 ((struct lyd_node_opaq *)child)->attr = attr;
1057 attr = NULL;
1058
1059 /* parser next element */
1060 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1061
1062 /* parse all the descendants */
1063 while (xmlctx->status == LYXML_ELEMENT) {
1064 rc = lydxml_opaq_r(xmlctx, child);
1065 LY_CHECK_GOTO(rc, cleanup);
1066 }
1067
1068 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001069 lyd_insert_node(parent, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +01001070
1071cleanup:
1072 lyd_free_attr_siblings(xmlctx->ctx, attr);
1073 if (rc) {
1074 lyd_free_tree(child);
1075 }
1076 return rc;
1077}
1078
1079/**
1080 * @brief Parse all expected non-data XML elements of the error-info element in NETCONF rpc-reply message.
1081 *
1082 * @param[in] xmlctx XML parser context.
1083 * @param[in] parent Parent to append nodes to.
1084 * @return LY_ERR value.
1085 */
1086static LY_ERR
1087lydxml_env_netconf_rpc_reply_error_info(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
1088{
1089 LY_ERR r;
1090 struct lyd_node *child, *iter;
1091 const struct lyxml_ns *ns;
1092 ly_bool no_dup;
1093
1094 /* there must be some child */
1095 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1096 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"error-info\".");
1097 return LY_EVALID;
1098 }
1099
1100 while (xmlctx->status == LYXML_ELEMENT) {
1101 child = NULL;
1102
1103 /*
1104 * session-id
1105 */
1106 r = lydxml_envelope(xmlctx, "session-id", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1107 if (r == LY_SUCCESS) {
1108 no_dup = 1;
1109 goto check_child;
1110 } else if (r != LY_ENOT) {
1111 goto error;
1112 }
1113
1114 /*
1115 * bad-attribute
1116 */
1117 r = lydxml_envelope(xmlctx, "bad-attribute", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1118 if (r == LY_SUCCESS) {
1119 no_dup = 1;
1120 goto check_child;
1121 } else if (r != LY_ENOT) {
1122 goto error;
1123 }
1124
1125 /*
1126 * bad-element
1127 */
1128 r = lydxml_envelope(xmlctx, "bad-element", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1129 if (r == LY_SUCCESS) {
1130 no_dup = 1;
1131 goto check_child;
1132 } else if (r != LY_ENOT) {
1133 goto error;
1134 }
1135
1136 /*
1137 * bad-namespace
1138 */
1139 r = lydxml_envelope(xmlctx, "bad-namespace", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1140 if (r == LY_SUCCESS) {
1141 no_dup = 1;
1142 goto check_child;
1143 } else if (r != LY_ENOT) {
1144 goto error;
1145 }
1146
1147 if (r == LY_ENOT) {
1148 assert(xmlctx->status == LYXML_ELEMENT);
1149
1150 /* learn namespace */
1151 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
1152 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +01001153 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)xmlctx->prefix_len, xmlctx->prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +01001154 r = LY_EVALID;
1155 goto error;
1156 } else if (!strcmp(ns->uri, "urn:ietf:params:xml:ns:netconf:base:1.0")) {
1157 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"error-info\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001158 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001159 r = LY_EVALID;
1160 goto error;
1161 }
1162
1163 /* custom elements */
1164 r = lydxml_opaq_r(xmlctx, parent);
1165 LY_CHECK_GOTO(r, error);
Michal Vaskoe5ff3672022-01-10 10:12:30 +01001166 continue;
Michal Vaskoe0665742021-02-11 11:08:44 +01001167 }
1168
1169check_child:
1170 /* check for duplicates */
1171 if (no_dup) {
1172 LY_LIST_FOR(lyd_child(parent), iter) {
1173 if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
1174 (((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
1175 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"error-info\".",
1176 ((struct lyd_node_opaq *)child)->name.name);
1177 r = LY_EVALID;
1178 goto error;
1179 }
1180 }
1181 }
1182
1183 /* finish child parsing */
1184 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1185 assert(xmlctx->status == LYXML_ELEMENT);
1186 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"error-info\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001187 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001188 r = LY_EVALID;
1189 goto error;
1190 }
1191 LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
1192
1193 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001194 lyd_insert_node(parent, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +01001195 }
1196
1197 return LY_SUCCESS;
1198
1199error:
1200 lyd_free_tree(child);
1201 return r;
1202}
1203
1204/**
1205 * @brief Parse all expected non-data XML elements of the rpc-error element in NETCONF rpc-reply message.
1206 *
1207 * @param[in] xmlctx XML parser context.
1208 * @param[in] parent Parent to append nodes to.
1209 * @return LY_ERR value.
1210 */
1211static LY_ERR
1212lydxml_env_netconf_rpc_reply_error(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
1213{
1214 LY_ERR r;
1215 struct lyd_node *child, *iter;
1216 const char *val;
1217 ly_bool no_dup;
1218
1219 /* there must be some child */
1220 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1221 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"rpc-error\".");
1222 return LY_EVALID;
1223 }
1224
1225 while (xmlctx->status == LYXML_ELEMENT) {
1226 child = NULL;
1227
1228 /*
1229 * error-type
1230 */
1231 r = lydxml_envelope(xmlctx, "error-type", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1232 if (r == LY_SUCCESS) {
1233 val = ((struct lyd_node_opaq *)child)->value;
1234 if (strcmp(val, "transport") && strcmp(val, "rpc") && strcmp(val, "protocol") && strcmp(val, "application")) {
1235 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1236 ((struct lyd_node_opaq *)child)->name.name);
1237 r = LY_EVALID;
1238 goto error;
1239 }
1240
1241 no_dup = 1;
1242 goto check_child;
1243 } else if (r != LY_ENOT) {
1244 goto error;
1245 }
1246
1247 /*
1248 * error-tag
1249 */
1250 r = lydxml_envelope(xmlctx, "error-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1251 if (r == LY_SUCCESS) {
1252 val = ((struct lyd_node_opaq *)child)->value;
1253 if (strcmp(val, "in-use") && strcmp(val, "invalid-value") && strcmp(val, "too-big") &&
1254 strcmp(val, "missing-attribute") && strcmp(val, "bad-attribute") &&
1255 strcmp(val, "unknown-attribute") && strcmp(val, "missing-element") && strcmp(val, "bad-element") &&
1256 strcmp(val, "unknown-element") && strcmp(val, "unknown-namespace") && strcmp(val, "access-denied") &&
1257 strcmp(val, "lock-denied") && strcmp(val, "resource-denied") && strcmp(val, "rollback-failed") &&
1258 strcmp(val, "data-exists") && strcmp(val, "data-missing") && strcmp(val, "operation-not-supported") &&
1259 strcmp(val, "operation-failed") && strcmp(val, "malformed-message")) {
1260 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1261 ((struct lyd_node_opaq *)child)->name.name);
1262 r = LY_EVALID;
1263 goto error;
1264 }
1265
1266 no_dup = 1;
1267 goto check_child;
1268 } else if (r != LY_ENOT) {
1269 goto error;
1270 }
1271
1272 /*
1273 * error-severity
1274 */
1275 r = lydxml_envelope(xmlctx, "error-severity", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1276 if (r == LY_SUCCESS) {
1277 val = ((struct lyd_node_opaq *)child)->value;
1278 if (strcmp(val, "error") && strcmp(val, "warning")) {
1279 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1280 ((struct lyd_node_opaq *)child)->name.name);
1281 r = LY_EVALID;
1282 goto error;
1283 }
1284
1285 no_dup = 1;
1286 goto check_child;
1287 } else if (r != LY_ENOT) {
1288 goto error;
1289 }
1290
1291 /*
1292 * error-app-tag
1293 */
1294 r = lydxml_envelope(xmlctx, "error-app-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1295 if (r == LY_SUCCESS) {
1296 no_dup = 1;
1297 goto check_child;
1298 } else if (r != LY_ENOT) {
1299 goto error;
1300 }
1301
1302 /*
1303 * error-path
1304 */
1305 r = lydxml_envelope(xmlctx, "error-path", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1306 if (r == LY_SUCCESS) {
1307 no_dup = 1;
1308 goto check_child;
1309 } else if (r != LY_ENOT) {
1310 goto error;
1311 }
1312
1313 /*
1314 * error-message
1315 */
1316 r = lydxml_envelope(xmlctx, "error-message", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1317 if (r == LY_SUCCESS) {
1318 no_dup = 1;
1319 goto check_child;
1320 } else if (r != LY_ENOT) {
1321 goto error;
1322 }
1323
1324 /* error-info */
1325 r = lydxml_envelope(xmlctx, "error-info", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1326 if (r == LY_SUCCESS) {
1327 /* parse all the descendants */
1328 LY_CHECK_GOTO(r = lydxml_env_netconf_rpc_reply_error_info(xmlctx, child), error);
1329
1330 no_dup = 0;
1331 goto check_child;
1332 } else if (r != LY_ENOT) {
1333 goto error;
1334 }
1335
1336 if (r == LY_ENOT) {
1337 assert(xmlctx->status == LYXML_ELEMENT);
1338 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001339 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001340 r = LY_EVALID;
1341 goto error;
1342 }
1343
1344check_child:
1345 /* check for duplicates */
1346 if (no_dup) {
1347 LY_LIST_FOR(lyd_child(parent), iter) {
1348 if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
1349 (((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
1350 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"rpc-error\".",
1351 ((struct lyd_node_opaq *)child)->name.name);
1352 r = LY_EVALID;
1353 goto error;
1354 }
1355 }
1356 }
1357
1358 /* finish child parsing */
1359 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1360 assert(xmlctx->status == LYXML_ELEMENT);
1361 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001362 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001363 r = LY_EVALID;
1364 goto error;
1365 }
1366 LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
1367
1368 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001369 lyd_insert_node(parent, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +01001370 }
1371
1372 return LY_SUCCESS;
1373
1374error:
1375 lyd_free_tree(child);
1376 return r;
1377}
1378
1379/**
1380 * @brief Parse all expected non-data XML elements of a NETCONF rpc-reply message.
1381 *
1382 * @param[in] xmlctx XML parser context.
1383 * @param[out] evnp Parsed envelope(s) (opaque node).
1384 * @param[out] int_opts Internal options for parsing the rest of YANG data.
1385 * @param[out] close_elem Number of parsed opened elements that need to be closed.
1386 * @return LY_SUCCESS on success.
1387 * @return LY_ERR value on error.
1388 */
1389static LY_ERR
1390lydxml_env_netconf_reply(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
1391{
1392 LY_ERR rc = LY_SUCCESS, r;
1393 struct lyd_node *child = NULL;
1394 const char *parsed_elem = NULL;
1395
1396 assert(envp && !*envp);
1397
1398 /* parse "rpc-reply" */
1399 r = lydxml_envelope(xmlctx, "rpc-reply", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +01001400 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1401
1402 /* there must be some child */
1403 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1404 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"rpc-reply\".");
1405 rc = LY_EVALID;
Michal Vaskocf770e22020-08-12 13:21:43 +02001406 goto cleanup;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001407 }
1408
Michal Vaskoe0665742021-02-11 11:08:44 +01001409 /* try to parse "ok" */
1410 r = lydxml_envelope(xmlctx, "ok", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1411 if (r == LY_SUCCESS) {
1412 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001413 lyd_insert_node(*envp, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +01001414
1415 /* finish child parsing */
1416 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1417 assert(xmlctx->status == LYXML_ELEMENT);
1418 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"ok\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001419 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001420 rc = LY_EVALID;
1421 goto cleanup;
1422 }
1423 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1424
1425 /* success */
1426 parsed_elem = "ok";
1427 goto finish;
1428 } else if (r != LY_ENOT) {
1429 rc = r;
1430 goto cleanup;
Michal Vasko2552ea32020-12-08 15:32:34 +01001431 }
1432
Michal Vaskoe0665742021-02-11 11:08:44 +01001433 /* try to parse all "rpc-error" elements */
1434 while (xmlctx->status == LYXML_ELEMENT) {
1435 r = lydxml_envelope(xmlctx, "rpc-error", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1436 if (r == LY_ENOT) {
1437 break;
1438 } else if (r) {
1439 rc = r;
1440 goto cleanup;
1441 }
1442
1443 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001444 lyd_insert_node(*envp, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +01001445
1446 /* parse all children of "rpc-error" */
1447 LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc_reply_error(xmlctx, child), cleanup);
1448
1449 /* finish child parsing */
1450 assert(xmlctx->status == LYXML_ELEM_CLOSE);
1451 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1452
1453 parsed_elem = "rpc-error";
Michal Vasko2552ea32020-12-08 15:32:34 +01001454 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001455
1456finish:
1457 if (parsed_elem) {
1458 /* NETCONF rpc-reply with no data */
1459 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1460 assert(xmlctx->status == LYXML_ELEMENT);
1461 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"%s\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001462 (int)xmlctx->name_len, xmlctx->name, parsed_elem);
Michal Vaskoe0665742021-02-11 11:08:44 +01001463 rc = LY_EVALID;
1464 goto cleanup;
1465 }
1466 }
1467
1468 /* NETCONF rpc-reply */
Michal Vasko1d991fd2021-07-09 13:14:40 +02001469 *int_opts = LYD_INTOPT_WITH_SIBLINGS | LYD_INTOPT_REPLY;
Michal Vaskoe0665742021-02-11 11:08:44 +01001470 *close_elem = 1;
1471
1472cleanup:
1473 if (rc) {
1474 lyd_free_tree(*envp);
1475 *envp = NULL;
1476 }
1477 return rc;
1478}
1479
Michal Vasko2552ea32020-12-08 15:32:34 +01001480LY_ERR
Radek Krejcif16e2542021-02-17 15:39:23 +01001481lyd_parse_xml(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
1482 struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type,
Michal Vaskoaac267d2022-01-17 13:34:48 +01001483 struct lyd_node **envp, struct ly_set *parsed, ly_bool *subtree_sibling, struct lyd_ctx **lydctx_p)
Michal Vasko2552ea32020-12-08 15:32:34 +01001484{
Michal Vaskoe0665742021-02-11 11:08:44 +01001485 LY_ERR rc = LY_SUCCESS;
1486 struct lyd_xml_ctx *lydctx;
Michal Vasko2ca9f9e2021-07-02 09:21:36 +02001487 uint32_t i, int_opts = 0, close_elem = 0;
Michal Vaskoe0665742021-02-11 11:08:44 +01001488 ly_bool parsed_data_nodes = 0;
Michal Vaskoaac267d2022-01-17 13:34:48 +01001489 enum LYXML_PARSER_STATUS status;
Michal Vasko2552ea32020-12-08 15:32:34 +01001490
Michal Vaskoe0665742021-02-11 11:08:44 +01001491 assert(ctx && in && lydctx_p);
1492 assert(!(parse_opts & ~LYD_PARSE_OPTS_MASK));
1493 assert(!(val_opts & ~LYD_VALIDATE_OPTS_MASK));
Michal Vasko2552ea32020-12-08 15:32:34 +01001494
Michal Vaskoe0665742021-02-11 11:08:44 +01001495 /* init context */
1496 lydctx = calloc(1, sizeof *lydctx);
1497 LY_CHECK_ERR_RET(!lydctx, LOGMEM(ctx), LY_EMEM);
1498 LY_CHECK_GOTO(rc = lyxml_ctx_new(ctx, in, &lydctx->xmlctx), cleanup);
1499 lydctx->parse_opts = parse_opts;
1500 lydctx->val_opts = val_opts;
1501 lydctx->free = lyd_xml_ctx_free;
Radek Krejcif16e2542021-02-17 15:39:23 +01001502 lydctx->ext = ext;
Michal Vasko2552ea32020-12-08 15:32:34 +01001503
Michal Vaskoe0665742021-02-11 11:08:44 +01001504 switch (data_type) {
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001505 case LYD_TYPE_DATA_YANG:
Michal Vaskoaac267d2022-01-17 13:34:48 +01001506 if (!(parse_opts & LYD_PARSE_SUBTREE)) {
1507 int_opts = LYD_INTOPT_WITH_SIBLINGS;
1508 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001509 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001510 case LYD_TYPE_RPC_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001511 int_opts = LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NO_SIBLINGS;
1512 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001513 case LYD_TYPE_NOTIF_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001514 int_opts = LYD_INTOPT_NOTIF | LYD_INTOPT_NO_SIBLINGS;
1515 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001516 case LYD_TYPE_REPLY_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001517 int_opts = LYD_INTOPT_REPLY | LYD_INTOPT_NO_SIBLINGS;
1518 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001519 case LYD_TYPE_RPC_NETCONF:
Michal Vaskoe0665742021-02-11 11:08:44 +01001520 assert(!parent);
1521 LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
1522 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001523 case LYD_TYPE_NOTIF_NETCONF:
1524 assert(!parent);
1525 LY_CHECK_GOTO(rc = lydxml_env_netconf_notif(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
1526 break;
1527 case LYD_TYPE_REPLY_NETCONF:
Michal Vaskoe0665742021-02-11 11:08:44 +01001528 assert(parent);
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001529 LY_CHECK_GOTO(rc = lydxml_env_netconf_reply(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
Michal Vaskoe0665742021-02-11 11:08:44 +01001530 break;
1531 }
1532 lydctx->int_opts = int_opts;
1533
1534 /* find the operation node if it exists already */
1535 LY_CHECK_GOTO(rc = lyd_parser_find_operation(parent, int_opts, &lydctx->op_node), cleanup);
1536
1537 /* parse XML data */
1538 while (lydctx->xmlctx->status == LYXML_ELEMENT) {
1539 LY_CHECK_GOTO(rc = lydxml_subtree_r(lydctx, parent, first_p, parsed), cleanup);
1540 parsed_data_nodes = 1;
1541
1542 if (!(int_opts & LYD_INTOPT_WITH_SIBLINGS)) {
1543 break;
1544 }
Michal Vasko2552ea32020-12-08 15:32:34 +01001545 }
1546
Michal Vaskoe0665742021-02-11 11:08:44 +01001547 /* close all opened elements */
1548 for (i = 0; i < close_elem; ++i) {
1549 if (lydctx->xmlctx->status != LYXML_ELEM_CLOSE) {
1550 assert(lydctx->xmlctx->status == LYXML_ELEMENT);
Radek Krejci422afb12021-03-04 16:38:16 +01001551 LOGVAL(lydctx->xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\".",
1552 (int)lydctx->xmlctx->name_len, lydctx->xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001553 rc = LY_EVALID;
1554 goto cleanup;
1555 }
1556
1557 LY_CHECK_GOTO(rc = lyxml_ctx_next(lydctx->xmlctx), cleanup);
Michal Vasko4189c0f2020-08-13 09:05:22 +02001558 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001559
1560 /* check final state */
1561 if ((int_opts & LYD_INTOPT_NO_SIBLINGS) && (lydctx->xmlctx->status == LYXML_ELEMENT)) {
1562 LOGVAL(ctx, LYVE_SYNTAX, "Unexpected sibling node.");
1563 rc = LY_EVALID;
1564 goto cleanup;
1565 }
Michal Vaskoe601aaa2022-01-03 11:35:13 +01001566 if ((int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NOTIF | LYD_INTOPT_REPLY)) && !lydctx->op_node) {
Michal Vaskoe0665742021-02-11 11:08:44 +01001567 LOGVAL(ctx, LYVE_DATA, "Missing the operation node.");
1568 rc = LY_EVALID;
1569 goto cleanup;
1570 }
1571
1572 if (!parsed_data_nodes) {
1573 /* no data nodes were parsed */
1574 lydctx->op_node = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001575 }
1576
Michal Vaskoaac267d2022-01-17 13:34:48 +01001577 if (parse_opts & LYD_PARSE_SUBTREE) {
1578 /* check for a sibling element */
1579 assert(subtree_sibling);
1580 if (!lyxml_ctx_peek(lydctx->xmlctx, &status) && (status == LYXML_ELEMENT)) {
1581 *subtree_sibling = 1;
1582 } else {
1583 *subtree_sibling = 0;
1584 }
1585 }
1586
Michal Vaskoa8edff02020-03-27 14:47:01 +01001587cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +01001588 /* there should be no unres stored if validation should be skipped */
1589 assert(!(parse_opts & LYD_PARSE_ONLY) || (!lydctx->node_types.count && !lydctx->meta_types.count &&
Michal Vaskoaac267d2022-01-17 13:34:48 +01001590 !lydctx->node_when.count));
Michal Vaskoe0665742021-02-11 11:08:44 +01001591
1592 if (rc) {
1593 lyd_xml_ctx_free((struct lyd_ctx *)lydctx);
1594 } else {
1595 *lydctx_p = (struct lyd_ctx *)lydctx;
1596
1597 /* the XML context is no more needed, freeing it also stops logging line numbers which would be confusing now */
1598 lyxml_ctx_free(lydctx->xmlctx);
1599 lydctx->xmlctx = NULL;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001600 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001601 return rc;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001602}