blob: 74bdf6e5d4af0b0ffa49f9de0c15ff55458250ca [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 Vasko742a5b12022-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 Vasko742a5b12022-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-vintrlik2aa36b42021-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 Vaskoddd76592022-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 Vaskoddd76592022-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 Vaskoddd76592022-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 Vaskoddd76592022-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 Vaskoe5e49e92022-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 Vaskoddd76592022-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) {
Michal Vaskob8262962022-03-17 11:11:13 +0100449 if (!nested_exts[u].def->plugin->parse) {
450 /* not an extension with parsed data */
451 continue;
452 }
453
Michal Vaskoddd76592022-01-17 13:34:48 +0100454 /* prepare the input and try to parse this extension data */
455 in_ext = in_start;
456 ext_parse_cb = nested_exts[u].def->plugin->parse;
457 r = ext_parse_cb(&in_ext, LYD_XML, &nested_exts[u], parent, lydctx->parse_opts | LYD_PARSE_ONLY);
458 if (!r) {
459 /* data successfully parsed, remember for validation */
460 if (!(lydctx->parse_opts & LYD_PARSE_ONLY)) {
461 ext_val = malloc(sizeof *ext_val);
462 LY_CHECK_ERR_RET(!ext_val, LOGMEM(lydctx->xmlctx->ctx), LY_EMEM);
463 ext_val->ext = &nested_exts[u];
Michal Vasko61ad1ff2022-02-10 15:48:39 +0100464 ext_val->sibling = lyd_child_no_keys(parent);
Michal Vaskoddd76592022-01-17 13:34:48 +0100465 LY_CHECK_RET(ly_set_add(&lydctx->ext_val, ext_val, 1, NULL));
466 }
467
468 /* adjust the xmlctx accordingly */
469 *lydctx->xmlctx->in = in_ext;
470 lydctx->xmlctx->status = LYXML_ELEM_CONTENT;
471 lydctx->xmlctx->dynamic = 0;
472 ly_set_rm_index(&lydctx->xmlctx->elements, lydctx->xmlctx->elements.count - 1, free);
473 lyxml_ns_rm(lydctx->xmlctx);
474 LY_CHECK_RET(lyxml_ctx_next(lydctx->xmlctx));
475 return LY_SUCCESS;
476 } else if (r != LY_ENOT) {
477 /* fatal error */
478 return r;
479 }
480 /* data was not from this module, continue */
481 }
482
483 /* no extensions or none matched, restore input */
484 *lydctx->xmlctx->in = in_bck;
485 return LY_ENOT;
486}
487
488/**
Michal Vaskoa5da3292020-08-12 13:10:50 +0200489 * @brief Parse XML subtree.
Radek Krejcie7b95092019-05-15 11:03:07 +0200490 *
Michal Vaskob36053d2020-03-26 15:49:30 +0100491 * @param[in] lydctx XML YANG data parser context.
Michal Vaskoe0665742021-02-11 11:08:44 +0100492 * @param[in,out] parent Parent node where the children are inserted. NULL in case of parsing top-level elements.
493 * @param[in,out] first_p Pointer to the first (@p parent or top-level) child. In case there were already some siblings,
494 * this may point to a previously existing node.
495 * @param[in,out] parsed Optional set to add all the parsed siblings into.
Michal Vasko9b368d32020-02-14 13:53:31 +0100496 * @return LY_ERR value.
Radek Krejcie7b95092019-05-15 11:03:07 +0200497 */
498static LY_ERR
Michal Vaskoe0665742021-02-11 11:08:44 +0100499lydxml_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 +0200500{
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +0100501 LY_ERR ret = LY_SUCCESS, r;
Michal Vasko742a5b12022-02-24 16:07:27 +0100502 const char *prefix, *name;
Michal Vasko1bf09392020-03-27 12:38:10 +0100503 size_t prefix_len, name_len;
Michal Vaskob36053d2020-03-26 15:49:30 +0100504 struct lyxml_ctx *xmlctx;
505 const struct ly_ctx *ctx;
Radek Krejcie7b95092019-05-15 11:03:07 +0200506 const struct lyxml_ns *ns;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200507 struct lyd_meta *meta = NULL;
508 struct lyd_attr *attr = NULL;
Radek Krejcie7b95092019-05-15 11:03:07 +0200509 const struct lysc_node *snode;
510 struct lys_module *mod;
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200511 uint32_t prev_parse_opts, prev_int_opts;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200512 struct lyd_node *node = NULL, *anchor;
Michal Vaskofc2cd072021-02-24 13:17:17 +0100513 void *val_prefix_data = NULL;
Radek Krejci8df109d2021-04-23 12:19:08 +0200514 LY_VALUE_FORMAT format;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200515 uint32_t getnext_opts;
Michal Vaskoddd76592022-01-17 13:34:48 +0100516 ly_bool parse_subtree;
Michal Vasko742a5b12022-02-24 16:07:27 +0100517 char *val;
Radek Krejcie7b95092019-05-15 11:03:07 +0200518
Michal Vaskoe0665742021-02-11 11:08:44 +0100519 assert(parent || first_p);
520
Michal Vaskob36053d2020-03-26 15:49:30 +0100521 xmlctx = lydctx->xmlctx;
522 ctx = xmlctx->ctx;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100523 getnext_opts = lydctx->int_opts & LYD_INTOPT_REPLY ? LYS_GETNEXT_OUTPUT : 0;
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100524
Michal Vaskoddd76592022-01-17 13:34:48 +0100525 parse_subtree = lydctx->parse_opts & LYD_PARSE_SUBTREE ? 1 : 0;
526 /* all descendants should be parsed */
527 lydctx->parse_opts &= ~LYD_PARSE_SUBTREE;
528
Michal Vaskoa5da3292020-08-12 13:10:50 +0200529 assert(xmlctx->status == LYXML_ELEMENT);
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200530
Michal Vaskoa5da3292020-08-12 13:10:50 +0200531 /* remember element prefix and name */
532 prefix = xmlctx->prefix;
533 prefix_len = xmlctx->prefix_len;
534 name = xmlctx->name;
535 name_len = xmlctx->name_len;
536
537 /* get the element module */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200538 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200539 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100540 LOGVAL(ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200541 ret = LY_EVALID;
542 goto error;
543 }
544 mod = ly_ctx_get_module_implemented_ns(ctx, ns->uri);
545 if (!mod) {
Michal Vaskoddd76592022-01-17 13:34:48 +0100546 /* check for extension data */
547 r = lydxml_nested_ext(lydctx, parent);
548 if (!r) {
549 /* successfully parsed */
550 return r;
551 } else if (r != LY_ENOT) {
552 /* error */
553 ret = r;
554 goto error;
555 }
556
557 /* unknown module */
Michal Vaskoe0665742021-02-11 11:08:44 +0100558 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100559 LOGVAL(ctx, LYVE_REFERENCE, "No module with namespace \"%s\" in the context.", ns->uri);
Michal Vasko90932a92020-02-12 14:33:03 +0100560 ret = LY_EVALID;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200561 goto error;
Radek Krejcie7b95092019-05-15 11:03:07 +0200562 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100563 if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
Michal Vaskoa5da3292020-08-12 13:10:50 +0200564 /* skip element with children */
565 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
566 return LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200567 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200568 }
569
Michal Vaskoa5da3292020-08-12 13:10:50 +0200570 /* parser next */
571 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
Michal Vasko90932a92020-02-12 14:33:03 +0100572
Michal Vaskoa5da3292020-08-12 13:10:50 +0200573 /* get the schema node */
574 snode = NULL;
Michal Vasko81008a52021-07-21 16:06:12 +0200575 if (mod) {
Radek Krejcif16e2542021-02-17 15:39:23 +0100576 if (!parent && lydctx->ext) {
Radek Krejciba05eab2021-03-10 13:19:29 +0100577 snode = lysc_ext_find_node(lydctx->ext, mod, name, name_len, 0, getnext_opts);
Radek Krejcif16e2542021-02-17 15:39:23 +0100578 } else {
579 snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
580 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200581 if (!snode) {
Michal Vaskoddd76592022-01-17 13:34:48 +0100582 /* check for extension data */
583 r = lydxml_nested_ext(lydctx, parent);
584 if (!r) {
585 /* successfully parsed */
586 return r;
587 } else if (r != LY_ENOT) {
588 /* error */
589 ret = r;
590 goto error;
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +0100591 }
Michal Vaskoddd76592022-01-17 13:34:48 +0100592
593 /* unknown data node */
Michal Vaskoe0665742021-02-11 11:08:44 +0100594 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
595 if (parent) {
Radek Krejci422afb12021-03-04 16:38:16 +0100596 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found as a child of \"%s\" node.",
Michal Vasko61ad1ff2022-02-10 15:48:39 +0100597 (int)name_len, name, LYD_NAME(parent));
Radek Krejcif16e2542021-02-17 15:39:23 +0100598 } else if (lydctx->ext) {
599 if (lydctx->ext->argument) {
Radek Krejci422afb12021-03-04 16:38:16 +0100600 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" %s extension instance.",
601 (int)name_len, name, lydctx->ext->argument, lydctx->ext->def->name);
Radek Krejcif16e2542021-02-17 15:39:23 +0100602 } else {
Radek Krejci422afb12021-03-04 16:38:16 +0100603 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the %s extension instance.",
604 (int)name_len, name, lydctx->ext->def->name);
Radek Krejcif16e2542021-02-17 15:39:23 +0100605 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100606 } else {
Radek Krejci422afb12021-03-04 16:38:16 +0100607 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" module.",
608 (int)name_len, name, mod->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100609 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200610 ret = LY_EVALID;
611 goto error;
Michal Vaskoe0665742021-02-11 11:08:44 +0100612 } else if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
Michal Vaskod68f8a22022-01-05 12:06:51 +0100613 LOGVRB("Skipping parsing of unknown node \"%.*s\".", name_len, name);
Michal Vaskod0237d42021-07-12 14:49:46 +0200614
Michal Vaskoa5da3292020-08-12 13:10:50 +0200615 /* skip element with children */
616 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
617 return LY_SUCCESS;
618 }
619 } else {
620 /* check that schema node is valid and can be used */
621 LY_CHECK_GOTO(ret = lyd_parser_check_schema((struct lyd_ctx *)lydctx, snode), error);
622 LY_CHECK_GOTO(ret = lydxml_data_check_opaq(lydctx, &snode), error);
623 }
624 }
625
626 /* create metadata/attributes */
627 if (xmlctx->status == LYXML_ATTRIBUTE) {
628 if (snode) {
Michal Vaskoddd76592022-01-17 13:34:48 +0100629 ret = lydxml_metadata(lydctx, snode, &meta);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200630 LY_CHECK_GOTO(ret, error);
631 } else {
Michal Vaskoe0665742021-02-11 11:08:44 +0100632 assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200633 ret = lydxml_attrs(xmlctx, &attr);
634 LY_CHECK_GOTO(ret, error);
635 }
636 }
637
638 assert(xmlctx->status == LYXML_ELEM_CONTENT);
639 if (!snode) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100640 assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200641
642 if (xmlctx->ws_only) {
643 /* ignore WS-only value */
Radek IÅ¡a017270d2021-02-16 10:26:15 +0100644 if (xmlctx->dynamic) {
645 free((char *) xmlctx->value);
646 }
647 xmlctx->dynamic = 0;
648 xmlctx->value = "";
Michal Vaskoa5da3292020-08-12 13:10:50 +0200649 xmlctx->value_len = 0;
Radek Krejci8df109d2021-04-23 12:19:08 +0200650 format = LY_VALUE_XML;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200651 } else {
652 /* get value prefixes */
Radek Krejci8df109d2021-04-23 12:19:08 +0200653 ret = ly_store_prefix_data(xmlctx->ctx, xmlctx->value, xmlctx->value_len, LY_VALUE_XML,
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100654 &xmlctx->ns, &format, &val_prefix_data);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200655 LY_CHECK_GOTO(ret, error);
656 }
657
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200658 /* get NS again, it may have been backed up and restored */
659 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
660 assert(ns);
661
Michal Vaskoa5da3292020-08-12 13:10:50 +0200662 /* create node */
Michal Vasko501af032020-11-11 20:27:44 +0100663 ret = lyd_create_opaq(ctx, name, name_len, prefix, prefix_len, ns->uri, strlen(ns->uri), xmlctx->value,
664 xmlctx->value_len, &xmlctx->dynamic, format, val_prefix_data, LYD_HINT_DATA, &node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200665 LY_CHECK_GOTO(ret, error);
666
667 /* parser next */
668 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
669
670 /* process children */
671 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100672 ret = lydxml_subtree_r(lydctx, node, lyd_node_child_p(node), NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200673 LY_CHECK_GOTO(ret, error);
674 }
675 } else if (snode->nodetype & LYD_NODE_TERM) {
676 /* create node */
Michal Vasko22df3f02020-08-24 13:29:22 +0200677 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 +0200678 &xmlctx->dynamic, LY_VALUE_XML, &xmlctx->ns, LYD_HINT_DATA, &node), error);
Radek Krejciddace2c2021-01-08 11:30:56 +0100679 LOG_LOCSET(snode, node, NULL, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200680
681 if (parent && (node->schema->flags & LYS_KEY)) {
682 /* check the key order, the anchor must never be a key */
Michal Vaskoe0665742021-02-11 11:08:44 +0100683 anchor = lyd_insert_get_next_anchor(lyd_child(parent), node);
Michal Vasko441e0fa2022-03-03 13:45:00 +0100684 if (anchor && anchor->schema && (anchor->schema->flags & LYS_KEY)) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100685 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100686 LOGVAL(ctx, LYVE_DATA, "Invalid position of the key \"%s\" in a list.", node->schema->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200687 ret = LY_EVALID;
688 goto error;
689 } else {
690 LOGWRN(ctx, "Invalid position of the key \"%s\" in a list.", node->schema->name);
691 }
692 }
693 }
694
695 /* parser next */
696 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
697
698 /* no children expected */
699 if (xmlctx->status == LYXML_ELEMENT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100700 LOGVAL(ctx, LYVE_SYNTAX, "Child element \"%.*s\" inside a terminal node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100701 (int)xmlctx->name_len, xmlctx->name, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200702 ret = LY_EVALID;
703 goto error;
704 }
705 } else if (snode->nodetype & LYD_NODE_INNER) {
706 if (!xmlctx->ws_only) {
707 /* value in inner node */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100708 LOGVAL(ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an inner node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100709 (int)xmlctx->value_len, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200710 ret = LY_EVALID;
711 goto error;
712 }
713
714 /* create node */
715 ret = lyd_create_inner(snode, &node);
716 LY_CHECK_GOTO(ret, error);
717
Radek Krejciddace2c2021-01-08 11:30:56 +0100718 LOG_LOCSET(snode, node, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100719
Michal Vaskoa5da3292020-08-12 13:10:50 +0200720 /* parser next */
721 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
722
723 /* process children */
724 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100725 ret = lydxml_subtree_r(lydctx, node, lyd_node_child_p(node), NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200726 LY_CHECK_GOTO(ret, error);
727 }
728
729 if (snode->nodetype == LYS_LIST) {
730 /* check all keys exist */
731 LY_CHECK_GOTO(ret = lyd_parse_check_keys(node), error);
732 }
733
Michal Vaskoe0665742021-02-11 11:08:44 +0100734 if (!(lydctx->parse_opts & LYD_PARSE_ONLY)) {
Michal Vaskoa5da3292020-08-12 13:10:50 +0200735 /* new node validation, autodelete CANNOT occur, all nodes are new */
Michal Vaskoe0665742021-02-11 11:08:44 +0100736 ret = lyd_validate_new(lyd_node_child_p(node), snode, NULL, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200737 LY_CHECK_GOTO(ret, error);
738
739 /* add any missing default children */
Michal Vaskoddd76592022-01-17 13:34:48 +0100740 ret = lyd_new_implicit_r(node, lyd_node_child_p(node), NULL, NULL, &lydctx->node_when, &lydctx->node_types,
741 (lydctx->val_opts & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200742 LY_CHECK_GOTO(ret, error);
743 }
744
745 if (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
746 /* rememeber the RPC/action/notification */
747 lydctx->op_node = node;
748 }
749 } else if (snode->nodetype & LYD_NODE_ANY) {
Michal Vasko27c4dce2021-03-04 15:50:50 +0100750 if ((snode->nodetype == LYS_ANYDATA) && !xmlctx->ws_only) {
751 /* value in anydata node, we expect a tree */
752 LOGVAL(ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an anydata node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100753 (int)xmlctx->value_len < 20 ? xmlctx->value_len : 20, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200754 ret = LY_EVALID;
755 goto error;
756 }
757
Michal Vasko27c4dce2021-03-04 15:50:50 +0100758 if (!xmlctx->ws_only) {
759 /* use an arbitrary text value for anyxml */
Michal Vasko742a5b12022-02-24 16:07:27 +0100760 val = strndup(xmlctx->value, xmlctx->value_len);
761 LY_CHECK_ERR_GOTO(!val, LOGMEM(xmlctx->ctx); ret = LY_EMEM, error);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200762
Michal Vasko27c4dce2021-03-04 15:50:50 +0100763 /* parser next */
764 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
765
766 /* create node */
767 ret = lyd_create_any(snode, val, LYD_ANYDATA_STRING, 1, &node);
Michal Vasko742a5b12022-02-24 16:07:27 +0100768 LY_CHECK_ERR_GOTO(ret, free(val), error);
Michal Vasko27c4dce2021-03-04 15:50:50 +0100769 } else {
770 /* parser next */
771 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
772
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200773 /* update options so that generic data can be parsed */
774 prev_parse_opts = lydctx->parse_opts;
Michal Vasko27c4dce2021-03-04 15:50:50 +0100775 lydctx->parse_opts &= ~LYD_PARSE_STRICT;
776 lydctx->parse_opts |= LYD_PARSE_OPAQ;
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200777 prev_int_opts = lydctx->int_opts;
Michal Vasko02ed9d82021-07-15 14:58:04 +0200778 lydctx->int_opts |= LYD_INTOPT_ANY | LYD_INTOPT_WITH_SIBLINGS;
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200779
780 /* parse any data tree */
Michal Vasko27c4dce2021-03-04 15:50:50 +0100781 anchor = NULL;
782 while (xmlctx->status == LYXML_ELEMENT) {
783 ret = lydxml_subtree_r(lydctx, NULL, &anchor, NULL);
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200784 if (ret) {
785 break;
786 }
Michal Vasko27c4dce2021-03-04 15:50:50 +0100787 }
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200788
789 /* restore options */
790 lydctx->parse_opts = prev_parse_opts;
791 lydctx->int_opts = prev_int_opts;
792
793 LY_CHECK_GOTO(ret, error);
Michal Vasko27c4dce2021-03-04 15:50:50 +0100794
795 /* create node */
796 ret = lyd_create_any(snode, anchor, LYD_ANYDATA_DATATREE, 1, &node);
797 LY_CHECK_GOTO(ret, error);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200798 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200799 }
800 assert(node);
801
802 /* add/correct flags */
803 if (snode) {
Michal Vaskoddd76592022-01-17 13:34:48 +0100804 lyd_parse_set_data_flags(node, &lydctx->node_when, &meta, lydctx->parse_opts);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200805 }
806
807 /* parser next */
808 assert(xmlctx->status == LYXML_ELEM_CLOSE);
Michal Vaskoddd76592022-01-17 13:34:48 +0100809 if (!parse_subtree) {
810 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
811 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200812
813 /* add metadata/attributes */
814 if (snode) {
Michal Vasko871a0252020-11-11 18:35:24 +0100815 lyd_insert_meta(node, meta, 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200816 } else {
817 lyd_insert_attr(node, attr);
818 }
819
820 /* insert, keep first pointer correct */
Michal Vasko6ee6f432021-07-16 09:49:14 +0200821 lyd_insert_node(parent, first_p, node, lydctx->parse_opts & LYD_PARSE_ORDERED ? 1 : 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200822 while (!parent && (*first_p)->prev->next) {
823 *first_p = (*first_p)->prev;
824 }
825
Michal Vaskoe0665742021-02-11 11:08:44 +0100826 /* rememeber a successfully parsed node */
827 if (parsed) {
828 ly_set_add(parsed, node, 1, NULL);
829 }
830
Radek Krejciddace2c2021-01-08 11:30:56 +0100831 LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200832 return LY_SUCCESS;
833
834error:
Radek Krejciddace2c2021-01-08 11:30:56 +0100835 LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
Michal Vasko3a41dff2020-07-15 14:30:28 +0200836 lyd_free_meta_siblings(meta);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200837 lyd_free_attr_siblings(ctx, attr);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200838 lyd_free_tree(node);
Radek Krejcie7b95092019-05-15 11:03:07 +0200839 return ret;
840}
841
Michal Vaskoe0665742021-02-11 11:08:44 +0100842/**
843 * @brief Parse a specific XML element into an opaque node.
844 *
845 * @param[in] xmlctx XML parser context.
846 * @param[in] name Name of the element.
847 * @param[in] uri URI of the element.
848 * @param[in] value Whether a value is expected in the element.
849 * @param[out] evnp Parsed envelope (opaque node).
850 * @return LY_SUCCESS on success.
851 * @return LY_ENOT if the specified element did not match.
852 * @return LY_ERR value on error.
853 */
Michal Vasko1bf09392020-03-27 12:38:10 +0100854static LY_ERR
Michal Vaskoe0665742021-02-11 11:08:44 +0100855lydxml_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 +0100856{
Michal Vaskoe0665742021-02-11 11:08:44 +0100857 LY_ERR rc = LY_SUCCESS;
858 const struct lyxml_ns *ns;
Radek Krejci1798aae2020-07-14 13:26:06 +0200859 struct lyd_attr *attr = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100860 const char *prefix;
861 size_t prefix_len;
862
Michal Vasko1bf09392020-03-27 12:38:10 +0100863 assert(xmlctx->status == LYXML_ELEMENT);
864 if (ly_strncmp(name, xmlctx->name, xmlctx->name_len)) {
865 /* not the expected element */
Michal Vaskoe0665742021-02-11 11:08:44 +0100866 return LY_ENOT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100867 }
868
869 prefix = xmlctx->prefix;
870 prefix_len = xmlctx->prefix_len;
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200871 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100872 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100873 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +0100874 return LY_EVALID;
875 } else if (strcmp(ns->uri, uri)) {
876 /* different namespace */
877 return LY_ENOT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100878 }
879
880 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
881
882 /* create attributes */
883 if (xmlctx->status == LYXML_ATTRIBUTE) {
884 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
885 }
886
Michal Vaskoe0665742021-02-11 11:08:44 +0100887 assert(xmlctx->status == LYXML_ELEM_CONTENT);
888 if (!value && !xmlctx->ws_only) {
889 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected value \"%.*s\" in the \"%s\" element.",
Radek Krejci422afb12021-03-04 16:38:16 +0100890 (int)xmlctx->value_len, xmlctx->value, name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100891 rc = LY_EVALID;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100892 goto cleanup;
Michal Vaskoe0665742021-02-11 11:08:44 +0100893 }
Michal Vaskoa8edff02020-03-27 14:47:01 +0100894
895 /* create node */
Michal Vaskoe0665742021-02-11 11:08:44 +0100896 rc = lyd_create_opaq(xmlctx->ctx, name, strlen(name), prefix, prefix_len, uri, strlen(uri), xmlctx->value,
Radek Krejci8df109d2021-04-23 12:19:08 +0200897 xmlctx->ws_only ? 0 : xmlctx->value_len, NULL, LY_VALUE_XML, NULL, 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100898 LY_CHECK_GOTO(rc, cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100899
900 /* assign atributes */
Michal Vaskoe0665742021-02-11 11:08:44 +0100901 ((struct lyd_node_opaq *)(*envp))->attr = attr;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100902 attr = NULL;
903
Michal Vaskoe0665742021-02-11 11:08:44 +0100904 /* parser next element */
905 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100906
Michal Vaskoe0665742021-02-11 11:08:44 +0100907cleanup:
908 lyd_free_attr_siblings(xmlctx->ctx, attr);
909 if (rc) {
910 lyd_free_tree(*envp);
911 *envp = NULL;
912 }
913 return rc;
914}
915
916/**
917 * @brief Parse all expected non-data XML elements of a NETCONF rpc message.
918 *
919 * @param[in] xmlctx XML parser context.
920 * @param[out] evnp Parsed envelope(s) (opaque node).
921 * @param[out] int_opts Internal options for parsing the rest of YANG data.
922 * @param[out] close_elem Number of parsed opened elements that need to be closed.
923 * @return LY_SUCCESS on success.
924 * @return LY_ERR value on error.
925 */
926static LY_ERR
927lydxml_env_netconf_rpc(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
928{
929 LY_ERR rc = LY_SUCCESS, r;
930 struct lyd_node *child;
931
932 assert(envp && !*envp);
933
934 /* parse "rpc" */
935 r = lydxml_envelope(xmlctx, "rpc", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100936 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
937
938 /* parse "action", if any */
939 r = lydxml_envelope(xmlctx, "action", "urn:ietf:params:xml:ns:yang:1", 0, &child);
940 if (r == LY_SUCCESS) {
941 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +0200942 lyd_insert_node(*envp, NULL, child, 0);
Michal Vaskoe0665742021-02-11 11:08:44 +0100943
944 /* NETCONF action */
945 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_ACTION;
946 *close_elem = 2;
947 } else if (r == LY_ENOT) {
948 /* NETCONF RPC */
949 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_RPC;
950 *close_elem = 1;
951 } else {
952 rc = r;
953 goto cleanup;
954 }
955
956cleanup:
957 if (rc) {
958 lyd_free_tree(*envp);
959 *envp = NULL;
960 }
961 return rc;
962}
963
964/**
965 * @brief Parse all expected non-data XML elements of a NETCONF notification message.
966 *
967 * @param[in] xmlctx XML parser context.
968 * @param[out] evnp Parsed envelope(s) (opaque node).
969 * @param[out] int_opts Internal options for parsing the rest of YANG data.
970 * @param[out] close_elem Number of parsed opened elements that need to be closed.
971 * @return LY_SUCCESS on success.
972 * @return LY_ERR value on error.
973 */
974static LY_ERR
975lydxml_env_netconf_notif(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
976{
977 LY_ERR rc = LY_SUCCESS, r;
978 struct lyd_node *child;
979
980 assert(envp && !*envp);
981
982 /* parse "notification" */
983 r = lydxml_envelope(xmlctx, "notification", "urn:ietf:params:xml:ns:netconf:notification:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100984 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
985
986 /* parse "eventTime" */
987 r = lydxml_envelope(xmlctx, "eventTime", "urn:ietf:params:xml:ns:netconf:notification:1.0", 1, &child);
988 if (r == LY_ENOT) {
Radek Krejci422afb12021-03-04 16:38:16 +0100989 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unexpected element \"%.*s\" instead of \"eventTime\".",
990 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100991 r = LY_EVALID;
992 }
993 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
994
995 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +0200996 lyd_insert_node(*envp, NULL, child, 0);
Michal Vaskoe0665742021-02-11 11:08:44 +0100997
998 /* validate value */
999 /* TODO validate child->value as yang:date-and-time */
1000
1001 /* finish child parsing */
Michal Vaskoa8edff02020-03-27 14:47:01 +01001002 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1003 assert(xmlctx->status == LYXML_ELEMENT);
Michal Vaskoe0665742021-02-11 11:08:44 +01001004 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"eventTime\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001005 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001006 rc = LY_EVALID;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001007 goto cleanup;
1008 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001009 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1010
1011 /* NETCONF notification */
1012 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_NOTIF;
1013 *close_elem = 1;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001014
1015cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +01001016 if (rc) {
Michal Vaskoa8edff02020-03-27 14:47:01 +01001017 lyd_free_tree(*envp);
Michal Vaskoe0665742021-02-11 11:08:44 +01001018 *envp = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001019 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001020 return rc;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001021}
Michal Vasko79135ae2020-12-16 10:08:35 +01001022
Michal Vaskoe0665742021-02-11 11:08:44 +01001023/**
1024 * @brief Parse an XML element as an opaque node subtree.
1025 *
1026 * @param[in] xmlctx XML parser context.
1027 * @param[in] parent Parent to append nodes to.
1028 * @return LY_ERR value.
1029 */
1030static LY_ERR
1031lydxml_opaq_r(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
Michal Vaskoa8edff02020-03-27 14:47:01 +01001032{
Michal Vaskoe0665742021-02-11 11:08:44 +01001033 LY_ERR rc = LY_SUCCESS;
1034 const struct lyxml_ns *ns;
1035 struct lyd_attr *attr = NULL;
1036 struct lyd_node *child = NULL;
1037 const char *name, *prefix;
1038 size_t name_len, prefix_len;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001039
Michal Vaskoe0665742021-02-11 11:08:44 +01001040 assert(xmlctx->status == LYXML_ELEMENT);
Michal Vaskoa8edff02020-03-27 14:47:01 +01001041
Michal Vaskoe0665742021-02-11 11:08:44 +01001042 name = xmlctx->name;
1043 name_len = xmlctx->name_len;
1044 prefix = xmlctx->prefix;
1045 prefix_len = xmlctx->prefix_len;
1046 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
1047 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +01001048 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +01001049 return LY_EVALID;
1050 }
Michal Vaskoa8edff02020-03-27 14:47:01 +01001051
Michal Vaskoe0665742021-02-11 11:08:44 +01001052 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
Michal Vaskoa8edff02020-03-27 14:47:01 +01001053
Michal Vaskoe0665742021-02-11 11:08:44 +01001054 /* create attributes */
1055 if (xmlctx->status == LYXML_ATTRIBUTE) {
1056 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
1057 }
1058
1059 /* create node */
1060 assert(xmlctx->status == LYXML_ELEM_CONTENT);
1061 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 +02001062 xmlctx->ws_only ? 0 : xmlctx->value_len, NULL, LY_VALUE_XML, NULL, 0, &child);
Michal Vaskoe0665742021-02-11 11:08:44 +01001063 LY_CHECK_GOTO(rc, cleanup);
1064
1065 /* assign atributes */
1066 ((struct lyd_node_opaq *)child)->attr = attr;
1067 attr = NULL;
1068
1069 /* parser next element */
1070 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1071
1072 /* parse all the descendants */
1073 while (xmlctx->status == LYXML_ELEMENT) {
1074 rc = lydxml_opaq_r(xmlctx, child);
1075 LY_CHECK_GOTO(rc, cleanup);
1076 }
1077
1078 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001079 lyd_insert_node(parent, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +01001080
1081cleanup:
1082 lyd_free_attr_siblings(xmlctx->ctx, attr);
1083 if (rc) {
1084 lyd_free_tree(child);
1085 }
1086 return rc;
1087}
1088
1089/**
1090 * @brief Parse all expected non-data XML elements of the error-info element in NETCONF rpc-reply message.
1091 *
1092 * @param[in] xmlctx XML parser context.
1093 * @param[in] parent Parent to append nodes to.
1094 * @return LY_ERR value.
1095 */
1096static LY_ERR
1097lydxml_env_netconf_rpc_reply_error_info(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
1098{
1099 LY_ERR r;
1100 struct lyd_node *child, *iter;
1101 const struct lyxml_ns *ns;
1102 ly_bool no_dup;
1103
1104 /* there must be some child */
1105 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1106 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"error-info\".");
1107 return LY_EVALID;
1108 }
1109
1110 while (xmlctx->status == LYXML_ELEMENT) {
1111 child = NULL;
1112
1113 /*
1114 * session-id
1115 */
1116 r = lydxml_envelope(xmlctx, "session-id", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1117 if (r == LY_SUCCESS) {
1118 no_dup = 1;
1119 goto check_child;
1120 } else if (r != LY_ENOT) {
1121 goto error;
1122 }
1123
1124 /*
1125 * bad-attribute
1126 */
1127 r = lydxml_envelope(xmlctx, "bad-attribute", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1128 if (r == LY_SUCCESS) {
1129 no_dup = 1;
1130 goto check_child;
1131 } else if (r != LY_ENOT) {
1132 goto error;
1133 }
1134
1135 /*
1136 * bad-element
1137 */
1138 r = lydxml_envelope(xmlctx, "bad-element", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1139 if (r == LY_SUCCESS) {
1140 no_dup = 1;
1141 goto check_child;
1142 } else if (r != LY_ENOT) {
1143 goto error;
1144 }
1145
1146 /*
1147 * bad-namespace
1148 */
1149 r = lydxml_envelope(xmlctx, "bad-namespace", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1150 if (r == LY_SUCCESS) {
1151 no_dup = 1;
1152 goto check_child;
1153 } else if (r != LY_ENOT) {
1154 goto error;
1155 }
1156
1157 if (r == LY_ENOT) {
1158 assert(xmlctx->status == LYXML_ELEMENT);
1159
1160 /* learn namespace */
1161 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
1162 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +01001163 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)xmlctx->prefix_len, xmlctx->prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +01001164 r = LY_EVALID;
1165 goto error;
1166 } else if (!strcmp(ns->uri, "urn:ietf:params:xml:ns:netconf:base:1.0")) {
1167 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"error-info\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001168 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001169 r = LY_EVALID;
1170 goto error;
1171 }
1172
1173 /* custom elements */
1174 r = lydxml_opaq_r(xmlctx, parent);
1175 LY_CHECK_GOTO(r, error);
Michal Vasko6398eaf2022-01-10 10:12:30 +01001176 continue;
Michal Vaskoe0665742021-02-11 11:08:44 +01001177 }
1178
1179check_child:
1180 /* check for duplicates */
1181 if (no_dup) {
1182 LY_LIST_FOR(lyd_child(parent), iter) {
1183 if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
1184 (((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
1185 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"error-info\".",
1186 ((struct lyd_node_opaq *)child)->name.name);
1187 r = LY_EVALID;
1188 goto error;
1189 }
1190 }
1191 }
1192
1193 /* finish child parsing */
1194 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1195 assert(xmlctx->status == LYXML_ELEMENT);
1196 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"error-info\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001197 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001198 r = LY_EVALID;
1199 goto error;
1200 }
1201 LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
1202
1203 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001204 lyd_insert_node(parent, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +01001205 }
1206
1207 return LY_SUCCESS;
1208
1209error:
1210 lyd_free_tree(child);
1211 return r;
1212}
1213
1214/**
1215 * @brief Parse all expected non-data XML elements of the rpc-error element in NETCONF rpc-reply message.
1216 *
1217 * @param[in] xmlctx XML parser context.
1218 * @param[in] parent Parent to append nodes to.
1219 * @return LY_ERR value.
1220 */
1221static LY_ERR
1222lydxml_env_netconf_rpc_reply_error(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
1223{
1224 LY_ERR r;
1225 struct lyd_node *child, *iter;
1226 const char *val;
1227 ly_bool no_dup;
1228
1229 /* there must be some child */
1230 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1231 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"rpc-error\".");
1232 return LY_EVALID;
1233 }
1234
1235 while (xmlctx->status == LYXML_ELEMENT) {
1236 child = NULL;
1237
1238 /*
1239 * error-type
1240 */
1241 r = lydxml_envelope(xmlctx, "error-type", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1242 if (r == LY_SUCCESS) {
1243 val = ((struct lyd_node_opaq *)child)->value;
1244 if (strcmp(val, "transport") && strcmp(val, "rpc") && strcmp(val, "protocol") && strcmp(val, "application")) {
1245 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1246 ((struct lyd_node_opaq *)child)->name.name);
1247 r = LY_EVALID;
1248 goto error;
1249 }
1250
1251 no_dup = 1;
1252 goto check_child;
1253 } else if (r != LY_ENOT) {
1254 goto error;
1255 }
1256
1257 /*
1258 * error-tag
1259 */
1260 r = lydxml_envelope(xmlctx, "error-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1261 if (r == LY_SUCCESS) {
1262 val = ((struct lyd_node_opaq *)child)->value;
1263 if (strcmp(val, "in-use") && strcmp(val, "invalid-value") && strcmp(val, "too-big") &&
1264 strcmp(val, "missing-attribute") && strcmp(val, "bad-attribute") &&
1265 strcmp(val, "unknown-attribute") && strcmp(val, "missing-element") && strcmp(val, "bad-element") &&
1266 strcmp(val, "unknown-element") && strcmp(val, "unknown-namespace") && strcmp(val, "access-denied") &&
1267 strcmp(val, "lock-denied") && strcmp(val, "resource-denied") && strcmp(val, "rollback-failed") &&
1268 strcmp(val, "data-exists") && strcmp(val, "data-missing") && strcmp(val, "operation-not-supported") &&
1269 strcmp(val, "operation-failed") && strcmp(val, "malformed-message")) {
1270 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1271 ((struct lyd_node_opaq *)child)->name.name);
1272 r = LY_EVALID;
1273 goto error;
1274 }
1275
1276 no_dup = 1;
1277 goto check_child;
1278 } else if (r != LY_ENOT) {
1279 goto error;
1280 }
1281
1282 /*
1283 * error-severity
1284 */
1285 r = lydxml_envelope(xmlctx, "error-severity", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1286 if (r == LY_SUCCESS) {
1287 val = ((struct lyd_node_opaq *)child)->value;
1288 if (strcmp(val, "error") && strcmp(val, "warning")) {
1289 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1290 ((struct lyd_node_opaq *)child)->name.name);
1291 r = LY_EVALID;
1292 goto error;
1293 }
1294
1295 no_dup = 1;
1296 goto check_child;
1297 } else if (r != LY_ENOT) {
1298 goto error;
1299 }
1300
1301 /*
1302 * error-app-tag
1303 */
1304 r = lydxml_envelope(xmlctx, "error-app-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1305 if (r == LY_SUCCESS) {
1306 no_dup = 1;
1307 goto check_child;
1308 } else if (r != LY_ENOT) {
1309 goto error;
1310 }
1311
1312 /*
1313 * error-path
1314 */
1315 r = lydxml_envelope(xmlctx, "error-path", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1316 if (r == LY_SUCCESS) {
1317 no_dup = 1;
1318 goto check_child;
1319 } else if (r != LY_ENOT) {
1320 goto error;
1321 }
1322
1323 /*
1324 * error-message
1325 */
1326 r = lydxml_envelope(xmlctx, "error-message", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1327 if (r == LY_SUCCESS) {
1328 no_dup = 1;
1329 goto check_child;
1330 } else if (r != LY_ENOT) {
1331 goto error;
1332 }
1333
1334 /* error-info */
1335 r = lydxml_envelope(xmlctx, "error-info", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1336 if (r == LY_SUCCESS) {
1337 /* parse all the descendants */
1338 LY_CHECK_GOTO(r = lydxml_env_netconf_rpc_reply_error_info(xmlctx, child), error);
1339
1340 no_dup = 0;
1341 goto check_child;
1342 } else if (r != LY_ENOT) {
1343 goto error;
1344 }
1345
1346 if (r == LY_ENOT) {
1347 assert(xmlctx->status == LYXML_ELEMENT);
1348 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001349 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001350 r = LY_EVALID;
1351 goto error;
1352 }
1353
1354check_child:
1355 /* check for duplicates */
1356 if (no_dup) {
1357 LY_LIST_FOR(lyd_child(parent), iter) {
1358 if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
1359 (((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
1360 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"rpc-error\".",
1361 ((struct lyd_node_opaq *)child)->name.name);
1362 r = LY_EVALID;
1363 goto error;
1364 }
1365 }
1366 }
1367
1368 /* finish child parsing */
1369 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1370 assert(xmlctx->status == LYXML_ELEMENT);
1371 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001372 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001373 r = LY_EVALID;
1374 goto error;
1375 }
1376 LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
1377
1378 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001379 lyd_insert_node(parent, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +01001380 }
1381
1382 return LY_SUCCESS;
1383
1384error:
1385 lyd_free_tree(child);
1386 return r;
1387}
1388
1389/**
1390 * @brief Parse all expected non-data XML elements of a NETCONF rpc-reply message.
1391 *
1392 * @param[in] xmlctx XML parser context.
1393 * @param[out] evnp Parsed envelope(s) (opaque node).
1394 * @param[out] int_opts Internal options for parsing the rest of YANG data.
1395 * @param[out] close_elem Number of parsed opened elements that need to be closed.
1396 * @return LY_SUCCESS on success.
1397 * @return LY_ERR value on error.
1398 */
1399static LY_ERR
1400lydxml_env_netconf_reply(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
1401{
1402 LY_ERR rc = LY_SUCCESS, r;
1403 struct lyd_node *child = NULL;
1404 const char *parsed_elem = NULL;
1405
1406 assert(envp && !*envp);
1407
1408 /* parse "rpc-reply" */
1409 r = lydxml_envelope(xmlctx, "rpc-reply", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +01001410 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1411
1412 /* there must be some child */
1413 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1414 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"rpc-reply\".");
1415 rc = LY_EVALID;
Michal Vaskocf770e22020-08-12 13:21:43 +02001416 goto cleanup;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001417 }
1418
Michal Vaskoe0665742021-02-11 11:08:44 +01001419 /* try to parse "ok" */
1420 r = lydxml_envelope(xmlctx, "ok", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1421 if (r == LY_SUCCESS) {
1422 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001423 lyd_insert_node(*envp, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +01001424
1425 /* finish child parsing */
1426 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1427 assert(xmlctx->status == LYXML_ELEMENT);
1428 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"ok\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001429 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001430 rc = LY_EVALID;
1431 goto cleanup;
1432 }
1433 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1434
1435 /* success */
1436 parsed_elem = "ok";
1437 goto finish;
1438 } else if (r != LY_ENOT) {
1439 rc = r;
1440 goto cleanup;
Michal Vasko2552ea32020-12-08 15:32:34 +01001441 }
1442
Michal Vaskoe0665742021-02-11 11:08:44 +01001443 /* try to parse all "rpc-error" elements */
1444 while (xmlctx->status == LYXML_ELEMENT) {
1445 r = lydxml_envelope(xmlctx, "rpc-error", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1446 if (r == LY_ENOT) {
1447 break;
1448 } else if (r) {
1449 rc = r;
1450 goto cleanup;
1451 }
1452
1453 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001454 lyd_insert_node(*envp, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +01001455
1456 /* parse all children of "rpc-error" */
1457 LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc_reply_error(xmlctx, child), cleanup);
1458
1459 /* finish child parsing */
1460 assert(xmlctx->status == LYXML_ELEM_CLOSE);
1461 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1462
1463 parsed_elem = "rpc-error";
Michal Vasko2552ea32020-12-08 15:32:34 +01001464 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001465
1466finish:
1467 if (parsed_elem) {
1468 /* NETCONF rpc-reply with no data */
1469 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1470 assert(xmlctx->status == LYXML_ELEMENT);
1471 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"%s\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001472 (int)xmlctx->name_len, xmlctx->name, parsed_elem);
Michal Vaskoe0665742021-02-11 11:08:44 +01001473 rc = LY_EVALID;
1474 goto cleanup;
1475 }
1476 }
1477
1478 /* NETCONF rpc-reply */
Michal Vasko1d991fd2021-07-09 13:14:40 +02001479 *int_opts = LYD_INTOPT_WITH_SIBLINGS | LYD_INTOPT_REPLY;
Michal Vaskoe0665742021-02-11 11:08:44 +01001480 *close_elem = 1;
1481
1482cleanup:
1483 if (rc) {
1484 lyd_free_tree(*envp);
1485 *envp = NULL;
1486 }
1487 return rc;
1488}
1489
Michal Vasko2552ea32020-12-08 15:32:34 +01001490LY_ERR
Radek Krejcif16e2542021-02-17 15:39:23 +01001491lyd_parse_xml(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
1492 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 +01001493 struct lyd_node **envp, struct ly_set *parsed, ly_bool *subtree_sibling, struct lyd_ctx **lydctx_p)
Michal Vasko2552ea32020-12-08 15:32:34 +01001494{
Michal Vaskoe0665742021-02-11 11:08:44 +01001495 LY_ERR rc = LY_SUCCESS;
1496 struct lyd_xml_ctx *lydctx;
Michal Vasko2ca9f9e2021-07-02 09:21:36 +02001497 uint32_t i, int_opts = 0, close_elem = 0;
Michal Vaskoe0665742021-02-11 11:08:44 +01001498 ly_bool parsed_data_nodes = 0;
Michal Vaskoddd76592022-01-17 13:34:48 +01001499 enum LYXML_PARSER_STATUS status;
Michal Vasko2552ea32020-12-08 15:32:34 +01001500
Michal Vaskoe0665742021-02-11 11:08:44 +01001501 assert(ctx && in && lydctx_p);
1502 assert(!(parse_opts & ~LYD_PARSE_OPTS_MASK));
1503 assert(!(val_opts & ~LYD_VALIDATE_OPTS_MASK));
Michal Vasko2552ea32020-12-08 15:32:34 +01001504
Michal Vaskoe0665742021-02-11 11:08:44 +01001505 /* init context */
1506 lydctx = calloc(1, sizeof *lydctx);
1507 LY_CHECK_ERR_RET(!lydctx, LOGMEM(ctx), LY_EMEM);
1508 LY_CHECK_GOTO(rc = lyxml_ctx_new(ctx, in, &lydctx->xmlctx), cleanup);
1509 lydctx->parse_opts = parse_opts;
1510 lydctx->val_opts = val_opts;
1511 lydctx->free = lyd_xml_ctx_free;
Radek Krejcif16e2542021-02-17 15:39:23 +01001512 lydctx->ext = ext;
Michal Vasko2552ea32020-12-08 15:32:34 +01001513
Michal Vaskoe0665742021-02-11 11:08:44 +01001514 switch (data_type) {
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001515 case LYD_TYPE_DATA_YANG:
Michal Vaskoddd76592022-01-17 13:34:48 +01001516 if (!(parse_opts & LYD_PARSE_SUBTREE)) {
1517 int_opts = LYD_INTOPT_WITH_SIBLINGS;
1518 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001519 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001520 case LYD_TYPE_RPC_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001521 int_opts = LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NO_SIBLINGS;
1522 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001523 case LYD_TYPE_NOTIF_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001524 int_opts = LYD_INTOPT_NOTIF | LYD_INTOPT_NO_SIBLINGS;
1525 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001526 case LYD_TYPE_REPLY_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001527 int_opts = LYD_INTOPT_REPLY | LYD_INTOPT_NO_SIBLINGS;
1528 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001529 case LYD_TYPE_RPC_NETCONF:
Michal Vaskoe0665742021-02-11 11:08:44 +01001530 assert(!parent);
1531 LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
1532 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001533 case LYD_TYPE_NOTIF_NETCONF:
1534 assert(!parent);
1535 LY_CHECK_GOTO(rc = lydxml_env_netconf_notif(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
1536 break;
1537 case LYD_TYPE_REPLY_NETCONF:
Michal Vaskoe0665742021-02-11 11:08:44 +01001538 assert(parent);
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001539 LY_CHECK_GOTO(rc = lydxml_env_netconf_reply(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
Michal Vaskoe0665742021-02-11 11:08:44 +01001540 break;
1541 }
1542 lydctx->int_opts = int_opts;
1543
1544 /* find the operation node if it exists already */
1545 LY_CHECK_GOTO(rc = lyd_parser_find_operation(parent, int_opts, &lydctx->op_node), cleanup);
1546
1547 /* parse XML data */
1548 while (lydctx->xmlctx->status == LYXML_ELEMENT) {
1549 LY_CHECK_GOTO(rc = lydxml_subtree_r(lydctx, parent, first_p, parsed), cleanup);
1550 parsed_data_nodes = 1;
1551
1552 if (!(int_opts & LYD_INTOPT_WITH_SIBLINGS)) {
1553 break;
1554 }
Michal Vasko2552ea32020-12-08 15:32:34 +01001555 }
1556
Michal Vaskoe0665742021-02-11 11:08:44 +01001557 /* close all opened elements */
1558 for (i = 0; i < close_elem; ++i) {
1559 if (lydctx->xmlctx->status != LYXML_ELEM_CLOSE) {
1560 assert(lydctx->xmlctx->status == LYXML_ELEMENT);
Radek Krejci422afb12021-03-04 16:38:16 +01001561 LOGVAL(lydctx->xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\".",
1562 (int)lydctx->xmlctx->name_len, lydctx->xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001563 rc = LY_EVALID;
1564 goto cleanup;
1565 }
1566
1567 LY_CHECK_GOTO(rc = lyxml_ctx_next(lydctx->xmlctx), cleanup);
Michal Vasko4189c0f2020-08-13 09:05:22 +02001568 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001569
1570 /* check final state */
1571 if ((int_opts & LYD_INTOPT_NO_SIBLINGS) && (lydctx->xmlctx->status == LYXML_ELEMENT)) {
1572 LOGVAL(ctx, LYVE_SYNTAX, "Unexpected sibling node.");
1573 rc = LY_EVALID;
1574 goto cleanup;
1575 }
Michal Vaskoc939fdd2022-01-03 11:35:13 +01001576 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 +01001577 LOGVAL(ctx, LYVE_DATA, "Missing the operation node.");
1578 rc = LY_EVALID;
1579 goto cleanup;
1580 }
1581
1582 if (!parsed_data_nodes) {
1583 /* no data nodes were parsed */
1584 lydctx->op_node = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001585 }
1586
Michal Vaskoddd76592022-01-17 13:34:48 +01001587 if (parse_opts & LYD_PARSE_SUBTREE) {
1588 /* check for a sibling element */
1589 assert(subtree_sibling);
1590 if (!lyxml_ctx_peek(lydctx->xmlctx, &status) && (status == LYXML_ELEMENT)) {
1591 *subtree_sibling = 1;
1592 } else {
1593 *subtree_sibling = 0;
1594 }
1595 }
1596
Michal Vaskoa8edff02020-03-27 14:47:01 +01001597cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +01001598 /* there should be no unres stored if validation should be skipped */
1599 assert(!(parse_opts & LYD_PARSE_ONLY) || (!lydctx->node_types.count && !lydctx->meta_types.count &&
Michal Vaskoddd76592022-01-17 13:34:48 +01001600 !lydctx->node_when.count));
Michal Vaskoe0665742021-02-11 11:08:44 +01001601
1602 if (rc) {
1603 lyd_xml_ctx_free((struct lyd_ctx *)lydctx);
1604 } else {
1605 *lydctx_p = (struct lyd_ctx *)lydctx;
1606
1607 /* the XML context is no more needed, freeing it also stops logging line numbers which would be confusing now */
1608 lyxml_ctx_free(lydctx->xmlctx);
1609 lydctx->xmlctx = NULL;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001610 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001611 return rc;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001612}