blob: 792d377d309581100d716240cf6eeb229a301e22 [file] [log] [blame]
Radek Krejcie7b95092019-05-15 11:03:07 +02001/**
2 * @file parser_xml.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief XML data parser for libyang
5 *
6 * Copyright (c) 2019 CESNET, z.s.p.o.
7 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
14
15#include "common.h"
16
17#include <stdint.h>
18#include <stdlib.h>
19#include <string.h>
Michal Vasko9b368d32020-02-14 13:53:31 +010020#include <assert.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020021
22#include "context.h"
23#include "dict.h"
24#include "log.h"
25#include "plugins_types.h"
26#include "set.h"
27#include "tree_data.h"
28#include "tree_data_internal.h"
29#include "tree_schema.h"
30#include "xml.h"
Michal Vaskocde73ac2019-11-14 16:10:27 +010031#include "validation.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020032
33/**
Michal Vaskob36053d2020-03-26 15:49:30 +010034 * @brief Internal context for XML YANG data parser.
Radek Krejcie7b95092019-05-15 11:03:07 +020035 */
36struct lyd_xml_ctx {
Michal Vaskob36053d2020-03-26 15:49:30 +010037 struct lyxml_ctx *xmlctx; /**< XML context */
Radek Krejcie7b95092019-05-15 11:03:07 +020038
Michal Vasko52927e22020-03-16 17:26:14 +010039 uint32_t options; /**< various @ref dataparseroptions. */
40 uint32_t path_len; /**< used bytes in the path buffer */
Radek Krejcie7b95092019-05-15 11:03:07 +020041#define LYD_PARSER_BUFSIZE 4078
42 char path[LYD_PARSER_BUFSIZE]; /**< buffer for the generated path */
Michal Vasko52927e22020-03-16 17:26:14 +010043 struct ly_set unres_node_type; /**< set of nodes validated with LY_EINCOMPLETE result */
44 struct ly_set unres_meta_type; /**< set of metadata validated with LY_EINCOMPLETE result */
Michal Vaskoecd62de2019-11-13 12:35:11 +010045 struct ly_set when_check; /**< set of nodes with "when" conditions */
Radek Krejcie7b95092019-05-15 11:03:07 +020046};
47
48/**
Michal Vaskob36053d2020-03-26 15:49:30 +010049 * @brief XML-parser's implementation of ly_type_resolve_prefix() callback to provide mapping between prefixes used
50 * in the values to the schema via XML namespaces.
Radek Krejciaca74032019-06-04 08:53:06 +020051 */
52static const struct lys_module *
Michal Vasko52927e22020-03-16 17:26:14 +010053lydxml_resolve_prefix(const struct ly_ctx *ctx, const char *prefix, size_t prefix_len, void *parser)
Radek Krejciaca74032019-06-04 08:53:06 +020054{
55 const struct lyxml_ns *ns;
Michal Vaskob36053d2020-03-26 15:49:30 +010056 struct lyxml_ctx *xmlctx = (struct lyxml_ctx *)parser;
Radek Krejciaca74032019-06-04 08:53:06 +020057
58 ns = lyxml_ns_get(xmlctx, prefix, prefix_len);
59 if (!ns) {
60 return NULL;
61 }
62
63 return ly_ctx_get_module_implemented_ns(ctx, ns->uri);
64}
65
Radek Krejcie7b95092019-05-15 11:03:07 +020066static LY_ERR
Michal Vaskob36053d2020-03-26 15:49:30 +010067lydxml_metadata(struct lyxml_ctx *xmlctx, const struct lysc_node *sparent, int strict, struct ly_set *type_meta_check,
68 struct lyd_meta **meta)
Radek Krejcie7b95092019-05-15 11:03:07 +020069{
Michal Vaskob36053d2020-03-26 15:49:30 +010070 LY_ERR ret = LY_EVALID;
Radek Krejci28681fa2019-09-06 13:08:45 +020071 const struct lyxml_ns *ns;
72 struct lys_module *mod;
Michal Vaskob36053d2020-03-26 15:49:30 +010073 const char *name;
74 size_t name_len;
Radek Krejci28681fa2019-09-06 13:08:45 +020075
Michal Vaskob36053d2020-03-26 15:49:30 +010076 *meta = NULL;
Radek Krejci28681fa2019-09-06 13:08:45 +020077
Michal Vaskob36053d2020-03-26 15:49:30 +010078 while (xmlctx->status == LYXML_ATTRIBUTE) {
79 if (!xmlctx->prefix_len) {
Radek Krejci28681fa2019-09-06 13:08:45 +020080 /* in XML, all attributes must be prefixed
81 * TODO exception for NETCONF filters which are supposed to map to the ietf-netconf without prefix */
Michal Vasko52927e22020-03-16 17:26:14 +010082 if (strict) {
83 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Missing mandatory prefix for XML metadata \"%.*s\".",
Michal Vaskob36053d2020-03-26 15:49:30 +010084 xmlctx->name_len, xmlctx->name);
85 goto cleanup;
Radek Krejci28681fa2019-09-06 13:08:45 +020086 }
Michal Vaskob36053d2020-03-26 15:49:30 +010087
Radek Krejci28681fa2019-09-06 13:08:45 +020088skip_attr:
Michal Vaskob36053d2020-03-26 15:49:30 +010089 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
90 assert(xmlctx->status == LYXML_ATTR_CONTENT);
91 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejci28681fa2019-09-06 13:08:45 +020092 continue;
93 }
94
95 /* get namespace of the attribute to find its annotation definition */
Michal Vaskob36053d2020-03-26 15:49:30 +010096 ns = lyxml_ns_get(xmlctx, xmlctx->prefix, xmlctx->prefix_len);
Radek Krejci28681fa2019-09-06 13:08:45 +020097 if (!ns) {
Michal Vasko52927e22020-03-16 17:26:14 +010098 /* unknown namespace, XML error */
99 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
Michal Vaskob36053d2020-03-26 15:49:30 +0100100 xmlctx->prefix_len, xmlctx->prefix);
Radek Krejci28681fa2019-09-06 13:08:45 +0200101 goto cleanup;
102 }
Michal Vasko52927e22020-03-16 17:26:14 +0100103 mod = ly_ctx_get_module_implemented_ns(xmlctx->ctx, ns->uri);
Radek Krejci28681fa2019-09-06 13:08:45 +0200104 if (!mod) {
105 /* module is not implemented or not present in the schema */
Michal Vasko52927e22020-03-16 17:26:14 +0100106 if (strict) {
107 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE,
Michal Vasko9f96a052020-03-10 09:41:45 +0100108 "Unknown (or not implemented) YANG module with namespace \"%s\" for metadata \"%.*s%s%.*s\".",
Michal Vaskob36053d2020-03-26 15:49:30 +0100109 ns->uri, xmlctx->prefix_len, xmlctx->prefix, xmlctx->prefix_len ? ":" : "", xmlctx->name_len,
110 xmlctx->name);
111 goto cleanup;
Radek Krejci28681fa2019-09-06 13:08:45 +0200112 }
113 goto skip_attr;
114 }
115
Michal Vaskob36053d2020-03-26 15:49:30 +0100116 /* remember attr name and get its content */
117 name = xmlctx->name;
118 name_len = xmlctx->name_len;
119 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
120 assert(xmlctx->status == LYXML_ATTR_CONTENT);
121
122 /* create metadata */
123 ret = lyd_create_meta(NULL, meta, mod, name, name_len, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic,
124 lydxml_resolve_prefix, xmlctx, LYD_XML, sparent);
125 if (ret == LY_EINCOMPLETE) {
Michal Vasko52927e22020-03-16 17:26:14 +0100126 if (type_meta_check) {
127 ly_set_add(type_meta_check, meta, LY_SET_OPT_USEASLIST);
128 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100129 } else if (ret) {
Radek Krejci28681fa2019-09-06 13:08:45 +0200130 goto cleanup;
131 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100132
133 /* next attribute */
134 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200135 }
Michal Vasko52927e22020-03-16 17:26:14 +0100136
Radek Krejci28681fa2019-09-06 13:08:45 +0200137 ret = LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200138
139cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100140 if (ret) {
141 lyd_free_meta(xmlctx->ctx, *meta, 1);
142 *meta = NULL;
Radek Krejci38d85362019-09-05 16:26:38 +0200143 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200144 return ret;
145}
146
Michal Vasko52927e22020-03-16 17:26:14 +0100147static LY_ERR
Michal Vaskob36053d2020-03-26 15:49:30 +0100148lydxml_attrs(struct lyxml_ctx *xmlctx, struct ly_attr **attr)
Michal Vasko52927e22020-03-16 17:26:14 +0100149{
150 LY_ERR ret = LY_SUCCESS;
151 const struct lyxml_ns *ns;
152 struct ly_prefix *val_prefs;
153 struct ly_attr *attr2;
Michal Vaskob36053d2020-03-26 15:49:30 +0100154 const char *name, *prefix;
155 size_t name_len, prefix_len;
Michal Vasko52927e22020-03-16 17:26:14 +0100156
157 assert(attr);
Michal Vaskob36053d2020-03-26 15:49:30 +0100158 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100159
Michal Vaskob36053d2020-03-26 15:49:30 +0100160 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vasko52927e22020-03-16 17:26:14 +0100161 ns = NULL;
Michal Vaskob36053d2020-03-26 15:49:30 +0100162 if (xmlctx->prefix_len) {
Michal Vasko52927e22020-03-16 17:26:14 +0100163 /* get namespace of the attribute */
Michal Vaskob36053d2020-03-26 15:49:30 +0100164 ns = lyxml_ns_get(xmlctx, xmlctx->prefix, xmlctx->prefix_len);
Michal Vasko52927e22020-03-16 17:26:14 +0100165 if (!ns) {
166 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
Michal Vaskob36053d2020-03-26 15:49:30 +0100167 xmlctx->prefix_len, xmlctx->prefix);
Michal Vasko52927e22020-03-16 17:26:14 +0100168 ret = LY_EVALID;
169 goto cleanup;
170 }
171 }
172
173 if (*attr) {
174 attr2 = *attr;
175 } else {
176 attr2 = NULL;
177 }
178
Michal Vaskob36053d2020-03-26 15:49:30 +0100179 /* remember attr prefix, name, and get its content */
180 prefix = xmlctx->prefix;
181 prefix_len = xmlctx->prefix_len;
182 name = xmlctx->name;
183 name_len = xmlctx->name_len;
184 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
185 assert(xmlctx->status == LYXML_ATTR_CONTENT);
186
Michal Vasko52927e22020-03-16 17:26:14 +0100187 /* get value prefixes */
Michal Vaskob36053d2020-03-26 15:49:30 +0100188 LY_CHECK_GOTO(ret = lyxml_get_prefixes(xmlctx, xmlctx->value, xmlctx->value_len, &val_prefs), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100189
190 /* attr2 is always changed to the created attribute */
Michal Vaskob36053d2020-03-26 15:49:30 +0100191 ret = ly_create_attr(NULL, &attr2, xmlctx->ctx, name, name_len, xmlctx->value, xmlctx->value_len,
192 &xmlctx->dynamic, LYD_XML, val_prefs, prefix, prefix_len, ns ? ns->uri : NULL);
Michal Vasko52927e22020-03-16 17:26:14 +0100193 LY_CHECK_GOTO(ret, cleanup);
194
195 if (!*attr) {
196 *attr = attr2;
197 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100198
199 /* next attribute */
200 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100201 }
202
203cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100204 if (ret) {
205 ly_free_attr(xmlctx->ctx, *attr, 1);
206 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100207 }
Michal Vasko52927e22020-03-16 17:26:14 +0100208 return ret;
209}
210
Michal Vasko44685da2020-03-17 15:38:06 +0100211static LY_ERR
Michal Vaskob36053d2020-03-26 15:49:30 +0100212lydxml_check_list(struct lyxml_ctx *xmlctx, const struct lysc_node *list)
Michal Vasko44685da2020-03-17 15:38:06 +0100213{
Michal Vaskob36053d2020-03-26 15:49:30 +0100214 LY_ERR ret = LY_SUCCESS, r;
215 enum LYXML_PARSER_STATUS next;
Michal Vasko44685da2020-03-17 15:38:06 +0100216 struct ly_set key_set = {0};
217 const struct lysc_node *snode;
Michal Vaskob36053d2020-03-26 15:49:30 +0100218 uint32_t i, parents_count;
Michal Vasko44685da2020-03-17 15:38:06 +0100219
220 assert(list && (list->nodetype == LYS_LIST));
221
222 /* get all keys into a set (keys do not have if-features or anything) */
223 snode = NULL;
224 while ((snode = lys_getnext(snode, list, NULL, LYS_GETNEXT_NOSTATECHECK)) && (snode->flags & LYS_KEY)) {
225 ly_set_add(&key_set, (void *)snode, LY_SET_OPT_USEASLIST);
226 }
227
Michal Vaskob36053d2020-03-26 15:49:30 +0100228 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vasko44685da2020-03-17 15:38:06 +0100229 /* find key definition */
230 for (i = 0; i < key_set.count; ++i) {
231 snode = (const struct lysc_node *)key_set.objs[i];
Michal Vaskob36053d2020-03-26 15:49:30 +0100232 if (!ly_strncmp(snode->name, xmlctx->name, xmlctx->name_len)) {
Michal Vasko44685da2020-03-17 15:38:06 +0100233 break;
234 }
235 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100236 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100237
238 /* skip attributes */
239 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100240 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
241 assert(xmlctx->status == LYXML_ATTR_CONTENT);
242 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100243 }
244
Michal Vaskob36053d2020-03-26 15:49:30 +0100245 assert(xmlctx->status == LYXML_ELEM_CONTENT);
246 if (i < key_set.count) {
247 /* validate the value */
248 r = lys_value_validate(NULL, snode, xmlctx->value, xmlctx->value_len, lydxml_resolve_prefix, xmlctx, LYD_XML);
249 if (!r) {
250 /* key with a valid value, remove from the set */
251 ly_set_rm_index(&key_set, i, NULL);
Michal Vasko44685da2020-03-17 15:38:06 +0100252 }
253 }
254
Michal Vaskob36053d2020-03-26 15:49:30 +0100255 /* parser next */
256 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100257
Michal Vaskob36053d2020-03-26 15:49:30 +0100258 /* skip any children, resursively */
259 parents_count = xmlctx->elements.count;
260 while ((parents_count < xmlctx->elements.count) || (xmlctx->status == LYXML_ELEMENT)) {
261 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
262 }
263
264 /* parser next, but do not parse closing element of the list because it would remove its namespaces */
265 assert(xmlctx->status == LYXML_ELEM_CLOSE);
266 LY_CHECK_GOTO(ret = lyxml_ctx_peek(xmlctx, &next), cleanup);
267 if (next != LYXML_ELEM_CLOSE) {
268 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
269 }
Michal Vasko44685da2020-03-17 15:38:06 +0100270 }
271
272 if (key_set.count) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100273 /* some keys are missing/did not validate */
Michal Vasko44685da2020-03-17 15:38:06 +0100274 ret = LY_ENOT;
Michal Vasko44685da2020-03-17 15:38:06 +0100275 }
276
277cleanup:
278 ly_set_erase(&key_set, NULL);
279 return ret;
280}
281
Radek Krejcie7b95092019-05-15 11:03:07 +0200282/**
Michal Vasko9f96a052020-03-10 09:41:45 +0100283 * @brief Parse XML elements as YANG data node children the specified parent node.
Radek Krejcie7b95092019-05-15 11:03:07 +0200284 *
Michal Vaskob36053d2020-03-26 15:49:30 +0100285 * @param[in] lydctx XML YANG data parser context.
Radek Krejcie7b95092019-05-15 11:03:07 +0200286 * @param[in] parent Parent node where the children are inserted. NULL in case of parsing top-level elements.
287 * @param[in,out] data Pointer to the XML string representation of the YANG data to parse.
288 * @param[out] node Resulting list of the parsed nodes.
Michal Vasko9b368d32020-02-14 13:53:31 +0100289 * @return LY_ERR value.
Radek Krejcie7b95092019-05-15 11:03:07 +0200290 */
291static LY_ERR
Michal Vaskob36053d2020-03-26 15:49:30 +0100292lydxml_data_r(struct lyd_xml_ctx *lydctx, struct lyd_node_inner *parent, const char **data, struct lyd_node **first)
Radek Krejcie7b95092019-05-15 11:03:07 +0200293{
Michal Vaskob36053d2020-03-26 15:49:30 +0100294 LY_ERR ret = LY_SUCCESS;
295 enum LYXML_PARSER_STATUS prev_status;
296 const char *prefix, *name, *prev_input, *pname, *pprefix;
297 size_t prefix_len, name_len, pprefix_len, pname_len;
298 struct lyxml_ctx *xmlctx;
299 const struct ly_ctx *ctx;
Radek Krejcie7b95092019-05-15 11:03:07 +0200300 const struct lyxml_ns *ns;
Michal Vasko52927e22020-03-16 17:26:14 +0100301 struct lyd_meta *meta = NULL, *meta2, *prev_meta;
302 struct ly_attr *attr = NULL;
Radek Krejcie7b95092019-05-15 11:03:07 +0200303 const struct lysc_node *snode;
304 struct lys_module *mod;
Michal Vaskob36053d2020-03-26 15:49:30 +0100305 uint32_t prev_opts, parents_count;
Michal Vasko52927e22020-03-16 17:26:14 +0100306 struct lyd_node *cur = NULL, *anchor;
307 struct ly_prefix *val_prefs;
Radek Krejcie7b95092019-05-15 11:03:07 +0200308
Michal Vaskob36053d2020-03-26 15:49:30 +0100309 xmlctx = lydctx->xmlctx;
310 ctx = xmlctx->ctx;
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100311
Michal Vaskob36053d2020-03-26 15:49:30 +0100312 while (xmlctx->status == LYXML_ELEMENT) {
313 /* remember element prefix and name */
314 prefix = xmlctx->prefix;
315 prefix_len = xmlctx->prefix_len;
316 name = xmlctx->name;
317 name_len = xmlctx->name_len;
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200318
Michal Vaskob36053d2020-03-26 15:49:30 +0100319 /* get the element module */
320 ns = lyxml_ns_get(xmlctx, prefix, prefix_len);
Radek Krejcie7b95092019-05-15 11:03:07 +0200321 if (!ns) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100322 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
323 prefix_len, prefix);
Michal Vasko90932a92020-02-12 14:33:03 +0100324 ret = LY_EVALID;
325 goto cleanup;
Radek Krejcie7b95092019-05-15 11:03:07 +0200326 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100327 mod = ly_ctx_get_module_implemented_ns(ctx, ns->uri);
328 if (!mod && (lydctx->options & LYD_OPT_STRICT)) {
329 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "No module with namespace \"%s\" in the context.", ns->uri);
Michal Vasko90932a92020-02-12 14:33:03 +0100330 ret = LY_EVALID;
331 goto cleanup;
Radek Krejcie7b95092019-05-15 11:03:07 +0200332 }
Michal Vasko52927e22020-03-16 17:26:14 +0100333
Michal Vaskob36053d2020-03-26 15:49:30 +0100334 /* get the schema node */
Michal Vasko52927e22020-03-16 17:26:14 +0100335 snode = NULL;
336 if (mod && (!parent || parent->schema)) {
337 /* leave if-feature check for validation */
338 snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, LYS_GETNEXT_NOSTATECHECK);
Michal Vaskob36053d2020-03-26 15:49:30 +0100339 if (!snode) {
340 if (lydctx->options & LYD_OPT_STRICT) {
341 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Element \"%.*s\" not found in the \"%s\" module.",
342 name_len, name, mod->name);
343 ret = LY_EVALID;
344 goto cleanup;
345 } else if (!(lydctx->options & LYD_OPT_OPAQ)) {
346 /* remember current number of parents */
347 parents_count = xmlctx->elements.count;
348
349 /* skip after the content */
350 while (xmlctx->status != LYXML_ELEM_CONTENT) {
351 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
352 }
353 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
354
355 /* skip all children elements, recursively, if any */
356 while (parents_count < xmlctx->elements.count) {
357 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
358 }
359
360 /* close element */
361 assert(xmlctx->status == LYXML_ELEM_CLOSE);
362 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
363 continue;
364 }
Michal Vasko52927e22020-03-16 17:26:14 +0100365 }
366 if (snode) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100367 if ((lydctx->options & LYD_OPT_NO_STATE) && (snode->flags & LYS_CONFIG_R)) {
368 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LY_VCODE_INSTATE, snode->name);
Michal Vasko52927e22020-03-16 17:26:14 +0100369 ret = LY_EVALID;
370 goto cleanup;
371 }
372 if (snode->nodetype & (LYS_ACTION | LYS_NOTIF)) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100373 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_DATA, "Unexpected %s element \"%.*s\".",
Michal Vasko52927e22020-03-16 17:26:14 +0100374 snode->nodetype == LYS_ACTION ? "RPC/action" : "notification", name_len, name);
375 ret = LY_EVALID;
376 goto cleanup;
377 }
378 }
Michal Vasko5b37a352020-03-06 13:38:33 +0100379 }
Radek Krejci710226d2019-07-24 17:24:59 +0200380
Michal Vaskob36053d2020-03-26 15:49:30 +0100381 /* parser next */
382 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100383
Michal Vaskob36053d2020-03-26 15:49:30 +0100384 if (snode && (lydctx->options & LYD_OPT_OPAQ) && (snode->nodetype & (LYD_NODE_TERM | LYS_LIST))) {
385 /* backup parser */
386 prev_status = xmlctx->status;
387 pprefix = xmlctx->prefix;
388 pprefix_len = xmlctx->prefix_len;
389 pname = xmlctx->name;
390 pname_len = xmlctx->name_len;
391 prev_input = xmlctx->input;
392 if ((xmlctx->status == LYXML_ELEM_CONTENT) && xmlctx->dynamic) {
393 /* it was backed up, do not free */
394 xmlctx->dynamic = 0;
395 }
396
397 /* skip attributes */
398 while (xmlctx->status == LYXML_ATTRIBUTE) {
399 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
400 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
401 }
402
Michal Vasko44685da2020-03-17 15:38:06 +0100403 if (snode->nodetype & LYD_NODE_TERM) {
404 /* value may not be valid in which case we parse it as an opaque node */
Michal Vaskob36053d2020-03-26 15:49:30 +0100405 if (lys_value_validate(NULL, snode, xmlctx->value, xmlctx->value_len, lydxml_resolve_prefix, xmlctx, LYD_XML)) {
Michal Vasko44685da2020-03-17 15:38:06 +0100406 snode = NULL;
407 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100408 } else {
409 /* skip content */
410 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100411
Michal Vaskob36053d2020-03-26 15:49:30 +0100412 if (lydxml_check_list(xmlctx, snode)) {
413 /* invalid list, parse as opaque if it does */
Michal Vasko44685da2020-03-17 15:38:06 +0100414 snode = NULL;
415 }
Michal Vasko44685da2020-03-17 15:38:06 +0100416 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100417
418 /* restore parser */
419 if (xmlctx->dynamic) {
420 free((char *)xmlctx->value);
421 }
422 xmlctx->status = prev_status;
423 xmlctx->prefix = pprefix;
424 xmlctx->prefix_len = pprefix_len;
425 xmlctx->name = pname;
426 xmlctx->name_len = pname_len;
427 xmlctx->input = prev_input;
Michal Vasko44685da2020-03-17 15:38:06 +0100428 }
429
Michal Vaskob36053d2020-03-26 15:49:30 +0100430 /* create metadata/attributes */
431 if (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vasko52927e22020-03-16 17:26:14 +0100432 if (snode) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100433 ret = lydxml_metadata(xmlctx, snode, lydctx->options & LYD_OPT_STRICT, &lydctx->unres_meta_type, &meta);
Michal Vasko52927e22020-03-16 17:26:14 +0100434 LY_CHECK_GOTO(ret, cleanup);
435 } else {
Michal Vaskob36053d2020-03-26 15:49:30 +0100436 assert(lydctx->options & LYD_OPT_OPAQ);
437 ret = lydxml_attrs(xmlctx, &attr);
438 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100439 }
Michal Vasko8d544252020-03-02 10:19:52 +0100440 }
441
Michal Vaskob36053d2020-03-26 15:49:30 +0100442 assert(xmlctx->status == LYXML_ELEM_CONTENT);
Michal Vasko52927e22020-03-16 17:26:14 +0100443 if (!snode) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100444 assert(lydctx->options & LYD_OPT_OPAQ);
Michal Vasko52927e22020-03-16 17:26:14 +0100445
Michal Vaskob36053d2020-03-26 15:49:30 +0100446 if (xmlctx->ws_only) {
447 /* ignore WS-only value */
448 xmlctx->value_len = 0;
449 val_prefs = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100450 } else {
Michal Vaskob36053d2020-03-26 15:49:30 +0100451 /* get value prefixes */
452 ret = lyxml_get_prefixes(xmlctx, xmlctx->value, xmlctx->value_len, &val_prefs);
Michal Vasko52927e22020-03-16 17:26:14 +0100453 LY_CHECK_GOTO(ret, cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200454 }
Michal Vasko90932a92020-02-12 14:33:03 +0100455
456 /* create node */
Michal Vaskob36053d2020-03-26 15:49:30 +0100457 ret = lyd_create_opaq(ctx, name, name_len, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic, LYD_XML,
458 val_prefs, prefix, prefix_len, ns->uri, &cur);
459 LY_CHECK_GOTO(ret, cleanup);
460
461 /* parser next */
462 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
463
464 /* process children */
465 if (xmlctx->status == LYXML_ELEMENT) {
466 ret = lydxml_data_r(lydctx, (struct lyd_node_inner *)cur, data, lyd_node_children_p(cur));
467 LY_CHECK_GOTO(ret, cleanup);
468 }
469 } else if (snode->nodetype & LYD_NODE_TERM) {
470 /* create node */
471 ret = lyd_create_term(snode, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic, lydxml_resolve_prefix,
472 xmlctx, LYD_XML, &cur);
Radek Krejcie553e6d2019-06-07 15:33:18 +0200473 if (ret == LY_EINCOMPLETE) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100474 if (!(lydctx->options & LYD_OPT_PARSE_ONLY)) {
475 ly_set_add(&lydctx->unres_node_type, cur, LY_SET_OPT_USEASLIST);
Michal Vasko9b368d32020-02-14 13:53:31 +0100476 }
Radek Krejcie553e6d2019-06-07 15:33:18 +0200477 } else if (ret) {
Radek Krejcie553e6d2019-06-07 15:33:18 +0200478 goto cleanup;
479 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100480
481 if (parent && (cur->schema->flags & LYS_KEY)) {
482 /* check the key order, the anchor must always be the last child */
Michal Vasko52927e22020-03-16 17:26:14 +0100483 anchor = lyd_get_prev_key_anchor(parent->child, cur->schema);
484 if ((!anchor && parent->child) || (anchor && anchor->next)) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100485 if (lydctx->options & LYD_OPT_STRICT) {
486 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_DATA, "Invalid position of the key \"%s\" in a list.",
Michal Vasko9b368d32020-02-14 13:53:31 +0100487 cur->schema->name);
488 ret = LY_EVALID;
489 goto cleanup;
490 } else {
Michal Vaskob36053d2020-03-26 15:49:30 +0100491 LOGWRN(ctx, "Invalid position of the key \"%s\" in a list.", cur->schema->name);
Michal Vasko9b368d32020-02-14 13:53:31 +0100492 }
493 }
494 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100495
496 /* parser next */
497 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
498
499 /* no children expected */
500 if (xmlctx->status == LYXML_ELEMENT) {
501 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Child element inside a terminal node \"%s\" found.",
Michal Vasko44685da2020-03-17 15:38:06 +0100502 snode->name);
503 ret = LY_EVALID;
504 goto cleanup;
Michal Vaskob36053d2020-03-26 15:49:30 +0100505 }
506 } else if (snode->nodetype & LYD_NODE_INNER) {
507 if (!xmlctx->ws_only) {
508 /* value in inner node */
509 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Text value inside an inner node \"%s\" found.",
510 snode->name);
511 ret = LY_EVALID;
512 goto cleanup;
Radek Krejcie7b95092019-05-15 11:03:07 +0200513 }
Michal Vasko90932a92020-02-12 14:33:03 +0100514
515 /* create node */
516 ret = lyd_create_inner(snode, &cur);
517 LY_CHECK_GOTO(ret, cleanup);
518
Michal Vaskob36053d2020-03-26 15:49:30 +0100519 /* parser next */
520 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
521
Radek Krejciee4cab22019-07-17 17:07:47 +0200522 /* process children */
Michal Vaskob36053d2020-03-26 15:49:30 +0100523 if (xmlctx->status == LYXML_ELEMENT) {
524 ret = lydxml_data_r(lydctx, (struct lyd_node_inner *)cur, data, lyd_node_children_p(cur));
Michal Vasko9f96a052020-03-10 09:41:45 +0100525 LY_CHECK_GOTO(ret, cleanup);
526 }
527
528 if (snode->nodetype == LYS_LIST) {
529 /* check all keys exist */
Michal Vasko44685da2020-03-17 15:38:06 +0100530 LY_CHECK_GOTO(ret = lyd_parse_check_keys(cur), cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200531 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100532
Michal Vaskob36053d2020-03-26 15:49:30 +0100533 if (!(lydctx->options & LYD_OPT_PARSE_ONLY)) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100534 /* new node validation, autodelete CANNOT occur, all nodes are new */
535 ret = lyd_validate_new(lyd_node_children_p(cur), snode, NULL);
536 LY_CHECK_GOTO(ret, cleanup);
537
Michal Vasko9b368d32020-02-14 13:53:31 +0100538 /* add any missing default children */
Michal Vaskob1b5c262020-03-05 14:29:47 +0100539 ret = lyd_validate_defaults_r((struct lyd_node_inner *)cur, lyd_node_children_p(cur), NULL, NULL,
Michal Vaskob36053d2020-03-26 15:49:30 +0100540 &lydctx->unres_node_type, &lydctx->when_check, lydctx->options);
Michal Vasko9b368d32020-02-14 13:53:31 +0100541 LY_CHECK_GOTO(ret, cleanup);
542 }
543
544 /* hash now that all keys should be parsed, rehash for key-less list */
545 if (snode->nodetype == LYS_LIST) {
546 lyd_hash(cur);
547 }
Radek Krejciee4cab22019-07-17 17:07:47 +0200548 } else if (snode->nodetype & LYD_NODE_ANY) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100549 if (!xmlctx->ws_only) {
550 /* value in inner node */
551 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Text value inside an any node \"%s\" found.",
552 snode->name);
553 ret = LY_EVALID;
554 goto cleanup;
Radek Krejciee4cab22019-07-17 17:07:47 +0200555 }
Michal Vasko90932a92020-02-12 14:33:03 +0100556
Michal Vaskob36053d2020-03-26 15:49:30 +0100557 /* parser next */
558 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
559
Michal Vasko52927e22020-03-16 17:26:14 +0100560 /* parse any data tree with correct options */
Michal Vaskob36053d2020-03-26 15:49:30 +0100561 prev_opts = lydctx->options;
562 lydctx->options &= ~LYD_OPT_STRICT;
563 lydctx->options |= LYD_OPT_OPAQ;
Michal Vasko52927e22020-03-16 17:26:14 +0100564 anchor = NULL;
Michal Vaskob36053d2020-03-26 15:49:30 +0100565 ret = lydxml_data_r(lydctx, NULL, data, &anchor);
566 lydctx->options = prev_opts;
Michal Vasko52927e22020-03-16 17:26:14 +0100567 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko90932a92020-02-12 14:33:03 +0100568
569 /* create node */
Michal Vasko52927e22020-03-16 17:26:14 +0100570 ret = lyd_create_any(snode, anchor, LYD_ANYDATA_DATATREE, &cur);
571 LY_CHECK_GOTO(ret, cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200572 }
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200573
Michal Vasko9b368d32020-02-14 13:53:31 +0100574 /* correct flags */
Michal Vasko52927e22020-03-16 17:26:14 +0100575 if (snode) {
576 if (!(snode->nodetype & (LYS_ACTION | LYS_NOTIF)) && snode->when) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100577 if (lydctx->options & LYD_OPT_TRUSTED) {
Michal Vasko52927e22020-03-16 17:26:14 +0100578 /* just set it to true */
579 cur->flags |= LYD_WHEN_TRUE;
580 } else {
581 /* remember we need to evaluate this node's when */
Michal Vaskob36053d2020-03-26 15:49:30 +0100582 ly_set_add(&lydctx->when_check, cur, LY_SET_OPT_USEASLIST);
Michal Vasko52927e22020-03-16 17:26:14 +0100583 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100584 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100585 if (lydctx->options & LYD_OPT_TRUSTED) {
Michal Vasko52927e22020-03-16 17:26:14 +0100586 /* node is valid */
587 cur->flags &= ~LYD_NEW;
588 }
589 prev_meta = NULL;
590 LY_LIST_FOR(meta, meta2) {
591 if (!strcmp(meta2->name, "default") && !strcmp(meta2->annotation->module->name, "ietf-netconf-with-defaults")
592 && meta2->value.boolean) {
593 /* node is default according to the metadata */
594 cur->flags |= LYD_DEFAULT;
595
596 /* delete the metadata */
597 if (prev_meta) {
598 prev_meta->next = meta2->next;
599 } else {
600 meta = meta->next;
601 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100602 lyd_free_meta(ctx, meta2, 0);
Michal Vasko52927e22020-03-16 17:26:14 +0100603 break;
604 }
605
606 prev_meta = meta2;
Michal Vasko8d544252020-03-02 10:19:52 +0100607 }
608 }
609
Michal Vasko52927e22020-03-16 17:26:14 +0100610 /* add metadata/attributes */
611 if (snode) {
612 cur->meta = meta;
613 meta = NULL;
614 } else {
615 assert(!cur->schema);
616 ((struct lyd_node_opaq *)cur)->attr = attr;
617 attr = NULL;
618 }
Radek Krejcib6f7ae52019-07-19 10:31:42 +0200619
Michal Vasko90932a92020-02-12 14:33:03 +0100620 /* insert */
Michal Vaskob1b5c262020-03-05 14:29:47 +0100621 lyd_insert_node((struct lyd_node *)parent, first, cur);
Michal Vasko90932a92020-02-12 14:33:03 +0100622 cur = NULL;
Michal Vaskob36053d2020-03-26 15:49:30 +0100623
624 /* parser next */
625 assert(xmlctx->status == LYXML_ELEM_CLOSE);
626 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200627 }
628
Michal Vasko90932a92020-02-12 14:33:03 +0100629 /* success */
630 ret = LY_SUCCESS;
631
Radek Krejcie7b95092019-05-15 11:03:07 +0200632cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100633 lyd_free_meta(ctx, meta, 1);
634 ly_free_attr(ctx, attr, 1);
Michal Vasko90932a92020-02-12 14:33:03 +0100635 lyd_free_tree(cur);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100636 if (ret && *first) {
637 lyd_free_siblings(*first);
638 *first = NULL;
Michal Vasko90932a92020-02-12 14:33:03 +0100639 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200640 return ret;
641}
642
643LY_ERR
Michal Vasko9f96a052020-03-10 09:41:45 +0100644lyd_parse_xml_data(struct ly_ctx *ctx, const char *data, int options, struct lyd_node **tree)
Radek Krejcie7b95092019-05-15 11:03:07 +0200645{
Radek Krejci18a57d92019-07-25 14:01:42 +0200646 LY_ERR ret = LY_SUCCESS;
Michal Vaskob36053d2020-03-26 15:49:30 +0100647 struct lyd_xml_ctx lydctx = {0};
Michal Vaskob1b5c262020-03-05 14:29:47 +0100648 uint32_t i = 0;
649 const struct lys_module *mod;
650 struct lyd_node *first, *next, **first2;
Radek Krejcie7b95092019-05-15 11:03:07 +0200651
Michal Vaskob36053d2020-03-26 15:49:30 +0100652 /* init context and tree */
653 LY_CHECK_GOTO(ret = lyxml_ctx_new(ctx, data, &lydctx.xmlctx), cleanup);
654 lydctx.options = options;
Michal Vaskob1b5c262020-03-05 14:29:47 +0100655 *tree = NULL;
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200656
Michal Vaskob1b5c262020-03-05 14:29:47 +0100657 /* parse XML data */
Michal Vaskob36053d2020-03-26 15:49:30 +0100658 ret = lydxml_data_r(&lydctx, NULL, &data, tree);
Michal Vaskocde73ac2019-11-14 16:10:27 +0100659 LY_CHECK_GOTO(ret, cleanup);
660
Michal Vasko9b368d32020-02-14 13:53:31 +0100661 if (!(options & LYD_OPT_PARSE_ONLY)) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100662 next = *tree;
663 while (1) {
664 if (options & LYD_VALOPT_DATA_ONLY) {
665 mod = lyd_data_next_module(&next, &first);
666 } else {
667 mod = lyd_mod_next_module(next, NULL, 0, ctx, &i, &first);
668 }
669 if (!mod) {
670 break;
671 }
672 if (first == *tree) {
673 /* make sure first2 changes are carried to tree */
674 first2 = tree;
675 } else {
676 first2 = &first;
677 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100678
Michal Vaskob1b5c262020-03-05 14:29:47 +0100679 /* validate new top-level nodes, autodelete CANNOT occur, all nodes are new */
680 ret = lyd_validate_new(first2, NULL, mod);
681 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko9b368d32020-02-14 13:53:31 +0100682
Michal Vaskob1b5c262020-03-05 14:29:47 +0100683 /* add all top-level defaults for this module */
Michal Vaskob36053d2020-03-26 15:49:30 +0100684 ret = lyd_validate_defaults_r(NULL, first2, NULL, mod, &lydctx.unres_node_type, &lydctx.when_check,
Michal Vasko52927e22020-03-16 17:26:14 +0100685 options & LYD_VALOPT_MASK);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100686 LY_CHECK_GOTO(ret, cleanup);
687
688 /* finish incompletely validated terminal values/attributes and when conditions */
Michal Vaskob36053d2020-03-26 15:49:30 +0100689 ret = lyd_validate_unres(tree, &lydctx.when_check, &lydctx.unres_node_type, &lydctx.unres_meta_type, LYD_XML,
690 lydxml_resolve_prefix, lydctx.xmlctx);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100691 LY_CHECK_GOTO(ret, cleanup);
692
693 /* perform final validation that assumes the data tree is final */
Michal Vasko5b37a352020-03-06 13:38:33 +0100694 ret = lyd_validate_siblings_r(*first2, NULL, mod, options & LYD_VALOPT_MASK);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100695 LY_CHECK_GOTO(ret, cleanup);
696 }
Michal Vaskocde73ac2019-11-14 16:10:27 +0100697 }
698
Michal Vaskocde73ac2019-11-14 16:10:27 +0100699cleanup:
Michal Vasko9b368d32020-02-14 13:53:31 +0100700 /* there should be no unresolved types stored */
Michal Vaskob36053d2020-03-26 15:49:30 +0100701 assert(!(options & LYD_OPT_PARSE_ONLY) || (!lydctx.unres_node_type.count && !lydctx.unres_meta_type.count
702 && !lydctx.when_check.count));
Michal Vasko9b368d32020-02-14 13:53:31 +0100703
Michal Vaskob36053d2020-03-26 15:49:30 +0100704 ly_set_erase(&lydctx.unres_node_type, NULL);
705 ly_set_erase(&lydctx.unres_meta_type, NULL);
706 ly_set_erase(&lydctx.when_check, NULL);
707 lyxml_ctx_free(lydctx.xmlctx);
Michal Vasko9f96a052020-03-10 09:41:45 +0100708 if (ret) {
709 lyd_free_all(*tree);
710 *tree = NULL;
711 }
712 return ret;
713}