blob: 1f395b87763c4f030aa19cb1573e3ce1e891e0f8 [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 Vaskocea58712022-04-01 14:37:08 +0200414 * @brief Get sensible data hints for an opaque node.
415 *
416 * @param[in] name Node name.
417 * @param[in] name_len Length of @p name.
418 * @param[in] value Node value.
419 * @param[in] value_len Length of @p value.
420 * @param[in] first Node first sibling.
421 * @param[in] ns Node module namespace.
422 * @param[out] hints Data hints to use.
423 * @param[out] anchor Anchor to insert after in case of a list.
424 */
425static void
426lydxml_get_hints_opaq(const char *name, size_t name_len, const char *value, size_t value_len, struct lyd_node *first,
427 const char *ns, uint32_t *hints, struct lyd_node **anchor)
428{
429 struct lyd_node_opaq *opaq;
430 char *ptr;
431 long num;
432
433 *hints = 0;
434 *anchor = NULL;
435
436 if (!value_len) {
437 /* no value */
438 *hints |= LYD_VALHINT_EMPTY;
439 } else if (!strncmp(value, "true", value_len) || !strncmp(value, "false", value_len)) {
440 /* boolean value */
441 *hints |= LYD_VALHINT_BOOLEAN;
442 } else {
443 num = strtol(value, &ptr, 10);
444 if ((unsigned)(ptr - value) == value_len) {
445 /* number value */
446 *hints |= LYD_VALHINT_DECNUM;
447 if ((num < INT32_MIN) || (num > UINT32_MAX)) {
448 /* large number */
449 *hints |= LYD_VALHINT_NUM64;
450 }
451 } else {
452 /* string value */
453 *hints |= LYD_VALHINT_STRING;
454 }
455 }
456
457 if (!first) {
458 return;
459 }
460
461 /* search backwards to find the last instance */
462 do {
463 first = first->prev;
464 if (first->schema) {
465 continue;
466 }
467
468 opaq = (struct lyd_node_opaq *)first;
469 assert(opaq->format == LY_VALUE_XML);
470 if (!ly_strncmp(opaq->name.name, name, name_len) && !strcmp(opaq->name.module_ns, ns)) {
471 if (opaq->value && opaq->value[0]) {
472 /* leaf-list nodes */
473 opaq->hints |= LYD_NODEHINT_LEAFLIST;
474 *hints |= LYD_NODEHINT_LEAFLIST;
475 } else {
476 /* list nodes */
477 opaq->hints |= LYD_NODEHINT_LIST;
478 *hints |= LYD_NODEHINT_LIST;
479 }
480 *anchor = first;
481 break;
482 }
483 } while (first->prev->next);
484}
485
486/**
Michal Vasko8cc3f662022-03-29 11:25:51 +0200487 * @brief Get schema node for the current element.
Michal Vaskoddd76592022-01-17 13:34:48 +0100488 *
489 * @param[in] lydctx XML data parser context.
Michal Vasko8cc3f662022-03-29 11:25:51 +0200490 * @param[in] parent Parsed parent data node, if any.
491 * @param[in] prefix Element prefix, if any.
492 * @param[in] prefix_len Length of @p prefix.
493 * @param[in] name Element name.
494 * @param[in] name_len Length of @p name.
495 * @param[out] snode Found schema node, NULL if no suitable was found.
496 * @param[out] ext Extension instance that provided @p snode, if any.
Michal Vaskoddd76592022-01-17 13:34:48 +0100497 * @return LY_SUCCESS on success;
Michal Vaskoddd76592022-01-17 13:34:48 +0100498 * @return LY_ERR on error.
499 */
500static LY_ERR
Michal Vasko8cc3f662022-03-29 11:25:51 +0200501lydxml_subtree_snode(struct lyd_xml_ctx *lydctx, const struct lyd_node *parent, const char *prefix, size_t prefix_len,
502 const char *name, size_t name_len, const struct lysc_node **snode, struct lysc_ext_instance **ext)
Michal Vaskoddd76592022-01-17 13:34:48 +0100503{
504 LY_ERR r;
Michal Vaskob36053d2020-03-26 15:49:30 +0100505 struct lyxml_ctx *xmlctx;
506 const struct ly_ctx *ctx;
Radek Krejcie7b95092019-05-15 11:03:07 +0200507 const struct lyxml_ns *ns;
Radek Krejcie7b95092019-05-15 11:03:07 +0200508 struct lys_module *mod;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200509 uint32_t getnext_opts;
Michal Vaskoe0665742021-02-11 11:08:44 +0100510
Michal Vaskob36053d2020-03-26 15:49:30 +0100511 xmlctx = lydctx->xmlctx;
512 ctx = xmlctx->ctx;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100513 getnext_opts = lydctx->int_opts & LYD_INTOPT_REPLY ? LYS_GETNEXT_OUTPUT : 0;
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100514
Michal Vasko8cc3f662022-03-29 11:25:51 +0200515 *snode = NULL;
516 *ext = NULL;
Michal Vaskoddd76592022-01-17 13:34:48 +0100517
Michal Vasko8cc3f662022-03-29 11:25:51 +0200518 /* get current namespace */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200519 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200520 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100521 LOGVAL(ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vasko8cc3f662022-03-29 11:25:51 +0200522 return LY_EVALID;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200523 }
Michal Vasko8cc3f662022-03-29 11:25:51 +0200524
525 /* get the element module, use parent context if possible because of extensions */
526 mod = ly_ctx_get_module_implemented_ns(parent ? LYD_CTX(parent) : ctx, ns->uri);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200527 if (!mod) {
Michal Vaskoddd76592022-01-17 13:34:48 +0100528 /* check for extension data */
Michal Vasko8cc3f662022-03-29 11:25:51 +0200529 r = ly_nested_ext_schema(parent, NULL, prefix, prefix_len, LY_VALUE_XML, &lydctx->xmlctx->ns, name, name_len,
530 snode, ext);
531 if (r != LY_ENOT) {
532 /* success or error */
Michal Vaskoddd76592022-01-17 13:34:48 +0100533 return r;
Michal Vaskoddd76592022-01-17 13:34:48 +0100534 }
535
536 /* unknown module */
Michal Vaskoe0665742021-02-11 11:08:44 +0100537 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100538 LOGVAL(ctx, LYVE_REFERENCE, "No module with namespace \"%s\" in the context.", ns->uri);
Michal Vasko8cc3f662022-03-29 11:25:51 +0200539 return LY_EVALID;
Radek Krejcie7b95092019-05-15 11:03:07 +0200540 }
Michal Vasko8cc3f662022-03-29 11:25:51 +0200541 return LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200542 }
543
Michal Vaskoa5da3292020-08-12 13:10:50 +0200544 /* get the schema node */
Michal Vasko81008a52021-07-21 16:06:12 +0200545 if (mod) {
Radek Krejcif16e2542021-02-17 15:39:23 +0100546 if (!parent && lydctx->ext) {
Michal Vasko8cc3f662022-03-29 11:25:51 +0200547 *snode = lysc_ext_find_node(lydctx->ext, mod, name, name_len, 0, getnext_opts);
Radek Krejcif16e2542021-02-17 15:39:23 +0100548 } else {
Michal Vasko8cc3f662022-03-29 11:25:51 +0200549 *snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
Radek Krejcif16e2542021-02-17 15:39:23 +0100550 }
Michal Vasko8cc3f662022-03-29 11:25:51 +0200551 if (!*snode) {
Michal Vaskoddd76592022-01-17 13:34:48 +0100552 /* check for extension data */
Michal Vasko8cc3f662022-03-29 11:25:51 +0200553 r = ly_nested_ext_schema(parent, NULL, prefix, prefix_len, LY_VALUE_XML, &lydctx->xmlctx->ns, name,
554 name_len, snode, ext);
555 if (r != LY_ENOT) {
556 /* success or error */
Michal Vaskoddd76592022-01-17 13:34:48 +0100557 return r;
tadeas-vintrlik2aa36b42021-11-03 13:07:34 +0100558 }
Michal Vaskoddd76592022-01-17 13:34:48 +0100559
560 /* unknown data node */
Michal Vaskoe0665742021-02-11 11:08:44 +0100561 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
562 if (parent) {
Radek Krejci422afb12021-03-04 16:38:16 +0100563 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found as a child of \"%s\" node.",
Michal Vasko61ad1ff2022-02-10 15:48:39 +0100564 (int)name_len, name, LYD_NAME(parent));
Radek Krejcif16e2542021-02-17 15:39:23 +0100565 } else if (lydctx->ext) {
566 if (lydctx->ext->argument) {
Radek Krejci422afb12021-03-04 16:38:16 +0100567 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" %s extension instance.",
568 (int)name_len, name, lydctx->ext->argument, lydctx->ext->def->name);
Radek Krejcif16e2542021-02-17 15:39:23 +0100569 } else {
Radek Krejci422afb12021-03-04 16:38:16 +0100570 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the %s extension instance.",
571 (int)name_len, name, lydctx->ext->def->name);
Radek Krejcif16e2542021-02-17 15:39:23 +0100572 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100573 } else {
Radek Krejci422afb12021-03-04 16:38:16 +0100574 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" module.",
575 (int)name_len, name, mod->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100576 }
Michal Vasko8cc3f662022-03-29 11:25:51 +0200577 return LY_EVALID;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200578 }
Michal Vasko8cc3f662022-03-29 11:25:51 +0200579 return LY_SUCCESS;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200580 } else {
581 /* check that schema node is valid and can be used */
Michal Vasko8cc3f662022-03-29 11:25:51 +0200582 LY_CHECK_RET(lyd_parser_check_schema((struct lyd_ctx *)lydctx, *snode));
583 LY_CHECK_RET(lydxml_data_check_opaq(lydctx, snode));
Michal Vaskoa5da3292020-08-12 13:10:50 +0200584 }
585 }
586
Michal Vasko8cc3f662022-03-29 11:25:51 +0200587 return LY_SUCCESS;
588}
589
590/**
591 * @brief Parse XML subtree.
592 *
593 * @param[in] lydctx XML YANG data parser context.
594 * @param[in,out] parent Parent node where the children are inserted. NULL in case of parsing top-level elements.
595 * @param[in,out] first_p Pointer to the first (@p parent or top-level) child. In case there were already some siblings,
596 * this may point to a previously existing node.
597 * @param[in,out] parsed Optional set to add all the parsed siblings into.
598 * @return LY_ERR value.
599 */
600static LY_ERR
601lydxml_subtree_r(struct lyd_xml_ctx *lydctx, struct lyd_node *parent, struct lyd_node **first_p, struct ly_set *parsed)
602{
603 LY_ERR ret = LY_SUCCESS;
604 const char *prefix, *name;
605 size_t prefix_len, name_len;
606 struct lyxml_ctx *xmlctx;
607 const struct ly_ctx *ctx;
608 const struct lyxml_ns *ns;
609 struct lyd_meta *meta = NULL;
610 struct lyd_attr *attr = NULL;
611 const struct lysc_node *snode;
612 struct lysc_ext_instance *ext;
Michal Vaskocea58712022-04-01 14:37:08 +0200613 uint32_t prev_parse_opts, orig_parse_opts, prev_int_opts, hints;
614 struct lyd_node *node = NULL, *anchor, *insert_anchor = NULL;
Michal Vasko8cc3f662022-03-29 11:25:51 +0200615 void *val_prefix_data = NULL;
616 LY_VALUE_FORMAT format;
617 ly_bool parse_subtree;
618 char *val;
619
620 assert(parent || first_p);
621
622 xmlctx = lydctx->xmlctx;
623 ctx = xmlctx->ctx;
624
625 parse_subtree = lydctx->parse_opts & LYD_PARSE_SUBTREE ? 1 : 0;
626 /* all descendants should be parsed */
627 lydctx->parse_opts &= ~LYD_PARSE_SUBTREE;
628 orig_parse_opts = lydctx->parse_opts;
629
630 assert(xmlctx->status == LYXML_ELEMENT);
631
632 /* remember element prefix and name */
633 prefix = xmlctx->prefix;
634 prefix_len = xmlctx->prefix_len;
635 name = xmlctx->name;
636 name_len = xmlctx->name_len;
637
638 /* parser next */
639 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
640
641 /* get the schema node */
642 LY_CHECK_GOTO(ret = lydxml_subtree_snode(lydctx, parent, prefix, prefix_len, name, name_len, &snode, &ext), error);
643
644 if (!snode && !(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
645 LOGVRB("Skipping parsing of unknown node \"%.*s\".", name_len, name);
646
647 /* skip element with children */
648 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
649 return LY_SUCCESS;
650 }
651
Michal Vaskoa5da3292020-08-12 13:10:50 +0200652 /* create metadata/attributes */
653 if (xmlctx->status == LYXML_ATTRIBUTE) {
654 if (snode) {
Michal Vaskoddd76592022-01-17 13:34:48 +0100655 ret = lydxml_metadata(lydctx, snode, &meta);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200656 LY_CHECK_GOTO(ret, error);
657 } else {
Michal Vaskoe0665742021-02-11 11:08:44 +0100658 assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200659 ret = lydxml_attrs(xmlctx, &attr);
660 LY_CHECK_GOTO(ret, error);
661 }
662 }
663
664 assert(xmlctx->status == LYXML_ELEM_CONTENT);
665 if (!snode) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100666 assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200667
668 if (xmlctx->ws_only) {
669 /* ignore WS-only value */
Radek IÅ¡a017270d2021-02-16 10:26:15 +0100670 if (xmlctx->dynamic) {
Michal Vaskocea58712022-04-01 14:37:08 +0200671 free((char *)xmlctx->value);
Radek IÅ¡a017270d2021-02-16 10:26:15 +0100672 }
673 xmlctx->dynamic = 0;
674 xmlctx->value = "";
Michal Vaskoa5da3292020-08-12 13:10:50 +0200675 xmlctx->value_len = 0;
Radek Krejci8df109d2021-04-23 12:19:08 +0200676 format = LY_VALUE_XML;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200677 } else {
678 /* get value prefixes */
Radek Krejci8df109d2021-04-23 12:19:08 +0200679 ret = ly_store_prefix_data(xmlctx->ctx, xmlctx->value, xmlctx->value_len, LY_VALUE_XML,
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100680 &xmlctx->ns, &format, &val_prefix_data);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200681 LY_CHECK_GOTO(ret, error);
682 }
683
Michal Vaskoda8fbbf2021-06-16 11:44:44 +0200684 /* get NS again, it may have been backed up and restored */
685 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
686 assert(ns);
687
Michal Vaskocea58712022-04-01 14:37:08 +0200688 /* get best-effort node hints */
689 lydxml_get_hints_opaq(name, name_len, xmlctx->value, xmlctx->value_len, parent ? lyd_child(parent) : *first_p,
690 ns->uri, &hints, &insert_anchor);
691
Michal Vaskoa5da3292020-08-12 13:10:50 +0200692 /* create node */
Michal Vasko501af032020-11-11 20:27:44 +0100693 ret = lyd_create_opaq(ctx, name, name_len, prefix, prefix_len, ns->uri, strlen(ns->uri), xmlctx->value,
Michal Vaskocea58712022-04-01 14:37:08 +0200694 xmlctx->value_len, &xmlctx->dynamic, format, val_prefix_data, hints, &node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200695 LY_CHECK_GOTO(ret, error);
696
697 /* parser next */
698 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
699
700 /* process children */
701 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100702 ret = lydxml_subtree_r(lydctx, node, lyd_node_child_p(node), NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200703 LY_CHECK_GOTO(ret, error);
704 }
705 } else if (snode->nodetype & LYD_NODE_TERM) {
706 /* create node */
Michal Vasko22df3f02020-08-24 13:29:22 +0200707 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 +0200708 &xmlctx->dynamic, LY_VALUE_XML, &xmlctx->ns, LYD_HINT_DATA, &node), error);
Radek Krejciddace2c2021-01-08 11:30:56 +0100709 LOG_LOCSET(snode, node, NULL, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200710
711 if (parent && (node->schema->flags & LYS_KEY)) {
712 /* check the key order, the anchor must never be a key */
Michal Vaskoe0665742021-02-11 11:08:44 +0100713 anchor = lyd_insert_get_next_anchor(lyd_child(parent), node);
Michal Vasko441e0fa2022-03-03 13:45:00 +0100714 if (anchor && anchor->schema && (anchor->schema->flags & LYS_KEY)) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100715 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100716 LOGVAL(ctx, LYVE_DATA, "Invalid position of the key \"%s\" in a list.", node->schema->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200717 ret = LY_EVALID;
718 goto error;
719 } else {
720 LOGWRN(ctx, "Invalid position of the key \"%s\" in a list.", node->schema->name);
721 }
722 }
723 }
724
725 /* parser next */
726 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
727
728 /* no children expected */
729 if (xmlctx->status == LYXML_ELEMENT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100730 LOGVAL(ctx, LYVE_SYNTAX, "Child element \"%.*s\" inside a terminal node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100731 (int)xmlctx->name_len, xmlctx->name, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200732 ret = LY_EVALID;
733 goto error;
734 }
735 } else if (snode->nodetype & LYD_NODE_INNER) {
736 if (!xmlctx->ws_only) {
737 /* value in inner node */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100738 LOGVAL(ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an inner node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100739 (int)xmlctx->value_len, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200740 ret = LY_EVALID;
741 goto error;
742 }
743
744 /* create node */
745 ret = lyd_create_inner(snode, &node);
746 LY_CHECK_GOTO(ret, error);
747
Radek Krejciddace2c2021-01-08 11:30:56 +0100748 LOG_LOCSET(snode, node, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100749
Michal Vaskoa5da3292020-08-12 13:10:50 +0200750 /* parser next */
751 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
752
Michal Vasko8cc3f662022-03-29 11:25:51 +0200753 prev_parse_opts = lydctx->parse_opts;
754 if (ext) {
755 /* only parse these extension data and validate afterwards */
756 lydctx->parse_opts |= LYD_PARSE_ONLY;
757 }
758
Michal Vaskoa5da3292020-08-12 13:10:50 +0200759 /* process children */
760 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100761 ret = lydxml_subtree_r(lydctx, node, lyd_node_child_p(node), NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200762 LY_CHECK_GOTO(ret, error);
763 }
764
Michal Vasko8cc3f662022-03-29 11:25:51 +0200765 /* restore options */
766 lydctx->parse_opts = prev_parse_opts;
767
Michal Vaskoa5da3292020-08-12 13:10:50 +0200768 if (snode->nodetype == LYS_LIST) {
769 /* check all keys exist */
770 LY_CHECK_GOTO(ret = lyd_parse_check_keys(node), error);
771 }
772
Michal Vaskoe0665742021-02-11 11:08:44 +0100773 if (!(lydctx->parse_opts & LYD_PARSE_ONLY)) {
Michal Vaskoa5da3292020-08-12 13:10:50 +0200774 /* new node validation, autodelete CANNOT occur, all nodes are new */
Michal Vaskoe0665742021-02-11 11:08:44 +0100775 ret = lyd_validate_new(lyd_node_child_p(node), snode, NULL, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200776 LY_CHECK_GOTO(ret, error);
777
778 /* add any missing default children */
Michal Vaskoddd76592022-01-17 13:34:48 +0100779 ret = lyd_new_implicit_r(node, lyd_node_child_p(node), NULL, NULL, &lydctx->node_when, &lydctx->node_types,
780 (lydctx->val_opts & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200781 LY_CHECK_GOTO(ret, error);
782 }
783
784 if (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
785 /* rememeber the RPC/action/notification */
786 lydctx->op_node = node;
787 }
788 } else if (snode->nodetype & LYD_NODE_ANY) {
Michal Vasko27c4dce2021-03-04 15:50:50 +0100789 if ((snode->nodetype == LYS_ANYDATA) && !xmlctx->ws_only) {
790 /* value in anydata node, we expect a tree */
791 LOGVAL(ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an anydata node \"%s\" found.",
Radek Krejci422afb12021-03-04 16:38:16 +0100792 (int)xmlctx->value_len < 20 ? xmlctx->value_len : 20, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200793 ret = LY_EVALID;
794 goto error;
795 }
796
Michal Vasko27c4dce2021-03-04 15:50:50 +0100797 if (!xmlctx->ws_only) {
798 /* use an arbitrary text value for anyxml */
Michal Vasko742a5b12022-02-24 16:07:27 +0100799 val = strndup(xmlctx->value, xmlctx->value_len);
800 LY_CHECK_ERR_GOTO(!val, LOGMEM(xmlctx->ctx); ret = LY_EMEM, error);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200801
Michal Vasko27c4dce2021-03-04 15:50:50 +0100802 /* parser next */
Michal Vaskoa04107f2022-03-29 12:09:50 +0200803 LY_CHECK_ERR_GOTO(ret = lyxml_ctx_next(xmlctx), free(val), error);
Michal Vasko27c4dce2021-03-04 15:50:50 +0100804
805 /* create node */
806 ret = lyd_create_any(snode, val, LYD_ANYDATA_STRING, 1, &node);
Michal Vasko742a5b12022-02-24 16:07:27 +0100807 LY_CHECK_ERR_GOTO(ret, free(val), error);
Michal Vasko27c4dce2021-03-04 15:50:50 +0100808 } else {
809 /* parser next */
810 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
811
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200812 /* update options so that generic data can be parsed */
813 prev_parse_opts = lydctx->parse_opts;
Michal Vasko27c4dce2021-03-04 15:50:50 +0100814 lydctx->parse_opts &= ~LYD_PARSE_STRICT;
Michal Vasko8cc3f662022-03-29 11:25:51 +0200815 lydctx->parse_opts |= LYD_PARSE_OPAQ | (ext ? LYD_PARSE_ONLY : 0);
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200816 prev_int_opts = lydctx->int_opts;
Michal Vasko02ed9d82021-07-15 14:58:04 +0200817 lydctx->int_opts |= LYD_INTOPT_ANY | LYD_INTOPT_WITH_SIBLINGS;
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200818
819 /* parse any data tree */
Michal Vasko27c4dce2021-03-04 15:50:50 +0100820 anchor = NULL;
821 while (xmlctx->status == LYXML_ELEMENT) {
822 ret = lydxml_subtree_r(lydctx, NULL, &anchor, NULL);
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200823 if (ret) {
Michal Vaskocc53c582022-04-01 12:07:44 +0200824 lyd_free_siblings(anchor);
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200825 break;
826 }
Michal Vasko27c4dce2021-03-04 15:50:50 +0100827 }
Michal Vaskoa98e3ea2021-06-03 09:13:33 +0200828
829 /* restore options */
830 lydctx->parse_opts = prev_parse_opts;
831 lydctx->int_opts = prev_int_opts;
832
833 LY_CHECK_GOTO(ret, error);
Michal Vasko27c4dce2021-03-04 15:50:50 +0100834
835 /* create node */
836 ret = lyd_create_any(snode, anchor, LYD_ANYDATA_DATATREE, 1, &node);
837 LY_CHECK_GOTO(ret, error);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200838 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200839 }
840 assert(node);
841
842 /* add/correct flags */
843 if (snode) {
Michal Vasko8cc3f662022-03-29 11:25:51 +0200844 LY_CHECK_GOTO(ret = lyd_parse_set_data_flags(node, &meta, (struct lyd_ctx *)lydctx, ext), error);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200845 }
846
847 /* parser next */
848 assert(xmlctx->status == LYXML_ELEM_CLOSE);
Michal Vaskoddd76592022-01-17 13:34:48 +0100849 if (!parse_subtree) {
850 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
851 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200852
853 /* add metadata/attributes */
854 if (snode) {
Michal Vasko871a0252020-11-11 18:35:24 +0100855 lyd_insert_meta(node, meta, 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200856 } else {
857 lyd_insert_attr(node, attr);
858 }
859
860 /* insert, keep first pointer correct */
Michal Vaskocea58712022-04-01 14:37:08 +0200861 if (insert_anchor) {
862 lyd_insert_after(insert_anchor, node);
863 } else if (ext) {
Michal Vasko8cc3f662022-03-29 11:25:51 +0200864 LY_CHECK_GOTO(ret = lyd_insert_ext(parent, node), error);
865 } else {
866 lyd_insert_node(parent, first_p, node, lydctx->parse_opts & LYD_PARSE_ORDERED ? 1 : 0);
867 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200868 while (!parent && (*first_p)->prev->next) {
869 *first_p = (*first_p)->prev;
870 }
871
Michal Vaskoe0665742021-02-11 11:08:44 +0100872 /* rememeber a successfully parsed node */
873 if (parsed) {
874 ly_set_add(parsed, node, 1, NULL);
875 }
876
Michal Vasko8cc3f662022-03-29 11:25:51 +0200877 lydctx->parse_opts = orig_parse_opts;
Radek Krejciddace2c2021-01-08 11:30:56 +0100878 LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200879 return LY_SUCCESS;
880
881error:
Michal Vasko8cc3f662022-03-29 11:25:51 +0200882 lydctx->parse_opts = orig_parse_opts;
Radek Krejciddace2c2021-01-08 11:30:56 +0100883 LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
Michal Vasko3a41dff2020-07-15 14:30:28 +0200884 lyd_free_meta_siblings(meta);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200885 lyd_free_attr_siblings(ctx, attr);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200886 lyd_free_tree(node);
Radek Krejcie7b95092019-05-15 11:03:07 +0200887 return ret;
888}
889
Michal Vaskoe0665742021-02-11 11:08:44 +0100890/**
891 * @brief Parse a specific XML element into an opaque node.
892 *
893 * @param[in] xmlctx XML parser context.
894 * @param[in] name Name of the element.
895 * @param[in] uri URI of the element.
896 * @param[in] value Whether a value is expected in the element.
897 * @param[out] evnp Parsed envelope (opaque node).
898 * @return LY_SUCCESS on success.
899 * @return LY_ENOT if the specified element did not match.
900 * @return LY_ERR value on error.
901 */
Michal Vasko1bf09392020-03-27 12:38:10 +0100902static LY_ERR
Michal Vaskoe0665742021-02-11 11:08:44 +0100903lydxml_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 +0100904{
Michal Vaskoe0665742021-02-11 11:08:44 +0100905 LY_ERR rc = LY_SUCCESS;
906 const struct lyxml_ns *ns;
Radek Krejci1798aae2020-07-14 13:26:06 +0200907 struct lyd_attr *attr = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100908 const char *prefix;
909 size_t prefix_len;
910
Michal Vasko1bf09392020-03-27 12:38:10 +0100911 assert(xmlctx->status == LYXML_ELEMENT);
912 if (ly_strncmp(name, xmlctx->name, xmlctx->name_len)) {
913 /* not the expected element */
Michal Vaskoe0665742021-02-11 11:08:44 +0100914 return LY_ENOT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100915 }
916
917 prefix = xmlctx->prefix;
918 prefix_len = xmlctx->prefix_len;
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200919 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100920 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +0100921 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +0100922 return LY_EVALID;
923 } else if (strcmp(ns->uri, uri)) {
924 /* different namespace */
925 return LY_ENOT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100926 }
927
928 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
929
930 /* create attributes */
931 if (xmlctx->status == LYXML_ATTRIBUTE) {
932 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
933 }
934
Michal Vaskoe0665742021-02-11 11:08:44 +0100935 assert(xmlctx->status == LYXML_ELEM_CONTENT);
936 if (!value && !xmlctx->ws_only) {
937 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected value \"%.*s\" in the \"%s\" element.",
Radek Krejci422afb12021-03-04 16:38:16 +0100938 (int)xmlctx->value_len, xmlctx->value, name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100939 rc = LY_EVALID;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100940 goto cleanup;
Michal Vaskoe0665742021-02-11 11:08:44 +0100941 }
Michal Vaskoa8edff02020-03-27 14:47:01 +0100942
943 /* create node */
Michal Vaskoe0665742021-02-11 11:08:44 +0100944 rc = lyd_create_opaq(xmlctx->ctx, name, strlen(name), prefix, prefix_len, uri, strlen(uri), xmlctx->value,
Radek Krejci8df109d2021-04-23 12:19:08 +0200945 xmlctx->ws_only ? 0 : xmlctx->value_len, NULL, LY_VALUE_XML, NULL, 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100946 LY_CHECK_GOTO(rc, cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100947
948 /* assign atributes */
Michal Vaskoe0665742021-02-11 11:08:44 +0100949 ((struct lyd_node_opaq *)(*envp))->attr = attr;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100950 attr = NULL;
951
Michal Vaskoe0665742021-02-11 11:08:44 +0100952 /* parser next element */
953 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100954
Michal Vaskoe0665742021-02-11 11:08:44 +0100955cleanup:
956 lyd_free_attr_siblings(xmlctx->ctx, attr);
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 rpc 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_rpc(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 "rpc" */
983 r = lydxml_envelope(xmlctx, "rpc", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100984 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
985
986 /* parse "action", if any */
987 r = lydxml_envelope(xmlctx, "action", "urn:ietf:params:xml:ns:yang:1", 0, &child);
988 if (r == LY_SUCCESS) {
989 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +0200990 lyd_insert_node(*envp, NULL, child, 0);
Michal Vaskoe0665742021-02-11 11:08:44 +0100991
992 /* NETCONF action */
993 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_ACTION;
994 *close_elem = 2;
995 } else if (r == LY_ENOT) {
996 /* NETCONF RPC */
997 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_RPC;
998 *close_elem = 1;
999 } else {
1000 rc = r;
1001 goto cleanup;
1002 }
1003
1004cleanup:
1005 if (rc) {
1006 lyd_free_tree(*envp);
1007 *envp = NULL;
1008 }
1009 return rc;
1010}
1011
1012/**
1013 * @brief Parse all expected non-data XML elements of a NETCONF notification message.
1014 *
1015 * @param[in] xmlctx XML parser context.
1016 * @param[out] evnp Parsed envelope(s) (opaque node).
1017 * @param[out] int_opts Internal options for parsing the rest of YANG data.
1018 * @param[out] close_elem Number of parsed opened elements that need to be closed.
1019 * @return LY_SUCCESS on success.
1020 * @return LY_ERR value on error.
1021 */
1022static LY_ERR
1023lydxml_env_netconf_notif(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
1024{
1025 LY_ERR rc = LY_SUCCESS, r;
1026 struct lyd_node *child;
1027
1028 assert(envp && !*envp);
1029
1030 /* parse "notification" */
1031 r = lydxml_envelope(xmlctx, "notification", "urn:ietf:params:xml:ns:netconf:notification:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +01001032 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1033
1034 /* parse "eventTime" */
1035 r = lydxml_envelope(xmlctx, "eventTime", "urn:ietf:params:xml:ns:netconf:notification:1.0", 1, &child);
1036 if (r == LY_ENOT) {
Radek Krejci422afb12021-03-04 16:38:16 +01001037 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unexpected element \"%.*s\" instead of \"eventTime\".",
1038 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001039 r = LY_EVALID;
1040 }
1041 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1042
1043 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001044 lyd_insert_node(*envp, NULL, child, 0);
Michal Vaskoe0665742021-02-11 11:08:44 +01001045
1046 /* validate value */
1047 /* TODO validate child->value as yang:date-and-time */
1048
1049 /* finish child parsing */
Michal Vaskoa8edff02020-03-27 14:47:01 +01001050 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1051 assert(xmlctx->status == LYXML_ELEMENT);
Michal Vaskoe0665742021-02-11 11:08:44 +01001052 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"eventTime\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001053 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001054 rc = LY_EVALID;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001055 goto cleanup;
1056 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001057 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1058
1059 /* NETCONF notification */
1060 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_NOTIF;
1061 *close_elem = 1;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001062
1063cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +01001064 if (rc) {
Michal Vaskoa8edff02020-03-27 14:47:01 +01001065 lyd_free_tree(*envp);
Michal Vaskoe0665742021-02-11 11:08:44 +01001066 *envp = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001067 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001068 return rc;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001069}
Michal Vasko79135ae2020-12-16 10:08:35 +01001070
Michal Vaskoe0665742021-02-11 11:08:44 +01001071/**
1072 * @brief Parse an XML element as an opaque node subtree.
1073 *
1074 * @param[in] xmlctx XML parser context.
1075 * @param[in] parent Parent to append nodes to.
1076 * @return LY_ERR value.
1077 */
1078static LY_ERR
1079lydxml_opaq_r(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
Michal Vaskoa8edff02020-03-27 14:47:01 +01001080{
Michal Vaskoe0665742021-02-11 11:08:44 +01001081 LY_ERR rc = LY_SUCCESS;
1082 const struct lyxml_ns *ns;
1083 struct lyd_attr *attr = NULL;
1084 struct lyd_node *child = NULL;
1085 const char *name, *prefix;
1086 size_t name_len, prefix_len;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001087
Michal Vaskoe0665742021-02-11 11:08:44 +01001088 assert(xmlctx->status == LYXML_ELEMENT);
Michal Vaskoa8edff02020-03-27 14:47:01 +01001089
Michal Vaskoe0665742021-02-11 11:08:44 +01001090 name = xmlctx->name;
1091 name_len = xmlctx->name_len;
1092 prefix = xmlctx->prefix;
1093 prefix_len = xmlctx->prefix_len;
1094 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
1095 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +01001096 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +01001097 return LY_EVALID;
1098 }
Michal Vaskoa8edff02020-03-27 14:47:01 +01001099
Michal Vaskoe0665742021-02-11 11:08:44 +01001100 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
Michal Vaskoa8edff02020-03-27 14:47:01 +01001101
Michal Vaskoe0665742021-02-11 11:08:44 +01001102 /* create attributes */
1103 if (xmlctx->status == LYXML_ATTRIBUTE) {
1104 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
1105 }
1106
1107 /* create node */
1108 assert(xmlctx->status == LYXML_ELEM_CONTENT);
1109 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 +02001110 xmlctx->ws_only ? 0 : xmlctx->value_len, NULL, LY_VALUE_XML, NULL, 0, &child);
Michal Vaskoe0665742021-02-11 11:08:44 +01001111 LY_CHECK_GOTO(rc, cleanup);
1112
1113 /* assign atributes */
1114 ((struct lyd_node_opaq *)child)->attr = attr;
1115 attr = NULL;
1116
1117 /* parser next element */
1118 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1119
1120 /* parse all the descendants */
1121 while (xmlctx->status == LYXML_ELEMENT) {
1122 rc = lydxml_opaq_r(xmlctx, child);
1123 LY_CHECK_GOTO(rc, cleanup);
1124 }
1125
1126 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001127 lyd_insert_node(parent, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +01001128
1129cleanup:
1130 lyd_free_attr_siblings(xmlctx->ctx, attr);
1131 if (rc) {
1132 lyd_free_tree(child);
1133 }
1134 return rc;
1135}
1136
1137/**
1138 * @brief Parse all expected non-data XML elements of the error-info element in NETCONF rpc-reply message.
1139 *
1140 * @param[in] xmlctx XML parser context.
1141 * @param[in] parent Parent to append nodes to.
1142 * @return LY_ERR value.
1143 */
1144static LY_ERR
1145lydxml_env_netconf_rpc_reply_error_info(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
1146{
1147 LY_ERR r;
1148 struct lyd_node *child, *iter;
1149 const struct lyxml_ns *ns;
1150 ly_bool no_dup;
1151
1152 /* there must be some child */
1153 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1154 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"error-info\".");
1155 return LY_EVALID;
1156 }
1157
1158 while (xmlctx->status == LYXML_ELEMENT) {
1159 child = NULL;
1160
1161 /*
1162 * session-id
1163 */
1164 r = lydxml_envelope(xmlctx, "session-id", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1165 if (r == LY_SUCCESS) {
1166 no_dup = 1;
1167 goto check_child;
1168 } else if (r != LY_ENOT) {
1169 goto error;
1170 }
1171
1172 /*
1173 * bad-attribute
1174 */
1175 r = lydxml_envelope(xmlctx, "bad-attribute", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1176 if (r == LY_SUCCESS) {
1177 no_dup = 1;
1178 goto check_child;
1179 } else if (r != LY_ENOT) {
1180 goto error;
1181 }
1182
1183 /*
1184 * bad-element
1185 */
1186 r = lydxml_envelope(xmlctx, "bad-element", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1187 if (r == LY_SUCCESS) {
1188 no_dup = 1;
1189 goto check_child;
1190 } else if (r != LY_ENOT) {
1191 goto error;
1192 }
1193
1194 /*
1195 * bad-namespace
1196 */
1197 r = lydxml_envelope(xmlctx, "bad-namespace", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1198 if (r == LY_SUCCESS) {
1199 no_dup = 1;
1200 goto check_child;
1201 } else if (r != LY_ENOT) {
1202 goto error;
1203 }
1204
1205 if (r == LY_ENOT) {
1206 assert(xmlctx->status == LYXML_ELEMENT);
1207
1208 /* learn namespace */
1209 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
1210 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +01001211 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)xmlctx->prefix_len, xmlctx->prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +01001212 r = LY_EVALID;
1213 goto error;
1214 } else if (!strcmp(ns->uri, "urn:ietf:params:xml:ns:netconf:base:1.0")) {
1215 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"error-info\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001216 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001217 r = LY_EVALID;
1218 goto error;
1219 }
1220
1221 /* custom elements */
1222 r = lydxml_opaq_r(xmlctx, parent);
1223 LY_CHECK_GOTO(r, error);
Michal Vasko6398eaf2022-01-10 10:12:30 +01001224 continue;
Michal Vaskoe0665742021-02-11 11:08:44 +01001225 }
1226
1227check_child:
1228 /* check for duplicates */
1229 if (no_dup) {
1230 LY_LIST_FOR(lyd_child(parent), iter) {
1231 if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
1232 (((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
1233 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"error-info\".",
1234 ((struct lyd_node_opaq *)child)->name.name);
1235 r = LY_EVALID;
1236 goto error;
1237 }
1238 }
1239 }
1240
1241 /* finish child parsing */
1242 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1243 assert(xmlctx->status == LYXML_ELEMENT);
1244 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"error-info\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001245 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001246 r = LY_EVALID;
1247 goto error;
1248 }
1249 LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
1250
1251 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001252 lyd_insert_node(parent, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +01001253 }
1254
1255 return LY_SUCCESS;
1256
1257error:
1258 lyd_free_tree(child);
1259 return r;
1260}
1261
1262/**
1263 * @brief Parse all expected non-data XML elements of the rpc-error element in NETCONF rpc-reply message.
1264 *
1265 * @param[in] xmlctx XML parser context.
1266 * @param[in] parent Parent to append nodes to.
1267 * @return LY_ERR value.
1268 */
1269static LY_ERR
1270lydxml_env_netconf_rpc_reply_error(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
1271{
1272 LY_ERR r;
1273 struct lyd_node *child, *iter;
1274 const char *val;
1275 ly_bool no_dup;
1276
1277 /* there must be some child */
1278 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1279 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"rpc-error\".");
1280 return LY_EVALID;
1281 }
1282
1283 while (xmlctx->status == LYXML_ELEMENT) {
1284 child = NULL;
1285
1286 /*
1287 * error-type
1288 */
1289 r = lydxml_envelope(xmlctx, "error-type", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1290 if (r == LY_SUCCESS) {
1291 val = ((struct lyd_node_opaq *)child)->value;
1292 if (strcmp(val, "transport") && strcmp(val, "rpc") && strcmp(val, "protocol") && strcmp(val, "application")) {
1293 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1294 ((struct lyd_node_opaq *)child)->name.name);
1295 r = LY_EVALID;
1296 goto error;
1297 }
1298
1299 no_dup = 1;
1300 goto check_child;
1301 } else if (r != LY_ENOT) {
1302 goto error;
1303 }
1304
1305 /*
1306 * error-tag
1307 */
1308 r = lydxml_envelope(xmlctx, "error-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1309 if (r == LY_SUCCESS) {
1310 val = ((struct lyd_node_opaq *)child)->value;
1311 if (strcmp(val, "in-use") && strcmp(val, "invalid-value") && strcmp(val, "too-big") &&
1312 strcmp(val, "missing-attribute") && strcmp(val, "bad-attribute") &&
1313 strcmp(val, "unknown-attribute") && strcmp(val, "missing-element") && strcmp(val, "bad-element") &&
1314 strcmp(val, "unknown-element") && strcmp(val, "unknown-namespace") && strcmp(val, "access-denied") &&
1315 strcmp(val, "lock-denied") && strcmp(val, "resource-denied") && strcmp(val, "rollback-failed") &&
1316 strcmp(val, "data-exists") && strcmp(val, "data-missing") && strcmp(val, "operation-not-supported") &&
1317 strcmp(val, "operation-failed") && strcmp(val, "malformed-message")) {
1318 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1319 ((struct lyd_node_opaq *)child)->name.name);
1320 r = LY_EVALID;
1321 goto error;
1322 }
1323
1324 no_dup = 1;
1325 goto check_child;
1326 } else if (r != LY_ENOT) {
1327 goto error;
1328 }
1329
1330 /*
1331 * error-severity
1332 */
1333 r = lydxml_envelope(xmlctx, "error-severity", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1334 if (r == LY_SUCCESS) {
1335 val = ((struct lyd_node_opaq *)child)->value;
1336 if (strcmp(val, "error") && strcmp(val, "warning")) {
1337 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1338 ((struct lyd_node_opaq *)child)->name.name);
1339 r = LY_EVALID;
1340 goto error;
1341 }
1342
1343 no_dup = 1;
1344 goto check_child;
1345 } else if (r != LY_ENOT) {
1346 goto error;
1347 }
1348
1349 /*
1350 * error-app-tag
1351 */
1352 r = lydxml_envelope(xmlctx, "error-app-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1353 if (r == LY_SUCCESS) {
1354 no_dup = 1;
1355 goto check_child;
1356 } else if (r != LY_ENOT) {
1357 goto error;
1358 }
1359
1360 /*
1361 * error-path
1362 */
1363 r = lydxml_envelope(xmlctx, "error-path", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1364 if (r == LY_SUCCESS) {
1365 no_dup = 1;
1366 goto check_child;
1367 } else if (r != LY_ENOT) {
1368 goto error;
1369 }
1370
1371 /*
1372 * error-message
1373 */
1374 r = lydxml_envelope(xmlctx, "error-message", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1375 if (r == LY_SUCCESS) {
1376 no_dup = 1;
1377 goto check_child;
1378 } else if (r != LY_ENOT) {
1379 goto error;
1380 }
1381
1382 /* error-info */
1383 r = lydxml_envelope(xmlctx, "error-info", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1384 if (r == LY_SUCCESS) {
1385 /* parse all the descendants */
1386 LY_CHECK_GOTO(r = lydxml_env_netconf_rpc_reply_error_info(xmlctx, child), error);
1387
1388 no_dup = 0;
1389 goto check_child;
1390 } else if (r != LY_ENOT) {
1391 goto error;
1392 }
1393
1394 if (r == LY_ENOT) {
1395 assert(xmlctx->status == LYXML_ELEMENT);
1396 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001397 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001398 r = LY_EVALID;
1399 goto error;
1400 }
1401
1402check_child:
1403 /* check for duplicates */
1404 if (no_dup) {
1405 LY_LIST_FOR(lyd_child(parent), iter) {
1406 if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
1407 (((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
1408 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"rpc-error\".",
1409 ((struct lyd_node_opaq *)child)->name.name);
1410 r = LY_EVALID;
1411 goto error;
1412 }
1413 }
1414 }
1415
1416 /* finish child parsing */
1417 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1418 assert(xmlctx->status == LYXML_ELEMENT);
1419 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001420 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001421 r = LY_EVALID;
1422 goto error;
1423 }
1424 LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
1425
1426 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001427 lyd_insert_node(parent, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +01001428 }
1429
1430 return LY_SUCCESS;
1431
1432error:
1433 lyd_free_tree(child);
1434 return r;
1435}
1436
1437/**
1438 * @brief Parse all expected non-data XML elements of a NETCONF rpc-reply message.
1439 *
1440 * @param[in] xmlctx XML parser context.
1441 * @param[out] evnp Parsed envelope(s) (opaque node).
1442 * @param[out] int_opts Internal options for parsing the rest of YANG data.
1443 * @param[out] close_elem Number of parsed opened elements that need to be closed.
1444 * @return LY_SUCCESS on success.
1445 * @return LY_ERR value on error.
1446 */
1447static LY_ERR
1448lydxml_env_netconf_reply(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
1449{
1450 LY_ERR rc = LY_SUCCESS, r;
1451 struct lyd_node *child = NULL;
1452 const char *parsed_elem = NULL;
1453
1454 assert(envp && !*envp);
1455
1456 /* parse "rpc-reply" */
1457 r = lydxml_envelope(xmlctx, "rpc-reply", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +01001458 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1459
1460 /* there must be some child */
1461 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1462 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"rpc-reply\".");
1463 rc = LY_EVALID;
Michal Vaskocf770e22020-08-12 13:21:43 +02001464 goto cleanup;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001465 }
1466
Michal Vaskoe0665742021-02-11 11:08:44 +01001467 /* try to parse "ok" */
1468 r = lydxml_envelope(xmlctx, "ok", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1469 if (r == LY_SUCCESS) {
1470 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001471 lyd_insert_node(*envp, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +01001472
1473 /* finish child parsing */
1474 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1475 assert(xmlctx->status == LYXML_ELEMENT);
1476 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"ok\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001477 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001478 rc = LY_EVALID;
1479 goto cleanup;
1480 }
1481 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1482
1483 /* success */
1484 parsed_elem = "ok";
1485 goto finish;
1486 } else if (r != LY_ENOT) {
1487 rc = r;
1488 goto cleanup;
Michal Vasko2552ea32020-12-08 15:32:34 +01001489 }
1490
Michal Vaskoe0665742021-02-11 11:08:44 +01001491 /* try to parse all "rpc-error" elements */
1492 while (xmlctx->status == LYXML_ELEMENT) {
1493 r = lydxml_envelope(xmlctx, "rpc-error", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1494 if (r == LY_ENOT) {
1495 break;
1496 } else if (r) {
1497 rc = r;
1498 goto cleanup;
1499 }
1500
1501 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001502 lyd_insert_node(*envp, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +01001503
1504 /* parse all children of "rpc-error" */
1505 LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc_reply_error(xmlctx, child), cleanup);
1506
1507 /* finish child parsing */
1508 assert(xmlctx->status == LYXML_ELEM_CLOSE);
1509 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1510
1511 parsed_elem = "rpc-error";
Michal Vasko2552ea32020-12-08 15:32:34 +01001512 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001513
1514finish:
1515 if (parsed_elem) {
1516 /* NETCONF rpc-reply with no data */
1517 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1518 assert(xmlctx->status == LYXML_ELEMENT);
1519 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"%s\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001520 (int)xmlctx->name_len, xmlctx->name, parsed_elem);
Michal Vaskoe0665742021-02-11 11:08:44 +01001521 rc = LY_EVALID;
1522 goto cleanup;
1523 }
1524 }
1525
1526 /* NETCONF rpc-reply */
Michal Vasko1d991fd2021-07-09 13:14:40 +02001527 *int_opts = LYD_INTOPT_WITH_SIBLINGS | LYD_INTOPT_REPLY;
Michal Vaskoe0665742021-02-11 11:08:44 +01001528 *close_elem = 1;
1529
1530cleanup:
1531 if (rc) {
1532 lyd_free_tree(*envp);
1533 *envp = NULL;
1534 }
1535 return rc;
1536}
1537
Michal Vasko2552ea32020-12-08 15:32:34 +01001538LY_ERR
Radek Krejcif16e2542021-02-17 15:39:23 +01001539lyd_parse_xml(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
1540 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 +01001541 struct lyd_node **envp, struct ly_set *parsed, ly_bool *subtree_sibling, struct lyd_ctx **lydctx_p)
Michal Vasko2552ea32020-12-08 15:32:34 +01001542{
Michal Vaskoe0665742021-02-11 11:08:44 +01001543 LY_ERR rc = LY_SUCCESS;
1544 struct lyd_xml_ctx *lydctx;
Michal Vasko2ca9f9e2021-07-02 09:21:36 +02001545 uint32_t i, int_opts = 0, close_elem = 0;
Michal Vaskoe0665742021-02-11 11:08:44 +01001546 ly_bool parsed_data_nodes = 0;
Michal Vaskoddd76592022-01-17 13:34:48 +01001547 enum LYXML_PARSER_STATUS status;
Michal Vasko2552ea32020-12-08 15:32:34 +01001548
Michal Vaskoe0665742021-02-11 11:08:44 +01001549 assert(ctx && in && lydctx_p);
1550 assert(!(parse_opts & ~LYD_PARSE_OPTS_MASK));
1551 assert(!(val_opts & ~LYD_VALIDATE_OPTS_MASK));
Michal Vasko2552ea32020-12-08 15:32:34 +01001552
Michal Vaskoe0665742021-02-11 11:08:44 +01001553 /* init context */
1554 lydctx = calloc(1, sizeof *lydctx);
1555 LY_CHECK_ERR_RET(!lydctx, LOGMEM(ctx), LY_EMEM);
1556 LY_CHECK_GOTO(rc = lyxml_ctx_new(ctx, in, &lydctx->xmlctx), cleanup);
1557 lydctx->parse_opts = parse_opts;
1558 lydctx->val_opts = val_opts;
1559 lydctx->free = lyd_xml_ctx_free;
Radek Krejcif16e2542021-02-17 15:39:23 +01001560 lydctx->ext = ext;
Michal Vasko2552ea32020-12-08 15:32:34 +01001561
Michal Vaskoe0665742021-02-11 11:08:44 +01001562 switch (data_type) {
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001563 case LYD_TYPE_DATA_YANG:
Michal Vaskoddd76592022-01-17 13:34:48 +01001564 if (!(parse_opts & LYD_PARSE_SUBTREE)) {
1565 int_opts = LYD_INTOPT_WITH_SIBLINGS;
1566 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001567 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001568 case LYD_TYPE_RPC_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001569 int_opts = LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NO_SIBLINGS;
1570 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001571 case LYD_TYPE_NOTIF_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001572 int_opts = LYD_INTOPT_NOTIF | LYD_INTOPT_NO_SIBLINGS;
1573 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001574 case LYD_TYPE_REPLY_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001575 int_opts = LYD_INTOPT_REPLY | LYD_INTOPT_NO_SIBLINGS;
1576 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001577 case LYD_TYPE_RPC_NETCONF:
Michal Vaskoe0665742021-02-11 11:08:44 +01001578 assert(!parent);
1579 LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
1580 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001581 case LYD_TYPE_NOTIF_NETCONF:
1582 assert(!parent);
1583 LY_CHECK_GOTO(rc = lydxml_env_netconf_notif(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
1584 break;
1585 case LYD_TYPE_REPLY_NETCONF:
Michal Vaskoe0665742021-02-11 11:08:44 +01001586 assert(parent);
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001587 LY_CHECK_GOTO(rc = lydxml_env_netconf_reply(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
Michal Vaskoe0665742021-02-11 11:08:44 +01001588 break;
1589 }
1590 lydctx->int_opts = int_opts;
1591
1592 /* find the operation node if it exists already */
1593 LY_CHECK_GOTO(rc = lyd_parser_find_operation(parent, int_opts, &lydctx->op_node), cleanup);
1594
1595 /* parse XML data */
1596 while (lydctx->xmlctx->status == LYXML_ELEMENT) {
1597 LY_CHECK_GOTO(rc = lydxml_subtree_r(lydctx, parent, first_p, parsed), cleanup);
1598 parsed_data_nodes = 1;
1599
1600 if (!(int_opts & LYD_INTOPT_WITH_SIBLINGS)) {
1601 break;
1602 }
Michal Vasko2552ea32020-12-08 15:32:34 +01001603 }
1604
Michal Vaskoe0665742021-02-11 11:08:44 +01001605 /* close all opened elements */
1606 for (i = 0; i < close_elem; ++i) {
1607 if (lydctx->xmlctx->status != LYXML_ELEM_CLOSE) {
1608 assert(lydctx->xmlctx->status == LYXML_ELEMENT);
Radek Krejci422afb12021-03-04 16:38:16 +01001609 LOGVAL(lydctx->xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\".",
1610 (int)lydctx->xmlctx->name_len, lydctx->xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001611 rc = LY_EVALID;
1612 goto cleanup;
1613 }
1614
1615 LY_CHECK_GOTO(rc = lyxml_ctx_next(lydctx->xmlctx), cleanup);
Michal Vasko4189c0f2020-08-13 09:05:22 +02001616 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001617
1618 /* check final state */
1619 if ((int_opts & LYD_INTOPT_NO_SIBLINGS) && (lydctx->xmlctx->status == LYXML_ELEMENT)) {
1620 LOGVAL(ctx, LYVE_SYNTAX, "Unexpected sibling node.");
1621 rc = LY_EVALID;
1622 goto cleanup;
1623 }
Michal Vaskoc939fdd2022-01-03 11:35:13 +01001624 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 +01001625 LOGVAL(ctx, LYVE_DATA, "Missing the operation node.");
1626 rc = LY_EVALID;
1627 goto cleanup;
1628 }
1629
1630 if (!parsed_data_nodes) {
1631 /* no data nodes were parsed */
1632 lydctx->op_node = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001633 }
1634
Michal Vaskoddd76592022-01-17 13:34:48 +01001635 if (parse_opts & LYD_PARSE_SUBTREE) {
1636 /* check for a sibling element */
1637 assert(subtree_sibling);
1638 if (!lyxml_ctx_peek(lydctx->xmlctx, &status) && (status == LYXML_ELEMENT)) {
1639 *subtree_sibling = 1;
1640 } else {
1641 *subtree_sibling = 0;
1642 }
1643 }
1644
Michal Vaskoa8edff02020-03-27 14:47:01 +01001645cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +01001646 /* there should be no unres stored if validation should be skipped */
1647 assert(!(parse_opts & LYD_PARSE_ONLY) || (!lydctx->node_types.count && !lydctx->meta_types.count &&
Michal Vaskoddd76592022-01-17 13:34:48 +01001648 !lydctx->node_when.count));
Michal Vaskoe0665742021-02-11 11:08:44 +01001649
1650 if (rc) {
1651 lyd_xml_ctx_free((struct lyd_ctx *)lydctx);
1652 } else {
1653 *lydctx_p = (struct lyd_ctx *)lydctx;
1654
1655 /* the XML context is no more needed, freeing it also stops logging line numbers which would be confusing now */
1656 lyxml_ctx_free(lydctx->xmlctx);
1657 lydctx->xmlctx = NULL;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001658 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001659 return rc;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001660}