blob: 77cd720b03a077e065ea4a4a1abdebe2659d6b67 [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 Vasko46f7ac92022-02-24 16:07:27 +010015#define _GNU_SOURCE
16
Michal Vasko69730152020-10-09 16:30:07 +020017#include <assert.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020018#include <stdint.h>
19#include <stdlib.h>
20#include <string.h>
21
Radek Krejci535ea9f2020-05-29 16:01:05 +020022#include "common.h"
Michal Vasko46f7ac92022-02-24 16:07:27 +010023#include "compat.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020024#include "context.h"
Radek Krejci77114102021-03-10 15:21:57 +010025#include "dict.h"
Michal Vaskoafac7822020-10-20 14:22:26 +020026#include "in_internal.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020027#include "log.h"
Radek Krejci7931b192020-06-25 17:05:03 +020028#include "parser_data.h"
29#include "parser_internal.h"
tadeas-vintrlikbf8aa6e2021-11-03 13:07:34 +010030#include "plugins_exts.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020031#include "set.h"
Radek Krejci77114102021-03-10 15:21:57 +010032#include "tree.h"
Radek Krejci47fab892020-11-05 17:02:41 +010033#include "tree_data.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020034#include "tree_data_internal.h"
35#include "tree_schema.h"
Radek Krejci77114102021-03-10 15:21:57 +010036#include "tree_schema_internal.h"
Michal Vaskocde73ac2019-11-14 16:10:27 +010037#include "validation.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020038#include "xml.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020039
Radek Krejci1798aae2020-07-14 13:26:06 +020040void
41lyd_xml_ctx_free(struct lyd_ctx *lydctx)
42{
43 struct lyd_xml_ctx *ctx = (struct lyd_xml_ctx *)lydctx;
44
45 lyd_ctx_free(lydctx);
46 lyxml_ctx_free(ctx->xmlctx);
47 free(ctx);
48}
49
Michal Vasko45791ad2021-06-17 08:45:03 +020050/**
51 * @brief Parse and create XML metadata.
52 *
53 * @param[in] lydctx XML data parser context.
Michal Vaskoaac267d2022-01-17 13:34:48 +010054 * @param[in] sparent Schema node of the parent.
Michal Vasko45791ad2021-06-17 08:45:03 +020055 * @param[out] meta List of created metadata instances.
56 * @return LY_ERR value.
57 */
Radek Krejcie7b95092019-05-15 11:03:07 +020058static LY_ERR
Michal Vaskoaac267d2022-01-17 13:34:48 +010059lydxml_metadata(struct lyd_xml_ctx *lydctx, const struct lysc_node *sparent, struct lyd_meta **meta)
Radek Krejcie7b95092019-05-15 11:03:07 +020060{
aPiecek1c4da362021-04-29 14:26:34 +020061 LY_ERR ret = LY_SUCCESS;
Radek Krejci28681fa2019-09-06 13:08:45 +020062 const struct lyxml_ns *ns;
63 struct lys_module *mod;
Michal Vaskob36053d2020-03-26 15:49:30 +010064 const char *name;
65 size_t name_len;
Michal Vasko45791ad2021-06-17 08:45:03 +020066 LY_ARRAY_COUNT_TYPE u;
67 ly_bool filter_attrs = 0;
Radek Krejci1798aae2020-07-14 13:26:06 +020068 struct lyxml_ctx *xmlctx = lydctx->xmlctx;
Radek Krejci28681fa2019-09-06 13:08:45 +020069
Michal Vaskob36053d2020-03-26 15:49:30 +010070 *meta = NULL;
Radek Krejci28681fa2019-09-06 13:08:45 +020071
Michal Vasko45791ad2021-06-17 08:45:03 +020072 /* check for NETCONF filter unqualified attributes */
Michal Vaskoaac267d2022-01-17 13:34:48 +010073 LY_ARRAY_FOR(sparent->exts, u) {
74 if (!strcmp(sparent->exts[u].def->name, "get-filter-element-attributes") &&
75 !strcmp(sparent->exts[u].def->module->name, "ietf-netconf")) {
Michal Vasko45791ad2021-06-17 08:45:03 +020076 filter_attrs = 1;
77 break;
78 }
79 }
80
Michal Vaskob36053d2020-03-26 15:49:30 +010081 while (xmlctx->status == LYXML_ATTRIBUTE) {
82 if (!xmlctx->prefix_len) {
Michal Vasko45791ad2021-06-17 08:45:03 +020083 /* in XML all attributes must be prefixed except NETCONF filter ones marked by an extension */
84 if (filter_attrs && (!ly_strncmp("type", xmlctx->name, xmlctx->name_len) ||
85 !ly_strncmp("select", xmlctx->name, xmlctx->name_len))) {
86 mod = ly_ctx_get_module_implemented(xmlctx->ctx, "ietf-netconf");
87 if (!mod) {
88 LOGVAL(xmlctx->ctx, LYVE_REFERENCE,
89 "Missing (or not implemented) YANG module \"ietf-netconf\" for special filter attributes.");
90 ret = LY_ENOTFOUND;
91 goto cleanup;
92 }
93 goto create_meta;
94 }
95
Michal Vaskoe0665742021-02-11 11:08:44 +010096 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +010097 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Missing mandatory prefix for XML metadata \"%.*s\".",
Radek Krejci422afb12021-03-04 16:38:16 +010098 (int)xmlctx->name_len, xmlctx->name);
Michal Vasko45791ad2021-06-17 08:45:03 +020099 ret = LY_EVALID;
Michal Vaskob36053d2020-03-26 15:49:30 +0100100 goto cleanup;
Radek Krejci28681fa2019-09-06 13:08:45 +0200101 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100102
Michal Vasko45791ad2021-06-17 08:45:03 +0200103 /* skip attr */
Michal Vaskob36053d2020-03-26 15:49:30 +0100104 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
105 assert(xmlctx->status == LYXML_ATTR_CONTENT);
106 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejci28681fa2019-09-06 13:08:45 +0200107 continue;
108 }
109
110 /* get namespace of the attribute to find its annotation definition */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200111 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
Radek Krejci28681fa2019-09-06 13:08:45 +0200112 if (!ns) {
Michal Vasko52927e22020-03-16 17:26:14 +0100113 /* unknown namespace, XML error */
Radek Krejci422afb12021-03-04 16:38:16 +0100114 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)xmlctx->prefix_len, xmlctx->prefix);
Michal Vasko45791ad2021-06-17 08:45:03 +0200115 ret = LY_ENOTFOUND;
Radek Krejci28681fa2019-09-06 13:08:45 +0200116 goto cleanup;
117 }
Michal Vasko45791ad2021-06-17 08:45:03 +0200118
119 /* get the module with metadata definition */
Michal Vasko52927e22020-03-16 17:26:14 +0100120 mod = ly_ctx_get_module_implemented_ns(xmlctx->ctx, ns->uri);
Radek Krejci28681fa2019-09-06 13:08:45 +0200121 if (!mod) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100122 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100123 LOGVAL(xmlctx->ctx, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +0200124 "Unknown (or not implemented) YANG module with namespace \"%s\" for metadata \"%.*s%s%.*s\".",
Radek Krejci422afb12021-03-04 16:38:16 +0100125 ns->uri, (int)xmlctx->prefix_len, xmlctx->prefix, xmlctx->prefix_len ? ":" : "",
126 (int)xmlctx->name_len, xmlctx->name);
Michal Vasko45791ad2021-06-17 08:45:03 +0200127 ret = LY_ENOTFOUND;
Michal Vaskob36053d2020-03-26 15:49:30 +0100128 goto cleanup;
Radek Krejci28681fa2019-09-06 13:08:45 +0200129 }
Michal Vasko45791ad2021-06-17 08:45:03 +0200130
131 /* skip attr */
132 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
133 assert(xmlctx->status == LYXML_ATTR_CONTENT);
134 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
135 continue;
Radek Krejci28681fa2019-09-06 13:08:45 +0200136 }
137
Michal Vasko45791ad2021-06-17 08:45:03 +0200138create_meta:
Michal Vasko60ea6352020-06-29 13:39:39 +0200139 /* remember meta name and get its content */
Michal Vaskob36053d2020-03-26 15:49:30 +0100140 name = xmlctx->name;
141 name_len = xmlctx->name_len;
142 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
143 assert(xmlctx->status == LYXML_ATTR_CONTENT);
144
145 /* create metadata */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200146 ret = lyd_parser_create_meta((struct lyd_ctx *)lydctx, NULL, meta, mod, name, name_len, xmlctx->value,
Michal Vaskoaac267d2022-01-17 13:34:48 +0100147 xmlctx->value_len, &xmlctx->dynamic, LY_VALUE_XML, &xmlctx->ns, LYD_HINT_DATA, sparent);
Radek Krejci1798aae2020-07-14 13:26:06 +0200148 LY_CHECK_GOTO(ret, cleanup);
Michal Vaskob36053d2020-03-26 15:49:30 +0100149
150 /* next attribute */
151 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200152 }
Michal Vasko52927e22020-03-16 17:26:14 +0100153
Radek Krejcie7b95092019-05-15 11:03:07 +0200154cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100155 if (ret) {
Michal Vasko3a41dff2020-07-15 14:30:28 +0200156 lyd_free_meta_siblings(*meta);
Michal Vaskob36053d2020-03-26 15:49:30 +0100157 *meta = NULL;
Radek Krejci38d85362019-09-05 16:26:38 +0200158 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200159 return ret;
160}
161
Michal Vasko52927e22020-03-16 17:26:14 +0100162static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200163lydxml_attrs(struct lyxml_ctx *xmlctx, struct lyd_attr **attr)
Michal Vasko52927e22020-03-16 17:26:14 +0100164{
165 LY_ERR ret = LY_SUCCESS;
166 const struct lyxml_ns *ns;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100167 void *val_prefix_data;
Radek Krejci8df109d2021-04-23 12:19:08 +0200168 LY_VALUE_FORMAT format;
Radek Krejci1798aae2020-07-14 13:26:06 +0200169 struct lyd_attr *attr2;
Michal Vaskob36053d2020-03-26 15:49:30 +0100170 const char *name, *prefix;
171 size_t name_len, prefix_len;
Michal Vasko52927e22020-03-16 17:26:14 +0100172
173 assert(attr);
Michal Vaskob36053d2020-03-26 15:49:30 +0100174 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100175
Michal Vaskob36053d2020-03-26 15:49:30 +0100176 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vasko52927e22020-03-16 17:26:14 +0100177 if (*attr) {
178 attr2 = *attr;
179 } else {
180 attr2 = NULL;
181 }
182
Michal Vaskob36053d2020-03-26 15:49:30 +0100183 /* remember attr prefix, name, and get its content */
184 prefix = xmlctx->prefix;
185 prefix_len = xmlctx->prefix_len;
186 name = xmlctx->name;
187 name_len = xmlctx->name_len;
188 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
189 assert(xmlctx->status == LYXML_ATTR_CONTENT);
190
Michal Vaskoe137fc42021-07-22 11:53:13 +0200191 /* handle special "xml" attribute prefix */
192 if ((prefix_len == 3) && !strncmp(prefix, "xml", 3)) {
193 name = prefix;
194 name_len += 1 + prefix_len;
195 prefix = NULL;
196 prefix_len = 0;
197 }
198
199 /* find namespace of the attribute, if any */
200 ns = NULL;
201 if (prefix_len) {
202 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
203 if (!ns) {
204 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
205 ret = LY_EVALID;
206 goto cleanup;
207 }
208 }
209
Michal Vasko52927e22020-03-16 17:26:14 +0100210 /* get value prefixes */
Michal Vaskofc2cd072021-02-24 13:17:17 +0100211 val_prefix_data = NULL;
Radek Krejci8df109d2021-04-23 12:19:08 +0200212 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 +0100213 &xmlctx->ns, &format, &val_prefix_data), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100214
215 /* attr2 is always changed to the created attribute */
Michal Vasko501af032020-11-11 20:27:44 +0100216 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 +0100217 ns ? strlen(ns->uri) : 0, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic, format, val_prefix_data,
218 LYD_HINT_DATA);
Michal Vasko52927e22020-03-16 17:26:14 +0100219 LY_CHECK_GOTO(ret, cleanup);
220
221 if (!*attr) {
222 *attr = attr2;
223 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100224
225 /* next attribute */
226 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100227 }
228
229cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100230 if (ret) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200231 lyd_free_attr_siblings(xmlctx->ctx, *attr);
Michal Vaskob36053d2020-03-26 15:49:30 +0100232 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100233 }
Michal Vasko52927e22020-03-16 17:26:14 +0100234 return ret;
235}
236
Michal Vasko44685da2020-03-17 15:38:06 +0100237static LY_ERR
Michal Vaskob36053d2020-03-26 15:49:30 +0100238lydxml_check_list(struct lyxml_ctx *xmlctx, const struct lysc_node *list)
Michal Vasko44685da2020-03-17 15:38:06 +0100239{
Michal Vaskob36053d2020-03-26 15:49:30 +0100240 LY_ERR ret = LY_SUCCESS, r;
241 enum LYXML_PARSER_STATUS next;
Michal Vasko44685da2020-03-17 15:38:06 +0100242 struct ly_set key_set = {0};
243 const struct lysc_node *snode;
Michal Vaskob36053d2020-03-26 15:49:30 +0100244 uint32_t i, parents_count;
Michal Vasko44685da2020-03-17 15:38:06 +0100245
246 assert(list && (list->nodetype == LYS_LIST));
247
248 /* get all keys into a set (keys do not have if-features or anything) */
249 snode = NULL;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100250 while ((snode = lys_getnext(snode, list, NULL, 0)) && (snode->flags & LYS_KEY)) {
Radek Krejci3d92e442020-10-12 12:48:13 +0200251 ret = ly_set_add(&key_set, (void *)snode, 1, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200252 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100253 }
254
Michal Vasko12d809c2021-03-03 16:34:32 +0100255 /* remember parent count */
256 parents_count = xmlctx->elements.count;
257
Michal Vaskob36053d2020-03-26 15:49:30 +0100258 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vasko44685da2020-03-17 15:38:06 +0100259 /* find key definition */
260 for (i = 0; i < key_set.count; ++i) {
261 snode = (const struct lysc_node *)key_set.objs[i];
Michal Vaskob36053d2020-03-26 15:49:30 +0100262 if (!ly_strncmp(snode->name, xmlctx->name, xmlctx->name_len)) {
Michal Vasko44685da2020-03-17 15:38:06 +0100263 break;
264 }
265 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100266 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100267
268 /* skip attributes */
269 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100270 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
271 assert(xmlctx->status == LYXML_ATTR_CONTENT);
272 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100273 }
274
Michal Vaskob36053d2020-03-26 15:49:30 +0100275 assert(xmlctx->status == LYXML_ELEM_CONTENT);
276 if (i < key_set.count) {
277 /* validate the value */
Radek Krejci8df109d2021-04-23 12:19:08 +0200278 r = lys_value_validate(NULL, snode, xmlctx->value, xmlctx->value_len, LY_VALUE_XML, &xmlctx->ns);
Michal Vaskob36053d2020-03-26 15:49:30 +0100279 if (!r) {
280 /* key with a valid value, remove from the set */
281 ly_set_rm_index(&key_set, i, NULL);
Michal Vasko44685da2020-03-17 15:38:06 +0100282 }
283 }
284
Michal Vaskob36053d2020-03-26 15:49:30 +0100285 /* parser next */
286 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100287
Michal Vaskob36053d2020-03-26 15:49:30 +0100288 /* skip any children, resursively */
Michal Vasko12d809c2021-03-03 16:34:32 +0100289 while (xmlctx->status == LYXML_ELEMENT) {
290 while (parents_count < xmlctx->elements.count) {
291 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
292 }
293 assert(xmlctx->status == LYXML_ELEM_CLOSE);
Michal Vaskob36053d2020-03-26 15:49:30 +0100294 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
295 }
296
297 /* parser next, but do not parse closing element of the list because it would remove its namespaces */
298 assert(xmlctx->status == LYXML_ELEM_CLOSE);
299 LY_CHECK_GOTO(ret = lyxml_ctx_peek(xmlctx, &next), cleanup);
300 if (next != LYXML_ELEM_CLOSE) {
301 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
302 }
Michal Vasko44685da2020-03-17 15:38:06 +0100303 }
304
305 if (key_set.count) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100306 /* some keys are missing/did not validate */
Michal Vasko44685da2020-03-17 15:38:06 +0100307 ret = LY_ENOT;
Michal Vasko44685da2020-03-17 15:38:06 +0100308 }
309
310cleanup:
311 ly_set_erase(&key_set, NULL);
312 return ret;
313}
314
Michal Vasko5c24ed12021-06-09 09:27:32 +0200315/**
316 * @brief Skip an element with all its descendants.
317 *
318 * @param[in] xmlctx XML parser context.
319 * @return LY_ERR value.
320 */
Michal Vasko1bf09392020-03-27 12:38:10 +0100321static LY_ERR
322lydxml_data_skip(struct lyxml_ctx *xmlctx)
323{
324 uint32_t parents_count;
325
326 /* remember current number of parents */
327 parents_count = xmlctx->elements.count;
aPiecek9cdb9e62021-05-18 09:46:20 +0200328 assert(parents_count);
Michal Vasko1bf09392020-03-27 12:38:10 +0100329
330 /* skip after the content */
331 while (xmlctx->status != LYXML_ELEM_CONTENT) {
332 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
333 }
334 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
335
336 /* skip all children elements, recursively, if any */
aPiecek9cdb9e62021-05-18 09:46:20 +0200337 while (parents_count <= xmlctx->elements.count) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100338 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
339 }
340
341 /* close element */
342 assert(xmlctx->status == LYXML_ELEM_CLOSE);
343 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
344
345 return LY_SUCCESS;
346}
347
Michal Vasko5c24ed12021-06-09 09:27:32 +0200348/**
349 * @brief Check that the current element can be parsed as a data node.
350 *
351 * @param[in] lydctx XML data parser context.
352 * @param[in,out] snode Found schema node, set to NULL if data node cannot be created.
353 * @return LY_ERR value.
354 */
Michal Vasko1bf09392020-03-27 12:38:10 +0100355static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200356lydxml_data_check_opaq(struct lyd_xml_ctx *lydctx, const struct lysc_node **snode)
Michal Vasko1bf09392020-03-27 12:38:10 +0100357{
358 LY_ERR ret = LY_SUCCESS;
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200359 struct lyxml_ctx *xmlctx = lydctx->xmlctx, pxmlctx;
Michal Vasko1bf09392020-03-27 12:38:10 +0100360
Radek IÅ¡a3930fd72021-03-08 10:48:40 +0100361 if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
362 /* only checks specific to opaque nodes */
363 return LY_SUCCESS;
364 }
365
Michal Vasko13854662021-06-09 09:27:50 +0200366 if (!((*snode)->nodetype & (LYD_NODE_TERM | LYD_NODE_INNER))) {
367 /* nothing to check */
368 return LY_SUCCESS;
369 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100370
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200371 assert(xmlctx->elements.count);
372
Michal Vasko13854662021-06-09 09:27:50 +0200373 /* backup parser */
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200374 LY_CHECK_RET(lyxml_ctx_backup(xmlctx, &pxmlctx));
Michal Vasko1bf09392020-03-27 12:38:10 +0100375
Michal Vasko13854662021-06-09 09:27:50 +0200376 /* skip attributes */
377 while (xmlctx->status == LYXML_ATTRIBUTE) {
378 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
379 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
380 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100381
Michal Vasko13854662021-06-09 09:27:50 +0200382 if ((*snode)->nodetype & LYD_NODE_TERM) {
383 /* value may not be valid in which case we parse it as an opaque node */
384 if (lys_value_validate(NULL, *snode, xmlctx->value, xmlctx->value_len, LY_VALUE_XML, &xmlctx->ns)) {
Michal Vaskod0237d42021-07-12 14:49:46 +0200385 LOGVRB("Parsing opaque term node \"%s\" with invalid value \"%.*s\".", (*snode)->name, xmlctx->value_len,
386 xmlctx->value);
Michal Vasko13854662021-06-09 09:27:50 +0200387 *snode = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100388 }
Michal Vasko13854662021-06-09 09:27:50 +0200389 } else if ((*snode)->nodetype == LYS_LIST) {
390 /* skip content */
391 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
Michal Vasko1bf09392020-03-27 12:38:10 +0100392
Michal Vasko13854662021-06-09 09:27:50 +0200393 if (lydxml_check_list(xmlctx, *snode)) {
394 /* invalid list, parse as opaque if it missing/has invalid some keys */
Michal Vaskod0237d42021-07-12 14:49:46 +0200395 LOGVRB("Parsing opaque list node \"%s\" with missing/invalid keys.", (*snode)->name);
Michal Vasko13854662021-06-09 09:27:50 +0200396 *snode = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100397 }
Michal Vasko13854662021-06-09 09:27:50 +0200398 } else {
Radek IÅ¡a3930fd72021-03-08 10:48:40 +0100399 /* if there is a non-WS value, it cannot be parsed as an inner node */
400 assert(xmlctx->status == LYXML_ELEM_CONTENT);
401 if (!xmlctx->ws_only) {
402 *snode = NULL;
403 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100404 }
405
Michal Vasko13854662021-06-09 09:27:50 +0200406restore:
407 /* restore parser */
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200408 lyxml_ctx_restore(xmlctx, &pxmlctx);
Michal Vasko1bf09392020-03-27 12:38:10 +0100409 return ret;
410}
411
Radek Krejcie7b95092019-05-15 11:03:07 +0200412/**
Michal Vaskoaac267d2022-01-17 13:34:48 +0100413 * @brief Try to parse data with a parent based on an extension instance.
414 *
415 * @param[in] lydctx XML data parser context.
416 * @param[in,out] parent Parent node where the children are inserted.
417 * @return LY_SUCCESS on success;
418 * @return LY_ENOT if no extension instance parsed the data;
419 * @return LY_ERR on error.
420 */
421static LY_ERR
422lydxml_nested_ext(struct lyd_xml_ctx *lydctx, struct lyd_node *parent)
423{
424 LY_ERR r;
425 struct ly_in in_bck, in_start, in_ext;
426 LY_ARRAY_COUNT_TYPE u;
427 struct lysc_ext_instance *nested_exts = NULL;
428 lyplg_ext_data_parse_clb ext_parse_cb;
429 struct lyd_ctx_ext_val *ext_val;
430
431 /* backup current input */
432 in_bck = *lydctx->xmlctx->in;
433
434 /* go back in the input for extension parsing */
435 in_start = *lydctx->xmlctx->in;
436 if (lydctx->xmlctx->status != LYXML_ELEM_CONTENT) {
437 assert((lydctx->xmlctx->status == LYXML_ELEMENT) || (lydctx->xmlctx->status == LYXML_ATTRIBUTE));
438 in_start.current = lydctx->xmlctx->prefix ? lydctx->xmlctx->prefix : lydctx->xmlctx->name;
439 }
440 do {
441 --in_start.current;
442 } while (in_start.current[0] != '<');
443
444 /* check if there are any nested extension instances */
445 if (parent && parent->schema) {
446 nested_exts = parent->schema->exts;
447 }
448 LY_ARRAY_FOR(nested_exts, u) {
449 /* prepare the input and try to parse this extension data */
450 in_ext = in_start;
451 ext_parse_cb = nested_exts[u].def->plugin->parse;
452 r = ext_parse_cb(&in_ext, LYD_XML, &nested_exts[u], parent, lydctx->parse_opts | LYD_PARSE_ONLY);
453 if (!r) {
454 /* data successfully parsed, remember for validation */
455 if (!(lydctx->parse_opts & LYD_PARSE_ONLY)) {
456 ext_val = malloc(sizeof *ext_val);
457 LY_CHECK_ERR_RET(!ext_val, LOGMEM(lydctx->xmlctx->ctx), LY_EMEM);
458 ext_val->ext = &nested_exts[u];
Michal Vaskoc08b9d22022-02-10 15:48:39 +0100459 ext_val->sibling = lyd_child_no_keys(parent);
Michal Vaskoaac267d2022-01-17 13:34:48 +0100460 LY_CHECK_RET(ly_set_add(&lydctx->ext_val, ext_val, 1, NULL));
461 }
462
463 /* adjust the xmlctx accordingly */
464 *lydctx->xmlctx->in = in_ext;
465 lydctx->xmlctx->status = LYXML_ELEM_CONTENT;
466 lydctx->xmlctx->dynamic = 0;
467 ly_set_rm_index(&lydctx->xmlctx->elements, lydctx->xmlctx->elements.count - 1, free);
468 lyxml_ns_rm(lydctx->xmlctx);
469 LY_CHECK_RET(lyxml_ctx_next(lydctx->xmlctx));
470 return LY_SUCCESS;
471 } else if (r != LY_ENOT) {
472 /* fatal error */
473 return r;
474 }
475 /* data was not from this module, continue */
476 }
477
478 /* no extensions or none matched, restore input */
479 *lydctx->xmlctx->in = in_bck;
480 return LY_ENOT;
481}
482
483/**
Michal Vaskoa5da3292020-08-12 13:10:50 +0200484 * @brief Parse XML subtree.
Radek Krejcie7b95092019-05-15 11:03:07 +0200485 *
Michal Vaskob36053d2020-03-26 15:49:30 +0100486 * @param[in] lydctx XML YANG data parser context.
Michal Vaskoe0665742021-02-11 11:08:44 +0100487 * @param[in,out] parent Parent node where the children are inserted. NULL in case of parsing top-level elements.
488 * @param[in,out] first_p Pointer to the first (@p parent or top-level) child. In case there were already some siblings,
489 * this may point to a previously existing node.
490 * @param[in,out] parsed Optional set to add all the parsed siblings into.
Michal Vasko9b368d32020-02-14 13:53:31 +0100491 * @return LY_ERR value.
Radek Krejcie7b95092019-05-15 11:03:07 +0200492 */
493static LY_ERR
Michal Vaskoe0665742021-02-11 11:08:44 +0100494lydxml_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 +0200495{
tadeas-vintrlikbf8aa6e2021-11-03 13:07:34 +0100496 LY_ERR ret = LY_SUCCESS, r;
Michal Vasko46f7ac92022-02-24 16:07:27 +0100497 const char *prefix, *name;
Michal Vasko1bf09392020-03-27 12:38:10 +0100498 size_t prefix_len, name_len;
Michal Vaskob36053d2020-03-26 15:49:30 +0100499 struct lyxml_ctx *xmlctx;
500 const struct ly_ctx *ctx;
Radek Krejcie7b95092019-05-15 11:03:07 +0200501 const struct lyxml_ns *ns;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200502 struct lyd_meta *meta = NULL;
503 struct lyd_attr *attr = NULL;
Radek Krejcie7b95092019-05-15 11:03:07 +0200504 const struct lysc_node *snode;
505 struct lys_module *mod;
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200506 uint32_t prev_parse_opts, prev_int_opts;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200507 struct lyd_node *node = NULL, *anchor;
Michal Vaskofc2cd072021-02-24 13:17:17 +0100508 void *val_prefix_data = NULL;
Radek Krejci8df109d2021-04-23 12:19:08 +0200509 LY_VALUE_FORMAT format;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200510 uint32_t getnext_opts;
Michal Vaskoaac267d2022-01-17 13:34:48 +0100511 ly_bool parse_subtree;
Michal Vasko46f7ac92022-02-24 16:07:27 +0100512 char *val;
Radek Krejcie7b95092019-05-15 11:03:07 +0200513
Michal Vaskoe0665742021-02-11 11:08:44 +0100514 assert(parent || first_p);
515
Michal Vaskob36053d2020-03-26 15:49:30 +0100516 xmlctx = lydctx->xmlctx;
517 ctx = xmlctx->ctx;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100518 getnext_opts = lydctx->int_opts & LYD_INTOPT_REPLY ? LYS_GETNEXT_OUTPUT : 0;
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100519
Michal Vaskoaac267d2022-01-17 13:34:48 +0100520 parse_subtree = lydctx->parse_opts & LYD_PARSE_SUBTREE ? 1 : 0;
521 /* all descendants should be parsed */
522 lydctx->parse_opts &= ~LYD_PARSE_SUBTREE;
523
Michal Vaskoa5da3292020-08-12 13:10:50 +0200524 assert(xmlctx->status == LYXML_ELEMENT);
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200525
Michal Vaskoa5da3292020-08-12 13:10:50 +0200526 /* remember element prefix and name */
527 prefix = xmlctx->prefix;
528 prefix_len = xmlctx->prefix_len;
529 name = xmlctx->name;
530 name_len = xmlctx->name_len;
531
532 /* get the element module */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200533 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200534 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100535 LOGVAL(ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200536 ret = LY_EVALID;
537 goto error;
538 }
539 mod = ly_ctx_get_module_implemented_ns(ctx, ns->uri);
540 if (!mod) {
Michal Vaskoaac267d2022-01-17 13:34:48 +0100541 /* check for extension data */
542 r = lydxml_nested_ext(lydctx, parent);
543 if (!r) {
544 /* successfully parsed */
545 return r;
546 } else if (r != LY_ENOT) {
547 /* error */
548 ret = r;
549 goto error;
550 }
551
552 /* unknown module */
Michal Vaskoe0665742021-02-11 11:08:44 +0100553 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100554 LOGVAL(ctx, LYVE_REFERENCE, "No module with namespace \"%s\" in the context.", ns->uri);
Michal Vasko90932a92020-02-12 14:33:03 +0100555 ret = LY_EVALID;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200556 goto error;
Radek Krejcie7b95092019-05-15 11:03:07 +0200557 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100558 if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
Michal Vaskoa5da3292020-08-12 13:10:50 +0200559 /* skip element with children */
560 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
561 return LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200562 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200563 }
564
Michal Vaskoa5da3292020-08-12 13:10:50 +0200565 /* parser next */
566 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
Michal Vasko90932a92020-02-12 14:33:03 +0100567
Michal Vaskoa5da3292020-08-12 13:10:50 +0200568 /* get the schema node */
569 snode = NULL;
Michal Vasko81008a52021-07-21 16:06:12 +0200570 if (mod) {
Radek Krejcif16e2542021-02-17 15:39:23 +0100571 if (!parent && lydctx->ext) {
Radek Krejciba05eab2021-03-10 13:19:29 +0100572 snode = lysc_ext_find_node(lydctx->ext, mod, name, name_len, 0, getnext_opts);
Radek Krejcif16e2542021-02-17 15:39:23 +0100573 } else {
574 snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
575 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200576 if (!snode) {
Michal Vaskoaac267d2022-01-17 13:34:48 +0100577 /* check for extension data */
578 r = lydxml_nested_ext(lydctx, parent);
579 if (!r) {
580 /* successfully parsed */
581 return r;
582 } else if (r != LY_ENOT) {
583 /* error */
584 ret = r;
585 goto error;
tadeas-vintrlikbf8aa6e2021-11-03 13:07:34 +0100586 }
Michal Vaskoaac267d2022-01-17 13:34:48 +0100587
588 /* unknown data node */
Michal Vaskoe0665742021-02-11 11:08:44 +0100589 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
590 if (parent) {
Radek Krejci422afb12021-03-04 16:38:16 +0100591 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found as a child of \"%s\" node.",
Michal Vaskoc08b9d22022-02-10 15:48:39 +0100592 (int)name_len, name, LYD_NAME(parent));
Radek Krejcif16e2542021-02-17 15:39:23 +0100593 } else if (lydctx->ext) {
594 if (lydctx->ext->argument) {
Radek Krejci422afb12021-03-04 16:38:16 +0100595 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" %s extension instance.",
596 (int)name_len, name, lydctx->ext->argument, lydctx->ext->def->name);
Radek Krejcif16e2542021-02-17 15:39:23 +0100597 } else {
Radek Krejci422afb12021-03-04 16:38:16 +0100598 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the %s extension instance.",
599 (int)name_len, name, lydctx->ext->def->name);
Radek Krejcif16e2542021-02-17 15:39:23 +0100600 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100601 } else {
Radek Krejci422afb12021-03-04 16:38:16 +0100602 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" module.",
603 (int)name_len, name, mod->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100604 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200605 ret = LY_EVALID;
606 goto error;
Michal Vaskoe0665742021-02-11 11:08:44 +0100607 } else if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
Michal Vaskod4f82492022-01-05 12:06:51 +0100608 LOGVRB("Skipping parsing of unknown node \"%.*s\".", name_len, name);
Michal Vaskod0237d42021-07-12 14:49:46 +0200609
Michal Vaskoa5da3292020-08-12 13:10:50 +0200610 /* skip element with children */
611 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
612 return LY_SUCCESS;
613 }
614 } else {
615 /* check that schema node is valid and can be used */
616 LY_CHECK_GOTO(ret = lyd_parser_check_schema((struct lyd_ctx *)lydctx, snode), error);
617 LY_CHECK_GOTO(ret = lydxml_data_check_opaq(lydctx, &snode), error);
618 }
619 }
620
621 /* create metadata/attributes */
622 if (xmlctx->status == LYXML_ATTRIBUTE) {
623 if (snode) {
Michal Vaskoaac267d2022-01-17 13:34:48 +0100624 ret = lydxml_metadata(lydctx, snode, &meta);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200625 LY_CHECK_GOTO(ret, error);
626 } else {
Michal Vaskoe0665742021-02-11 11:08:44 +0100627 assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200628 ret = lydxml_attrs(xmlctx, &attr);
629 LY_CHECK_GOTO(ret, error);
630 }
631 }
632
633 assert(xmlctx->status == LYXML_ELEM_CONTENT);
634 if (!snode) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100635 assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200636
637 if (xmlctx->ws_only) {
638 /* ignore WS-only value */
Radek IÅ¡a017270d2021-02-16 10:26:15 +0100639 if (xmlctx->dynamic) {
640 free((char *) xmlctx->value);
641 }
642 xmlctx->dynamic = 0;
643 xmlctx->value = "";
Michal Vaskoa5da3292020-08-12 13:10:50 +0200644 xmlctx->value_len = 0;
Radek Krejci8df109d2021-04-23 12:19:08 +0200645 format = LY_VALUE_XML;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200646 } else {
647 /* get value prefixes */
Radek Krejci8df109d2021-04-23 12:19:08 +0200648 ret = ly_store_prefix_data(xmlctx->ctx, xmlctx->value, xmlctx->value_len, LY_VALUE_XML,
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100649 &xmlctx->ns, &format, &val_prefix_data);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200650 LY_CHECK_GOTO(ret, error);
651 }
652
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200653 /* get NS again, it may have been backed up and restored */
654 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
655 assert(ns);
656
Michal Vaskoa5da3292020-08-12 13:10:50 +0200657 /* create node */
Michal Vasko501af032020-11-11 20:27:44 +0100658 ret = lyd_create_opaq(ctx, name, name_len, prefix, prefix_len, ns->uri, strlen(ns->uri), xmlctx->value,
659 xmlctx->value_len, &xmlctx->dynamic, format, val_prefix_data, LYD_HINT_DATA, &node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200660 LY_CHECK_GOTO(ret, error);
661
662 /* parser next */
663 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
664
665 /* process children */
666 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100667 ret = lydxml_subtree_r(lydctx, node, lyd_node_child_p(node), NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200668 LY_CHECK_GOTO(ret, error);
669 }
670 } else if (snode->nodetype & LYD_NODE_TERM) {
671 /* create node */
Michal Vasko22df3f02020-08-24 13:29:22 +0200672 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 +0200673 &xmlctx->dynamic, LY_VALUE_XML, &xmlctx->ns, LYD_HINT_DATA, &node), error);
Radek Krejciddace2c2021-01-08 11:30:56 +0100674 LOG_LOCSET(snode, node, NULL, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200675
676 if (parent && (node->schema->flags & LYS_KEY)) {
677 /* check the key order, the anchor must never be a key */
Michal Vaskoe0665742021-02-11 11:08:44 +0100678 anchor = lyd_insert_get_next_anchor(lyd_child(parent), node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200679 if (anchor && (anchor->schema->flags & LYS_KEY)) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100680 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100681 LOGVAL(ctx, LYVE_DATA, "Invalid position of the key \"%s\" in a list.", node->schema->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200682 ret = LY_EVALID;
683 goto error;
684 } else {
685 LOGWRN(ctx, "Invalid position of the key \"%s\" in a list.", node->schema->name);
686 }
687 }
688 }
689
690 /* parser next */
691 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
692
693 /* no children expected */
694 if (xmlctx->status == LYXML_ELEMENT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100695 LOGVAL(ctx, LYVE_SYNTAX, "Child element \"%.*s\" inside a terminal node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100696 (int)xmlctx->name_len, xmlctx->name, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200697 ret = LY_EVALID;
698 goto error;
699 }
700 } else if (snode->nodetype & LYD_NODE_INNER) {
701 if (!xmlctx->ws_only) {
702 /* value in inner node */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100703 LOGVAL(ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an inner node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100704 (int)xmlctx->value_len, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200705 ret = LY_EVALID;
706 goto error;
707 }
708
709 /* create node */
710 ret = lyd_create_inner(snode, &node);
711 LY_CHECK_GOTO(ret, error);
712
Radek Krejciddace2c2021-01-08 11:30:56 +0100713 LOG_LOCSET(snode, node, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100714
Michal Vaskoa5da3292020-08-12 13:10:50 +0200715 /* parser next */
716 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
717
718 /* process children */
719 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100720 ret = lydxml_subtree_r(lydctx, node, lyd_node_child_p(node), NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200721 LY_CHECK_GOTO(ret, error);
722 }
723
724 if (snode->nodetype == LYS_LIST) {
725 /* check all keys exist */
726 LY_CHECK_GOTO(ret = lyd_parse_check_keys(node), error);
727 }
728
Michal Vaskoe0665742021-02-11 11:08:44 +0100729 if (!(lydctx->parse_opts & LYD_PARSE_ONLY)) {
Michal Vaskoa5da3292020-08-12 13:10:50 +0200730 /* new node validation, autodelete CANNOT occur, all nodes are new */
Michal Vaskoe0665742021-02-11 11:08:44 +0100731 ret = lyd_validate_new(lyd_node_child_p(node), snode, NULL, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200732 LY_CHECK_GOTO(ret, error);
733
734 /* add any missing default children */
Michal Vaskoaac267d2022-01-17 13:34:48 +0100735 ret = lyd_new_implicit_r(node, lyd_node_child_p(node), NULL, NULL, &lydctx->node_when, &lydctx->node_types,
736 (lydctx->val_opts & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200737 LY_CHECK_GOTO(ret, error);
738 }
739
740 if (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
741 /* rememeber the RPC/action/notification */
742 lydctx->op_node = node;
743 }
744 } else if (snode->nodetype & LYD_NODE_ANY) {
Michal Vasko27c4dce2021-03-04 15:50:50 +0100745 if ((snode->nodetype == LYS_ANYDATA) && !xmlctx->ws_only) {
746 /* value in anydata node, we expect a tree */
747 LOGVAL(ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an anydata node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100748 (int)xmlctx->value_len < 20 ? xmlctx->value_len : 20, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200749 ret = LY_EVALID;
750 goto error;
751 }
752
Michal Vasko27c4dce2021-03-04 15:50:50 +0100753 if (!xmlctx->ws_only) {
754 /* use an arbitrary text value for anyxml */
Michal Vasko46f7ac92022-02-24 16:07:27 +0100755 val = strndup(xmlctx->value, xmlctx->value_len);
756 LY_CHECK_ERR_GOTO(!val, LOGMEM(xmlctx->ctx); ret = LY_EMEM, error);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200757
Michal Vasko27c4dce2021-03-04 15:50:50 +0100758 /* parser next */
759 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
760
761 /* create node */
762 ret = lyd_create_any(snode, val, LYD_ANYDATA_STRING, 1, &node);
Michal Vasko46f7ac92022-02-24 16:07:27 +0100763 LY_CHECK_ERR_GOTO(ret, free(val), error);
Michal Vasko27c4dce2021-03-04 15:50:50 +0100764 } else {
765 /* parser next */
766 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
767
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200768 /* update options so that generic data can be parsed */
769 prev_parse_opts = lydctx->parse_opts;
Michal Vasko27c4dce2021-03-04 15:50:50 +0100770 lydctx->parse_opts &= ~LYD_PARSE_STRICT;
771 lydctx->parse_opts |= LYD_PARSE_OPAQ;
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200772 prev_int_opts = lydctx->int_opts;
Michal Vasko02ed9d82021-07-15 14:58:04 +0200773 lydctx->int_opts |= LYD_INTOPT_ANY | LYD_INTOPT_WITH_SIBLINGS;
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200774
775 /* parse any data tree */
Michal Vasko27c4dce2021-03-04 15:50:50 +0100776 anchor = NULL;
777 while (xmlctx->status == LYXML_ELEMENT) {
778 ret = lydxml_subtree_r(lydctx, NULL, &anchor, NULL);
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200779 if (ret) {
780 break;
781 }
Michal Vasko27c4dce2021-03-04 15:50:50 +0100782 }
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200783
784 /* restore options */
785 lydctx->parse_opts = prev_parse_opts;
786 lydctx->int_opts = prev_int_opts;
787
788 LY_CHECK_GOTO(ret, error);
Michal Vasko27c4dce2021-03-04 15:50:50 +0100789
790 /* create node */
791 ret = lyd_create_any(snode, anchor, LYD_ANYDATA_DATATREE, 1, &node);
792 LY_CHECK_GOTO(ret, error);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200793 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200794 }
795 assert(node);
796
797 /* add/correct flags */
798 if (snode) {
Michal Vaskoaac267d2022-01-17 13:34:48 +0100799 lyd_parse_set_data_flags(node, &lydctx->node_when, &meta, lydctx->parse_opts);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200800 }
801
802 /* parser next */
803 assert(xmlctx->status == LYXML_ELEM_CLOSE);
Michal Vaskoaac267d2022-01-17 13:34:48 +0100804 if (!parse_subtree) {
805 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
806 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200807
808 /* add metadata/attributes */
809 if (snode) {
Michal Vasko871a0252020-11-11 18:35:24 +0100810 lyd_insert_meta(node, meta, 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200811 } else {
812 lyd_insert_attr(node, attr);
813 }
814
815 /* insert, keep first pointer correct */
Michal Vasko6ee6f432021-07-16 09:49:14 +0200816 lyd_insert_node(parent, first_p, node, lydctx->parse_opts & LYD_PARSE_ORDERED ? 1 : 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200817 while (!parent && (*first_p)->prev->next) {
818 *first_p = (*first_p)->prev;
819 }
820
Michal Vaskoe0665742021-02-11 11:08:44 +0100821 /* rememeber a successfully parsed node */
822 if (parsed) {
823 ly_set_add(parsed, node, 1, NULL);
824 }
825
Radek Krejciddace2c2021-01-08 11:30:56 +0100826 LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200827 return LY_SUCCESS;
828
829error:
Radek Krejciddace2c2021-01-08 11:30:56 +0100830 LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
Michal Vasko3a41dff2020-07-15 14:30:28 +0200831 lyd_free_meta_siblings(meta);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200832 lyd_free_attr_siblings(ctx, attr);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200833 lyd_free_tree(node);
Radek Krejcie7b95092019-05-15 11:03:07 +0200834 return ret;
835}
836
Michal Vaskoe0665742021-02-11 11:08:44 +0100837/**
838 * @brief Parse a specific XML element into an opaque node.
839 *
840 * @param[in] xmlctx XML parser context.
841 * @param[in] name Name of the element.
842 * @param[in] uri URI of the element.
843 * @param[in] value Whether a value is expected in the element.
844 * @param[out] evnp Parsed envelope (opaque node).
845 * @return LY_SUCCESS on success.
846 * @return LY_ENOT if the specified element did not match.
847 * @return LY_ERR value on error.
848 */
Michal Vasko1bf09392020-03-27 12:38:10 +0100849static LY_ERR
Michal Vaskoe0665742021-02-11 11:08:44 +0100850lydxml_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 +0100851{
Michal Vaskoe0665742021-02-11 11:08:44 +0100852 LY_ERR rc = LY_SUCCESS;
853 const struct lyxml_ns *ns;
Radek Krejci1798aae2020-07-14 13:26:06 +0200854 struct lyd_attr *attr = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100855 const char *prefix;
856 size_t prefix_len;
857
Michal Vasko1bf09392020-03-27 12:38:10 +0100858 assert(xmlctx->status == LYXML_ELEMENT);
859 if (ly_strncmp(name, xmlctx->name, xmlctx->name_len)) {
860 /* not the expected element */
Michal Vaskoe0665742021-02-11 11:08:44 +0100861 return LY_ENOT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100862 }
863
864 prefix = xmlctx->prefix;
865 prefix_len = xmlctx->prefix_len;
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200866 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100867 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100868 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +0100869 return LY_EVALID;
870 } else if (strcmp(ns->uri, uri)) {
871 /* different namespace */
872 return LY_ENOT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100873 }
874
875 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
876
877 /* create attributes */
878 if (xmlctx->status == LYXML_ATTRIBUTE) {
879 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
880 }
881
Michal Vaskoe0665742021-02-11 11:08:44 +0100882 assert(xmlctx->status == LYXML_ELEM_CONTENT);
883 if (!value && !xmlctx->ws_only) {
884 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected value \"%.*s\" in the \"%s\" element.",
Radek Krejci422afb12021-03-04 16:38:16 +0100885 (int)xmlctx->value_len, xmlctx->value, name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100886 rc = LY_EVALID;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100887 goto cleanup;
Michal Vaskoe0665742021-02-11 11:08:44 +0100888 }
Michal Vaskoa8edff02020-03-27 14:47:01 +0100889
890 /* create node */
Michal Vaskoe0665742021-02-11 11:08:44 +0100891 rc = lyd_create_opaq(xmlctx->ctx, name, strlen(name), prefix, prefix_len, uri, strlen(uri), xmlctx->value,
Radek Krejci8df109d2021-04-23 12:19:08 +0200892 xmlctx->ws_only ? 0 : xmlctx->value_len, NULL, LY_VALUE_XML, NULL, 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100893 LY_CHECK_GOTO(rc, cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100894
895 /* assign atributes */
Michal Vaskoe0665742021-02-11 11:08:44 +0100896 ((struct lyd_node_opaq *)(*envp))->attr = attr;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100897 attr = NULL;
898
Michal Vaskoe0665742021-02-11 11:08:44 +0100899 /* parser next element */
900 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100901
Michal Vaskoe0665742021-02-11 11:08:44 +0100902cleanup:
903 lyd_free_attr_siblings(xmlctx->ctx, attr);
904 if (rc) {
905 lyd_free_tree(*envp);
906 *envp = NULL;
907 }
908 return rc;
909}
910
911/**
912 * @brief Parse all expected non-data XML elements of a NETCONF rpc message.
913 *
914 * @param[in] xmlctx XML parser context.
915 * @param[out] evnp Parsed envelope(s) (opaque node).
916 * @param[out] int_opts Internal options for parsing the rest of YANG data.
917 * @param[out] close_elem Number of parsed opened elements that need to be closed.
918 * @return LY_SUCCESS on success.
919 * @return LY_ERR value on error.
920 */
921static LY_ERR
922lydxml_env_netconf_rpc(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
923{
924 LY_ERR rc = LY_SUCCESS, r;
925 struct lyd_node *child;
926
927 assert(envp && !*envp);
928
929 /* parse "rpc" */
930 r = lydxml_envelope(xmlctx, "rpc", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100931 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
932
933 /* parse "action", if any */
934 r = lydxml_envelope(xmlctx, "action", "urn:ietf:params:xml:ns:yang:1", 0, &child);
935 if (r == LY_SUCCESS) {
936 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +0200937 lyd_insert_node(*envp, NULL, child, 0);
Michal Vaskoe0665742021-02-11 11:08:44 +0100938
939 /* NETCONF action */
940 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_ACTION;
941 *close_elem = 2;
942 } else if (r == LY_ENOT) {
943 /* NETCONF RPC */
944 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_RPC;
945 *close_elem = 1;
946 } else {
947 rc = r;
948 goto cleanup;
949 }
950
951cleanup:
952 if (rc) {
953 lyd_free_tree(*envp);
954 *envp = NULL;
955 }
956 return rc;
957}
958
959/**
960 * @brief Parse all expected non-data XML elements of a NETCONF notification message.
961 *
962 * @param[in] xmlctx XML parser context.
963 * @param[out] evnp Parsed envelope(s) (opaque node).
964 * @param[out] int_opts Internal options for parsing the rest of YANG data.
965 * @param[out] close_elem Number of parsed opened elements that need to be closed.
966 * @return LY_SUCCESS on success.
967 * @return LY_ERR value on error.
968 */
969static LY_ERR
970lydxml_env_netconf_notif(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
971{
972 LY_ERR rc = LY_SUCCESS, r;
973 struct lyd_node *child;
974
975 assert(envp && !*envp);
976
977 /* parse "notification" */
978 r = lydxml_envelope(xmlctx, "notification", "urn:ietf:params:xml:ns:netconf:notification:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100979 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
980
981 /* parse "eventTime" */
982 r = lydxml_envelope(xmlctx, "eventTime", "urn:ietf:params:xml:ns:netconf:notification:1.0", 1, &child);
983 if (r == LY_ENOT) {
Radek Krejci422afb12021-03-04 16:38:16 +0100984 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unexpected element \"%.*s\" instead of \"eventTime\".",
985 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100986 r = LY_EVALID;
987 }
988 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
989
990 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +0200991 lyd_insert_node(*envp, NULL, child, 0);
Michal Vaskoe0665742021-02-11 11:08:44 +0100992
993 /* validate value */
994 /* TODO validate child->value as yang:date-and-time */
995
996 /* finish child parsing */
Michal Vaskoa8edff02020-03-27 14:47:01 +0100997 if (xmlctx->status != LYXML_ELEM_CLOSE) {
998 assert(xmlctx->status == LYXML_ELEMENT);
Michal Vaskoe0665742021-02-11 11:08:44 +0100999 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"eventTime\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001000 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001001 rc = LY_EVALID;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001002 goto cleanup;
1003 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001004 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1005
1006 /* NETCONF notification */
1007 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_NOTIF;
1008 *close_elem = 1;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001009
1010cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +01001011 if (rc) {
Michal Vaskoa8edff02020-03-27 14:47:01 +01001012 lyd_free_tree(*envp);
Michal Vaskoe0665742021-02-11 11:08:44 +01001013 *envp = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001014 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001015 return rc;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001016}
Michal Vasko79135ae2020-12-16 10:08:35 +01001017
Michal Vaskoe0665742021-02-11 11:08:44 +01001018/**
1019 * @brief Parse an XML element as an opaque node subtree.
1020 *
1021 * @param[in] xmlctx XML parser context.
1022 * @param[in] parent Parent to append nodes to.
1023 * @return LY_ERR value.
1024 */
1025static LY_ERR
1026lydxml_opaq_r(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
Michal Vaskoa8edff02020-03-27 14:47:01 +01001027{
Michal Vaskoe0665742021-02-11 11:08:44 +01001028 LY_ERR rc = LY_SUCCESS;
1029 const struct lyxml_ns *ns;
1030 struct lyd_attr *attr = NULL;
1031 struct lyd_node *child = NULL;
1032 const char *name, *prefix;
1033 size_t name_len, prefix_len;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001034
Michal Vaskoe0665742021-02-11 11:08:44 +01001035 assert(xmlctx->status == LYXML_ELEMENT);
Michal Vaskoa8edff02020-03-27 14:47:01 +01001036
Michal Vaskoe0665742021-02-11 11:08:44 +01001037 name = xmlctx->name;
1038 name_len = xmlctx->name_len;
1039 prefix = xmlctx->prefix;
1040 prefix_len = xmlctx->prefix_len;
1041 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
1042 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +01001043 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +01001044 return LY_EVALID;
1045 }
Michal Vaskoa8edff02020-03-27 14:47:01 +01001046
Michal Vaskoe0665742021-02-11 11:08:44 +01001047 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
Michal Vaskoa8edff02020-03-27 14:47:01 +01001048
Michal Vaskoe0665742021-02-11 11:08:44 +01001049 /* create attributes */
1050 if (xmlctx->status == LYXML_ATTRIBUTE) {
1051 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
1052 }
1053
1054 /* create node */
1055 assert(xmlctx->status == LYXML_ELEM_CONTENT);
1056 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 +02001057 xmlctx->ws_only ? 0 : xmlctx->value_len, NULL, LY_VALUE_XML, NULL, 0, &child);
Michal Vaskoe0665742021-02-11 11:08:44 +01001058 LY_CHECK_GOTO(rc, cleanup);
1059
1060 /* assign atributes */
1061 ((struct lyd_node_opaq *)child)->attr = attr;
1062 attr = NULL;
1063
1064 /* parser next element */
1065 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1066
1067 /* parse all the descendants */
1068 while (xmlctx->status == LYXML_ELEMENT) {
1069 rc = lydxml_opaq_r(xmlctx, child);
1070 LY_CHECK_GOTO(rc, cleanup);
1071 }
1072
1073 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001074 lyd_insert_node(parent, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +01001075
1076cleanup:
1077 lyd_free_attr_siblings(xmlctx->ctx, attr);
1078 if (rc) {
1079 lyd_free_tree(child);
1080 }
1081 return rc;
1082}
1083
1084/**
1085 * @brief Parse all expected non-data XML elements of the error-info element in NETCONF rpc-reply message.
1086 *
1087 * @param[in] xmlctx XML parser context.
1088 * @param[in] parent Parent to append nodes to.
1089 * @return LY_ERR value.
1090 */
1091static LY_ERR
1092lydxml_env_netconf_rpc_reply_error_info(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
1093{
1094 LY_ERR r;
1095 struct lyd_node *child, *iter;
1096 const struct lyxml_ns *ns;
1097 ly_bool no_dup;
1098
1099 /* there must be some child */
1100 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1101 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"error-info\".");
1102 return LY_EVALID;
1103 }
1104
1105 while (xmlctx->status == LYXML_ELEMENT) {
1106 child = NULL;
1107
1108 /*
1109 * session-id
1110 */
1111 r = lydxml_envelope(xmlctx, "session-id", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1112 if (r == LY_SUCCESS) {
1113 no_dup = 1;
1114 goto check_child;
1115 } else if (r != LY_ENOT) {
1116 goto error;
1117 }
1118
1119 /*
1120 * bad-attribute
1121 */
1122 r = lydxml_envelope(xmlctx, "bad-attribute", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1123 if (r == LY_SUCCESS) {
1124 no_dup = 1;
1125 goto check_child;
1126 } else if (r != LY_ENOT) {
1127 goto error;
1128 }
1129
1130 /*
1131 * bad-element
1132 */
1133 r = lydxml_envelope(xmlctx, "bad-element", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1134 if (r == LY_SUCCESS) {
1135 no_dup = 1;
1136 goto check_child;
1137 } else if (r != LY_ENOT) {
1138 goto error;
1139 }
1140
1141 /*
1142 * bad-namespace
1143 */
1144 r = lydxml_envelope(xmlctx, "bad-namespace", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1145 if (r == LY_SUCCESS) {
1146 no_dup = 1;
1147 goto check_child;
1148 } else if (r != LY_ENOT) {
1149 goto error;
1150 }
1151
1152 if (r == LY_ENOT) {
1153 assert(xmlctx->status == LYXML_ELEMENT);
1154
1155 /* learn namespace */
1156 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
1157 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +01001158 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)xmlctx->prefix_len, xmlctx->prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +01001159 r = LY_EVALID;
1160 goto error;
1161 } else if (!strcmp(ns->uri, "urn:ietf:params:xml:ns:netconf:base:1.0")) {
1162 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"error-info\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001163 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001164 r = LY_EVALID;
1165 goto error;
1166 }
1167
1168 /* custom elements */
1169 r = lydxml_opaq_r(xmlctx, parent);
1170 LY_CHECK_GOTO(r, error);
Michal Vaskoe5ff3672022-01-10 10:12:30 +01001171 continue;
Michal Vaskoe0665742021-02-11 11:08:44 +01001172 }
1173
1174check_child:
1175 /* check for duplicates */
1176 if (no_dup) {
1177 LY_LIST_FOR(lyd_child(parent), iter) {
1178 if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
1179 (((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
1180 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"error-info\".",
1181 ((struct lyd_node_opaq *)child)->name.name);
1182 r = LY_EVALID;
1183 goto error;
1184 }
1185 }
1186 }
1187
1188 /* finish child parsing */
1189 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1190 assert(xmlctx->status == LYXML_ELEMENT);
1191 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"error-info\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001192 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001193 r = LY_EVALID;
1194 goto error;
1195 }
1196 LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
1197
1198 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001199 lyd_insert_node(parent, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +01001200 }
1201
1202 return LY_SUCCESS;
1203
1204error:
1205 lyd_free_tree(child);
1206 return r;
1207}
1208
1209/**
1210 * @brief Parse all expected non-data XML elements of the rpc-error element in NETCONF rpc-reply message.
1211 *
1212 * @param[in] xmlctx XML parser context.
1213 * @param[in] parent Parent to append nodes to.
1214 * @return LY_ERR value.
1215 */
1216static LY_ERR
1217lydxml_env_netconf_rpc_reply_error(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
1218{
1219 LY_ERR r;
1220 struct lyd_node *child, *iter;
1221 const char *val;
1222 ly_bool no_dup;
1223
1224 /* there must be some child */
1225 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1226 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"rpc-error\".");
1227 return LY_EVALID;
1228 }
1229
1230 while (xmlctx->status == LYXML_ELEMENT) {
1231 child = NULL;
1232
1233 /*
1234 * error-type
1235 */
1236 r = lydxml_envelope(xmlctx, "error-type", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1237 if (r == LY_SUCCESS) {
1238 val = ((struct lyd_node_opaq *)child)->value;
1239 if (strcmp(val, "transport") && strcmp(val, "rpc") && strcmp(val, "protocol") && strcmp(val, "application")) {
1240 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1241 ((struct lyd_node_opaq *)child)->name.name);
1242 r = LY_EVALID;
1243 goto error;
1244 }
1245
1246 no_dup = 1;
1247 goto check_child;
1248 } else if (r != LY_ENOT) {
1249 goto error;
1250 }
1251
1252 /*
1253 * error-tag
1254 */
1255 r = lydxml_envelope(xmlctx, "error-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1256 if (r == LY_SUCCESS) {
1257 val = ((struct lyd_node_opaq *)child)->value;
1258 if (strcmp(val, "in-use") && strcmp(val, "invalid-value") && strcmp(val, "too-big") &&
1259 strcmp(val, "missing-attribute") && strcmp(val, "bad-attribute") &&
1260 strcmp(val, "unknown-attribute") && strcmp(val, "missing-element") && strcmp(val, "bad-element") &&
1261 strcmp(val, "unknown-element") && strcmp(val, "unknown-namespace") && strcmp(val, "access-denied") &&
1262 strcmp(val, "lock-denied") && strcmp(val, "resource-denied") && strcmp(val, "rollback-failed") &&
1263 strcmp(val, "data-exists") && strcmp(val, "data-missing") && strcmp(val, "operation-not-supported") &&
1264 strcmp(val, "operation-failed") && strcmp(val, "malformed-message")) {
1265 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1266 ((struct lyd_node_opaq *)child)->name.name);
1267 r = LY_EVALID;
1268 goto error;
1269 }
1270
1271 no_dup = 1;
1272 goto check_child;
1273 } else if (r != LY_ENOT) {
1274 goto error;
1275 }
1276
1277 /*
1278 * error-severity
1279 */
1280 r = lydxml_envelope(xmlctx, "error-severity", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1281 if (r == LY_SUCCESS) {
1282 val = ((struct lyd_node_opaq *)child)->value;
1283 if (strcmp(val, "error") && strcmp(val, "warning")) {
1284 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1285 ((struct lyd_node_opaq *)child)->name.name);
1286 r = LY_EVALID;
1287 goto error;
1288 }
1289
1290 no_dup = 1;
1291 goto check_child;
1292 } else if (r != LY_ENOT) {
1293 goto error;
1294 }
1295
1296 /*
1297 * error-app-tag
1298 */
1299 r = lydxml_envelope(xmlctx, "error-app-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1300 if (r == LY_SUCCESS) {
1301 no_dup = 1;
1302 goto check_child;
1303 } else if (r != LY_ENOT) {
1304 goto error;
1305 }
1306
1307 /*
1308 * error-path
1309 */
1310 r = lydxml_envelope(xmlctx, "error-path", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1311 if (r == LY_SUCCESS) {
1312 no_dup = 1;
1313 goto check_child;
1314 } else if (r != LY_ENOT) {
1315 goto error;
1316 }
1317
1318 /*
1319 * error-message
1320 */
1321 r = lydxml_envelope(xmlctx, "error-message", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1322 if (r == LY_SUCCESS) {
1323 no_dup = 1;
1324 goto check_child;
1325 } else if (r != LY_ENOT) {
1326 goto error;
1327 }
1328
1329 /* error-info */
1330 r = lydxml_envelope(xmlctx, "error-info", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1331 if (r == LY_SUCCESS) {
1332 /* parse all the descendants */
1333 LY_CHECK_GOTO(r = lydxml_env_netconf_rpc_reply_error_info(xmlctx, child), error);
1334
1335 no_dup = 0;
1336 goto check_child;
1337 } else if (r != LY_ENOT) {
1338 goto error;
1339 }
1340
1341 if (r == LY_ENOT) {
1342 assert(xmlctx->status == LYXML_ELEMENT);
1343 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001344 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001345 r = LY_EVALID;
1346 goto error;
1347 }
1348
1349check_child:
1350 /* check for duplicates */
1351 if (no_dup) {
1352 LY_LIST_FOR(lyd_child(parent), iter) {
1353 if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
1354 (((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
1355 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"rpc-error\".",
1356 ((struct lyd_node_opaq *)child)->name.name);
1357 r = LY_EVALID;
1358 goto error;
1359 }
1360 }
1361 }
1362
1363 /* finish child parsing */
1364 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1365 assert(xmlctx->status == LYXML_ELEMENT);
1366 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001367 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001368 r = LY_EVALID;
1369 goto error;
1370 }
1371 LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
1372
1373 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001374 lyd_insert_node(parent, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +01001375 }
1376
1377 return LY_SUCCESS;
1378
1379error:
1380 lyd_free_tree(child);
1381 return r;
1382}
1383
1384/**
1385 * @brief Parse all expected non-data XML elements of a NETCONF rpc-reply message.
1386 *
1387 * @param[in] xmlctx XML parser context.
1388 * @param[out] evnp Parsed envelope(s) (opaque node).
1389 * @param[out] int_opts Internal options for parsing the rest of YANG data.
1390 * @param[out] close_elem Number of parsed opened elements that need to be closed.
1391 * @return LY_SUCCESS on success.
1392 * @return LY_ERR value on error.
1393 */
1394static LY_ERR
1395lydxml_env_netconf_reply(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
1396{
1397 LY_ERR rc = LY_SUCCESS, r;
1398 struct lyd_node *child = NULL;
1399 const char *parsed_elem = NULL;
1400
1401 assert(envp && !*envp);
1402
1403 /* parse "rpc-reply" */
1404 r = lydxml_envelope(xmlctx, "rpc-reply", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +01001405 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1406
1407 /* there must be some child */
1408 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1409 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"rpc-reply\".");
1410 rc = LY_EVALID;
Michal Vaskocf770e22020-08-12 13:21:43 +02001411 goto cleanup;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001412 }
1413
Michal Vaskoe0665742021-02-11 11:08:44 +01001414 /* try to parse "ok" */
1415 r = lydxml_envelope(xmlctx, "ok", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1416 if (r == LY_SUCCESS) {
1417 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001418 lyd_insert_node(*envp, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +01001419
1420 /* finish child parsing */
1421 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1422 assert(xmlctx->status == LYXML_ELEMENT);
1423 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"ok\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001424 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001425 rc = LY_EVALID;
1426 goto cleanup;
1427 }
1428 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1429
1430 /* success */
1431 parsed_elem = "ok";
1432 goto finish;
1433 } else if (r != LY_ENOT) {
1434 rc = r;
1435 goto cleanup;
Michal Vasko2552ea32020-12-08 15:32:34 +01001436 }
1437
Michal Vaskoe0665742021-02-11 11:08:44 +01001438 /* try to parse all "rpc-error" elements */
1439 while (xmlctx->status == LYXML_ELEMENT) {
1440 r = lydxml_envelope(xmlctx, "rpc-error", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1441 if (r == LY_ENOT) {
1442 break;
1443 } else if (r) {
1444 rc = r;
1445 goto cleanup;
1446 }
1447
1448 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001449 lyd_insert_node(*envp, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +01001450
1451 /* parse all children of "rpc-error" */
1452 LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc_reply_error(xmlctx, child), cleanup);
1453
1454 /* finish child parsing */
1455 assert(xmlctx->status == LYXML_ELEM_CLOSE);
1456 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1457
1458 parsed_elem = "rpc-error";
Michal Vasko2552ea32020-12-08 15:32:34 +01001459 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001460
1461finish:
1462 if (parsed_elem) {
1463 /* NETCONF rpc-reply with no data */
1464 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1465 assert(xmlctx->status == LYXML_ELEMENT);
1466 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"%s\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001467 (int)xmlctx->name_len, xmlctx->name, parsed_elem);
Michal Vaskoe0665742021-02-11 11:08:44 +01001468 rc = LY_EVALID;
1469 goto cleanup;
1470 }
1471 }
1472
1473 /* NETCONF rpc-reply */
Michal Vasko1d991fd2021-07-09 13:14:40 +02001474 *int_opts = LYD_INTOPT_WITH_SIBLINGS | LYD_INTOPT_REPLY;
Michal Vaskoe0665742021-02-11 11:08:44 +01001475 *close_elem = 1;
1476
1477cleanup:
1478 if (rc) {
1479 lyd_free_tree(*envp);
1480 *envp = NULL;
1481 }
1482 return rc;
1483}
1484
Michal Vasko2552ea32020-12-08 15:32:34 +01001485LY_ERR
Radek Krejcif16e2542021-02-17 15:39:23 +01001486lyd_parse_xml(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
1487 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 +01001488 struct lyd_node **envp, struct ly_set *parsed, ly_bool *subtree_sibling, struct lyd_ctx **lydctx_p)
Michal Vasko2552ea32020-12-08 15:32:34 +01001489{
Michal Vaskoe0665742021-02-11 11:08:44 +01001490 LY_ERR rc = LY_SUCCESS;
1491 struct lyd_xml_ctx *lydctx;
Michal Vasko2ca9f9e2021-07-02 09:21:36 +02001492 uint32_t i, int_opts = 0, close_elem = 0;
Michal Vaskoe0665742021-02-11 11:08:44 +01001493 ly_bool parsed_data_nodes = 0;
Michal Vaskoaac267d2022-01-17 13:34:48 +01001494 enum LYXML_PARSER_STATUS status;
Michal Vasko2552ea32020-12-08 15:32:34 +01001495
Michal Vaskoe0665742021-02-11 11:08:44 +01001496 assert(ctx && in && lydctx_p);
1497 assert(!(parse_opts & ~LYD_PARSE_OPTS_MASK));
1498 assert(!(val_opts & ~LYD_VALIDATE_OPTS_MASK));
Michal Vasko2552ea32020-12-08 15:32:34 +01001499
Michal Vaskoe0665742021-02-11 11:08:44 +01001500 /* init context */
1501 lydctx = calloc(1, sizeof *lydctx);
1502 LY_CHECK_ERR_RET(!lydctx, LOGMEM(ctx), LY_EMEM);
1503 LY_CHECK_GOTO(rc = lyxml_ctx_new(ctx, in, &lydctx->xmlctx), cleanup);
1504 lydctx->parse_opts = parse_opts;
1505 lydctx->val_opts = val_opts;
1506 lydctx->free = lyd_xml_ctx_free;
Radek Krejcif16e2542021-02-17 15:39:23 +01001507 lydctx->ext = ext;
Michal Vasko2552ea32020-12-08 15:32:34 +01001508
Michal Vaskoe0665742021-02-11 11:08:44 +01001509 switch (data_type) {
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001510 case LYD_TYPE_DATA_YANG:
Michal Vaskoaac267d2022-01-17 13:34:48 +01001511 if (!(parse_opts & LYD_PARSE_SUBTREE)) {
1512 int_opts = LYD_INTOPT_WITH_SIBLINGS;
1513 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001514 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001515 case LYD_TYPE_RPC_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001516 int_opts = LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NO_SIBLINGS;
1517 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001518 case LYD_TYPE_NOTIF_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001519 int_opts = LYD_INTOPT_NOTIF | LYD_INTOPT_NO_SIBLINGS;
1520 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001521 case LYD_TYPE_REPLY_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001522 int_opts = LYD_INTOPT_REPLY | LYD_INTOPT_NO_SIBLINGS;
1523 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001524 case LYD_TYPE_RPC_NETCONF:
Michal Vaskoe0665742021-02-11 11:08:44 +01001525 assert(!parent);
1526 LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
1527 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001528 case LYD_TYPE_NOTIF_NETCONF:
1529 assert(!parent);
1530 LY_CHECK_GOTO(rc = lydxml_env_netconf_notif(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
1531 break;
1532 case LYD_TYPE_REPLY_NETCONF:
Michal Vaskoe0665742021-02-11 11:08:44 +01001533 assert(parent);
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001534 LY_CHECK_GOTO(rc = lydxml_env_netconf_reply(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
Michal Vaskoe0665742021-02-11 11:08:44 +01001535 break;
1536 }
1537 lydctx->int_opts = int_opts;
1538
1539 /* find the operation node if it exists already */
1540 LY_CHECK_GOTO(rc = lyd_parser_find_operation(parent, int_opts, &lydctx->op_node), cleanup);
1541
1542 /* parse XML data */
1543 while (lydctx->xmlctx->status == LYXML_ELEMENT) {
1544 LY_CHECK_GOTO(rc = lydxml_subtree_r(lydctx, parent, first_p, parsed), cleanup);
1545 parsed_data_nodes = 1;
1546
1547 if (!(int_opts & LYD_INTOPT_WITH_SIBLINGS)) {
1548 break;
1549 }
Michal Vasko2552ea32020-12-08 15:32:34 +01001550 }
1551
Michal Vaskoe0665742021-02-11 11:08:44 +01001552 /* close all opened elements */
1553 for (i = 0; i < close_elem; ++i) {
1554 if (lydctx->xmlctx->status != LYXML_ELEM_CLOSE) {
1555 assert(lydctx->xmlctx->status == LYXML_ELEMENT);
Radek Krejci422afb12021-03-04 16:38:16 +01001556 LOGVAL(lydctx->xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\".",
1557 (int)lydctx->xmlctx->name_len, lydctx->xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001558 rc = LY_EVALID;
1559 goto cleanup;
1560 }
1561
1562 LY_CHECK_GOTO(rc = lyxml_ctx_next(lydctx->xmlctx), cleanup);
Michal Vasko4189c0f2020-08-13 09:05:22 +02001563 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001564
1565 /* check final state */
1566 if ((int_opts & LYD_INTOPT_NO_SIBLINGS) && (lydctx->xmlctx->status == LYXML_ELEMENT)) {
1567 LOGVAL(ctx, LYVE_SYNTAX, "Unexpected sibling node.");
1568 rc = LY_EVALID;
1569 goto cleanup;
1570 }
Michal Vaskoe601aaa2022-01-03 11:35:13 +01001571 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 +01001572 LOGVAL(ctx, LYVE_DATA, "Missing the operation node.");
1573 rc = LY_EVALID;
1574 goto cleanup;
1575 }
1576
1577 if (!parsed_data_nodes) {
1578 /* no data nodes were parsed */
1579 lydctx->op_node = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001580 }
1581
Michal Vaskoaac267d2022-01-17 13:34:48 +01001582 if (parse_opts & LYD_PARSE_SUBTREE) {
1583 /* check for a sibling element */
1584 assert(subtree_sibling);
1585 if (!lyxml_ctx_peek(lydctx->xmlctx, &status) && (status == LYXML_ELEMENT)) {
1586 *subtree_sibling = 1;
1587 } else {
1588 *subtree_sibling = 0;
1589 }
1590 }
1591
Michal Vaskoa8edff02020-03-27 14:47:01 +01001592cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +01001593 /* there should be no unres stored if validation should be skipped */
1594 assert(!(parse_opts & LYD_PARSE_ONLY) || (!lydctx->node_types.count && !lydctx->meta_types.count &&
Michal Vaskoaac267d2022-01-17 13:34:48 +01001595 !lydctx->node_when.count));
Michal Vaskoe0665742021-02-11 11:08:44 +01001596
1597 if (rc) {
1598 lyd_xml_ctx_free((struct lyd_ctx *)lydctx);
1599 } else {
1600 *lydctx_p = (struct lyd_ctx *)lydctx;
1601
1602 /* the XML context is no more needed, freeing it also stops logging line numbers which would be confusing now */
1603 lyxml_ctx_free(lydctx->xmlctx);
1604 lydctx->xmlctx = NULL;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001605 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001606 return rc;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001607}