blob: 69d1b4553d24653acdc3079d6827873debc0d000 [file] [log] [blame]
Radek Krejcie7b95092019-05-15 11:03:07 +02001/**
2 * @file parser_xml.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
Michal Vasko8cc3f662022-03-29 11:25:51 +02004 * @author Michal Vasko <mvasko@cesnet.cz>
Radek Krejcie7b95092019-05-15 11:03:07 +02005 * @brief XML data parser for libyang
6 *
Michal Vasko8cc3f662022-03-29 11:25:51 +02007 * Copyright (c) 2019 - 2022 CESNET, z.s.p.o.
Radek Krejcie7b95092019-05-15 11:03:07 +02008 *
9 * This source code is licensed under BSD 3-Clause License (the "License").
10 * You may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 * https://opensource.org/licenses/BSD-3-Clause
14 */
15
Michal Vasko742a5b12022-02-24 16:07:27 +010016#define _GNU_SOURCE
17
Michal Vasko69730152020-10-09 16:30:07 +020018#include <assert.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020019#include <stdint.h>
20#include <stdlib.h>
21#include <string.h>
22
Radek Krejci535ea9f2020-05-29 16:01:05 +020023#include "common.h"
Michal Vasko742a5b12022-02-24 16:07:27 +010024#include "compat.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020025#include "context.h"
Radek Krejci77114102021-03-10 15:21:57 +010026#include "dict.h"
Michal Vaskoafac7822020-10-20 14:22:26 +020027#include "in_internal.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020028#include "log.h"
Radek Krejci7931b192020-06-25 17:05:03 +020029#include "parser_data.h"
30#include "parser_internal.h"
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +010031#include "plugins_exts.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020032#include "set.h"
Radek Krejci77114102021-03-10 15:21:57 +010033#include "tree.h"
Radek Krejci47fab892020-11-05 17:02:41 +010034#include "tree_data.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020035#include "tree_data_internal.h"
36#include "tree_schema.h"
Radek Krejci77114102021-03-10 15:21:57 +010037#include "tree_schema_internal.h"
Michal Vaskocde73ac2019-11-14 16:10:27 +010038#include "validation.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020039#include "xml.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020040
Radek Krejci1798aae2020-07-14 13:26:06 +020041void
42lyd_xml_ctx_free(struct lyd_ctx *lydctx)
43{
44 struct lyd_xml_ctx *ctx = (struct lyd_xml_ctx *)lydctx;
45
46 lyd_ctx_free(lydctx);
47 lyxml_ctx_free(ctx->xmlctx);
48 free(ctx);
49}
50
Michal Vasko45791ad2021-06-17 08:45:03 +020051/**
52 * @brief Parse and create XML metadata.
53 *
54 * @param[in] lydctx XML data parser context.
Michal Vaskoddd76592022-01-17 13:34:48 +010055 * @param[in] sparent Schema node of the parent.
Michal Vasko45791ad2021-06-17 08:45:03 +020056 * @param[out] meta List of created metadata instances.
57 * @return LY_ERR value.
58 */
Radek Krejcie7b95092019-05-15 11:03:07 +020059static LY_ERR
Michal Vaskoddd76592022-01-17 13:34:48 +010060lydxml_metadata(struct lyd_xml_ctx *lydctx, const struct lysc_node *sparent, struct lyd_meta **meta)
Radek Krejcie7b95092019-05-15 11:03:07 +020061{
aPiecek1c4da362021-04-29 14:26:34 +020062 LY_ERR ret = LY_SUCCESS;
Radek Krejci28681fa2019-09-06 13:08:45 +020063 const struct lyxml_ns *ns;
64 struct lys_module *mod;
Michal Vaskob36053d2020-03-26 15:49:30 +010065 const char *name;
66 size_t name_len;
Michal Vasko45791ad2021-06-17 08:45:03 +020067 LY_ARRAY_COUNT_TYPE u;
68 ly_bool filter_attrs = 0;
Radek Krejci1798aae2020-07-14 13:26:06 +020069 struct lyxml_ctx *xmlctx = lydctx->xmlctx;
Radek Krejci28681fa2019-09-06 13:08:45 +020070
Michal Vaskob36053d2020-03-26 15:49:30 +010071 *meta = NULL;
Radek Krejci28681fa2019-09-06 13:08:45 +020072
Michal Vasko45791ad2021-06-17 08:45:03 +020073 /* check for NETCONF filter unqualified attributes */
Michal Vaskoddd76592022-01-17 13:34:48 +010074 LY_ARRAY_FOR(sparent->exts, u) {
75 if (!strcmp(sparent->exts[u].def->name, "get-filter-element-attributes") &&
76 !strcmp(sparent->exts[u].def->module->name, "ietf-netconf")) {
Michal Vasko45791ad2021-06-17 08:45:03 +020077 filter_attrs = 1;
78 break;
79 }
80 }
81
Michal Vaskob36053d2020-03-26 15:49:30 +010082 while (xmlctx->status == LYXML_ATTRIBUTE) {
83 if (!xmlctx->prefix_len) {
Michal Vasko45791ad2021-06-17 08:45:03 +020084 /* in XML all attributes must be prefixed except NETCONF filter ones marked by an extension */
85 if (filter_attrs && (!ly_strncmp("type", xmlctx->name, xmlctx->name_len) ||
86 !ly_strncmp("select", xmlctx->name, xmlctx->name_len))) {
87 mod = ly_ctx_get_module_implemented(xmlctx->ctx, "ietf-netconf");
88 if (!mod) {
89 LOGVAL(xmlctx->ctx, LYVE_REFERENCE,
90 "Missing (or not implemented) YANG module \"ietf-netconf\" for special filter attributes.");
91 ret = LY_ENOTFOUND;
92 goto cleanup;
93 }
94 goto create_meta;
95 }
96
Michal Vaskoe0665742021-02-11 11:08:44 +010097 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +010098 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Missing mandatory prefix for XML metadata \"%.*s\".",
Radek Krejci422afb12021-03-04 16:38:16 +010099 (int)xmlctx->name_len, xmlctx->name);
Michal Vasko45791ad2021-06-17 08:45:03 +0200100 ret = LY_EVALID;
Michal Vaskob36053d2020-03-26 15:49:30 +0100101 goto cleanup;
Radek Krejci28681fa2019-09-06 13:08:45 +0200102 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100103
Michal Vasko45791ad2021-06-17 08:45:03 +0200104 /* skip attr */
Michal Vaskob36053d2020-03-26 15:49:30 +0100105 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
106 assert(xmlctx->status == LYXML_ATTR_CONTENT);
107 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejci28681fa2019-09-06 13:08:45 +0200108 continue;
109 }
110
111 /* get namespace of the attribute to find its annotation definition */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200112 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
Radek Krejci28681fa2019-09-06 13:08:45 +0200113 if (!ns) {
Michal Vasko52927e22020-03-16 17:26:14 +0100114 /* unknown namespace, XML error */
Radek Krejci422afb12021-03-04 16:38:16 +0100115 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)xmlctx->prefix_len, xmlctx->prefix);
Michal Vasko45791ad2021-06-17 08:45:03 +0200116 ret = LY_ENOTFOUND;
Radek Krejci28681fa2019-09-06 13:08:45 +0200117 goto cleanup;
118 }
Michal Vasko45791ad2021-06-17 08:45:03 +0200119
120 /* get the module with metadata definition */
Michal Vasko52927e22020-03-16 17:26:14 +0100121 mod = ly_ctx_get_module_implemented_ns(xmlctx->ctx, ns->uri);
Radek Krejci28681fa2019-09-06 13:08:45 +0200122 if (!mod) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100123 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100124 LOGVAL(xmlctx->ctx, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +0200125 "Unknown (or not implemented) YANG module with namespace \"%s\" for metadata \"%.*s%s%.*s\".",
Radek Krejci422afb12021-03-04 16:38:16 +0100126 ns->uri, (int)xmlctx->prefix_len, xmlctx->prefix, xmlctx->prefix_len ? ":" : "",
127 (int)xmlctx->name_len, xmlctx->name);
Michal Vasko45791ad2021-06-17 08:45:03 +0200128 ret = LY_ENOTFOUND;
Michal Vaskob36053d2020-03-26 15:49:30 +0100129 goto cleanup;
Radek Krejci28681fa2019-09-06 13:08:45 +0200130 }
Michal Vasko45791ad2021-06-17 08:45:03 +0200131
132 /* skip attr */
133 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
134 assert(xmlctx->status == LYXML_ATTR_CONTENT);
135 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
136 continue;
Radek Krejci28681fa2019-09-06 13:08:45 +0200137 }
138
Michal Vasko45791ad2021-06-17 08:45:03 +0200139create_meta:
Michal Vasko60ea6352020-06-29 13:39:39 +0200140 /* remember meta name and get its content */
Michal Vaskob36053d2020-03-26 15:49:30 +0100141 name = xmlctx->name;
142 name_len = xmlctx->name_len;
143 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
144 assert(xmlctx->status == LYXML_ATTR_CONTENT);
145
146 /* create metadata */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200147 ret = lyd_parser_create_meta((struct lyd_ctx *)lydctx, NULL, meta, mod, name, name_len, xmlctx->value,
Michal Vaskoddd76592022-01-17 13:34:48 +0100148 xmlctx->value_len, &xmlctx->dynamic, LY_VALUE_XML, &xmlctx->ns, LYD_HINT_DATA, sparent);
Radek Krejci1798aae2020-07-14 13:26:06 +0200149 LY_CHECK_GOTO(ret, cleanup);
Michal Vaskob36053d2020-03-26 15:49:30 +0100150
151 /* next attribute */
152 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200153 }
Michal Vasko52927e22020-03-16 17:26:14 +0100154
Radek Krejcie7b95092019-05-15 11:03:07 +0200155cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100156 if (ret) {
Michal Vasko3a41dff2020-07-15 14:30:28 +0200157 lyd_free_meta_siblings(*meta);
Michal Vaskob36053d2020-03-26 15:49:30 +0100158 *meta = NULL;
Radek Krejci38d85362019-09-05 16:26:38 +0200159 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200160 return ret;
161}
162
Michal Vasko52927e22020-03-16 17:26:14 +0100163static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200164lydxml_attrs(struct lyxml_ctx *xmlctx, struct lyd_attr **attr)
Michal Vasko52927e22020-03-16 17:26:14 +0100165{
166 LY_ERR ret = LY_SUCCESS;
167 const struct lyxml_ns *ns;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100168 void *val_prefix_data;
Radek Krejci8df109d2021-04-23 12:19:08 +0200169 LY_VALUE_FORMAT format;
Radek Krejci1798aae2020-07-14 13:26:06 +0200170 struct lyd_attr *attr2;
Michal Vaskob36053d2020-03-26 15:49:30 +0100171 const char *name, *prefix;
172 size_t name_len, prefix_len;
Michal Vasko52927e22020-03-16 17:26:14 +0100173
174 assert(attr);
Michal Vaskob36053d2020-03-26 15:49:30 +0100175 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100176
Michal Vaskob36053d2020-03-26 15:49:30 +0100177 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vasko52927e22020-03-16 17:26:14 +0100178 if (*attr) {
179 attr2 = *attr;
180 } else {
181 attr2 = NULL;
182 }
183
Michal Vaskob36053d2020-03-26 15:49:30 +0100184 /* remember attr prefix, name, and get its content */
185 prefix = xmlctx->prefix;
186 prefix_len = xmlctx->prefix_len;
187 name = xmlctx->name;
188 name_len = xmlctx->name_len;
189 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
190 assert(xmlctx->status == LYXML_ATTR_CONTENT);
191
Michal Vaskoe137fc42021-07-22 11:53:13 +0200192 /* handle special "xml" attribute prefix */
193 if ((prefix_len == 3) && !strncmp(prefix, "xml", 3)) {
194 name = prefix;
195 name_len += 1 + prefix_len;
196 prefix = NULL;
197 prefix_len = 0;
198 }
199
200 /* find namespace of the attribute, if any */
201 ns = NULL;
202 if (prefix_len) {
203 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
204 if (!ns) {
205 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
206 ret = LY_EVALID;
207 goto cleanup;
208 }
209 }
210
Michal Vasko52927e22020-03-16 17:26:14 +0100211 /* get value prefixes */
Michal Vaskofc2cd072021-02-24 13:17:17 +0100212 val_prefix_data = NULL;
Radek Krejci8df109d2021-04-23 12:19:08 +0200213 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 +0100214 &xmlctx->ns, &format, &val_prefix_data), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100215
216 /* attr2 is always changed to the created attribute */
Michal Vasko501af032020-11-11 20:27:44 +0100217 ret = lyd_create_attr(NULL, &attr2, xmlctx->ctx, name, name_len, prefix, prefix_len, ns ? ns->uri : NULL,
Michal Vaskoe5e49e92022-02-01 13:15:08 +0100218 ns ? strlen(ns->uri) : 0, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic, format, val_prefix_data,
219 LYD_HINT_DATA);
Michal Vasko52927e22020-03-16 17:26:14 +0100220 LY_CHECK_GOTO(ret, cleanup);
221
222 if (!*attr) {
223 *attr = attr2;
224 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100225
226 /* next attribute */
227 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100228 }
229
230cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100231 if (ret) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200232 lyd_free_attr_siblings(xmlctx->ctx, *attr);
Michal Vaskob36053d2020-03-26 15:49:30 +0100233 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100234 }
Michal Vasko52927e22020-03-16 17:26:14 +0100235 return ret;
236}
237
Michal Vasko44685da2020-03-17 15:38:06 +0100238static LY_ERR
Michal Vaskob36053d2020-03-26 15:49:30 +0100239lydxml_check_list(struct lyxml_ctx *xmlctx, const struct lysc_node *list)
Michal Vasko44685da2020-03-17 15:38:06 +0100240{
Michal Vaskob36053d2020-03-26 15:49:30 +0100241 LY_ERR ret = LY_SUCCESS, r;
242 enum LYXML_PARSER_STATUS next;
Michal Vasko44685da2020-03-17 15:38:06 +0100243 struct ly_set key_set = {0};
244 const struct lysc_node *snode;
Michal Vaskob36053d2020-03-26 15:49:30 +0100245 uint32_t i, parents_count;
Michal Vasko44685da2020-03-17 15:38:06 +0100246
247 assert(list && (list->nodetype == LYS_LIST));
248
249 /* get all keys into a set (keys do not have if-features or anything) */
250 snode = NULL;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100251 while ((snode = lys_getnext(snode, list, NULL, 0)) && (snode->flags & LYS_KEY)) {
Radek Krejci3d92e442020-10-12 12:48:13 +0200252 ret = ly_set_add(&key_set, (void *)snode, 1, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200253 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100254 }
255
Michal Vasko12d809c2021-03-03 16:34:32 +0100256 /* remember parent count */
257 parents_count = xmlctx->elements.count;
258
Michal Vaskob36053d2020-03-26 15:49:30 +0100259 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vasko44685da2020-03-17 15:38:06 +0100260 /* find key definition */
261 for (i = 0; i < key_set.count; ++i) {
262 snode = (const struct lysc_node *)key_set.objs[i];
Michal Vaskob36053d2020-03-26 15:49:30 +0100263 if (!ly_strncmp(snode->name, xmlctx->name, xmlctx->name_len)) {
Michal Vasko44685da2020-03-17 15:38:06 +0100264 break;
265 }
266 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100267 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100268
269 /* skip attributes */
270 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100271 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
272 assert(xmlctx->status == LYXML_ATTR_CONTENT);
273 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100274 }
275
Michal Vaskob36053d2020-03-26 15:49:30 +0100276 assert(xmlctx->status == LYXML_ELEM_CONTENT);
277 if (i < key_set.count) {
278 /* validate the value */
Radek Krejci8df109d2021-04-23 12:19:08 +0200279 r = lys_value_validate(NULL, snode, xmlctx->value, xmlctx->value_len, LY_VALUE_XML, &xmlctx->ns);
Michal Vaskob36053d2020-03-26 15:49:30 +0100280 if (!r) {
281 /* key with a valid value, remove from the set */
282 ly_set_rm_index(&key_set, i, NULL);
Michal Vasko44685da2020-03-17 15:38:06 +0100283 }
284 }
285
Michal Vaskob36053d2020-03-26 15:49:30 +0100286 /* parser next */
287 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100288
Michal Vaskob36053d2020-03-26 15:49:30 +0100289 /* skip any children, resursively */
Michal Vasko12d809c2021-03-03 16:34:32 +0100290 while (xmlctx->status == LYXML_ELEMENT) {
291 while (parents_count < xmlctx->elements.count) {
292 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
293 }
294 assert(xmlctx->status == LYXML_ELEM_CLOSE);
Michal Vaskob36053d2020-03-26 15:49:30 +0100295 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
296 }
297
298 /* parser next, but do not parse closing element of the list because it would remove its namespaces */
299 assert(xmlctx->status == LYXML_ELEM_CLOSE);
300 LY_CHECK_GOTO(ret = lyxml_ctx_peek(xmlctx, &next), cleanup);
301 if (next != LYXML_ELEM_CLOSE) {
302 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
303 }
Michal Vasko44685da2020-03-17 15:38:06 +0100304 }
305
306 if (key_set.count) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100307 /* some keys are missing/did not validate */
Michal Vasko44685da2020-03-17 15:38:06 +0100308 ret = LY_ENOT;
Michal Vasko44685da2020-03-17 15:38:06 +0100309 }
310
311cleanup:
312 ly_set_erase(&key_set, NULL);
313 return ret;
314}
315
Michal Vasko5c24ed12021-06-09 09:27:32 +0200316/**
317 * @brief Skip an element with all its descendants.
318 *
319 * @param[in] xmlctx XML parser context.
320 * @return LY_ERR value.
321 */
Michal Vasko1bf09392020-03-27 12:38:10 +0100322static LY_ERR
323lydxml_data_skip(struct lyxml_ctx *xmlctx)
324{
325 uint32_t parents_count;
326
327 /* remember current number of parents */
328 parents_count = xmlctx->elements.count;
aPiecek9cdb9e62021-05-18 09:46:20 +0200329 assert(parents_count);
Michal Vasko1bf09392020-03-27 12:38:10 +0100330
331 /* skip after the content */
332 while (xmlctx->status != LYXML_ELEM_CONTENT) {
333 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
334 }
335 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
336
337 /* skip all children elements, recursively, if any */
aPiecek9cdb9e62021-05-18 09:46:20 +0200338 while (parents_count <= xmlctx->elements.count) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100339 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
340 }
341
342 /* close element */
343 assert(xmlctx->status == LYXML_ELEM_CLOSE);
344 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
345
346 return LY_SUCCESS;
347}
348
Michal Vasko5c24ed12021-06-09 09:27:32 +0200349/**
350 * @brief Check that the current element can be parsed as a data node.
351 *
352 * @param[in] lydctx XML data parser context.
353 * @param[in,out] snode Found schema node, set to NULL if data node cannot be created.
354 * @return LY_ERR value.
355 */
Michal Vasko1bf09392020-03-27 12:38:10 +0100356static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200357lydxml_data_check_opaq(struct lyd_xml_ctx *lydctx, const struct lysc_node **snode)
Michal Vasko1bf09392020-03-27 12:38:10 +0100358{
359 LY_ERR ret = LY_SUCCESS;
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200360 struct lyxml_ctx *xmlctx = lydctx->xmlctx, pxmlctx;
Michal Vasko1bf09392020-03-27 12:38:10 +0100361
Radek IÅ¡a3930fd72021-03-08 10:48:40 +0100362 if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
363 /* only checks specific to opaque nodes */
364 return LY_SUCCESS;
365 }
366
Michal Vasko13854662021-06-09 09:27:50 +0200367 if (!((*snode)->nodetype & (LYD_NODE_TERM | LYD_NODE_INNER))) {
368 /* nothing to check */
369 return LY_SUCCESS;
370 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100371
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200372 assert(xmlctx->elements.count);
373
Michal Vasko13854662021-06-09 09:27:50 +0200374 /* backup parser */
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200375 LY_CHECK_RET(lyxml_ctx_backup(xmlctx, &pxmlctx));
Michal Vasko1bf09392020-03-27 12:38:10 +0100376
Michal Vasko13854662021-06-09 09:27:50 +0200377 /* skip attributes */
378 while (xmlctx->status == LYXML_ATTRIBUTE) {
379 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
380 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
381 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100382
Michal Vasko13854662021-06-09 09:27:50 +0200383 if ((*snode)->nodetype & LYD_NODE_TERM) {
384 /* value may not be valid in which case we parse it as an opaque node */
385 if (lys_value_validate(NULL, *snode, xmlctx->value, xmlctx->value_len, LY_VALUE_XML, &xmlctx->ns)) {
Michal Vaskod0237d42021-07-12 14:49:46 +0200386 LOGVRB("Parsing opaque term node \"%s\" with invalid value \"%.*s\".", (*snode)->name, xmlctx->value_len,
387 xmlctx->value);
Michal Vasko13854662021-06-09 09:27:50 +0200388 *snode = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100389 }
Michal Vasko13854662021-06-09 09:27:50 +0200390 } else if ((*snode)->nodetype == LYS_LIST) {
391 /* skip content */
392 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
Michal Vasko1bf09392020-03-27 12:38:10 +0100393
Michal Vasko13854662021-06-09 09:27:50 +0200394 if (lydxml_check_list(xmlctx, *snode)) {
395 /* invalid list, parse as opaque if it missing/has invalid some keys */
Michal Vaskod0237d42021-07-12 14:49:46 +0200396 LOGVRB("Parsing opaque list node \"%s\" with missing/invalid keys.", (*snode)->name);
Michal Vasko13854662021-06-09 09:27:50 +0200397 *snode = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100398 }
Michal Vasko13854662021-06-09 09:27:50 +0200399 } else {
Radek IÅ¡a3930fd72021-03-08 10:48:40 +0100400 /* if there is a non-WS value, it cannot be parsed as an inner node */
401 assert(xmlctx->status == LYXML_ELEM_CONTENT);
402 if (!xmlctx->ws_only) {
403 *snode = NULL;
404 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100405 }
406
Michal Vasko13854662021-06-09 09:27:50 +0200407restore:
408 /* restore parser */
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200409 lyxml_ctx_restore(xmlctx, &pxmlctx);
Michal Vasko1bf09392020-03-27 12:38:10 +0100410 return ret;
411}
412
Radek Krejcie7b95092019-05-15 11:03:07 +0200413/**
Michal Vasko8cc3f662022-03-29 11:25:51 +0200414 * @brief Get schema node for the current element.
Michal Vaskoddd76592022-01-17 13:34:48 +0100415 *
416 * @param[in] lydctx XML data parser context.
Michal Vasko8cc3f662022-03-29 11:25:51 +0200417 * @param[in] parent Parsed parent data node, if any.
418 * @param[in] prefix Element prefix, if any.
419 * @param[in] prefix_len Length of @p prefix.
420 * @param[in] name Element name.
421 * @param[in] name_len Length of @p name.
422 * @param[out] snode Found schema node, NULL if no suitable was found.
423 * @param[out] ext Extension instance that provided @p snode, if any.
Michal Vaskoddd76592022-01-17 13:34:48 +0100424 * @return LY_SUCCESS on success;
Michal Vaskoddd76592022-01-17 13:34:48 +0100425 * @return LY_ERR on error.
426 */
427static LY_ERR
Michal Vasko8cc3f662022-03-29 11:25:51 +0200428lydxml_subtree_snode(struct lyd_xml_ctx *lydctx, const struct lyd_node *parent, const char *prefix, size_t prefix_len,
429 const char *name, size_t name_len, const struct lysc_node **snode, struct lysc_ext_instance **ext)
Michal Vaskoddd76592022-01-17 13:34:48 +0100430{
431 LY_ERR r;
Michal Vaskob36053d2020-03-26 15:49:30 +0100432 struct lyxml_ctx *xmlctx;
433 const struct ly_ctx *ctx;
Radek Krejcie7b95092019-05-15 11:03:07 +0200434 const struct lyxml_ns *ns;
Radek Krejcie7b95092019-05-15 11:03:07 +0200435 struct lys_module *mod;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200436 uint32_t getnext_opts;
Michal Vaskoe0665742021-02-11 11:08:44 +0100437
Michal Vaskob36053d2020-03-26 15:49:30 +0100438 xmlctx = lydctx->xmlctx;
439 ctx = xmlctx->ctx;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100440 getnext_opts = lydctx->int_opts & LYD_INTOPT_REPLY ? LYS_GETNEXT_OUTPUT : 0;
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100441
Michal Vasko8cc3f662022-03-29 11:25:51 +0200442 *snode = NULL;
443 *ext = NULL;
Michal Vaskoddd76592022-01-17 13:34:48 +0100444
Michal Vasko8cc3f662022-03-29 11:25:51 +0200445 /* get current namespace */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200446 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200447 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100448 LOGVAL(ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vasko8cc3f662022-03-29 11:25:51 +0200449 return LY_EVALID;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200450 }
Michal Vasko8cc3f662022-03-29 11:25:51 +0200451
452 /* get the element module, use parent context if possible because of extensions */
453 mod = ly_ctx_get_module_implemented_ns(parent ? LYD_CTX(parent) : ctx, ns->uri);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200454 if (!mod) {
Michal Vaskoddd76592022-01-17 13:34:48 +0100455 /* check for extension data */
Michal Vasko8cc3f662022-03-29 11:25:51 +0200456 r = ly_nested_ext_schema(parent, NULL, prefix, prefix_len, LY_VALUE_XML, &lydctx->xmlctx->ns, name, name_len,
457 snode, ext);
458 if (r != LY_ENOT) {
459 /* success or error */
Michal Vaskoddd76592022-01-17 13:34:48 +0100460 return r;
Michal Vaskoddd76592022-01-17 13:34:48 +0100461 }
462
463 /* unknown module */
Michal Vaskoe0665742021-02-11 11:08:44 +0100464 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100465 LOGVAL(ctx, LYVE_REFERENCE, "No module with namespace \"%s\" in the context.", ns->uri);
Michal Vasko8cc3f662022-03-29 11:25:51 +0200466 return LY_EVALID;
Radek Krejcie7b95092019-05-15 11:03:07 +0200467 }
Michal Vasko8cc3f662022-03-29 11:25:51 +0200468 return LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200469 }
470
Michal Vaskoa5da3292020-08-12 13:10:50 +0200471 /* get the schema node */
Michal Vasko81008a52021-07-21 16:06:12 +0200472 if (mod) {
Radek Krejcif16e2542021-02-17 15:39:23 +0100473 if (!parent && lydctx->ext) {
Michal Vasko8cc3f662022-03-29 11:25:51 +0200474 *snode = lysc_ext_find_node(lydctx->ext, mod, name, name_len, 0, getnext_opts);
Radek Krejcif16e2542021-02-17 15:39:23 +0100475 } else {
Michal Vasko8cc3f662022-03-29 11:25:51 +0200476 *snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
Radek Krejcif16e2542021-02-17 15:39:23 +0100477 }
Michal Vasko8cc3f662022-03-29 11:25:51 +0200478 if (!*snode) {
Michal Vaskoddd76592022-01-17 13:34:48 +0100479 /* check for extension data */
Michal Vasko8cc3f662022-03-29 11:25:51 +0200480 r = ly_nested_ext_schema(parent, NULL, prefix, prefix_len, LY_VALUE_XML, &lydctx->xmlctx->ns, name,
481 name_len, snode, ext);
482 if (r != LY_ENOT) {
483 /* success or error */
Michal Vaskoddd76592022-01-17 13:34:48 +0100484 return r;
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +0100485 }
Michal Vaskoddd76592022-01-17 13:34:48 +0100486
487 /* unknown data node */
Michal Vaskoe0665742021-02-11 11:08:44 +0100488 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
489 if (parent) {
Radek Krejci422afb12021-03-04 16:38:16 +0100490 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found as a child of \"%s\" node.",
Michal Vasko61ad1ff2022-02-10 15:48:39 +0100491 (int)name_len, name, LYD_NAME(parent));
Radek Krejcif16e2542021-02-17 15:39:23 +0100492 } else if (lydctx->ext) {
493 if (lydctx->ext->argument) {
Radek Krejci422afb12021-03-04 16:38:16 +0100494 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" %s extension instance.",
495 (int)name_len, name, lydctx->ext->argument, lydctx->ext->def->name);
Radek Krejcif16e2542021-02-17 15:39:23 +0100496 } else {
Radek Krejci422afb12021-03-04 16:38:16 +0100497 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the %s extension instance.",
498 (int)name_len, name, lydctx->ext->def->name);
Radek Krejcif16e2542021-02-17 15:39:23 +0100499 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100500 } else {
Radek Krejci422afb12021-03-04 16:38:16 +0100501 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" module.",
502 (int)name_len, name, mod->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100503 }
Michal Vasko8cc3f662022-03-29 11:25:51 +0200504 return LY_EVALID;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200505 }
Michal Vasko8cc3f662022-03-29 11:25:51 +0200506 return LY_SUCCESS;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200507 } else {
508 /* check that schema node is valid and can be used */
Michal Vasko8cc3f662022-03-29 11:25:51 +0200509 LY_CHECK_RET(lyd_parser_check_schema((struct lyd_ctx *)lydctx, *snode));
510 LY_CHECK_RET(lydxml_data_check_opaq(lydctx, snode));
Michal Vaskoa5da3292020-08-12 13:10:50 +0200511 }
512 }
513
Michal Vasko8cc3f662022-03-29 11:25:51 +0200514 return LY_SUCCESS;
515}
516
517/**
518 * @brief Parse XML subtree.
519 *
520 * @param[in] lydctx XML YANG data parser context.
521 * @param[in,out] parent Parent node where the children are inserted. NULL in case of parsing top-level elements.
522 * @param[in,out] first_p Pointer to the first (@p parent or top-level) child. In case there were already some siblings,
523 * this may point to a previously existing node.
524 * @param[in,out] parsed Optional set to add all the parsed siblings into.
525 * @return LY_ERR value.
526 */
527static LY_ERR
528lydxml_subtree_r(struct lyd_xml_ctx *lydctx, struct lyd_node *parent, struct lyd_node **first_p, struct ly_set *parsed)
529{
530 LY_ERR ret = LY_SUCCESS;
531 const char *prefix, *name;
532 size_t prefix_len, name_len;
533 struct lyxml_ctx *xmlctx;
534 const struct ly_ctx *ctx;
535 const struct lyxml_ns *ns;
536 struct lyd_meta *meta = NULL;
537 struct lyd_attr *attr = NULL;
538 const struct lysc_node *snode;
539 struct lysc_ext_instance *ext;
540 uint32_t prev_parse_opts, orig_parse_opts, prev_int_opts;
541 struct lyd_node *node = NULL, *anchor;
542 void *val_prefix_data = NULL;
543 LY_VALUE_FORMAT format;
544 ly_bool parse_subtree;
545 char *val;
546
547 assert(parent || first_p);
548
549 xmlctx = lydctx->xmlctx;
550 ctx = xmlctx->ctx;
551
552 parse_subtree = lydctx->parse_opts & LYD_PARSE_SUBTREE ? 1 : 0;
553 /* all descendants should be parsed */
554 lydctx->parse_opts &= ~LYD_PARSE_SUBTREE;
555 orig_parse_opts = lydctx->parse_opts;
556
557 assert(xmlctx->status == LYXML_ELEMENT);
558
559 /* remember element prefix and name */
560 prefix = xmlctx->prefix;
561 prefix_len = xmlctx->prefix_len;
562 name = xmlctx->name;
563 name_len = xmlctx->name_len;
564
565 /* parser next */
566 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
567
568 /* get the schema node */
569 LY_CHECK_GOTO(ret = lydxml_subtree_snode(lydctx, parent, prefix, prefix_len, name, name_len, &snode, &ext), error);
570
571 if (!snode && !(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
572 LOGVRB("Skipping parsing of unknown node \"%.*s\".", name_len, name);
573
574 /* skip element with children */
575 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
576 return LY_SUCCESS;
577 }
578
Michal Vaskoa5da3292020-08-12 13:10:50 +0200579 /* create metadata/attributes */
580 if (xmlctx->status == LYXML_ATTRIBUTE) {
581 if (snode) {
Michal Vaskoddd76592022-01-17 13:34:48 +0100582 ret = lydxml_metadata(lydctx, snode, &meta);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200583 LY_CHECK_GOTO(ret, error);
584 } else {
Michal Vaskoe0665742021-02-11 11:08:44 +0100585 assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200586 ret = lydxml_attrs(xmlctx, &attr);
587 LY_CHECK_GOTO(ret, error);
588 }
589 }
590
591 assert(xmlctx->status == LYXML_ELEM_CONTENT);
592 if (!snode) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100593 assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200594
595 if (xmlctx->ws_only) {
596 /* ignore WS-only value */
Radek IÅ¡a017270d2021-02-16 10:26:15 +0100597 if (xmlctx->dynamic) {
598 free((char *) xmlctx->value);
599 }
600 xmlctx->dynamic = 0;
601 xmlctx->value = "";
Michal Vaskoa5da3292020-08-12 13:10:50 +0200602 xmlctx->value_len = 0;
Radek Krejci8df109d2021-04-23 12:19:08 +0200603 format = LY_VALUE_XML;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200604 } else {
605 /* get value prefixes */
Radek Krejci8df109d2021-04-23 12:19:08 +0200606 ret = ly_store_prefix_data(xmlctx->ctx, xmlctx->value, xmlctx->value_len, LY_VALUE_XML,
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100607 &xmlctx->ns, &format, &val_prefix_data);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200608 LY_CHECK_GOTO(ret, error);
609 }
610
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200611 /* get NS again, it may have been backed up and restored */
612 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
613 assert(ns);
614
Michal Vaskoa5da3292020-08-12 13:10:50 +0200615 /* create node */
Michal Vasko501af032020-11-11 20:27:44 +0100616 ret = lyd_create_opaq(ctx, name, name_len, prefix, prefix_len, ns->uri, strlen(ns->uri), xmlctx->value,
617 xmlctx->value_len, &xmlctx->dynamic, format, val_prefix_data, LYD_HINT_DATA, &node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200618 LY_CHECK_GOTO(ret, error);
619
620 /* parser next */
621 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
622
623 /* process children */
624 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100625 ret = lydxml_subtree_r(lydctx, node, lyd_node_child_p(node), NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200626 LY_CHECK_GOTO(ret, error);
627 }
628 } else if (snode->nodetype & LYD_NODE_TERM) {
629 /* create node */
Michal Vasko22df3f02020-08-24 13:29:22 +0200630 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 +0200631 &xmlctx->dynamic, LY_VALUE_XML, &xmlctx->ns, LYD_HINT_DATA, &node), error);
Radek Krejciddace2c2021-01-08 11:30:56 +0100632 LOG_LOCSET(snode, node, NULL, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200633
634 if (parent && (node->schema->flags & LYS_KEY)) {
635 /* check the key order, the anchor must never be a key */
Michal Vaskoe0665742021-02-11 11:08:44 +0100636 anchor = lyd_insert_get_next_anchor(lyd_child(parent), node);
Michal Vasko441e0fa2022-03-03 13:45:00 +0100637 if (anchor && anchor->schema && (anchor->schema->flags & LYS_KEY)) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100638 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100639 LOGVAL(ctx, LYVE_DATA, "Invalid position of the key \"%s\" in a list.", node->schema->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200640 ret = LY_EVALID;
641 goto error;
642 } else {
643 LOGWRN(ctx, "Invalid position of the key \"%s\" in a list.", node->schema->name);
644 }
645 }
646 }
647
648 /* parser next */
649 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
650
651 /* no children expected */
652 if (xmlctx->status == LYXML_ELEMENT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100653 LOGVAL(ctx, LYVE_SYNTAX, "Child element \"%.*s\" inside a terminal node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100654 (int)xmlctx->name_len, xmlctx->name, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200655 ret = LY_EVALID;
656 goto error;
657 }
658 } else if (snode->nodetype & LYD_NODE_INNER) {
659 if (!xmlctx->ws_only) {
660 /* value in inner node */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100661 LOGVAL(ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an inner node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100662 (int)xmlctx->value_len, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200663 ret = LY_EVALID;
664 goto error;
665 }
666
667 /* create node */
668 ret = lyd_create_inner(snode, &node);
669 LY_CHECK_GOTO(ret, error);
670
Radek Krejciddace2c2021-01-08 11:30:56 +0100671 LOG_LOCSET(snode, node, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100672
Michal Vaskoa5da3292020-08-12 13:10:50 +0200673 /* parser next */
674 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
675
Michal Vasko8cc3f662022-03-29 11:25:51 +0200676 prev_parse_opts = lydctx->parse_opts;
677 if (ext) {
678 /* only parse these extension data and validate afterwards */
679 lydctx->parse_opts |= LYD_PARSE_ONLY;
680 }
681
Michal Vaskoa5da3292020-08-12 13:10:50 +0200682 /* process children */
683 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100684 ret = lydxml_subtree_r(lydctx, node, lyd_node_child_p(node), NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200685 LY_CHECK_GOTO(ret, error);
686 }
687
Michal Vasko8cc3f662022-03-29 11:25:51 +0200688 /* restore options */
689 lydctx->parse_opts = prev_parse_opts;
690
Michal Vaskoa5da3292020-08-12 13:10:50 +0200691 if (snode->nodetype == LYS_LIST) {
692 /* check all keys exist */
693 LY_CHECK_GOTO(ret = lyd_parse_check_keys(node), error);
694 }
695
Michal Vaskoe0665742021-02-11 11:08:44 +0100696 if (!(lydctx->parse_opts & LYD_PARSE_ONLY)) {
Michal Vaskoa5da3292020-08-12 13:10:50 +0200697 /* new node validation, autodelete CANNOT occur, all nodes are new */
Michal Vaskoe0665742021-02-11 11:08:44 +0100698 ret = lyd_validate_new(lyd_node_child_p(node), snode, NULL, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200699 LY_CHECK_GOTO(ret, error);
700
701 /* add any missing default children */
Michal Vaskoddd76592022-01-17 13:34:48 +0100702 ret = lyd_new_implicit_r(node, lyd_node_child_p(node), NULL, NULL, &lydctx->node_when, &lydctx->node_types,
703 (lydctx->val_opts & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200704 LY_CHECK_GOTO(ret, error);
705 }
706
707 if (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
708 /* rememeber the RPC/action/notification */
709 lydctx->op_node = node;
710 }
711 } else if (snode->nodetype & LYD_NODE_ANY) {
Michal Vasko27c4dce2021-03-04 15:50:50 +0100712 if ((snode->nodetype == LYS_ANYDATA) && !xmlctx->ws_only) {
713 /* value in anydata node, we expect a tree */
714 LOGVAL(ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an anydata node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100715 (int)xmlctx->value_len < 20 ? xmlctx->value_len : 20, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200716 ret = LY_EVALID;
717 goto error;
718 }
719
Michal Vasko27c4dce2021-03-04 15:50:50 +0100720 if (!xmlctx->ws_only) {
721 /* use an arbitrary text value for anyxml */
Michal Vasko742a5b12022-02-24 16:07:27 +0100722 val = strndup(xmlctx->value, xmlctx->value_len);
723 LY_CHECK_ERR_GOTO(!val, LOGMEM(xmlctx->ctx); ret = LY_EMEM, error);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200724
Michal Vasko27c4dce2021-03-04 15:50:50 +0100725 /* parser next */
Michal Vaskoa04107f2022-03-29 12:09:50 +0200726 LY_CHECK_ERR_GOTO(ret = lyxml_ctx_next(xmlctx), free(val), error);
Michal Vasko27c4dce2021-03-04 15:50:50 +0100727
728 /* create node */
729 ret = lyd_create_any(snode, val, LYD_ANYDATA_STRING, 1, &node);
Michal Vasko742a5b12022-02-24 16:07:27 +0100730 LY_CHECK_ERR_GOTO(ret, free(val), error);
Michal Vasko27c4dce2021-03-04 15:50:50 +0100731 } else {
732 /* parser next */
733 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
734
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200735 /* update options so that generic data can be parsed */
736 prev_parse_opts = lydctx->parse_opts;
Michal Vasko27c4dce2021-03-04 15:50:50 +0100737 lydctx->parse_opts &= ~LYD_PARSE_STRICT;
Michal Vasko8cc3f662022-03-29 11:25:51 +0200738 lydctx->parse_opts |= LYD_PARSE_OPAQ | (ext ? LYD_PARSE_ONLY : 0);
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200739 prev_int_opts = lydctx->int_opts;
Michal Vasko02ed9d82021-07-15 14:58:04 +0200740 lydctx->int_opts |= LYD_INTOPT_ANY | LYD_INTOPT_WITH_SIBLINGS;
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200741
742 /* parse any data tree */
Michal Vasko27c4dce2021-03-04 15:50:50 +0100743 anchor = NULL;
744 while (xmlctx->status == LYXML_ELEMENT) {
745 ret = lydxml_subtree_r(lydctx, NULL, &anchor, NULL);
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200746 if (ret) {
Michal Vaskocc53c582022-04-01 12:07:44 +0200747 lyd_free_siblings(anchor);
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200748 break;
749 }
Michal Vasko27c4dce2021-03-04 15:50:50 +0100750 }
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200751
752 /* restore options */
753 lydctx->parse_opts = prev_parse_opts;
754 lydctx->int_opts = prev_int_opts;
755
756 LY_CHECK_GOTO(ret, error);
Michal Vasko27c4dce2021-03-04 15:50:50 +0100757
758 /* create node */
759 ret = lyd_create_any(snode, anchor, LYD_ANYDATA_DATATREE, 1, &node);
760 LY_CHECK_GOTO(ret, error);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200761 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200762 }
763 assert(node);
764
765 /* add/correct flags */
766 if (snode) {
Michal Vasko8cc3f662022-03-29 11:25:51 +0200767 LY_CHECK_GOTO(ret = lyd_parse_set_data_flags(node, &meta, (struct lyd_ctx *)lydctx, ext), error);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200768 }
769
770 /* parser next */
771 assert(xmlctx->status == LYXML_ELEM_CLOSE);
Michal Vaskoddd76592022-01-17 13:34:48 +0100772 if (!parse_subtree) {
773 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
774 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200775
776 /* add metadata/attributes */
777 if (snode) {
Michal Vasko871a0252020-11-11 18:35:24 +0100778 lyd_insert_meta(node, meta, 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200779 } else {
780 lyd_insert_attr(node, attr);
781 }
782
783 /* insert, keep first pointer correct */
Michal Vasko8cc3f662022-03-29 11:25:51 +0200784 if (ext) {
785 LY_CHECK_GOTO(ret = lyd_insert_ext(parent, node), error);
786 } else {
787 lyd_insert_node(parent, first_p, node, lydctx->parse_opts & LYD_PARSE_ORDERED ? 1 : 0);
788 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200789 while (!parent && (*first_p)->prev->next) {
790 *first_p = (*first_p)->prev;
791 }
792
Michal Vaskoe0665742021-02-11 11:08:44 +0100793 /* rememeber a successfully parsed node */
794 if (parsed) {
795 ly_set_add(parsed, node, 1, NULL);
796 }
797
Michal Vasko8cc3f662022-03-29 11:25:51 +0200798 lydctx->parse_opts = orig_parse_opts;
Radek Krejciddace2c2021-01-08 11:30:56 +0100799 LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200800 return LY_SUCCESS;
801
802error:
Michal Vasko8cc3f662022-03-29 11:25:51 +0200803 lydctx->parse_opts = orig_parse_opts;
Radek Krejciddace2c2021-01-08 11:30:56 +0100804 LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
Michal Vasko3a41dff2020-07-15 14:30:28 +0200805 lyd_free_meta_siblings(meta);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200806 lyd_free_attr_siblings(ctx, attr);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200807 lyd_free_tree(node);
Radek Krejcie7b95092019-05-15 11:03:07 +0200808 return ret;
809}
810
Michal Vaskoe0665742021-02-11 11:08:44 +0100811/**
812 * @brief Parse a specific XML element into an opaque node.
813 *
814 * @param[in] xmlctx XML parser context.
815 * @param[in] name Name of the element.
816 * @param[in] uri URI of the element.
817 * @param[in] value Whether a value is expected in the element.
818 * @param[out] evnp Parsed envelope (opaque node).
819 * @return LY_SUCCESS on success.
820 * @return LY_ENOT if the specified element did not match.
821 * @return LY_ERR value on error.
822 */
Michal Vasko1bf09392020-03-27 12:38:10 +0100823static LY_ERR
Michal Vaskoe0665742021-02-11 11:08:44 +0100824lydxml_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 +0100825{
Michal Vaskoe0665742021-02-11 11:08:44 +0100826 LY_ERR rc = LY_SUCCESS;
827 const struct lyxml_ns *ns;
Radek Krejci1798aae2020-07-14 13:26:06 +0200828 struct lyd_attr *attr = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100829 const char *prefix;
830 size_t prefix_len;
831
Michal Vasko1bf09392020-03-27 12:38:10 +0100832 assert(xmlctx->status == LYXML_ELEMENT);
833 if (ly_strncmp(name, xmlctx->name, xmlctx->name_len)) {
834 /* not the expected element */
Michal Vaskoe0665742021-02-11 11:08:44 +0100835 return LY_ENOT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100836 }
837
838 prefix = xmlctx->prefix;
839 prefix_len = xmlctx->prefix_len;
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200840 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100841 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100842 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +0100843 return LY_EVALID;
844 } else if (strcmp(ns->uri, uri)) {
845 /* different namespace */
846 return LY_ENOT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100847 }
848
849 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
850
851 /* create attributes */
852 if (xmlctx->status == LYXML_ATTRIBUTE) {
853 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
854 }
855
Michal Vaskoe0665742021-02-11 11:08:44 +0100856 assert(xmlctx->status == LYXML_ELEM_CONTENT);
857 if (!value && !xmlctx->ws_only) {
858 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected value \"%.*s\" in the \"%s\" element.",
Radek Krejci422afb12021-03-04 16:38:16 +0100859 (int)xmlctx->value_len, xmlctx->value, name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100860 rc = LY_EVALID;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100861 goto cleanup;
Michal Vaskoe0665742021-02-11 11:08:44 +0100862 }
Michal Vaskoa8edff02020-03-27 14:47:01 +0100863
864 /* create node */
Michal Vaskoe0665742021-02-11 11:08:44 +0100865 rc = lyd_create_opaq(xmlctx->ctx, name, strlen(name), prefix, prefix_len, uri, strlen(uri), xmlctx->value,
Radek Krejci8df109d2021-04-23 12:19:08 +0200866 xmlctx->ws_only ? 0 : xmlctx->value_len, NULL, LY_VALUE_XML, NULL, 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100867 LY_CHECK_GOTO(rc, cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100868
869 /* assign atributes */
Michal Vaskoe0665742021-02-11 11:08:44 +0100870 ((struct lyd_node_opaq *)(*envp))->attr = attr;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100871 attr = NULL;
872
Michal Vaskoe0665742021-02-11 11:08:44 +0100873 /* parser next element */
874 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100875
Michal Vaskoe0665742021-02-11 11:08:44 +0100876cleanup:
877 lyd_free_attr_siblings(xmlctx->ctx, attr);
878 if (rc) {
879 lyd_free_tree(*envp);
880 *envp = NULL;
881 }
882 return rc;
883}
884
885/**
886 * @brief Parse all expected non-data XML elements of a NETCONF rpc message.
887 *
888 * @param[in] xmlctx XML parser context.
889 * @param[out] evnp Parsed envelope(s) (opaque node).
890 * @param[out] int_opts Internal options for parsing the rest of YANG data.
891 * @param[out] close_elem Number of parsed opened elements that need to be closed.
892 * @return LY_SUCCESS on success.
893 * @return LY_ERR value on error.
894 */
895static LY_ERR
896lydxml_env_netconf_rpc(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
897{
898 LY_ERR rc = LY_SUCCESS, r;
899 struct lyd_node *child;
900
901 assert(envp && !*envp);
902
903 /* parse "rpc" */
904 r = lydxml_envelope(xmlctx, "rpc", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100905 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
906
907 /* parse "action", if any */
908 r = lydxml_envelope(xmlctx, "action", "urn:ietf:params:xml:ns:yang:1", 0, &child);
909 if (r == LY_SUCCESS) {
910 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +0200911 lyd_insert_node(*envp, NULL, child, 0);
Michal Vaskoe0665742021-02-11 11:08:44 +0100912
913 /* NETCONF action */
914 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_ACTION;
915 *close_elem = 2;
916 } else if (r == LY_ENOT) {
917 /* NETCONF RPC */
918 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_RPC;
919 *close_elem = 1;
920 } else {
921 rc = r;
922 goto cleanup;
923 }
924
925cleanup:
926 if (rc) {
927 lyd_free_tree(*envp);
928 *envp = NULL;
929 }
930 return rc;
931}
932
933/**
934 * @brief Parse all expected non-data XML elements of a NETCONF notification message.
935 *
936 * @param[in] xmlctx XML parser context.
937 * @param[out] evnp Parsed envelope(s) (opaque node).
938 * @param[out] int_opts Internal options for parsing the rest of YANG data.
939 * @param[out] close_elem Number of parsed opened elements that need to be closed.
940 * @return LY_SUCCESS on success.
941 * @return LY_ERR value on error.
942 */
943static LY_ERR
944lydxml_env_netconf_notif(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
945{
946 LY_ERR rc = LY_SUCCESS, r;
947 struct lyd_node *child;
948
949 assert(envp && !*envp);
950
951 /* parse "notification" */
952 r = lydxml_envelope(xmlctx, "notification", "urn:ietf:params:xml:ns:netconf:notification:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100953 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
954
955 /* parse "eventTime" */
956 r = lydxml_envelope(xmlctx, "eventTime", "urn:ietf:params:xml:ns:netconf:notification:1.0", 1, &child);
957 if (r == LY_ENOT) {
Radek Krejci422afb12021-03-04 16:38:16 +0100958 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unexpected element \"%.*s\" instead of \"eventTime\".",
959 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100960 r = LY_EVALID;
961 }
962 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
963
964 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +0200965 lyd_insert_node(*envp, NULL, child, 0);
Michal Vaskoe0665742021-02-11 11:08:44 +0100966
967 /* validate value */
968 /* TODO validate child->value as yang:date-and-time */
969
970 /* finish child parsing */
Michal Vaskoa8edff02020-03-27 14:47:01 +0100971 if (xmlctx->status != LYXML_ELEM_CLOSE) {
972 assert(xmlctx->status == LYXML_ELEMENT);
Michal Vaskoe0665742021-02-11 11:08:44 +0100973 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"eventTime\".",
Radek Krejci422afb12021-03-04 16:38:16 +0100974 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100975 rc = LY_EVALID;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100976 goto cleanup;
977 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100978 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
979
980 /* NETCONF notification */
981 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_NOTIF;
982 *close_elem = 1;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100983
984cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +0100985 if (rc) {
Michal Vaskoa8edff02020-03-27 14:47:01 +0100986 lyd_free_tree(*envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100987 *envp = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100988 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100989 return rc;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100990}
Michal Vasko79135ae2020-12-16 10:08:35 +0100991
Michal Vaskoe0665742021-02-11 11:08:44 +0100992/**
993 * @brief Parse an XML element as an opaque node subtree.
994 *
995 * @param[in] xmlctx XML parser context.
996 * @param[in] parent Parent to append nodes to.
997 * @return LY_ERR value.
998 */
999static LY_ERR
1000lydxml_opaq_r(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
Michal Vaskoa8edff02020-03-27 14:47:01 +01001001{
Michal Vaskoe0665742021-02-11 11:08:44 +01001002 LY_ERR rc = LY_SUCCESS;
1003 const struct lyxml_ns *ns;
1004 struct lyd_attr *attr = NULL;
1005 struct lyd_node *child = NULL;
1006 const char *name, *prefix;
1007 size_t name_len, prefix_len;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001008
Michal Vaskoe0665742021-02-11 11:08:44 +01001009 assert(xmlctx->status == LYXML_ELEMENT);
Michal Vaskoa8edff02020-03-27 14:47:01 +01001010
Michal Vaskoe0665742021-02-11 11:08:44 +01001011 name = xmlctx->name;
1012 name_len = xmlctx->name_len;
1013 prefix = xmlctx->prefix;
1014 prefix_len = xmlctx->prefix_len;
1015 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
1016 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +01001017 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +01001018 return LY_EVALID;
1019 }
Michal Vaskoa8edff02020-03-27 14:47:01 +01001020
Michal Vaskoe0665742021-02-11 11:08:44 +01001021 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
Michal Vaskoa8edff02020-03-27 14:47:01 +01001022
Michal Vaskoe0665742021-02-11 11:08:44 +01001023 /* create attributes */
1024 if (xmlctx->status == LYXML_ATTRIBUTE) {
1025 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
1026 }
1027
1028 /* create node */
1029 assert(xmlctx->status == LYXML_ELEM_CONTENT);
1030 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 +02001031 xmlctx->ws_only ? 0 : xmlctx->value_len, NULL, LY_VALUE_XML, NULL, 0, &child);
Michal Vaskoe0665742021-02-11 11:08:44 +01001032 LY_CHECK_GOTO(rc, cleanup);
1033
1034 /* assign atributes */
1035 ((struct lyd_node_opaq *)child)->attr = attr;
1036 attr = NULL;
1037
1038 /* parser next element */
1039 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1040
1041 /* parse all the descendants */
1042 while (xmlctx->status == LYXML_ELEMENT) {
1043 rc = lydxml_opaq_r(xmlctx, child);
1044 LY_CHECK_GOTO(rc, cleanup);
1045 }
1046
1047 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001048 lyd_insert_node(parent, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +01001049
1050cleanup:
1051 lyd_free_attr_siblings(xmlctx->ctx, attr);
1052 if (rc) {
1053 lyd_free_tree(child);
1054 }
1055 return rc;
1056}
1057
1058/**
1059 * @brief Parse all expected non-data XML elements of the error-info element in NETCONF rpc-reply message.
1060 *
1061 * @param[in] xmlctx XML parser context.
1062 * @param[in] parent Parent to append nodes to.
1063 * @return LY_ERR value.
1064 */
1065static LY_ERR
1066lydxml_env_netconf_rpc_reply_error_info(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
1067{
1068 LY_ERR r;
1069 struct lyd_node *child, *iter;
1070 const struct lyxml_ns *ns;
1071 ly_bool no_dup;
1072
1073 /* there must be some child */
1074 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1075 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"error-info\".");
1076 return LY_EVALID;
1077 }
1078
1079 while (xmlctx->status == LYXML_ELEMENT) {
1080 child = NULL;
1081
1082 /*
1083 * session-id
1084 */
1085 r = lydxml_envelope(xmlctx, "session-id", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1086 if (r == LY_SUCCESS) {
1087 no_dup = 1;
1088 goto check_child;
1089 } else if (r != LY_ENOT) {
1090 goto error;
1091 }
1092
1093 /*
1094 * bad-attribute
1095 */
1096 r = lydxml_envelope(xmlctx, "bad-attribute", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1097 if (r == LY_SUCCESS) {
1098 no_dup = 1;
1099 goto check_child;
1100 } else if (r != LY_ENOT) {
1101 goto error;
1102 }
1103
1104 /*
1105 * bad-element
1106 */
1107 r = lydxml_envelope(xmlctx, "bad-element", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1108 if (r == LY_SUCCESS) {
1109 no_dup = 1;
1110 goto check_child;
1111 } else if (r != LY_ENOT) {
1112 goto error;
1113 }
1114
1115 /*
1116 * bad-namespace
1117 */
1118 r = lydxml_envelope(xmlctx, "bad-namespace", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1119 if (r == LY_SUCCESS) {
1120 no_dup = 1;
1121 goto check_child;
1122 } else if (r != LY_ENOT) {
1123 goto error;
1124 }
1125
1126 if (r == LY_ENOT) {
1127 assert(xmlctx->status == LYXML_ELEMENT);
1128
1129 /* learn namespace */
1130 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
1131 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +01001132 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)xmlctx->prefix_len, xmlctx->prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +01001133 r = LY_EVALID;
1134 goto error;
1135 } else if (!strcmp(ns->uri, "urn:ietf:params:xml:ns:netconf:base:1.0")) {
1136 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"error-info\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001137 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001138 r = LY_EVALID;
1139 goto error;
1140 }
1141
1142 /* custom elements */
1143 r = lydxml_opaq_r(xmlctx, parent);
1144 LY_CHECK_GOTO(r, error);
Michal Vasko6398eaf2022-01-10 10:12:30 +01001145 continue;
Michal Vaskoe0665742021-02-11 11:08:44 +01001146 }
1147
1148check_child:
1149 /* check for duplicates */
1150 if (no_dup) {
1151 LY_LIST_FOR(lyd_child(parent), iter) {
1152 if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
1153 (((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
1154 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"error-info\".",
1155 ((struct lyd_node_opaq *)child)->name.name);
1156 r = LY_EVALID;
1157 goto error;
1158 }
1159 }
1160 }
1161
1162 /* finish child parsing */
1163 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1164 assert(xmlctx->status == LYXML_ELEMENT);
1165 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"error-info\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001166 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001167 r = LY_EVALID;
1168 goto error;
1169 }
1170 LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
1171
1172 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001173 lyd_insert_node(parent, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +01001174 }
1175
1176 return LY_SUCCESS;
1177
1178error:
1179 lyd_free_tree(child);
1180 return r;
1181}
1182
1183/**
1184 * @brief Parse all expected non-data XML elements of the rpc-error element in NETCONF rpc-reply message.
1185 *
1186 * @param[in] xmlctx XML parser context.
1187 * @param[in] parent Parent to append nodes to.
1188 * @return LY_ERR value.
1189 */
1190static LY_ERR
1191lydxml_env_netconf_rpc_reply_error(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
1192{
1193 LY_ERR r;
1194 struct lyd_node *child, *iter;
1195 const char *val;
1196 ly_bool no_dup;
1197
1198 /* there must be some child */
1199 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1200 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"rpc-error\".");
1201 return LY_EVALID;
1202 }
1203
1204 while (xmlctx->status == LYXML_ELEMENT) {
1205 child = NULL;
1206
1207 /*
1208 * error-type
1209 */
1210 r = lydxml_envelope(xmlctx, "error-type", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1211 if (r == LY_SUCCESS) {
1212 val = ((struct lyd_node_opaq *)child)->value;
1213 if (strcmp(val, "transport") && strcmp(val, "rpc") && strcmp(val, "protocol") && strcmp(val, "application")) {
1214 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1215 ((struct lyd_node_opaq *)child)->name.name);
1216 r = LY_EVALID;
1217 goto error;
1218 }
1219
1220 no_dup = 1;
1221 goto check_child;
1222 } else if (r != LY_ENOT) {
1223 goto error;
1224 }
1225
1226 /*
1227 * error-tag
1228 */
1229 r = lydxml_envelope(xmlctx, "error-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1230 if (r == LY_SUCCESS) {
1231 val = ((struct lyd_node_opaq *)child)->value;
1232 if (strcmp(val, "in-use") && strcmp(val, "invalid-value") && strcmp(val, "too-big") &&
1233 strcmp(val, "missing-attribute") && strcmp(val, "bad-attribute") &&
1234 strcmp(val, "unknown-attribute") && strcmp(val, "missing-element") && strcmp(val, "bad-element") &&
1235 strcmp(val, "unknown-element") && strcmp(val, "unknown-namespace") && strcmp(val, "access-denied") &&
1236 strcmp(val, "lock-denied") && strcmp(val, "resource-denied") && strcmp(val, "rollback-failed") &&
1237 strcmp(val, "data-exists") && strcmp(val, "data-missing") && strcmp(val, "operation-not-supported") &&
1238 strcmp(val, "operation-failed") && strcmp(val, "malformed-message")) {
1239 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1240 ((struct lyd_node_opaq *)child)->name.name);
1241 r = LY_EVALID;
1242 goto error;
1243 }
1244
1245 no_dup = 1;
1246 goto check_child;
1247 } else if (r != LY_ENOT) {
1248 goto error;
1249 }
1250
1251 /*
1252 * error-severity
1253 */
1254 r = lydxml_envelope(xmlctx, "error-severity", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1255 if (r == LY_SUCCESS) {
1256 val = ((struct lyd_node_opaq *)child)->value;
1257 if (strcmp(val, "error") && strcmp(val, "warning")) {
1258 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1259 ((struct lyd_node_opaq *)child)->name.name);
1260 r = LY_EVALID;
1261 goto error;
1262 }
1263
1264 no_dup = 1;
1265 goto check_child;
1266 } else if (r != LY_ENOT) {
1267 goto error;
1268 }
1269
1270 /*
1271 * error-app-tag
1272 */
1273 r = lydxml_envelope(xmlctx, "error-app-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1274 if (r == LY_SUCCESS) {
1275 no_dup = 1;
1276 goto check_child;
1277 } else if (r != LY_ENOT) {
1278 goto error;
1279 }
1280
1281 /*
1282 * error-path
1283 */
1284 r = lydxml_envelope(xmlctx, "error-path", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1285 if (r == LY_SUCCESS) {
1286 no_dup = 1;
1287 goto check_child;
1288 } else if (r != LY_ENOT) {
1289 goto error;
1290 }
1291
1292 /*
1293 * error-message
1294 */
1295 r = lydxml_envelope(xmlctx, "error-message", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1296 if (r == LY_SUCCESS) {
1297 no_dup = 1;
1298 goto check_child;
1299 } else if (r != LY_ENOT) {
1300 goto error;
1301 }
1302
1303 /* error-info */
1304 r = lydxml_envelope(xmlctx, "error-info", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1305 if (r == LY_SUCCESS) {
1306 /* parse all the descendants */
1307 LY_CHECK_GOTO(r = lydxml_env_netconf_rpc_reply_error_info(xmlctx, child), error);
1308
1309 no_dup = 0;
1310 goto check_child;
1311 } else if (r != LY_ENOT) {
1312 goto error;
1313 }
1314
1315 if (r == LY_ENOT) {
1316 assert(xmlctx->status == LYXML_ELEMENT);
1317 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001318 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001319 r = LY_EVALID;
1320 goto error;
1321 }
1322
1323check_child:
1324 /* check for duplicates */
1325 if (no_dup) {
1326 LY_LIST_FOR(lyd_child(parent), iter) {
1327 if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
1328 (((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
1329 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"rpc-error\".",
1330 ((struct lyd_node_opaq *)child)->name.name);
1331 r = LY_EVALID;
1332 goto error;
1333 }
1334 }
1335 }
1336
1337 /* finish child parsing */
1338 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1339 assert(xmlctx->status == LYXML_ELEMENT);
1340 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001341 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001342 r = LY_EVALID;
1343 goto error;
1344 }
1345 LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
1346
1347 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001348 lyd_insert_node(parent, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +01001349 }
1350
1351 return LY_SUCCESS;
1352
1353error:
1354 lyd_free_tree(child);
1355 return r;
1356}
1357
1358/**
1359 * @brief Parse all expected non-data XML elements of a NETCONF rpc-reply message.
1360 *
1361 * @param[in] xmlctx XML parser context.
1362 * @param[out] evnp Parsed envelope(s) (opaque node).
1363 * @param[out] int_opts Internal options for parsing the rest of YANG data.
1364 * @param[out] close_elem Number of parsed opened elements that need to be closed.
1365 * @return LY_SUCCESS on success.
1366 * @return LY_ERR value on error.
1367 */
1368static LY_ERR
1369lydxml_env_netconf_reply(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
1370{
1371 LY_ERR rc = LY_SUCCESS, r;
1372 struct lyd_node *child = NULL;
1373 const char *parsed_elem = NULL;
1374
1375 assert(envp && !*envp);
1376
1377 /* parse "rpc-reply" */
1378 r = lydxml_envelope(xmlctx, "rpc-reply", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +01001379 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1380
1381 /* there must be some child */
1382 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1383 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"rpc-reply\".");
1384 rc = LY_EVALID;
Michal Vaskocf770e22020-08-12 13:21:43 +02001385 goto cleanup;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001386 }
1387
Michal Vaskoe0665742021-02-11 11:08:44 +01001388 /* try to parse "ok" */
1389 r = lydxml_envelope(xmlctx, "ok", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1390 if (r == LY_SUCCESS) {
1391 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001392 lyd_insert_node(*envp, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +01001393
1394 /* finish child parsing */
1395 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1396 assert(xmlctx->status == LYXML_ELEMENT);
1397 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"ok\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001398 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001399 rc = LY_EVALID;
1400 goto cleanup;
1401 }
1402 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1403
1404 /* success */
1405 parsed_elem = "ok";
1406 goto finish;
1407 } else if (r != LY_ENOT) {
1408 rc = r;
1409 goto cleanup;
Michal Vasko2552ea32020-12-08 15:32:34 +01001410 }
1411
Michal Vaskoe0665742021-02-11 11:08:44 +01001412 /* try to parse all "rpc-error" elements */
1413 while (xmlctx->status == LYXML_ELEMENT) {
1414 r = lydxml_envelope(xmlctx, "rpc-error", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1415 if (r == LY_ENOT) {
1416 break;
1417 } else if (r) {
1418 rc = r;
1419 goto cleanup;
1420 }
1421
1422 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001423 lyd_insert_node(*envp, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +01001424
1425 /* parse all children of "rpc-error" */
1426 LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc_reply_error(xmlctx, child), cleanup);
1427
1428 /* finish child parsing */
1429 assert(xmlctx->status == LYXML_ELEM_CLOSE);
1430 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1431
1432 parsed_elem = "rpc-error";
Michal Vasko2552ea32020-12-08 15:32:34 +01001433 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001434
1435finish:
1436 if (parsed_elem) {
1437 /* NETCONF rpc-reply with no data */
1438 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1439 assert(xmlctx->status == LYXML_ELEMENT);
1440 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"%s\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001441 (int)xmlctx->name_len, xmlctx->name, parsed_elem);
Michal Vaskoe0665742021-02-11 11:08:44 +01001442 rc = LY_EVALID;
1443 goto cleanup;
1444 }
1445 }
1446
1447 /* NETCONF rpc-reply */
Michal Vasko1d991fd2021-07-09 13:14:40 +02001448 *int_opts = LYD_INTOPT_WITH_SIBLINGS | LYD_INTOPT_REPLY;
Michal Vaskoe0665742021-02-11 11:08:44 +01001449 *close_elem = 1;
1450
1451cleanup:
1452 if (rc) {
1453 lyd_free_tree(*envp);
1454 *envp = NULL;
1455 }
1456 return rc;
1457}
1458
Michal Vasko2552ea32020-12-08 15:32:34 +01001459LY_ERR
Radek Krejcif16e2542021-02-17 15:39:23 +01001460lyd_parse_xml(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
1461 struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type,
Michal Vaskoddd76592022-01-17 13:34:48 +01001462 struct lyd_node **envp, struct ly_set *parsed, ly_bool *subtree_sibling, struct lyd_ctx **lydctx_p)
Michal Vasko2552ea32020-12-08 15:32:34 +01001463{
Michal Vaskoe0665742021-02-11 11:08:44 +01001464 LY_ERR rc = LY_SUCCESS;
1465 struct lyd_xml_ctx *lydctx;
Michal Vasko2ca9f9e2021-07-02 09:21:36 +02001466 uint32_t i, int_opts = 0, close_elem = 0;
Michal Vaskoe0665742021-02-11 11:08:44 +01001467 ly_bool parsed_data_nodes = 0;
Michal Vaskoddd76592022-01-17 13:34:48 +01001468 enum LYXML_PARSER_STATUS status;
Michal Vasko2552ea32020-12-08 15:32:34 +01001469
Michal Vaskoe0665742021-02-11 11:08:44 +01001470 assert(ctx && in && lydctx_p);
1471 assert(!(parse_opts & ~LYD_PARSE_OPTS_MASK));
1472 assert(!(val_opts & ~LYD_VALIDATE_OPTS_MASK));
Michal Vasko2552ea32020-12-08 15:32:34 +01001473
Michal Vaskoe0665742021-02-11 11:08:44 +01001474 /* init context */
1475 lydctx = calloc(1, sizeof *lydctx);
1476 LY_CHECK_ERR_RET(!lydctx, LOGMEM(ctx), LY_EMEM);
1477 LY_CHECK_GOTO(rc = lyxml_ctx_new(ctx, in, &lydctx->xmlctx), cleanup);
1478 lydctx->parse_opts = parse_opts;
1479 lydctx->val_opts = val_opts;
1480 lydctx->free = lyd_xml_ctx_free;
Radek Krejcif16e2542021-02-17 15:39:23 +01001481 lydctx->ext = ext;
Michal Vasko2552ea32020-12-08 15:32:34 +01001482
Michal Vaskoe0665742021-02-11 11:08:44 +01001483 switch (data_type) {
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001484 case LYD_TYPE_DATA_YANG:
Michal Vaskoddd76592022-01-17 13:34:48 +01001485 if (!(parse_opts & LYD_PARSE_SUBTREE)) {
1486 int_opts = LYD_INTOPT_WITH_SIBLINGS;
1487 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001488 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001489 case LYD_TYPE_RPC_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001490 int_opts = LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NO_SIBLINGS;
1491 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001492 case LYD_TYPE_NOTIF_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001493 int_opts = LYD_INTOPT_NOTIF | LYD_INTOPT_NO_SIBLINGS;
1494 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001495 case LYD_TYPE_REPLY_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001496 int_opts = LYD_INTOPT_REPLY | LYD_INTOPT_NO_SIBLINGS;
1497 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001498 case LYD_TYPE_RPC_NETCONF:
Michal Vaskoe0665742021-02-11 11:08:44 +01001499 assert(!parent);
1500 LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
1501 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001502 case LYD_TYPE_NOTIF_NETCONF:
1503 assert(!parent);
1504 LY_CHECK_GOTO(rc = lydxml_env_netconf_notif(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
1505 break;
1506 case LYD_TYPE_REPLY_NETCONF:
Michal Vaskoe0665742021-02-11 11:08:44 +01001507 assert(parent);
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001508 LY_CHECK_GOTO(rc = lydxml_env_netconf_reply(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
Michal Vaskoe0665742021-02-11 11:08:44 +01001509 break;
1510 }
1511 lydctx->int_opts = int_opts;
1512
1513 /* find the operation node if it exists already */
1514 LY_CHECK_GOTO(rc = lyd_parser_find_operation(parent, int_opts, &lydctx->op_node), cleanup);
1515
1516 /* parse XML data */
1517 while (lydctx->xmlctx->status == LYXML_ELEMENT) {
1518 LY_CHECK_GOTO(rc = lydxml_subtree_r(lydctx, parent, first_p, parsed), cleanup);
1519 parsed_data_nodes = 1;
1520
1521 if (!(int_opts & LYD_INTOPT_WITH_SIBLINGS)) {
1522 break;
1523 }
Michal Vasko2552ea32020-12-08 15:32:34 +01001524 }
1525
Michal Vaskoe0665742021-02-11 11:08:44 +01001526 /* close all opened elements */
1527 for (i = 0; i < close_elem; ++i) {
1528 if (lydctx->xmlctx->status != LYXML_ELEM_CLOSE) {
1529 assert(lydctx->xmlctx->status == LYXML_ELEMENT);
Radek Krejci422afb12021-03-04 16:38:16 +01001530 LOGVAL(lydctx->xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\".",
1531 (int)lydctx->xmlctx->name_len, lydctx->xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001532 rc = LY_EVALID;
1533 goto cleanup;
1534 }
1535
1536 LY_CHECK_GOTO(rc = lyxml_ctx_next(lydctx->xmlctx), cleanup);
Michal Vasko4189c0f2020-08-13 09:05:22 +02001537 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001538
1539 /* check final state */
1540 if ((int_opts & LYD_INTOPT_NO_SIBLINGS) && (lydctx->xmlctx->status == LYXML_ELEMENT)) {
1541 LOGVAL(ctx, LYVE_SYNTAX, "Unexpected sibling node.");
1542 rc = LY_EVALID;
1543 goto cleanup;
1544 }
Michal Vaskoc939fdd2022-01-03 11:35:13 +01001545 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 +01001546 LOGVAL(ctx, LYVE_DATA, "Missing the operation node.");
1547 rc = LY_EVALID;
1548 goto cleanup;
1549 }
1550
1551 if (!parsed_data_nodes) {
1552 /* no data nodes were parsed */
1553 lydctx->op_node = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001554 }
1555
Michal Vaskoddd76592022-01-17 13:34:48 +01001556 if (parse_opts & LYD_PARSE_SUBTREE) {
1557 /* check for a sibling element */
1558 assert(subtree_sibling);
1559 if (!lyxml_ctx_peek(lydctx->xmlctx, &status) && (status == LYXML_ELEMENT)) {
1560 *subtree_sibling = 1;
1561 } else {
1562 *subtree_sibling = 0;
1563 }
1564 }
1565
Michal Vaskoa8edff02020-03-27 14:47:01 +01001566cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +01001567 /* there should be no unres stored if validation should be skipped */
1568 assert(!(parse_opts & LYD_PARSE_ONLY) || (!lydctx->node_types.count && !lydctx->meta_types.count &&
Michal Vaskoddd76592022-01-17 13:34:48 +01001569 !lydctx->node_when.count));
Michal Vaskoe0665742021-02-11 11:08:44 +01001570
1571 if (rc) {
1572 lyd_xml_ctx_free((struct lyd_ctx *)lydctx);
1573 } else {
1574 *lydctx_p = (struct lyd_ctx *)lydctx;
1575
1576 /* the XML context is no more needed, freeing it also stops logging line numbers which would be confusing now */
1577 lyxml_ctx_free(lydctx->xmlctx);
1578 lydctx->xmlctx = NULL;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001579 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001580 return rc;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001581}