blob: 5e9d5c3c634d04462479461b321a3ad001e739b4 [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
Michal Vasko50375272022-04-26 12:07:46 +0200982 if (xmlctx->status != LYXML_ELEMENT) {
983 /* nothing to parse */
984 assert(xmlctx->status == LYXML_END);
985 goto cleanup;
986 }
987
Michal Vaskoe0665742021-02-11 11:08:44 +0100988 /* parse "rpc" */
989 r = lydxml_envelope(xmlctx, "rpc", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100990 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
991
992 /* parse "action", if any */
993 r = lydxml_envelope(xmlctx, "action", "urn:ietf:params:xml:ns:yang:1", 0, &child);
994 if (r == LY_SUCCESS) {
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 /* NETCONF action */
999 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_ACTION;
1000 *close_elem = 2;
1001 } else if (r == LY_ENOT) {
1002 /* NETCONF RPC */
1003 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_RPC;
1004 *close_elem = 1;
1005 } else {
1006 rc = r;
1007 goto cleanup;
1008 }
1009
1010cleanup:
1011 if (rc) {
1012 lyd_free_tree(*envp);
1013 *envp = NULL;
1014 }
1015 return rc;
1016}
1017
1018/**
1019 * @brief Parse all expected non-data XML elements of a NETCONF notification message.
1020 *
1021 * @param[in] xmlctx XML parser context.
1022 * @param[out] evnp Parsed envelope(s) (opaque node).
1023 * @param[out] int_opts Internal options for parsing the rest of YANG data.
1024 * @param[out] close_elem Number of parsed opened elements that need to be closed.
1025 * @return LY_SUCCESS on success.
1026 * @return LY_ERR value on error.
1027 */
1028static LY_ERR
1029lydxml_env_netconf_notif(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
1030{
1031 LY_ERR rc = LY_SUCCESS, r;
1032 struct lyd_node *child;
1033
1034 assert(envp && !*envp);
1035
Michal Vasko50375272022-04-26 12:07:46 +02001036 if (xmlctx->status != LYXML_ELEMENT) {
1037 /* nothing to parse */
1038 assert(xmlctx->status == LYXML_END);
1039 goto cleanup;
1040 }
1041
Michal Vaskoe0665742021-02-11 11:08:44 +01001042 /* parse "notification" */
1043 r = lydxml_envelope(xmlctx, "notification", "urn:ietf:params:xml:ns:netconf:notification:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +01001044 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1045
1046 /* parse "eventTime" */
1047 r = lydxml_envelope(xmlctx, "eventTime", "urn:ietf:params:xml:ns:netconf:notification:1.0", 1, &child);
1048 if (r == LY_ENOT) {
Radek Krejci422afb12021-03-04 16:38:16 +01001049 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unexpected element \"%.*s\" instead of \"eventTime\".",
1050 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001051 r = LY_EVALID;
1052 }
1053 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1054
1055 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001056 lyd_insert_node(*envp, NULL, child, 0);
Michal Vaskoe0665742021-02-11 11:08:44 +01001057
1058 /* validate value */
1059 /* TODO validate child->value as yang:date-and-time */
1060
1061 /* finish child parsing */
Michal Vaskoa8edff02020-03-27 14:47:01 +01001062 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1063 assert(xmlctx->status == LYXML_ELEMENT);
Michal Vaskoe0665742021-02-11 11:08:44 +01001064 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"eventTime\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001065 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001066 rc = LY_EVALID;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001067 goto cleanup;
1068 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001069 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1070
1071 /* NETCONF notification */
1072 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_NOTIF;
1073 *close_elem = 1;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001074
1075cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +01001076 if (rc) {
Michal Vaskoa8edff02020-03-27 14:47:01 +01001077 lyd_free_tree(*envp);
Michal Vaskoe0665742021-02-11 11:08:44 +01001078 *envp = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001079 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001080 return rc;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001081}
Michal Vasko79135ae2020-12-16 10:08:35 +01001082
Michal Vaskoe0665742021-02-11 11:08:44 +01001083/**
1084 * @brief Parse an XML element as an opaque node subtree.
1085 *
1086 * @param[in] xmlctx XML parser context.
1087 * @param[in] parent Parent to append nodes to.
1088 * @return LY_ERR value.
1089 */
1090static LY_ERR
1091lydxml_opaq_r(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
Michal Vaskoa8edff02020-03-27 14:47:01 +01001092{
Michal Vaskoe0665742021-02-11 11:08:44 +01001093 LY_ERR rc = LY_SUCCESS;
1094 const struct lyxml_ns *ns;
1095 struct lyd_attr *attr = NULL;
1096 struct lyd_node *child = NULL;
1097 const char *name, *prefix;
1098 size_t name_len, prefix_len;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001099
Michal Vaskoe0665742021-02-11 11:08:44 +01001100 assert(xmlctx->status == LYXML_ELEMENT);
Michal Vaskoa8edff02020-03-27 14:47:01 +01001101
Michal Vaskoe0665742021-02-11 11:08:44 +01001102 name = xmlctx->name;
1103 name_len = xmlctx->name_len;
1104 prefix = xmlctx->prefix;
1105 prefix_len = xmlctx->prefix_len;
1106 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
1107 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +01001108 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)prefix_len, prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +01001109 return LY_EVALID;
1110 }
Michal Vaskoa8edff02020-03-27 14:47:01 +01001111
Michal Vaskoe0665742021-02-11 11:08:44 +01001112 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
Michal Vaskoa8edff02020-03-27 14:47:01 +01001113
Michal Vaskoe0665742021-02-11 11:08:44 +01001114 /* create attributes */
1115 if (xmlctx->status == LYXML_ATTRIBUTE) {
1116 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
1117 }
1118
1119 /* create node */
1120 assert(xmlctx->status == LYXML_ELEM_CONTENT);
1121 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 +02001122 xmlctx->ws_only ? 0 : xmlctx->value_len, NULL, LY_VALUE_XML, NULL, 0, &child);
Michal Vaskoe0665742021-02-11 11:08:44 +01001123 LY_CHECK_GOTO(rc, cleanup);
1124
1125 /* assign atributes */
1126 ((struct lyd_node_opaq *)child)->attr = attr;
1127 attr = NULL;
1128
1129 /* parser next element */
1130 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1131
1132 /* parse all the descendants */
1133 while (xmlctx->status == LYXML_ELEMENT) {
1134 rc = lydxml_opaq_r(xmlctx, child);
1135 LY_CHECK_GOTO(rc, cleanup);
1136 }
1137
1138 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001139 lyd_insert_node(parent, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +01001140
1141cleanup:
1142 lyd_free_attr_siblings(xmlctx->ctx, attr);
1143 if (rc) {
1144 lyd_free_tree(child);
1145 }
1146 return rc;
1147}
1148
1149/**
1150 * @brief Parse all expected non-data XML elements of the error-info element in NETCONF rpc-reply message.
1151 *
1152 * @param[in] xmlctx XML parser context.
1153 * @param[in] parent Parent to append nodes to.
1154 * @return LY_ERR value.
1155 */
1156static LY_ERR
1157lydxml_env_netconf_rpc_reply_error_info(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
1158{
1159 LY_ERR r;
1160 struct lyd_node *child, *iter;
1161 const struct lyxml_ns *ns;
1162 ly_bool no_dup;
1163
1164 /* there must be some child */
1165 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1166 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"error-info\".");
1167 return LY_EVALID;
1168 }
1169
1170 while (xmlctx->status == LYXML_ELEMENT) {
1171 child = NULL;
1172
1173 /*
1174 * session-id
1175 */
1176 r = lydxml_envelope(xmlctx, "session-id", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1177 if (r == LY_SUCCESS) {
1178 no_dup = 1;
1179 goto check_child;
1180 } else if (r != LY_ENOT) {
1181 goto error;
1182 }
1183
1184 /*
1185 * bad-attribute
1186 */
1187 r = lydxml_envelope(xmlctx, "bad-attribute", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1188 if (r == LY_SUCCESS) {
1189 no_dup = 1;
1190 goto check_child;
1191 } else if (r != LY_ENOT) {
1192 goto error;
1193 }
1194
1195 /*
1196 * bad-element
1197 */
1198 r = lydxml_envelope(xmlctx, "bad-element", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1199 if (r == LY_SUCCESS) {
1200 no_dup = 1;
1201 goto check_child;
1202 } else if (r != LY_ENOT) {
1203 goto error;
1204 }
1205
1206 /*
1207 * bad-namespace
1208 */
1209 r = lydxml_envelope(xmlctx, "bad-namespace", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1210 if (r == LY_SUCCESS) {
1211 no_dup = 1;
1212 goto check_child;
1213 } else if (r != LY_ENOT) {
1214 goto error;
1215 }
1216
1217 if (r == LY_ENOT) {
1218 assert(xmlctx->status == LYXML_ELEMENT);
1219
1220 /* learn namespace */
1221 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
1222 if (!ns) {
Radek Krejci422afb12021-03-04 16:38:16 +01001223 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", (int)xmlctx->prefix_len, xmlctx->prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +01001224 r = LY_EVALID;
1225 goto error;
1226 } else if (!strcmp(ns->uri, "urn:ietf:params:xml:ns:netconf:base:1.0")) {
1227 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"error-info\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001228 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001229 r = LY_EVALID;
1230 goto error;
1231 }
1232
1233 /* custom elements */
1234 r = lydxml_opaq_r(xmlctx, parent);
1235 LY_CHECK_GOTO(r, error);
Michal Vasko6398eaf2022-01-10 10:12:30 +01001236 continue;
Michal Vaskoe0665742021-02-11 11:08:44 +01001237 }
1238
1239check_child:
1240 /* check for duplicates */
1241 if (no_dup) {
1242 LY_LIST_FOR(lyd_child(parent), iter) {
1243 if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
1244 (((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
1245 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"error-info\".",
1246 ((struct lyd_node_opaq *)child)->name.name);
1247 r = LY_EVALID;
1248 goto error;
1249 }
1250 }
1251 }
1252
1253 /* finish child parsing */
1254 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1255 assert(xmlctx->status == LYXML_ELEMENT);
1256 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"error-info\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001257 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001258 r = LY_EVALID;
1259 goto error;
1260 }
1261 LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
1262
1263 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001264 lyd_insert_node(parent, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +01001265 }
1266
1267 return LY_SUCCESS;
1268
1269error:
1270 lyd_free_tree(child);
1271 return r;
1272}
1273
1274/**
1275 * @brief Parse all expected non-data XML elements of the rpc-error element in NETCONF rpc-reply message.
1276 *
1277 * @param[in] xmlctx XML parser context.
1278 * @param[in] parent Parent to append nodes to.
1279 * @return LY_ERR value.
1280 */
1281static LY_ERR
1282lydxml_env_netconf_rpc_reply_error(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
1283{
1284 LY_ERR r;
1285 struct lyd_node *child, *iter;
1286 const char *val;
1287 ly_bool no_dup;
1288
1289 /* there must be some child */
1290 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1291 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"rpc-error\".");
1292 return LY_EVALID;
1293 }
1294
1295 while (xmlctx->status == LYXML_ELEMENT) {
1296 child = NULL;
1297
1298 /*
1299 * error-type
1300 */
1301 r = lydxml_envelope(xmlctx, "error-type", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1302 if (r == LY_SUCCESS) {
1303 val = ((struct lyd_node_opaq *)child)->value;
1304 if (strcmp(val, "transport") && strcmp(val, "rpc") && strcmp(val, "protocol") && strcmp(val, "application")) {
1305 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1306 ((struct lyd_node_opaq *)child)->name.name);
1307 r = LY_EVALID;
1308 goto error;
1309 }
1310
1311 no_dup = 1;
1312 goto check_child;
1313 } else if (r != LY_ENOT) {
1314 goto error;
1315 }
1316
1317 /*
1318 * error-tag
1319 */
1320 r = lydxml_envelope(xmlctx, "error-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1321 if (r == LY_SUCCESS) {
1322 val = ((struct lyd_node_opaq *)child)->value;
1323 if (strcmp(val, "in-use") && strcmp(val, "invalid-value") && strcmp(val, "too-big") &&
1324 strcmp(val, "missing-attribute") && strcmp(val, "bad-attribute") &&
1325 strcmp(val, "unknown-attribute") && strcmp(val, "missing-element") && strcmp(val, "bad-element") &&
1326 strcmp(val, "unknown-element") && strcmp(val, "unknown-namespace") && strcmp(val, "access-denied") &&
1327 strcmp(val, "lock-denied") && strcmp(val, "resource-denied") && strcmp(val, "rollback-failed") &&
1328 strcmp(val, "data-exists") && strcmp(val, "data-missing") && strcmp(val, "operation-not-supported") &&
1329 strcmp(val, "operation-failed") && strcmp(val, "malformed-message")) {
1330 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1331 ((struct lyd_node_opaq *)child)->name.name);
1332 r = LY_EVALID;
1333 goto error;
1334 }
1335
1336 no_dup = 1;
1337 goto check_child;
1338 } else if (r != LY_ENOT) {
1339 goto error;
1340 }
1341
1342 /*
1343 * error-severity
1344 */
1345 r = lydxml_envelope(xmlctx, "error-severity", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1346 if (r == LY_SUCCESS) {
1347 val = ((struct lyd_node_opaq *)child)->value;
1348 if (strcmp(val, "error") && strcmp(val, "warning")) {
1349 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1350 ((struct lyd_node_opaq *)child)->name.name);
1351 r = LY_EVALID;
1352 goto error;
1353 }
1354
1355 no_dup = 1;
1356 goto check_child;
1357 } else if (r != LY_ENOT) {
1358 goto error;
1359 }
1360
1361 /*
1362 * error-app-tag
1363 */
1364 r = lydxml_envelope(xmlctx, "error-app-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1365 if (r == LY_SUCCESS) {
1366 no_dup = 1;
1367 goto check_child;
1368 } else if (r != LY_ENOT) {
1369 goto error;
1370 }
1371
1372 /*
1373 * error-path
1374 */
1375 r = lydxml_envelope(xmlctx, "error-path", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1376 if (r == LY_SUCCESS) {
1377 no_dup = 1;
1378 goto check_child;
1379 } else if (r != LY_ENOT) {
1380 goto error;
1381 }
1382
1383 /*
1384 * error-message
1385 */
1386 r = lydxml_envelope(xmlctx, "error-message", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1387 if (r == LY_SUCCESS) {
1388 no_dup = 1;
1389 goto check_child;
1390 } else if (r != LY_ENOT) {
1391 goto error;
1392 }
1393
1394 /* error-info */
1395 r = lydxml_envelope(xmlctx, "error-info", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1396 if (r == LY_SUCCESS) {
1397 /* parse all the descendants */
1398 LY_CHECK_GOTO(r = lydxml_env_netconf_rpc_reply_error_info(xmlctx, child), error);
1399
1400 no_dup = 0;
1401 goto check_child;
1402 } else if (r != LY_ENOT) {
1403 goto error;
1404 }
1405
1406 if (r == LY_ENOT) {
1407 assert(xmlctx->status == LYXML_ELEMENT);
1408 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001409 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001410 r = LY_EVALID;
1411 goto error;
1412 }
1413
1414check_child:
1415 /* check for duplicates */
1416 if (no_dup) {
1417 LY_LIST_FOR(lyd_child(parent), iter) {
1418 if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
1419 (((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
1420 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"rpc-error\".",
1421 ((struct lyd_node_opaq *)child)->name.name);
1422 r = LY_EVALID;
1423 goto error;
1424 }
1425 }
1426 }
1427
1428 /* finish child parsing */
1429 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1430 assert(xmlctx->status == LYXML_ELEMENT);
1431 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001432 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001433 r = LY_EVALID;
1434 goto error;
1435 }
1436 LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
1437
1438 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001439 lyd_insert_node(parent, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +01001440 }
1441
1442 return LY_SUCCESS;
1443
1444error:
1445 lyd_free_tree(child);
1446 return r;
1447}
1448
1449/**
1450 * @brief Parse all expected non-data XML elements of a NETCONF rpc-reply message.
1451 *
1452 * @param[in] xmlctx XML parser context.
1453 * @param[out] evnp Parsed envelope(s) (opaque node).
1454 * @param[out] int_opts Internal options for parsing the rest of YANG data.
1455 * @param[out] close_elem Number of parsed opened elements that need to be closed.
1456 * @return LY_SUCCESS on success.
1457 * @return LY_ERR value on error.
1458 */
1459static LY_ERR
1460lydxml_env_netconf_reply(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
1461{
1462 LY_ERR rc = LY_SUCCESS, r;
1463 struct lyd_node *child = NULL;
1464 const char *parsed_elem = NULL;
1465
1466 assert(envp && !*envp);
1467
Michal Vasko50375272022-04-26 12:07:46 +02001468 if (xmlctx->status != LYXML_ELEMENT) {
1469 /* nothing to parse */
1470 assert(xmlctx->status == LYXML_END);
1471 goto cleanup;
1472 }
1473
Michal Vaskoe0665742021-02-11 11:08:44 +01001474 /* parse "rpc-reply" */
1475 r = lydxml_envelope(xmlctx, "rpc-reply", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, envp);
Michal Vaskoe0665742021-02-11 11:08:44 +01001476 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1477
1478 /* there must be some child */
1479 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1480 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"rpc-reply\".");
1481 rc = LY_EVALID;
Michal Vaskocf770e22020-08-12 13:21:43 +02001482 goto cleanup;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001483 }
1484
Michal Vaskoe0665742021-02-11 11:08:44 +01001485 /* try to parse "ok" */
1486 r = lydxml_envelope(xmlctx, "ok", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1487 if (r == LY_SUCCESS) {
1488 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001489 lyd_insert_node(*envp, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +01001490
1491 /* finish child parsing */
1492 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1493 assert(xmlctx->status == LYXML_ELEMENT);
1494 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"ok\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001495 (int)xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001496 rc = LY_EVALID;
1497 goto cleanup;
1498 }
1499 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1500
1501 /* success */
1502 parsed_elem = "ok";
1503 goto finish;
1504 } else if (r != LY_ENOT) {
1505 rc = r;
1506 goto cleanup;
Michal Vasko2552ea32020-12-08 15:32:34 +01001507 }
1508
Michal Vaskoe0665742021-02-11 11:08:44 +01001509 /* try to parse all "rpc-error" elements */
1510 while (xmlctx->status == LYXML_ELEMENT) {
1511 r = lydxml_envelope(xmlctx, "rpc-error", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1512 if (r == LY_ENOT) {
1513 break;
1514 } else if (r) {
1515 rc = r;
1516 goto cleanup;
1517 }
1518
1519 /* insert */
Michal Vasko6ee6f432021-07-16 09:49:14 +02001520 lyd_insert_node(*envp, NULL, child, 1);
Michal Vaskoe0665742021-02-11 11:08:44 +01001521
1522 /* parse all children of "rpc-error" */
1523 LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc_reply_error(xmlctx, child), cleanup);
1524
1525 /* finish child parsing */
1526 assert(xmlctx->status == LYXML_ELEM_CLOSE);
1527 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1528
1529 parsed_elem = "rpc-error";
Michal Vasko2552ea32020-12-08 15:32:34 +01001530 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001531
1532finish:
1533 if (parsed_elem) {
1534 /* NETCONF rpc-reply with no data */
1535 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1536 assert(xmlctx->status == LYXML_ELEMENT);
1537 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"%s\".",
Radek Krejci422afb12021-03-04 16:38:16 +01001538 (int)xmlctx->name_len, xmlctx->name, parsed_elem);
Michal Vaskoe0665742021-02-11 11:08:44 +01001539 rc = LY_EVALID;
1540 goto cleanup;
1541 }
1542 }
1543
1544 /* NETCONF rpc-reply */
Michal Vasko1d991fd2021-07-09 13:14:40 +02001545 *int_opts = LYD_INTOPT_WITH_SIBLINGS | LYD_INTOPT_REPLY;
Michal Vaskoe0665742021-02-11 11:08:44 +01001546 *close_elem = 1;
1547
1548cleanup:
1549 if (rc) {
1550 lyd_free_tree(*envp);
1551 *envp = NULL;
1552 }
1553 return rc;
1554}
1555
Michal Vasko2552ea32020-12-08 15:32:34 +01001556LY_ERR
Radek Krejcif16e2542021-02-17 15:39:23 +01001557lyd_parse_xml(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
1558 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 +01001559 struct lyd_node **envp, struct ly_set *parsed, ly_bool *subtree_sibling, struct lyd_ctx **lydctx_p)
Michal Vasko2552ea32020-12-08 15:32:34 +01001560{
Michal Vaskoe0665742021-02-11 11:08:44 +01001561 LY_ERR rc = LY_SUCCESS;
1562 struct lyd_xml_ctx *lydctx;
Michal Vasko2ca9f9e2021-07-02 09:21:36 +02001563 uint32_t i, int_opts = 0, close_elem = 0;
Michal Vaskoe0665742021-02-11 11:08:44 +01001564 ly_bool parsed_data_nodes = 0;
Michal Vaskoddd76592022-01-17 13:34:48 +01001565 enum LYXML_PARSER_STATUS status;
Michal Vasko2552ea32020-12-08 15:32:34 +01001566
Michal Vaskoe0665742021-02-11 11:08:44 +01001567 assert(ctx && in && lydctx_p);
1568 assert(!(parse_opts & ~LYD_PARSE_OPTS_MASK));
1569 assert(!(val_opts & ~LYD_VALIDATE_OPTS_MASK));
Michal Vasko2552ea32020-12-08 15:32:34 +01001570
Michal Vaskoe0665742021-02-11 11:08:44 +01001571 /* init context */
1572 lydctx = calloc(1, sizeof *lydctx);
1573 LY_CHECK_ERR_RET(!lydctx, LOGMEM(ctx), LY_EMEM);
1574 LY_CHECK_GOTO(rc = lyxml_ctx_new(ctx, in, &lydctx->xmlctx), cleanup);
1575 lydctx->parse_opts = parse_opts;
1576 lydctx->val_opts = val_opts;
1577 lydctx->free = lyd_xml_ctx_free;
Radek Krejcif16e2542021-02-17 15:39:23 +01001578 lydctx->ext = ext;
Michal Vasko2552ea32020-12-08 15:32:34 +01001579
Michal Vaskoe0665742021-02-11 11:08:44 +01001580 switch (data_type) {
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001581 case LYD_TYPE_DATA_YANG:
Michal Vaskoddd76592022-01-17 13:34:48 +01001582 if (!(parse_opts & LYD_PARSE_SUBTREE)) {
1583 int_opts = LYD_INTOPT_WITH_SIBLINGS;
1584 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001585 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001586 case LYD_TYPE_RPC_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001587 int_opts = LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NO_SIBLINGS;
1588 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001589 case LYD_TYPE_NOTIF_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001590 int_opts = LYD_INTOPT_NOTIF | LYD_INTOPT_NO_SIBLINGS;
1591 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001592 case LYD_TYPE_REPLY_YANG:
Michal Vaskoe0665742021-02-11 11:08:44 +01001593 int_opts = LYD_INTOPT_REPLY | LYD_INTOPT_NO_SIBLINGS;
1594 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001595 case LYD_TYPE_RPC_NETCONF:
Michal Vaskoe0665742021-02-11 11:08:44 +01001596 assert(!parent);
1597 LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
1598 break;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001599 case LYD_TYPE_NOTIF_NETCONF:
1600 assert(!parent);
1601 LY_CHECK_GOTO(rc = lydxml_env_netconf_notif(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
1602 break;
1603 case LYD_TYPE_REPLY_NETCONF:
Michal Vaskoe0665742021-02-11 11:08:44 +01001604 assert(parent);
Michal Vasko1e4c68e2021-02-18 15:03:01 +01001605 LY_CHECK_GOTO(rc = lydxml_env_netconf_reply(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
Michal Vaskoe0665742021-02-11 11:08:44 +01001606 break;
1607 }
1608 lydctx->int_opts = int_opts;
1609
1610 /* find the operation node if it exists already */
1611 LY_CHECK_GOTO(rc = lyd_parser_find_operation(parent, int_opts, &lydctx->op_node), cleanup);
1612
1613 /* parse XML data */
1614 while (lydctx->xmlctx->status == LYXML_ELEMENT) {
1615 LY_CHECK_GOTO(rc = lydxml_subtree_r(lydctx, parent, first_p, parsed), cleanup);
1616 parsed_data_nodes = 1;
1617
1618 if (!(int_opts & LYD_INTOPT_WITH_SIBLINGS)) {
1619 break;
1620 }
Michal Vasko2552ea32020-12-08 15:32:34 +01001621 }
1622
Michal Vaskoe0665742021-02-11 11:08:44 +01001623 /* close all opened elements */
1624 for (i = 0; i < close_elem; ++i) {
1625 if (lydctx->xmlctx->status != LYXML_ELEM_CLOSE) {
1626 assert(lydctx->xmlctx->status == LYXML_ELEMENT);
Radek Krejci422afb12021-03-04 16:38:16 +01001627 LOGVAL(lydctx->xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\".",
1628 (int)lydctx->xmlctx->name_len, lydctx->xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +01001629 rc = LY_EVALID;
1630 goto cleanup;
1631 }
1632
1633 LY_CHECK_GOTO(rc = lyxml_ctx_next(lydctx->xmlctx), cleanup);
Michal Vasko4189c0f2020-08-13 09:05:22 +02001634 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001635
1636 /* check final state */
1637 if ((int_opts & LYD_INTOPT_NO_SIBLINGS) && (lydctx->xmlctx->status == LYXML_ELEMENT)) {
1638 LOGVAL(ctx, LYVE_SYNTAX, "Unexpected sibling node.");
1639 rc = LY_EVALID;
1640 goto cleanup;
1641 }
Michal Vaskoc939fdd2022-01-03 11:35:13 +01001642 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 +01001643 LOGVAL(ctx, LYVE_DATA, "Missing the operation node.");
1644 rc = LY_EVALID;
1645 goto cleanup;
1646 }
1647
1648 if (!parsed_data_nodes) {
1649 /* no data nodes were parsed */
1650 lydctx->op_node = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001651 }
1652
Michal Vaskoddd76592022-01-17 13:34:48 +01001653 if (parse_opts & LYD_PARSE_SUBTREE) {
1654 /* check for a sibling element */
1655 assert(subtree_sibling);
1656 if (!lyxml_ctx_peek(lydctx->xmlctx, &status) && (status == LYXML_ELEMENT)) {
1657 *subtree_sibling = 1;
1658 } else {
1659 *subtree_sibling = 0;
1660 }
1661 }
1662
Michal Vaskoa8edff02020-03-27 14:47:01 +01001663cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +01001664 /* there should be no unres stored if validation should be skipped */
1665 assert(!(parse_opts & LYD_PARSE_ONLY) || (!lydctx->node_types.count && !lydctx->meta_types.count &&
Michal Vaskoddd76592022-01-17 13:34:48 +01001666 !lydctx->node_when.count));
Michal Vaskoe0665742021-02-11 11:08:44 +01001667
1668 if (rc) {
1669 lyd_xml_ctx_free((struct lyd_ctx *)lydctx);
1670 } else {
1671 *lydctx_p = (struct lyd_ctx *)lydctx;
1672
1673 /* the XML context is no more needed, freeing it also stops logging line numbers which would be confusing now */
1674 lyxml_ctx_free(lydctx->xmlctx);
1675 lydctx->xmlctx = NULL;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001676 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001677 return rc;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001678}