blob: fc7f3d8f53207cdd980ea66bb979fb936a8fddec [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 */
726 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
727
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) {
747 break;
748 }
Michal Vasko27c4dce2021-03-04 15:50:50 +0100749 }
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200750
751 /* restore options */
752 lydctx->parse_opts = prev_parse_opts;
753 lydctx->int_opts = prev_int_opts;
754
755 LY_CHECK_GOTO(ret, error);
Michal Vasko27c4dce2021-03-04 15:50:50 +0100756
757 /* create node */
758 ret = lyd_create_any(snode, anchor, LYD_ANYDATA_DATATREE, 1, &node);
759 LY_CHECK_GOTO(ret, error);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200760 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200761 }
762 assert(node);
763
764 /* add/correct flags */
765 if (snode) {
Michal Vasko8cc3f662022-03-29 11:25:51 +0200766 LY_CHECK_GOTO(ret = lyd_parse_set_data_flags(node, &meta, (struct lyd_ctx *)lydctx, ext), error);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200767 }
768
769 /* parser next */
770 assert(xmlctx->status == LYXML_ELEM_CLOSE);
Michal Vaskoddd76592022-01-17 13:34:48 +0100771 if (!parse_subtree) {
772 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
773 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200774
775 /* add metadata/attributes */
776 if (snode) {
Michal Vasko871a0252020-11-11 18:35:24 +0100777 lyd_insert_meta(node, meta, 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200778 } else {
779 lyd_insert_attr(node, attr);
780 }
781
782 /* insert, keep first pointer correct */
Michal Vasko8cc3f662022-03-29 11:25:51 +0200783 if (ext) {
784 LY_CHECK_GOTO(ret = lyd_insert_ext(parent, node), error);
785 } else {
786 lyd_insert_node(parent, first_p, node, lydctx->parse_opts & LYD_PARSE_ORDERED ? 1 : 0);
787 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200788 while (!parent && (*first_p)->prev->next) {
789 *first_p = (*first_p)->prev;
790 }
791
Michal Vaskoe0665742021-02-11 11:08:44 +0100792 /* rememeber a successfully parsed node */
793 if (parsed) {
794 ly_set_add(parsed, node, 1, NULL);
795 }
796
Michal Vasko8cc3f662022-03-29 11:25:51 +0200797 lydctx->parse_opts = orig_parse_opts;
Radek Krejciddace2c2021-01-08 11:30:56 +0100798 LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200799 return LY_SUCCESS;
800
801error:
Michal Vasko8cc3f662022-03-29 11:25:51 +0200802 lydctx->parse_opts = orig_parse_opts;
Radek Krejciddace2c2021-01-08 11:30:56 +0100803 LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
Michal Vasko3a41dff2020-07-15 14:30:28 +0200804 lyd_free_meta_siblings(meta);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200805 lyd_free_attr_siblings(ctx, attr);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200806 lyd_free_tree(node);
Radek Krejcie7b95092019-05-15 11:03:07 +0200807 return ret;
808}
809
Michal Vaskoe0665742021-02-11 11:08:44 +0100810/**
811 * @brief Parse a specific XML element into an opaque node.
812 *
813 * @param[in] xmlctx XML parser context.
814 * @param[in] name Name of the element.
815 * @param[in] uri URI of the element.
816 * @param[in] value Whether a value is expected in the element.
817 * @param[out] evnp Parsed envelope (opaque node).
818 * @return LY_SUCCESS on success.
819 * @return LY_ENOT if the specified element did not match.
820 * @return LY_ERR value on error.
821 */
Michal Vasko1bf09392020-03-27 12:38:10 +0100822static LY_ERR
Michal Vaskoe0665742021-02-11 11:08:44 +0100823lydxml_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 +0100824{
Michal Vaskoe0665742021-02-11 11:08:44 +0100825 LY_ERR rc = LY_SUCCESS;
826 const struct lyxml_ns *ns;
Radek Krejci1798aae2020-07-14 13:26:06 +0200827 struct lyd_attr *attr = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100828 const char *prefix;
829 size_t prefix_len;
830
Michal Vasko1bf09392020-03-27 12:38:10 +0100831 assert(xmlctx->status == LYXML_ELEMENT);
832 if (ly_strncmp(name, xmlctx->name, xmlctx->name_len)) {
833 /* not the expected element */
Michal Vaskoe0665742021-02-11 11:08:44 +0100834 return LY_ENOT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100835 }
836
837 prefix = xmlctx->prefix;
838 prefix_len = xmlctx->prefix_len;
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200839 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100840 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100841 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +0100842 return LY_EVALID;
843 } else if (strcmp(ns->uri, uri)) {
844 /* different namespace */
845 return LY_ENOT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100846 }
847
848 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
849
850 /* create attributes */
851 if (xmlctx->status == LYXML_ATTRIBUTE) {
852 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
853 }
854
Michal Vaskoe0665742021-02-11 11:08:44 +0100855 assert(xmlctx->status == LYXML_ELEM_CONTENT);
856 if (!value && !xmlctx->ws_only) {
857 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected value \"%.*s\" in the \"%s\" element.",
Radek Krejci422afb12021-03-04 16:38:16 +0100858 (int)xmlctx->value_len, xmlctx->value, name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100859 rc = LY_EVALID;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100860 goto cleanup;
Michal Vaskoe0665742021-02-11 11:08:44 +0100861 }
Michal Vaskoa8edff02020-03-27 14:47:01 +0100862
863 /* create node */
Michal Vaskoe0665742021-02-11 11:08:44 +0100864 rc = lyd_create_opaq(xmlctx->ctx, name, strlen(name), prefix, prefix_len, uri, strlen(uri), xmlctx->value,
Radek Krejci8df109d2021-04-23 12:19:08 +0200865 xmlctx->ws_only ? 0 : xmlctx->value_len, NULL, LY_VALUE_XML, NULL, 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100866 LY_CHECK_GOTO(rc, cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100867
868 /* assign atributes */
Michal Vaskoe0665742021-02-11 11:08:44 +0100869 ((struct lyd_node_opaq *)(*envp))->attr = attr;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100870 attr = NULL;
871
Michal Vaskoe0665742021-02-11 11:08:44 +0100872 /* parser next element */
873 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100874
Michal Vaskoe0665742021-02-11 11:08:44 +0100875cleanup:
876 lyd_free_attr_siblings(xmlctx->ctx, attr);
877 if (rc) {
878 lyd_free_tree(*envp);
879 *envp = NULL;
880 }
881 return rc;
882}
883
884/**
885 * @brief Parse all expected non-data XML elements of a NETCONF rpc message.
886 *
887 * @param[in] xmlctx XML parser context.
888 * @param[out] evnp Parsed envelope(s) (opaque node).
889 * @param[out] int_opts Internal options for parsing the rest of YANG data.
890 * @param[out] close_elem Number of parsed opened elements that need to be closed.
891 * @return LY_SUCCESS on success.
892 * @return LY_ERR value on error.
893 */
894static LY_ERR
895lydxml_env_netconf_rpc(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
896{
897 LY_ERR rc = LY_SUCCESS, r;
898 struct lyd_node *child;
899
900 assert(envp && !*envp);
901
902 /* parse "rpc" */
903 r = lydxml_envelope(xmlctx, "rpc", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100904 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
905
906 /* parse "action", if any */
907 r = lydxml_envelope(xmlctx, "action", "urn:ietf:params:xml:ns:yang:1", 0, &child);
908 if (r == LY_SUCCESS) {
909 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +0200910 lyd_insert_node(*envp, NULL, child, 0);
Michal Vaskoe0665742021-02-11 11:08:44 +0100911
912 /* NETCONF action */
913 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_ACTION;
914 *close_elem = 2;
915 } else if (r == LY_ENOT) {
916 /* NETCONF RPC */
917 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_RPC;
918 *close_elem = 1;
919 } else {
920 rc = r;
921 goto cleanup;
922 }
923
924cleanup:
925 if (rc) {
926 lyd_free_tree(*envp);
927 *envp = NULL;
928 }
929 return rc;
930}
931
932/**
933 * @brief Parse all expected non-data XML elements of a NETCONF notification message.
934 *
935 * @param[in] xmlctx XML parser context.
936 * @param[out] evnp Parsed envelope(s) (opaque node).
937 * @param[out] int_opts Internal options for parsing the rest of YANG data.
938 * @param[out] close_elem Number of parsed opened elements that need to be closed.
939 * @return LY_SUCCESS on success.
940 * @return LY_ERR value on error.
941 */
942static LY_ERR
943lydxml_env_netconf_notif(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
944{
945 LY_ERR rc = LY_SUCCESS, r;
946 struct lyd_node *child;
947
948 assert(envp && !*envp);
949
950 /* parse "notification" */
951 r = lydxml_envelope(xmlctx, "notification", "urn:ietf:params:xml:ns:netconf:notification:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100952 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
953
954 /* parse "eventTime" */
955 r = lydxml_envelope(xmlctx, "eventTime", "urn:ietf:params:xml:ns:netconf:notification:1.0", 1, &child);
956 if (r == LY_ENOT) {
Radek Krejci422afb12021-03-04 16:38:16 +0100957 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unexpected element \"%.*s\" instead of \"eventTime\".",
958 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100959 r = LY_EVALID;
960 }
961 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
962
963 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +0200964 lyd_insert_node(*envp, NULL, child, 0);
Michal Vaskoe0665742021-02-11 11:08:44 +0100965
966 /* validate value */
967 /* TODO validate child->value as yang:date-and-time */
968
969 /* finish child parsing */
Michal Vaskoa8edff02020-03-27 14:47:01 +0100970 if (xmlctx->status != LYXML_ELEM_CLOSE) {
971 assert(xmlctx->status == LYXML_ELEMENT);
Michal Vaskoe0665742021-02-11 11:08:44 +0100972 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"eventTime\".",
Radek Krejci422afb12021-03-04 16:38:16 +0100973 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100974 rc = LY_EVALID;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100975 goto cleanup;
976 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100977 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
978
979 /* NETCONF notification */
980 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_NOTIF;
981 *close_elem = 1;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100982
983cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +0100984 if (rc) {
Michal Vaskoa8edff02020-03-27 14:47:01 +0100985 lyd_free_tree(*envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100986 *envp = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100987 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100988 return rc;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100989}
Michal Vasko79135ae2020-12-16 10:08:35 +0100990
Michal Vaskoe0665742021-02-11 11:08:44 +0100991/**
992 * @brief Parse an XML element as an opaque node subtree.
993 *
994 * @param[in] xmlctx XML parser context.
995 * @param[in] parent Parent to append nodes to.
996 * @return LY_ERR value.
997 */
998static LY_ERR
999lydxml_opaq_r(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
Michal Vaskoa8edff02020-03-27 14:47:01 +01001000{
Michal Vaskoe0665742021-02-11 11:08:44 +01001001 LY_ERR rc = LY_SUCCESS;
1002 const struct lyxml_ns *ns;
1003 struct lyd_attr *attr = NULL;
1004 struct lyd_node *child = NULL;
1005 const char *name, *prefix;
1006 size_t name_len, prefix_len;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001007
Michal Vaskoe0665742021-02-11 11:08:44 +01001008 assert(xmlctx->status == LYXML_ELEMENT);
Michal Vaskoa8edff02020-03-27 14:47:01 +01001009
Michal Vaskoe0665742021-02-11 11:08:44 +01001010 name = xmlctx->name;
1011 name_len = xmlctx->name_len;
1012 prefix = xmlctx->prefix;
1013 prefix_len = xmlctx->prefix_len;
1014 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
1015 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +01001016 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +01001017 return LY_EVALID;
1018 }
Michal Vaskoa8edff02020-03-27 14:47:01 +01001019
Michal Vaskoe0665742021-02-11 11:08:44 +01001020 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
Michal Vaskoa8edff02020-03-27 14:47:01 +01001021
Michal Vaskoe0665742021-02-11 11:08:44 +01001022 /* create attributes */
1023 if (xmlctx->status == LYXML_ATTRIBUTE) {
1024 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
1025 }
1026
1027 /* create node */
1028 assert(xmlctx->status == LYXML_ELEM_CONTENT);
1029 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 +02001030 xmlctx->ws_only ? 0 : xmlctx->value_len, NULL, LY_VALUE_XML, NULL, 0, &child);
Michal Vaskoe0665742021-02-11 11:08:44 +01001031 LY_CHECK_GOTO(rc, cleanup);
1032
1033 /* assign atributes */
1034 ((struct lyd_node_opaq *)child)->attr = attr;
1035 attr = NULL;
1036
1037 /* parser next element */
1038 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1039
1040 /* parse all the descendants */
1041 while (xmlctx->status == LYXML_ELEMENT) {
1042 rc = lydxml_opaq_r(xmlctx, child);
1043 LY_CHECK_GOTO(rc, cleanup);
1044 }
1045
1046 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001047 lyd_insert_node(parent, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +01001048
1049cleanup:
1050 lyd_free_attr_siblings(xmlctx->ctx, attr);
1051 if (rc) {
1052 lyd_free_tree(child);
1053 }
1054 return rc;
1055}
1056
1057/**
1058 * @brief Parse all expected non-data XML elements of the error-info element in NETCONF rpc-reply message.
1059 *
1060 * @param[in] xmlctx XML parser context.
1061 * @param[in] parent Parent to append nodes to.
1062 * @return LY_ERR value.
1063 */
1064static LY_ERR
1065lydxml_env_netconf_rpc_reply_error_info(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
1066{
1067 LY_ERR r;
1068 struct lyd_node *child, *iter;
1069 const struct lyxml_ns *ns;
1070 ly_bool no_dup;
1071
1072 /* there must be some child */
1073 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1074 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"error-info\".");
1075 return LY_EVALID;
1076 }
1077
1078 while (xmlctx->status == LYXML_ELEMENT) {
1079 child = NULL;
1080
1081 /*
1082 * session-id
1083 */
1084 r = lydxml_envelope(xmlctx, "session-id", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1085 if (r == LY_SUCCESS) {
1086 no_dup = 1;
1087 goto check_child;
1088 } else if (r != LY_ENOT) {
1089 goto error;
1090 }
1091
1092 /*
1093 * bad-attribute
1094 */
1095 r = lydxml_envelope(xmlctx, "bad-attribute", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1096 if (r == LY_SUCCESS) {
1097 no_dup = 1;
1098 goto check_child;
1099 } else if (r != LY_ENOT) {
1100 goto error;
1101 }
1102
1103 /*
1104 * bad-element
1105 */
1106 r = lydxml_envelope(xmlctx, "bad-element", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1107 if (r == LY_SUCCESS) {
1108 no_dup = 1;
1109 goto check_child;
1110 } else if (r != LY_ENOT) {
1111 goto error;
1112 }
1113
1114 /*
1115 * bad-namespace
1116 */
1117 r = lydxml_envelope(xmlctx, "bad-namespace", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1118 if (r == LY_SUCCESS) {
1119 no_dup = 1;
1120 goto check_child;
1121 } else if (r != LY_ENOT) {
1122 goto error;
1123 }
1124
1125 if (r == LY_ENOT) {
1126 assert(xmlctx->status == LYXML_ELEMENT);
1127
1128 /* learn namespace */
1129 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
1130 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +01001131 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)xmlctx->prefix_len, xmlctx->prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +01001132 r = LY_EVALID;
1133 goto error;
1134 } else if (!strcmp(ns->uri, "urn:ietf:params:xml:ns:netconf:base:1.0")) {
1135 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"error-info\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001136 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001137 r = LY_EVALID;
1138 goto error;
1139 }
1140
1141 /* custom elements */
1142 r = lydxml_opaq_r(xmlctx, parent);
1143 LY_CHECK_GOTO(r, error);
Michal Vasko6398eaf2022-01-10 10:12:30 +01001144 continue;
Michal Vaskoe0665742021-02-11 11:08:44 +01001145 }
1146
1147check_child:
1148 /* check for duplicates */
1149 if (no_dup) {
1150 LY_LIST_FOR(lyd_child(parent), iter) {
1151 if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
1152 (((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
1153 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"error-info\".",
1154 ((struct lyd_node_opaq *)child)->name.name);
1155 r = LY_EVALID;
1156 goto error;
1157 }
1158 }
1159 }
1160
1161 /* finish child parsing */
1162 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1163 assert(xmlctx->status == LYXML_ELEMENT);
1164 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"error-info\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001165 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001166 r = LY_EVALID;
1167 goto error;
1168 }
1169 LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
1170
1171 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001172 lyd_insert_node(parent, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +01001173 }
1174
1175 return LY_SUCCESS;
1176
1177error:
1178 lyd_free_tree(child);
1179 return r;
1180}
1181
1182/**
1183 * @brief Parse all expected non-data XML elements of the rpc-error element in NETCONF rpc-reply message.
1184 *
1185 * @param[in] xmlctx XML parser context.
1186 * @param[in] parent Parent to append nodes to.
1187 * @return LY_ERR value.
1188 */
1189static LY_ERR
1190lydxml_env_netconf_rpc_reply_error(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
1191{
1192 LY_ERR r;
1193 struct lyd_node *child, *iter;
1194 const char *val;
1195 ly_bool no_dup;
1196
1197 /* there must be some child */
1198 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1199 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"rpc-error\".");
1200 return LY_EVALID;
1201 }
1202
1203 while (xmlctx->status == LYXML_ELEMENT) {
1204 child = NULL;
1205
1206 /*
1207 * error-type
1208 */
1209 r = lydxml_envelope(xmlctx, "error-type", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1210 if (r == LY_SUCCESS) {
1211 val = ((struct lyd_node_opaq *)child)->value;
1212 if (strcmp(val, "transport") && strcmp(val, "rpc") && strcmp(val, "protocol") && strcmp(val, "application")) {
1213 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1214 ((struct lyd_node_opaq *)child)->name.name);
1215 r = LY_EVALID;
1216 goto error;
1217 }
1218
1219 no_dup = 1;
1220 goto check_child;
1221 } else if (r != LY_ENOT) {
1222 goto error;
1223 }
1224
1225 /*
1226 * error-tag
1227 */
1228 r = lydxml_envelope(xmlctx, "error-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1229 if (r == LY_SUCCESS) {
1230 val = ((struct lyd_node_opaq *)child)->value;
1231 if (strcmp(val, "in-use") && strcmp(val, "invalid-value") && strcmp(val, "too-big") &&
1232 strcmp(val, "missing-attribute") && strcmp(val, "bad-attribute") &&
1233 strcmp(val, "unknown-attribute") && strcmp(val, "missing-element") && strcmp(val, "bad-element") &&
1234 strcmp(val, "unknown-element") && strcmp(val, "unknown-namespace") && strcmp(val, "access-denied") &&
1235 strcmp(val, "lock-denied") && strcmp(val, "resource-denied") && strcmp(val, "rollback-failed") &&
1236 strcmp(val, "data-exists") && strcmp(val, "data-missing") && strcmp(val, "operation-not-supported") &&
1237 strcmp(val, "operation-failed") && strcmp(val, "malformed-message")) {
1238 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1239 ((struct lyd_node_opaq *)child)->name.name);
1240 r = LY_EVALID;
1241 goto error;
1242 }
1243
1244 no_dup = 1;
1245 goto check_child;
1246 } else if (r != LY_ENOT) {
1247 goto error;
1248 }
1249
1250 /*
1251 * error-severity
1252 */
1253 r = lydxml_envelope(xmlctx, "error-severity", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1254 if (r == LY_SUCCESS) {
1255 val = ((struct lyd_node_opaq *)child)->value;
1256 if (strcmp(val, "error") && strcmp(val, "warning")) {
1257 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1258 ((struct lyd_node_opaq *)child)->name.name);
1259 r = LY_EVALID;
1260 goto error;
1261 }
1262
1263 no_dup = 1;
1264 goto check_child;
1265 } else if (r != LY_ENOT) {
1266 goto error;
1267 }
1268
1269 /*
1270 * error-app-tag
1271 */
1272 r = lydxml_envelope(xmlctx, "error-app-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1273 if (r == LY_SUCCESS) {
1274 no_dup = 1;
1275 goto check_child;
1276 } else if (r != LY_ENOT) {
1277 goto error;
1278 }
1279
1280 /*
1281 * error-path
1282 */
1283 r = lydxml_envelope(xmlctx, "error-path", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1284 if (r == LY_SUCCESS) {
1285 no_dup = 1;
1286 goto check_child;
1287 } else if (r != LY_ENOT) {
1288 goto error;
1289 }
1290
1291 /*
1292 * error-message
1293 */
1294 r = lydxml_envelope(xmlctx, "error-message", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1295 if (r == LY_SUCCESS) {
1296 no_dup = 1;
1297 goto check_child;
1298 } else if (r != LY_ENOT) {
1299 goto error;
1300 }
1301
1302 /* error-info */
1303 r = lydxml_envelope(xmlctx, "error-info", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1304 if (r == LY_SUCCESS) {
1305 /* parse all the descendants */
1306 LY_CHECK_GOTO(r = lydxml_env_netconf_rpc_reply_error_info(xmlctx, child), error);
1307
1308 no_dup = 0;
1309 goto check_child;
1310 } else if (r != LY_ENOT) {
1311 goto error;
1312 }
1313
1314 if (r == LY_ENOT) {
1315 assert(xmlctx->status == LYXML_ELEMENT);
1316 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001317 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001318 r = LY_EVALID;
1319 goto error;
1320 }
1321
1322check_child:
1323 /* check for duplicates */
1324 if (no_dup) {
1325 LY_LIST_FOR(lyd_child(parent), iter) {
1326 if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
1327 (((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
1328 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"rpc-error\".",
1329 ((struct lyd_node_opaq *)child)->name.name);
1330 r = LY_EVALID;
1331 goto error;
1332 }
1333 }
1334 }
1335
1336 /* finish child parsing */
1337 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1338 assert(xmlctx->status == LYXML_ELEMENT);
1339 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001340 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001341 r = LY_EVALID;
1342 goto error;
1343 }
1344 LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
1345
1346 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001347 lyd_insert_node(parent, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +01001348 }
1349
1350 return LY_SUCCESS;
1351
1352error:
1353 lyd_free_tree(child);
1354 return r;
1355}
1356
1357/**
1358 * @brief Parse all expected non-data XML elements of a NETCONF rpc-reply message.
1359 *
1360 * @param[in] xmlctx XML parser context.
1361 * @param[out] evnp Parsed envelope(s) (opaque node).
1362 * @param[out] int_opts Internal options for parsing the rest of YANG data.
1363 * @param[out] close_elem Number of parsed opened elements that need to be closed.
1364 * @return LY_SUCCESS on success.
1365 * @return LY_ERR value on error.
1366 */
1367static LY_ERR
1368lydxml_env_netconf_reply(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
1369{
1370 LY_ERR rc = LY_SUCCESS, r;
1371 struct lyd_node *child = NULL;
1372 const char *parsed_elem = NULL;
1373
1374 assert(envp && !*envp);
1375
1376 /* parse "rpc-reply" */
1377 r = lydxml_envelope(xmlctx, "rpc-reply", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +01001378 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1379
1380 /* there must be some child */
1381 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1382 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"rpc-reply\".");
1383 rc = LY_EVALID;
Michal Vaskocf770e22020-08-12 13:21:43 +02001384 goto cleanup;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001385 }
1386
Michal Vaskoe0665742021-02-11 11:08:44 +01001387 /* try to parse "ok" */
1388 r = lydxml_envelope(xmlctx, "ok", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1389 if (r == LY_SUCCESS) {
1390 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001391 lyd_insert_node(*envp, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +01001392
1393 /* finish child parsing */
1394 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1395 assert(xmlctx->status == LYXML_ELEMENT);
1396 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"ok\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001397 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001398 rc = LY_EVALID;
1399 goto cleanup;
1400 }
1401 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1402
1403 /* success */
1404 parsed_elem = "ok";
1405 goto finish;
1406 } else if (r != LY_ENOT) {
1407 rc = r;
1408 goto cleanup;
Michal Vasko2552ea32020-12-08 15:32:34 +01001409 }
1410
Michal Vaskoe0665742021-02-11 11:08:44 +01001411 /* try to parse all "rpc-error" elements */
1412 while (xmlctx->status == LYXML_ELEMENT) {
1413 r = lydxml_envelope(xmlctx, "rpc-error", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1414 if (r == LY_ENOT) {
1415 break;
1416 } else if (r) {
1417 rc = r;
1418 goto cleanup;
1419 }
1420
1421 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001422 lyd_insert_node(*envp, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +01001423
1424 /* parse all children of "rpc-error" */
1425 LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc_reply_error(xmlctx, child), cleanup);
1426
1427 /* finish child parsing */
1428 assert(xmlctx->status == LYXML_ELEM_CLOSE);
1429 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1430
1431 parsed_elem = "rpc-error";
Michal Vasko2552ea32020-12-08 15:32:34 +01001432 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001433
1434finish:
1435 if (parsed_elem) {
1436 /* NETCONF rpc-reply with no data */
1437 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1438 assert(xmlctx->status == LYXML_ELEMENT);
1439 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"%s\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001440 (int)xmlctx->name_len, xmlctx->name, parsed_elem);
Michal Vaskoe0665742021-02-11 11:08:44 +01001441 rc = LY_EVALID;
1442 goto cleanup;
1443 }
1444 }
1445
1446 /* NETCONF rpc-reply */
Michal Vasko1d991fd2021-07-09 13:14:40 +02001447 *int_opts = LYD_INTOPT_WITH_SIBLINGS | LYD_INTOPT_REPLY;
Michal Vaskoe0665742021-02-11 11:08:44 +01001448 *close_elem = 1;
1449
1450cleanup:
1451 if (rc) {
1452 lyd_free_tree(*envp);
1453 *envp = NULL;
1454 }
1455 return rc;
1456}
1457
Michal Vasko2552ea32020-12-08 15:32:34 +01001458LY_ERR
Radek Krejcif16e2542021-02-17 15:39:23 +01001459lyd_parse_xml(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
1460 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 +01001461 struct lyd_node **envp, struct ly_set *parsed, ly_bool *subtree_sibling, struct lyd_ctx **lydctx_p)
Michal Vasko2552ea32020-12-08 15:32:34 +01001462{
Michal Vaskoe0665742021-02-11 11:08:44 +01001463 LY_ERR rc = LY_SUCCESS;
1464 struct lyd_xml_ctx *lydctx;
Michal Vasko2ca9f9e2021-07-02 09:21:36 +02001465 uint32_t i, int_opts = 0, close_elem = 0;
Michal Vaskoe0665742021-02-11 11:08:44 +01001466 ly_bool parsed_data_nodes = 0;
Michal Vaskoddd76592022-01-17 13:34:48 +01001467 enum LYXML_PARSER_STATUS status;
Michal Vasko2552ea32020-12-08 15:32:34 +01001468
Michal Vaskoe0665742021-02-11 11:08:44 +01001469 assert(ctx && in && lydctx_p);
1470 assert(!(parse_opts & ~LYD_PARSE_OPTS_MASK));
1471 assert(!(val_opts & ~LYD_VALIDATE_OPTS_MASK));
Michal Vasko2552ea32020-12-08 15:32:34 +01001472
Michal Vaskoe0665742021-02-11 11:08:44 +01001473 /* init context */
1474 lydctx = calloc(1, sizeof *lydctx);
1475 LY_CHECK_ERR_RET(!lydctx, LOGMEM(ctx), LY_EMEM);
1476 LY_CHECK_GOTO(rc = lyxml_ctx_new(ctx, in, &lydctx->xmlctx), cleanup);
1477 lydctx->parse_opts = parse_opts;
1478 lydctx->val_opts = val_opts;
1479 lydctx->free = lyd_xml_ctx_free;
Radek Krejcif16e2542021-02-17 15:39:23 +01001480 lydctx->ext = ext;
Michal Vasko2552ea32020-12-08 15:32:34 +01001481
Michal Vaskoe0665742021-02-11 11:08:44 +01001482 switch (data_type) {
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001483 case LYD_TYPE_DATA_YANG:
Michal Vaskoddd76592022-01-17 13:34:48 +01001484 if (!(parse_opts & LYD_PARSE_SUBTREE)) {
1485 int_opts = LYD_INTOPT_WITH_SIBLINGS;
1486 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001487 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001488 case LYD_TYPE_RPC_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001489 int_opts = LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NO_SIBLINGS;
1490 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001491 case LYD_TYPE_NOTIF_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001492 int_opts = LYD_INTOPT_NOTIF | LYD_INTOPT_NO_SIBLINGS;
1493 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001494 case LYD_TYPE_REPLY_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001495 int_opts = LYD_INTOPT_REPLY | LYD_INTOPT_NO_SIBLINGS;
1496 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001497 case LYD_TYPE_RPC_NETCONF:
Michal Vaskoe0665742021-02-11 11:08:44 +01001498 assert(!parent);
1499 LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
1500 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001501 case LYD_TYPE_NOTIF_NETCONF:
1502 assert(!parent);
1503 LY_CHECK_GOTO(rc = lydxml_env_netconf_notif(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
1504 break;
1505 case LYD_TYPE_REPLY_NETCONF:
Michal Vaskoe0665742021-02-11 11:08:44 +01001506 assert(parent);
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001507 LY_CHECK_GOTO(rc = lydxml_env_netconf_reply(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
Michal Vaskoe0665742021-02-11 11:08:44 +01001508 break;
1509 }
1510 lydctx->int_opts = int_opts;
1511
1512 /* find the operation node if it exists already */
1513 LY_CHECK_GOTO(rc = lyd_parser_find_operation(parent, int_opts, &lydctx->op_node), cleanup);
1514
1515 /* parse XML data */
1516 while (lydctx->xmlctx->status == LYXML_ELEMENT) {
1517 LY_CHECK_GOTO(rc = lydxml_subtree_r(lydctx, parent, first_p, parsed), cleanup);
1518 parsed_data_nodes = 1;
1519
1520 if (!(int_opts & LYD_INTOPT_WITH_SIBLINGS)) {
1521 break;
1522 }
Michal Vasko2552ea32020-12-08 15:32:34 +01001523 }
1524
Michal Vaskoe0665742021-02-11 11:08:44 +01001525 /* close all opened elements */
1526 for (i = 0; i < close_elem; ++i) {
1527 if (lydctx->xmlctx->status != LYXML_ELEM_CLOSE) {
1528 assert(lydctx->xmlctx->status == LYXML_ELEMENT);
Radek Krejci422afb12021-03-04 16:38:16 +01001529 LOGVAL(lydctx->xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\".",
1530 (int)lydctx->xmlctx->name_len, lydctx->xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001531 rc = LY_EVALID;
1532 goto cleanup;
1533 }
1534
1535 LY_CHECK_GOTO(rc = lyxml_ctx_next(lydctx->xmlctx), cleanup);
Michal Vasko4189c0f2020-08-13 09:05:22 +02001536 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001537
1538 /* check final state */
1539 if ((int_opts & LYD_INTOPT_NO_SIBLINGS) && (lydctx->xmlctx->status == LYXML_ELEMENT)) {
1540 LOGVAL(ctx, LYVE_SYNTAX, "Unexpected sibling node.");
1541 rc = LY_EVALID;
1542 goto cleanup;
1543 }
Michal Vaskoc939fdd2022-01-03 11:35:13 +01001544 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 +01001545 LOGVAL(ctx, LYVE_DATA, "Missing the operation node.");
1546 rc = LY_EVALID;
1547 goto cleanup;
1548 }
1549
1550 if (!parsed_data_nodes) {
1551 /* no data nodes were parsed */
1552 lydctx->op_node = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001553 }
1554
Michal Vaskoddd76592022-01-17 13:34:48 +01001555 if (parse_opts & LYD_PARSE_SUBTREE) {
1556 /* check for a sibling element */
1557 assert(subtree_sibling);
1558 if (!lyxml_ctx_peek(lydctx->xmlctx, &status) && (status == LYXML_ELEMENT)) {
1559 *subtree_sibling = 1;
1560 } else {
1561 *subtree_sibling = 0;
1562 }
1563 }
1564
Michal Vaskoa8edff02020-03-27 14:47:01 +01001565cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +01001566 /* there should be no unres stored if validation should be skipped */
1567 assert(!(parse_opts & LYD_PARSE_ONLY) || (!lydctx->node_types.count && !lydctx->meta_types.count &&
Michal Vaskoddd76592022-01-17 13:34:48 +01001568 !lydctx->node_when.count));
Michal Vaskoe0665742021-02-11 11:08:44 +01001569
1570 if (rc) {
1571 lyd_xml_ctx_free((struct lyd_ctx *)lydctx);
1572 } else {
1573 *lydctx_p = (struct lyd_ctx *)lydctx;
1574
1575 /* the XML context is no more needed, freeing it also stops logging line numbers which would be confusing now */
1576 lyxml_ctx_free(lydctx->xmlctx);
1577 lydctx->xmlctx = NULL;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001578 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001579 return rc;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001580}