blob: 0ebd959583fd378e670c724083605497667d3e29 [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
Radek Krejcie7b95092019-05-15 11:03:07 +020015#include <stdint.h>
16#include <stdlib.h>
17#include <string.h>
Michal Vasko9b368d32020-02-14 13:53:31 +010018#include <assert.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020019
Radek Krejci535ea9f2020-05-29 16:01:05 +020020#include "common.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020021#include "context.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020022#include "log.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020023#include "set.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020024#include "tree.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020025#include "tree_data_internal.h"
26#include "tree_schema.h"
Michal Vaskocde73ac2019-11-14 16:10:27 +010027#include "validation.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020028#include "xml.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020029
Michal Vasko1bf09392020-03-27 12:38:10 +010030#define LYD_INTOPT_RPC 0x01 /**< RPC/action invocation is being parsed */
31#define LYD_INTOPT_NOTIF 0x02 /**< notification is being parsed */
Michal Vasko1ce933a2020-03-30 12:38:22 +020032#define LYD_INTOPT_REPLY 0x04 /**< RPC/action reply is being parsed */
Michal Vasko1bf09392020-03-27 12:38:10 +010033
Radek Krejcie7b95092019-05-15 11:03:07 +020034/**
Michal Vaskob36053d2020-03-26 15:49:30 +010035 * @brief Internal context for XML YANG data parser.
Radek Krejcie7b95092019-05-15 11:03:07 +020036 */
37struct lyd_xml_ctx {
Michal Vaskob36053d2020-03-26 15:49:30 +010038 struct lyxml_ctx *xmlctx; /**< XML context */
Radek Krejcie7b95092019-05-15 11:03:07 +020039
Michal Vasko52927e22020-03-16 17:26:14 +010040 uint32_t options; /**< various @ref dataparseroptions. */
Michal Vasko1bf09392020-03-27 12:38:10 +010041 uint32_t int_opts; /**< internal data parser options */
Michal Vasko52927e22020-03-16 17:26:14 +010042 uint32_t path_len; /**< used bytes in the path buffer */
Radek Krejcie7b95092019-05-15 11:03:07 +020043#define LYD_PARSER_BUFSIZE 4078
44 char path[LYD_PARSER_BUFSIZE]; /**< buffer for the generated path */
Michal Vasko52927e22020-03-16 17:26:14 +010045 struct ly_set unres_node_type; /**< set of nodes validated with LY_EINCOMPLETE result */
46 struct ly_set unres_meta_type; /**< set of metadata validated with LY_EINCOMPLETE result */
Michal Vaskoecd62de2019-11-13 12:35:11 +010047 struct ly_set when_check; /**< set of nodes with "when" conditions */
Michal Vasko1bf09392020-03-27 12:38:10 +010048 struct lyd_node *op_ntf; /**< if an RPC/action/notification is being parsed, store the pointer to it */
Radek Krejcie7b95092019-05-15 11:03:07 +020049};
50
51/**
Michal Vaskob36053d2020-03-26 15:49:30 +010052 * @brief XML-parser's implementation of ly_type_resolve_prefix() callback to provide mapping between prefixes used
53 * in the values to the schema via XML namespaces.
Radek Krejciaca74032019-06-04 08:53:06 +020054 */
55static const struct lys_module *
Michal Vasko52927e22020-03-16 17:26:14 +010056lydxml_resolve_prefix(const struct ly_ctx *ctx, const char *prefix, size_t prefix_len, void *parser)
Radek Krejciaca74032019-06-04 08:53:06 +020057{
58 const struct lyxml_ns *ns;
Michal Vaskob36053d2020-03-26 15:49:30 +010059 struct lyxml_ctx *xmlctx = (struct lyxml_ctx *)parser;
Radek Krejciaca74032019-06-04 08:53:06 +020060
61 ns = lyxml_ns_get(xmlctx, prefix, prefix_len);
62 if (!ns) {
63 return NULL;
64 }
65
66 return ly_ctx_get_module_implemented_ns(ctx, ns->uri);
67}
68
Radek Krejcie7b95092019-05-15 11:03:07 +020069static LY_ERR
Michal Vaskob36053d2020-03-26 15:49:30 +010070lydxml_metadata(struct lyxml_ctx *xmlctx, const struct lysc_node *sparent, int strict, struct ly_set *type_meta_check,
71 struct lyd_meta **meta)
Radek Krejcie7b95092019-05-15 11:03:07 +020072{
Michal Vaskob36053d2020-03-26 15:49:30 +010073 LY_ERR ret = LY_EVALID;
Radek Krejci28681fa2019-09-06 13:08:45 +020074 const struct lyxml_ns *ns;
75 struct lys_module *mod;
Michal Vaskob36053d2020-03-26 15:49:30 +010076 const char *name;
77 size_t name_len;
Radek Krejci28681fa2019-09-06 13:08:45 +020078
Michal Vaskob36053d2020-03-26 15:49:30 +010079 *meta = NULL;
Radek Krejci28681fa2019-09-06 13:08:45 +020080
Michal Vaskob36053d2020-03-26 15:49:30 +010081 while (xmlctx->status == LYXML_ATTRIBUTE) {
82 if (!xmlctx->prefix_len) {
Radek Krejci28681fa2019-09-06 13:08:45 +020083 /* in XML, all attributes must be prefixed
84 * TODO exception for NETCONF filters which are supposed to map to the ietf-netconf without prefix */
Michal Vasko52927e22020-03-16 17:26:14 +010085 if (strict) {
86 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Missing mandatory prefix for XML metadata \"%.*s\".",
Michal Vaskob36053d2020-03-26 15:49:30 +010087 xmlctx->name_len, xmlctx->name);
88 goto cleanup;
Radek Krejci28681fa2019-09-06 13:08:45 +020089 }
Michal Vaskob36053d2020-03-26 15:49:30 +010090
Radek Krejci28681fa2019-09-06 13:08:45 +020091skip_attr:
Michal Vaskob36053d2020-03-26 15:49:30 +010092 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
93 assert(xmlctx->status == LYXML_ATTR_CONTENT);
94 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejci28681fa2019-09-06 13:08:45 +020095 continue;
96 }
97
98 /* get namespace of the attribute to find its annotation definition */
Michal Vaskob36053d2020-03-26 15:49:30 +010099 ns = lyxml_ns_get(xmlctx, xmlctx->prefix, xmlctx->prefix_len);
Radek Krejci28681fa2019-09-06 13:08:45 +0200100 if (!ns) {
Michal Vasko52927e22020-03-16 17:26:14 +0100101 /* unknown namespace, XML error */
102 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
Michal Vaskob36053d2020-03-26 15:49:30 +0100103 xmlctx->prefix_len, xmlctx->prefix);
Radek Krejci28681fa2019-09-06 13:08:45 +0200104 goto cleanup;
105 }
Michal Vasko52927e22020-03-16 17:26:14 +0100106 mod = ly_ctx_get_module_implemented_ns(xmlctx->ctx, ns->uri);
Radek Krejci28681fa2019-09-06 13:08:45 +0200107 if (!mod) {
108 /* module is not implemented or not present in the schema */
Michal Vasko52927e22020-03-16 17:26:14 +0100109 if (strict) {
110 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE,
Michal Vasko9f96a052020-03-10 09:41:45 +0100111 "Unknown (or not implemented) YANG module with namespace \"%s\" for metadata \"%.*s%s%.*s\".",
Michal Vaskob36053d2020-03-26 15:49:30 +0100112 ns->uri, xmlctx->prefix_len, xmlctx->prefix, xmlctx->prefix_len ? ":" : "", xmlctx->name_len,
113 xmlctx->name);
114 goto cleanup;
Radek Krejci28681fa2019-09-06 13:08:45 +0200115 }
116 goto skip_attr;
117 }
118
Michal Vaskob36053d2020-03-26 15:49:30 +0100119 /* remember attr name and get its content */
120 name = xmlctx->name;
121 name_len = xmlctx->name_len;
122 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
123 assert(xmlctx->status == LYXML_ATTR_CONTENT);
124
125 /* create metadata */
126 ret = lyd_create_meta(NULL, meta, mod, name, name_len, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic,
127 lydxml_resolve_prefix, xmlctx, LYD_XML, sparent);
128 if (ret == LY_EINCOMPLETE) {
Michal Vasko52927e22020-03-16 17:26:14 +0100129 if (type_meta_check) {
130 ly_set_add(type_meta_check, meta, LY_SET_OPT_USEASLIST);
131 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100132 } else if (ret) {
Radek Krejci28681fa2019-09-06 13:08:45 +0200133 goto cleanup;
134 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100135
136 /* next attribute */
137 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200138 }
Michal Vasko52927e22020-03-16 17:26:14 +0100139
Radek Krejci28681fa2019-09-06 13:08:45 +0200140 ret = LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200141
142cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100143 if (ret) {
144 lyd_free_meta(xmlctx->ctx, *meta, 1);
145 *meta = NULL;
Radek Krejci38d85362019-09-05 16:26:38 +0200146 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200147 return ret;
148}
149
Michal Vasko52927e22020-03-16 17:26:14 +0100150static LY_ERR
Michal Vaskob36053d2020-03-26 15:49:30 +0100151lydxml_attrs(struct lyxml_ctx *xmlctx, struct ly_attr **attr)
Michal Vasko52927e22020-03-16 17:26:14 +0100152{
153 LY_ERR ret = LY_SUCCESS;
154 const struct lyxml_ns *ns;
155 struct ly_prefix *val_prefs;
156 struct ly_attr *attr2;
Michal Vaskob36053d2020-03-26 15:49:30 +0100157 const char *name, *prefix;
158 size_t name_len, prefix_len;
Michal Vasko52927e22020-03-16 17:26:14 +0100159
160 assert(attr);
Michal Vaskob36053d2020-03-26 15:49:30 +0100161 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100162
Michal Vaskob36053d2020-03-26 15:49:30 +0100163 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vasko52927e22020-03-16 17:26:14 +0100164 ns = NULL;
Michal Vaskob36053d2020-03-26 15:49:30 +0100165 if (xmlctx->prefix_len) {
Michal Vasko52927e22020-03-16 17:26:14 +0100166 /* get namespace of the attribute */
Michal Vaskob36053d2020-03-26 15:49:30 +0100167 ns = lyxml_ns_get(xmlctx, xmlctx->prefix, xmlctx->prefix_len);
Michal Vasko52927e22020-03-16 17:26:14 +0100168 if (!ns) {
169 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
Michal Vaskob36053d2020-03-26 15:49:30 +0100170 xmlctx->prefix_len, xmlctx->prefix);
Michal Vasko52927e22020-03-16 17:26:14 +0100171 ret = LY_EVALID;
172 goto cleanup;
173 }
174 }
175
176 if (*attr) {
177 attr2 = *attr;
178 } else {
179 attr2 = NULL;
180 }
181
Michal Vaskob36053d2020-03-26 15:49:30 +0100182 /* remember attr prefix, name, and get its content */
183 prefix = xmlctx->prefix;
184 prefix_len = xmlctx->prefix_len;
185 name = xmlctx->name;
186 name_len = xmlctx->name_len;
187 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
188 assert(xmlctx->status == LYXML_ATTR_CONTENT);
189
Michal Vasko52927e22020-03-16 17:26:14 +0100190 /* get value prefixes */
Michal Vaskob36053d2020-03-26 15:49:30 +0100191 LY_CHECK_GOTO(ret = lyxml_get_prefixes(xmlctx, xmlctx->value, xmlctx->value_len, &val_prefs), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100192
193 /* attr2 is always changed to the created attribute */
Michal Vaskob36053d2020-03-26 15:49:30 +0100194 ret = ly_create_attr(NULL, &attr2, xmlctx->ctx, name, name_len, xmlctx->value, xmlctx->value_len,
195 &xmlctx->dynamic, LYD_XML, val_prefs, prefix, prefix_len, ns ? ns->uri : NULL);
Michal Vasko52927e22020-03-16 17:26:14 +0100196 LY_CHECK_GOTO(ret, cleanup);
197
198 if (!*attr) {
199 *attr = attr2;
200 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100201
202 /* next attribute */
203 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100204 }
205
206cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100207 if (ret) {
208 ly_free_attr(xmlctx->ctx, *attr, 1);
209 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100210 }
Michal Vasko52927e22020-03-16 17:26:14 +0100211 return ret;
212}
213
Michal Vasko44685da2020-03-17 15:38:06 +0100214static LY_ERR
Michal Vaskob36053d2020-03-26 15:49:30 +0100215lydxml_check_list(struct lyxml_ctx *xmlctx, const struct lysc_node *list)
Michal Vasko44685da2020-03-17 15:38:06 +0100216{
Michal Vaskob36053d2020-03-26 15:49:30 +0100217 LY_ERR ret = LY_SUCCESS, r;
218 enum LYXML_PARSER_STATUS next;
Michal Vasko44685da2020-03-17 15:38:06 +0100219 struct ly_set key_set = {0};
220 const struct lysc_node *snode;
Michal Vaskob36053d2020-03-26 15:49:30 +0100221 uint32_t i, parents_count;
Michal Vasko44685da2020-03-17 15:38:06 +0100222
223 assert(list && (list->nodetype == LYS_LIST));
224
225 /* get all keys into a set (keys do not have if-features or anything) */
226 snode = NULL;
227 while ((snode = lys_getnext(snode, list, NULL, LYS_GETNEXT_NOSTATECHECK)) && (snode->flags & LYS_KEY)) {
228 ly_set_add(&key_set, (void *)snode, LY_SET_OPT_USEASLIST);
229 }
230
Michal Vaskob36053d2020-03-26 15:49:30 +0100231 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vasko44685da2020-03-17 15:38:06 +0100232 /* find key definition */
233 for (i = 0; i < key_set.count; ++i) {
234 snode = (const struct lysc_node *)key_set.objs[i];
Michal Vaskob36053d2020-03-26 15:49:30 +0100235 if (!ly_strncmp(snode->name, xmlctx->name, xmlctx->name_len)) {
Michal Vasko44685da2020-03-17 15:38:06 +0100236 break;
237 }
238 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100239 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100240
241 /* skip attributes */
242 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100243 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
244 assert(xmlctx->status == LYXML_ATTR_CONTENT);
245 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100246 }
247
Michal Vaskob36053d2020-03-26 15:49:30 +0100248 assert(xmlctx->status == LYXML_ELEM_CONTENT);
249 if (i < key_set.count) {
250 /* validate the value */
251 r = lys_value_validate(NULL, snode, xmlctx->value, xmlctx->value_len, lydxml_resolve_prefix, xmlctx, LYD_XML);
252 if (!r) {
253 /* key with a valid value, remove from the set */
254 ly_set_rm_index(&key_set, i, NULL);
Michal Vasko44685da2020-03-17 15:38:06 +0100255 }
256 }
257
Michal Vaskob36053d2020-03-26 15:49:30 +0100258 /* parser next */
259 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100260
Michal Vaskob36053d2020-03-26 15:49:30 +0100261 /* skip any children, resursively */
262 parents_count = xmlctx->elements.count;
263 while ((parents_count < xmlctx->elements.count) || (xmlctx->status == LYXML_ELEMENT)) {
264 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
265 }
266
267 /* parser next, but do not parse closing element of the list because it would remove its namespaces */
268 assert(xmlctx->status == LYXML_ELEM_CLOSE);
269 LY_CHECK_GOTO(ret = lyxml_ctx_peek(xmlctx, &next), cleanup);
270 if (next != LYXML_ELEM_CLOSE) {
271 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
272 }
Michal Vasko44685da2020-03-17 15:38:06 +0100273 }
274
275 if (key_set.count) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100276 /* some keys are missing/did not validate */
Michal Vasko44685da2020-03-17 15:38:06 +0100277 ret = LY_ENOT;
Michal Vasko44685da2020-03-17 15:38:06 +0100278 }
279
280cleanup:
281 ly_set_erase(&key_set, NULL);
282 return ret;
283}
284
Michal Vasko1bf09392020-03-27 12:38:10 +0100285static LY_ERR
286lydxml_data_skip(struct lyxml_ctx *xmlctx)
287{
288 uint32_t parents_count;
289
290 /* remember current number of parents */
291 parents_count = xmlctx->elements.count;
292
293 /* skip after the content */
294 while (xmlctx->status != LYXML_ELEM_CONTENT) {
295 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
296 }
297 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
298
299 /* skip all children elements, recursively, if any */
300 while (parents_count < xmlctx->elements.count) {
301 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
302 }
303
304 /* close element */
305 assert(xmlctx->status == LYXML_ELEM_CLOSE);
306 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
307
308 return LY_SUCCESS;
309}
310
311static LY_ERR
312lydxml_data_check_schema(struct lyd_xml_ctx *lydctx, const struct lysc_node **snode)
313{
314 LY_ERR ret = LY_SUCCESS;
315 enum LYXML_PARSER_STATUS prev_status;
316 const char *prev_input, *pname, *pprefix;
317 size_t pprefix_len, pname_len;
318 struct lyxml_ctx *xmlctx = lydctx->xmlctx;
319
320 if ((lydctx->options & LYD_OPT_NO_STATE) && ((*snode)->flags & LYS_CONFIG_R)) {
Michal Vaskocb7526d2020-03-30 15:08:26 +0200321 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LY_VCODE_INNODE, "state", (*snode)->name);
Michal Vasko1bf09392020-03-27 12:38:10 +0100322 return LY_EVALID;
323 }
324
325 if ((*snode)->nodetype & (LYS_RPC | LYS_ACTION)) {
326 if (lydctx->int_opts & LYD_INTOPT_RPC) {
327 if (lydctx->op_ntf) {
328 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_DATA, "Unexpected %s element \"%s\", %s \"%s\" already parsed.",
329 lys_nodetype2str((*snode)->nodetype), (*snode)->name,
330 lys_nodetype2str(lydctx->op_ntf->schema->nodetype), lydctx->op_ntf->schema->name);
331 return LY_EVALID;
332 }
333 } else {
334 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_DATA, "Unexpected %s element \"%s\".",
335 lys_nodetype2str((*snode)->nodetype), (*snode)->name);
336 return LY_EVALID;
337 }
338 } else if ((*snode)->nodetype == LYS_NOTIF) {
339 if (lydctx->int_opts & LYD_INTOPT_NOTIF) {
340 if (lydctx->op_ntf) {
341 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_DATA, "Unexpected %s element \"%s\", %s \"%s\" already parsed.",
342 lys_nodetype2str((*snode)->nodetype), (*snode)->name,
343 lys_nodetype2str(lydctx->op_ntf->schema->nodetype), lydctx->op_ntf->schema->name);
344 return LY_EVALID;
345 }
346 } else {
347 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_DATA, "Unexpected %s element \"%s\".",
348 lys_nodetype2str((*snode)->nodetype), (*snode)->name);
349 return LY_EVALID;
350 }
351 }
352
353 if ((lydctx->options & LYD_OPT_OPAQ) && ((*snode)->nodetype & (LYD_NODE_TERM | LYS_LIST))) {
354 /* backup parser */
355 prev_status = xmlctx->status;
356 pprefix = xmlctx->prefix;
357 pprefix_len = xmlctx->prefix_len;
358 pname = xmlctx->name;
359 pname_len = xmlctx->name_len;
360 prev_input = xmlctx->input;
361 if ((xmlctx->status == LYXML_ELEM_CONTENT) && xmlctx->dynamic) {
362 /* it was backed up, do not free */
363 xmlctx->dynamic = 0;
364 }
365
366 /* skip attributes */
367 while (xmlctx->status == LYXML_ATTRIBUTE) {
368 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
369 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
370 }
371
372 if ((*snode)->nodetype & LYD_NODE_TERM) {
373 /* value may not be valid in which case we parse it as an opaque node */
374 if (lys_value_validate(NULL, *snode, xmlctx->value, xmlctx->value_len, lydxml_resolve_prefix, xmlctx, LYD_XML)) {
375 *snode = NULL;
376 }
377 } else {
378 /* skip content */
379 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
380
381 if (lydxml_check_list(xmlctx, *snode)) {
382 /* invalid list, parse as opaque if it missing/has invalid some keys */
383 *snode = NULL;
384 }
385 }
386
387restore:
388 /* restore parser */
389 if (xmlctx->dynamic) {
390 free((char *)xmlctx->value);
391 }
392 xmlctx->status = prev_status;
393 xmlctx->prefix = pprefix;
394 xmlctx->prefix_len = pprefix_len;
395 xmlctx->name = pname;
396 xmlctx->name_len = pname_len;
397 xmlctx->input = prev_input;
398 }
399
400 return ret;
401}
402
403static void
404lydxml_data_flags(struct lyd_xml_ctx *lydctx, struct lyd_node *node, struct lyd_meta **meta)
405{
406 struct lyd_meta *meta2, *prev_meta = NULL;
407
408 if (!(node->schema->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && node->schema->when) {
409 if (lydctx->options & LYD_OPT_TRUSTED) {
410 /* just set it to true */
411 node->flags |= LYD_WHEN_TRUE;
412 } else {
413 /* remember we need to evaluate this node's when */
414 ly_set_add(&lydctx->when_check, node, LY_SET_OPT_USEASLIST);
415 }
416 }
417
418 if (lydctx->options & LYD_OPT_TRUSTED) {
419 /* node is valid */
420 node->flags &= ~LYD_NEW;
421 }
422
423 LY_LIST_FOR(*meta, meta2) {
424 if (!strcmp(meta2->name, "default") && !strcmp(meta2->annotation->module->name, "ietf-netconf-with-defaults")
425 && meta2->value.boolean) {
426 /* node is default according to the metadata */
427 node->flags |= LYD_DEFAULT;
428
429 /* delete the metadata */
430 if (prev_meta) {
431 prev_meta->next = meta2->next;
432 } else {
433 *meta = (*meta)->next;
434 }
435 lyd_free_meta(lydctx->xmlctx->ctx, meta2, 0);
436 break;
437 }
438
439 prev_meta = meta2;
440 }
441}
442
Radek Krejcie7b95092019-05-15 11:03:07 +0200443/**
Michal Vasko9f96a052020-03-10 09:41:45 +0100444 * @brief Parse XML elements as YANG data node children the specified parent node.
Radek Krejcie7b95092019-05-15 11:03:07 +0200445 *
Michal Vaskob36053d2020-03-26 15:49:30 +0100446 * @param[in] lydctx XML YANG data parser context.
Radek Krejcie7b95092019-05-15 11:03:07 +0200447 * @param[in] parent Parent node where the children are inserted. NULL in case of parsing top-level elements.
Radek Krejcie7b95092019-05-15 11:03:07 +0200448 * @param[out] node Resulting list of the parsed nodes.
Michal Vasko9b368d32020-02-14 13:53:31 +0100449 * @return LY_ERR value.
Radek Krejcie7b95092019-05-15 11:03:07 +0200450 */
451static LY_ERR
Michal Vasko1bf09392020-03-27 12:38:10 +0100452lydxml_data_r(struct lyd_xml_ctx *lydctx, struct lyd_node_inner *parent, struct lyd_node **first)
Radek Krejcie7b95092019-05-15 11:03:07 +0200453{
Michal Vaskob36053d2020-03-26 15:49:30 +0100454 LY_ERR ret = LY_SUCCESS;
Michal Vasko1bf09392020-03-27 12:38:10 +0100455 const char *prefix, *name;
456 size_t prefix_len, name_len;
Michal Vaskob36053d2020-03-26 15:49:30 +0100457 struct lyxml_ctx *xmlctx;
458 const struct ly_ctx *ctx;
Radek Krejcie7b95092019-05-15 11:03:07 +0200459 const struct lyxml_ns *ns;
Michal Vasko5ab0d5c2020-06-29 11:48:05 +0200460 struct lyd_meta *meta = NULL, *m;
461 struct ly_attr *attr = NULL, *a;
Radek Krejcie7b95092019-05-15 11:03:07 +0200462 const struct lysc_node *snode;
463 struct lys_module *mod;
Michal Vasko1bf09392020-03-27 12:38:10 +0100464 uint32_t prev_opts;
Michal Vasko52927e22020-03-16 17:26:14 +0100465 struct lyd_node *cur = NULL, *anchor;
466 struct ly_prefix *val_prefs;
Michal Vasko1ce933a2020-03-30 12:38:22 +0200467 int getnext_opts;
Radek Krejcie7b95092019-05-15 11:03:07 +0200468
Michal Vaskob36053d2020-03-26 15:49:30 +0100469 xmlctx = lydctx->xmlctx;
470 ctx = xmlctx->ctx;
Michal Vasko1ce933a2020-03-30 12:38:22 +0200471 /* leave if-feature check for validation */
472 getnext_opts = LYS_GETNEXT_NOSTATECHECK | (lydctx->int_opts & LYD_INTOPT_REPLY ? LYS_GETNEXT_OUTPUT : 0);
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100473
Michal Vaskob36053d2020-03-26 15:49:30 +0100474 while (xmlctx->status == LYXML_ELEMENT) {
475 /* remember element prefix and name */
476 prefix = xmlctx->prefix;
477 prefix_len = xmlctx->prefix_len;
478 name = xmlctx->name;
479 name_len = xmlctx->name_len;
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200480
Michal Vaskob36053d2020-03-26 15:49:30 +0100481 /* get the element module */
482 ns = lyxml_ns_get(xmlctx, prefix, prefix_len);
Radek Krejcie7b95092019-05-15 11:03:07 +0200483 if (!ns) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100484 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
485 prefix_len, prefix);
Michal Vasko90932a92020-02-12 14:33:03 +0100486 ret = LY_EVALID;
487 goto cleanup;
Radek Krejcie7b95092019-05-15 11:03:07 +0200488 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100489 mod = ly_ctx_get_module_implemented_ns(ctx, ns->uri);
Michal Vaskoaa7f4fa2020-06-22 10:03:53 +0200490 if (!mod) {
491 if (lydctx->options & LYD_OPT_STRICT) {
492 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "No module with namespace \"%s\" in the context.",
493 ns->uri);
494 ret = LY_EVALID;
495 goto cleanup;
496 }
Michal Vasko2acb5a62020-06-23 13:23:53 +0200497 if (!(lydctx->options & LYD_OPT_OPAQ)) {
498 /* skip element with children */
499 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), cleanup);
500 continue;
501 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200502 }
Michal Vasko52927e22020-03-16 17:26:14 +0100503
Michal Vasko1bf09392020-03-27 12:38:10 +0100504 /* parser next */
505 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
506
Michal Vaskob36053d2020-03-26 15:49:30 +0100507 /* get the schema node */
Michal Vasko52927e22020-03-16 17:26:14 +0100508 snode = NULL;
509 if (mod && (!parent || parent->schema)) {
Michal Vasko1ce933a2020-03-30 12:38:22 +0200510 snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
Michal Vaskob36053d2020-03-26 15:49:30 +0100511 if (!snode) {
512 if (lydctx->options & LYD_OPT_STRICT) {
513 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Element \"%.*s\" not found in the \"%s\" module.",
514 name_len, name, mod->name);
515 ret = LY_EVALID;
516 goto cleanup;
517 } else if (!(lydctx->options & LYD_OPT_OPAQ)) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100518 /* skip element with children */
519 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), cleanup);
Michal Vaskob36053d2020-03-26 15:49:30 +0100520 continue;
521 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100522 } else {
Michal Vasko1bf09392020-03-27 12:38:10 +0100523 /* check that schema node is valid and can be used */
524 LY_CHECK_GOTO(ret = lydxml_data_check_schema(lydctx, &snode), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100525 }
526 }
527
Michal Vaskob36053d2020-03-26 15:49:30 +0100528 /* create metadata/attributes */
529 if (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vasko52927e22020-03-16 17:26:14 +0100530 if (snode) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100531 ret = lydxml_metadata(xmlctx, snode, lydctx->options & LYD_OPT_STRICT, &lydctx->unres_meta_type, &meta);
Michal Vasko52927e22020-03-16 17:26:14 +0100532 LY_CHECK_GOTO(ret, cleanup);
533 } else {
Michal Vaskob36053d2020-03-26 15:49:30 +0100534 assert(lydctx->options & LYD_OPT_OPAQ);
535 ret = lydxml_attrs(xmlctx, &attr);
536 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100537 }
Michal Vasko8d544252020-03-02 10:19:52 +0100538 }
539
Michal Vaskob36053d2020-03-26 15:49:30 +0100540 assert(xmlctx->status == LYXML_ELEM_CONTENT);
Michal Vasko52927e22020-03-16 17:26:14 +0100541 if (!snode) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100542 assert(lydctx->options & LYD_OPT_OPAQ);
Michal Vasko52927e22020-03-16 17:26:14 +0100543
Michal Vaskob36053d2020-03-26 15:49:30 +0100544 if (xmlctx->ws_only) {
545 /* ignore WS-only value */
546 xmlctx->value_len = 0;
547 val_prefs = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100548 } else {
Michal Vaskob36053d2020-03-26 15:49:30 +0100549 /* get value prefixes */
550 ret = lyxml_get_prefixes(xmlctx, xmlctx->value, xmlctx->value_len, &val_prefs);
Michal Vasko52927e22020-03-16 17:26:14 +0100551 LY_CHECK_GOTO(ret, cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200552 }
Michal Vasko90932a92020-02-12 14:33:03 +0100553
554 /* create node */
Michal Vaskob36053d2020-03-26 15:49:30 +0100555 ret = lyd_create_opaq(ctx, name, name_len, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic, LYD_XML,
556 val_prefs, prefix, prefix_len, ns->uri, &cur);
557 LY_CHECK_GOTO(ret, cleanup);
558
559 /* parser next */
560 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
561
562 /* process children */
563 if (xmlctx->status == LYXML_ELEMENT) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100564 ret = lydxml_data_r(lydctx, (struct lyd_node_inner *)cur, lyd_node_children_p(cur));
Michal Vaskob36053d2020-03-26 15:49:30 +0100565 LY_CHECK_GOTO(ret, cleanup);
566 }
567 } else if (snode->nodetype & LYD_NODE_TERM) {
568 /* create node */
569 ret = lyd_create_term(snode, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic, lydxml_resolve_prefix,
570 xmlctx, LYD_XML, &cur);
Radek Krejcie553e6d2019-06-07 15:33:18 +0200571 if (ret == LY_EINCOMPLETE) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100572 if (!(lydctx->options & LYD_OPT_PARSE_ONLY)) {
573 ly_set_add(&lydctx->unres_node_type, cur, LY_SET_OPT_USEASLIST);
Michal Vasko9b368d32020-02-14 13:53:31 +0100574 }
Radek Krejcie553e6d2019-06-07 15:33:18 +0200575 } else if (ret) {
Radek Krejcie553e6d2019-06-07 15:33:18 +0200576 goto cleanup;
577 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100578
579 if (parent && (cur->schema->flags & LYS_KEY)) {
580 /* check the key order, the anchor must always be the last child */
Michal Vasko52927e22020-03-16 17:26:14 +0100581 anchor = lyd_get_prev_key_anchor(parent->child, cur->schema);
582 if ((!anchor && parent->child) || (anchor && anchor->next)) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100583 if (lydctx->options & LYD_OPT_STRICT) {
584 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 +0100585 cur->schema->name);
586 ret = LY_EVALID;
587 goto cleanup;
588 } else {
Michal Vaskob36053d2020-03-26 15:49:30 +0100589 LOGWRN(ctx, "Invalid position of the key \"%s\" in a list.", cur->schema->name);
Michal Vasko9b368d32020-02-14 13:53:31 +0100590 }
591 }
592 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100593
594 /* parser next */
595 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
596
597 /* no children expected */
598 if (xmlctx->status == LYXML_ELEMENT) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100599 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Child element \"%.*s\" inside a terminal node \"%s\" found.",
600 xmlctx->name_len, xmlctx->name, snode->name);
Michal Vasko44685da2020-03-17 15:38:06 +0100601 ret = LY_EVALID;
602 goto cleanup;
Michal Vaskob36053d2020-03-26 15:49:30 +0100603 }
604 } else if (snode->nodetype & LYD_NODE_INNER) {
605 if (!xmlctx->ws_only) {
606 /* value in inner node */
Michal Vasko1bf09392020-03-27 12:38:10 +0100607 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Text value \"%.*s\" inside an inner node \"%s\" found.",
608 xmlctx->value_len, xmlctx->value, snode->name);
Michal Vaskob36053d2020-03-26 15:49:30 +0100609 ret = LY_EVALID;
610 goto cleanup;
Radek Krejcie7b95092019-05-15 11:03:07 +0200611 }
Michal Vasko90932a92020-02-12 14:33:03 +0100612
613 /* create node */
614 ret = lyd_create_inner(snode, &cur);
615 LY_CHECK_GOTO(ret, cleanup);
616
Michal Vaskob36053d2020-03-26 15:49:30 +0100617 /* parser next */
618 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
619
Radek Krejciee4cab22019-07-17 17:07:47 +0200620 /* process children */
Michal Vaskob36053d2020-03-26 15:49:30 +0100621 if (xmlctx->status == LYXML_ELEMENT) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100622 ret = lydxml_data_r(lydctx, (struct lyd_node_inner *)cur, lyd_node_children_p(cur));
Michal Vasko9f96a052020-03-10 09:41:45 +0100623 LY_CHECK_GOTO(ret, cleanup);
624 }
625
626 if (snode->nodetype == LYS_LIST) {
627 /* check all keys exist */
Michal Vasko44685da2020-03-17 15:38:06 +0100628 LY_CHECK_GOTO(ret = lyd_parse_check_keys(cur), cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200629 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100630
Michal Vaskob36053d2020-03-26 15:49:30 +0100631 if (!(lydctx->options & LYD_OPT_PARSE_ONLY)) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100632 /* new node validation, autodelete CANNOT occur, all nodes are new */
633 ret = lyd_validate_new(lyd_node_children_p(cur), snode, NULL);
634 LY_CHECK_GOTO(ret, cleanup);
635
Michal Vasko9b368d32020-02-14 13:53:31 +0100636 /* add any missing default children */
Michal Vaskob1b5c262020-03-05 14:29:47 +0100637 ret = lyd_validate_defaults_r((struct lyd_node_inner *)cur, lyd_node_children_p(cur), NULL, NULL,
Michal Vaskob36053d2020-03-26 15:49:30 +0100638 &lydctx->unres_node_type, &lydctx->when_check, lydctx->options);
Michal Vasko9b368d32020-02-14 13:53:31 +0100639 LY_CHECK_GOTO(ret, cleanup);
640 }
641
Michal Vasko9b368d32020-02-14 13:53:31 +0100642 if (snode->nodetype == LYS_LIST) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100643 /* hash now that all keys should be parsed, rehash for key-less list */
Michal Vasko9b368d32020-02-14 13:53:31 +0100644 lyd_hash(cur);
Michal Vasko1bf09392020-03-27 12:38:10 +0100645 } else if (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
646 /* rememeber the RPC/action/notification */
647 lydctx->op_ntf = cur;
Michal Vasko9b368d32020-02-14 13:53:31 +0100648 }
Radek Krejciee4cab22019-07-17 17:07:47 +0200649 } else if (snode->nodetype & LYD_NODE_ANY) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100650 if (!xmlctx->ws_only) {
651 /* value in inner node */
Michal Vasko1bf09392020-03-27 12:38:10 +0100652 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Text value \"%.*s\" inside an any node \"%s\" found.",
653 xmlctx->value_len, xmlctx->value, snode->name);
Michal Vaskob36053d2020-03-26 15:49:30 +0100654 ret = LY_EVALID;
655 goto cleanup;
Radek Krejciee4cab22019-07-17 17:07:47 +0200656 }
Michal Vasko90932a92020-02-12 14:33:03 +0100657
Michal Vaskob36053d2020-03-26 15:49:30 +0100658 /* parser next */
659 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
660
Michal Vasko52927e22020-03-16 17:26:14 +0100661 /* parse any data tree with correct options */
Michal Vaskob36053d2020-03-26 15:49:30 +0100662 prev_opts = lydctx->options;
663 lydctx->options &= ~LYD_OPT_STRICT;
664 lydctx->options |= LYD_OPT_OPAQ;
Michal Vasko52927e22020-03-16 17:26:14 +0100665 anchor = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100666 ret = lydxml_data_r(lydctx, NULL, &anchor);
Michal Vaskob36053d2020-03-26 15:49:30 +0100667 lydctx->options = prev_opts;
Michal Vasko52927e22020-03-16 17:26:14 +0100668 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko90932a92020-02-12 14:33:03 +0100669
670 /* create node */
Michal Vasko52927e22020-03-16 17:26:14 +0100671 ret = lyd_create_any(snode, anchor, LYD_ANYDATA_DATATREE, &cur);
672 LY_CHECK_GOTO(ret, cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200673 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100674 assert(cur);
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200675
Michal Vasko1bf09392020-03-27 12:38:10 +0100676 /* add/correct flags */
Michal Vasko52927e22020-03-16 17:26:14 +0100677 if (snode) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100678 lydxml_data_flags(lydctx, cur, &meta);
Michal Vasko8d544252020-03-02 10:19:52 +0100679 }
680
Michal Vasko52927e22020-03-16 17:26:14 +0100681 /* add metadata/attributes */
682 if (snode) {
Michal Vasko5ab0d5c2020-06-29 11:48:05 +0200683 LY_LIST_FOR(meta, m) {
684 m->parent = cur;
685 }
Michal Vasko52927e22020-03-16 17:26:14 +0100686 cur->meta = meta;
687 meta = NULL;
688 } else {
689 assert(!cur->schema);
Michal Vasko5ab0d5c2020-06-29 11:48:05 +0200690 LY_LIST_FOR(attr, a) {
691 a->parent = (struct lyd_node_opaq *)cur;
692 }
Michal Vasko52927e22020-03-16 17:26:14 +0100693 ((struct lyd_node_opaq *)cur)->attr = attr;
694 attr = NULL;
695 }
Radek Krejcib6f7ae52019-07-19 10:31:42 +0200696
Michal Vasko90932a92020-02-12 14:33:03 +0100697 /* insert */
Michal Vaskob1b5c262020-03-05 14:29:47 +0100698 lyd_insert_node((struct lyd_node *)parent, first, cur);
Michal Vasko90932a92020-02-12 14:33:03 +0100699 cur = NULL;
Michal Vaskob36053d2020-03-26 15:49:30 +0100700
701 /* parser next */
702 assert(xmlctx->status == LYXML_ELEM_CLOSE);
703 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200704 }
705
Michal Vasko90932a92020-02-12 14:33:03 +0100706 /* success */
707 ret = LY_SUCCESS;
708
Radek Krejcie7b95092019-05-15 11:03:07 +0200709cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100710 lyd_free_meta(ctx, meta, 1);
711 ly_free_attr(ctx, attr, 1);
Michal Vasko90932a92020-02-12 14:33:03 +0100712 lyd_free_tree(cur);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100713 if (ret && *first) {
714 lyd_free_siblings(*first);
715 *first = NULL;
Michal Vasko90932a92020-02-12 14:33:03 +0100716 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200717 return ret;
718}
719
720LY_ERR
Michal Vasko1bf09392020-03-27 12:38:10 +0100721lyd_parse_xml_data(const struct ly_ctx *ctx, const char *data, int options, struct lyd_node **tree)
Radek Krejcie7b95092019-05-15 11:03:07 +0200722{
Radek Krejci18a57d92019-07-25 14:01:42 +0200723 LY_ERR ret = LY_SUCCESS;
Michal Vaskob36053d2020-03-26 15:49:30 +0100724 struct lyd_xml_ctx lydctx = {0};
Michal Vaskob1b5c262020-03-05 14:29:47 +0100725 uint32_t i = 0;
726 const struct lys_module *mod;
727 struct lyd_node *first, *next, **first2;
Radek Krejcie7b95092019-05-15 11:03:07 +0200728
Michal Vaskob36053d2020-03-26 15:49:30 +0100729 /* init context and tree */
730 LY_CHECK_GOTO(ret = lyxml_ctx_new(ctx, data, &lydctx.xmlctx), cleanup);
731 lydctx.options = options;
Michal Vaskob1b5c262020-03-05 14:29:47 +0100732 *tree = NULL;
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200733
Michal Vaskob1b5c262020-03-05 14:29:47 +0100734 /* parse XML data */
Michal Vasko1bf09392020-03-27 12:38:10 +0100735 LY_CHECK_GOTO(ret = lydxml_data_r(&lydctx, NULL, tree), cleanup);
Michal Vaskocde73ac2019-11-14 16:10:27 +0100736
Michal Vasko9b368d32020-02-14 13:53:31 +0100737 if (!(options & LYD_OPT_PARSE_ONLY)) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100738 next = *tree;
739 while (1) {
740 if (options & LYD_VALOPT_DATA_ONLY) {
741 mod = lyd_data_next_module(&next, &first);
742 } else {
743 mod = lyd_mod_next_module(next, NULL, 0, ctx, &i, &first);
744 }
745 if (!mod) {
746 break;
747 }
748 if (first == *tree) {
749 /* make sure first2 changes are carried to tree */
750 first2 = tree;
751 } else {
752 first2 = &first;
753 }
Michal Vasko9b368d32020-02-14 13:53:31 +0100754
Michal Vaskob1b5c262020-03-05 14:29:47 +0100755 /* validate new top-level nodes, autodelete CANNOT occur, all nodes are new */
Michal Vasko1bf09392020-03-27 12:38:10 +0100756 LY_CHECK_GOTO(ret = lyd_validate_new(first2, NULL, mod), cleanup);
Michal Vasko9b368d32020-02-14 13:53:31 +0100757
Michal Vaskob1b5c262020-03-05 14:29:47 +0100758 /* add all top-level defaults for this module */
Michal Vaskob36053d2020-03-26 15:49:30 +0100759 ret = lyd_validate_defaults_r(NULL, first2, NULL, mod, &lydctx.unres_node_type, &lydctx.when_check,
Michal Vasko52927e22020-03-16 17:26:14 +0100760 options & LYD_VALOPT_MASK);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100761 LY_CHECK_GOTO(ret, cleanup);
762
763 /* finish incompletely validated terminal values/attributes and when conditions */
Michal Vaskob36053d2020-03-26 15:49:30 +0100764 ret = lyd_validate_unres(tree, &lydctx.when_check, &lydctx.unres_node_type, &lydctx.unres_meta_type, LYD_XML,
765 lydxml_resolve_prefix, lydctx.xmlctx);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100766 LY_CHECK_GOTO(ret, cleanup);
767
768 /* perform final validation that assumes the data tree is final */
Michal Vaskofea12c62020-03-30 11:00:15 +0200769 LY_CHECK_GOTO(ret = lyd_validate_final_r(*first2, NULL, mod, options & LYD_VALOPT_MASK), cleanup);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100770 }
Michal Vaskocde73ac2019-11-14 16:10:27 +0100771 }
772
Michal Vaskocde73ac2019-11-14 16:10:27 +0100773cleanup:
Michal Vasko9b368d32020-02-14 13:53:31 +0100774 /* there should be no unresolved types stored */
Michal Vaskob36053d2020-03-26 15:49:30 +0100775 assert(!(options & LYD_OPT_PARSE_ONLY) || (!lydctx.unres_node_type.count && !lydctx.unres_meta_type.count
776 && !lydctx.when_check.count));
Michal Vasko9b368d32020-02-14 13:53:31 +0100777
Michal Vaskob36053d2020-03-26 15:49:30 +0100778 ly_set_erase(&lydctx.unres_node_type, NULL);
779 ly_set_erase(&lydctx.unres_meta_type, NULL);
780 ly_set_erase(&lydctx.when_check, NULL);
781 lyxml_ctx_free(lydctx.xmlctx);
Michal Vasko9f96a052020-03-10 09:41:45 +0100782 if (ret) {
783 lyd_free_all(*tree);
784 *tree = NULL;
785 }
786 return ret;
787}
Michal Vasko1bf09392020-03-27 12:38:10 +0100788
789static LY_ERR
790lydxml_envelope(struct lyxml_ctx *xmlctx, const char *name, const char *uri, struct lyd_node **envp)
791{
792 LY_ERR ret = LY_SUCCESS;
793 const struct lyxml_ns *ns = NULL;
794 struct ly_attr *attr = NULL;
795 const char *prefix;
796 size_t prefix_len;
797
798 *envp = NULL;
799
800 assert(xmlctx->status == LYXML_ELEMENT);
801 if (ly_strncmp(name, xmlctx->name, xmlctx->name_len)) {
802 /* not the expected element */
803 return LY_SUCCESS;
804 }
805
806 prefix = xmlctx->prefix;
807 prefix_len = xmlctx->prefix_len;
808 ns = lyxml_ns_get(xmlctx, prefix, prefix_len);
809 if (!ns) {
810 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
811 prefix_len, prefix);
812 return LY_EVALID;
813 } else if (strcmp(ns->uri, uri)) {
814 /* different namespace */
815 return LY_SUCCESS;
816 }
817
818 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
819
820 /* create attributes */
821 if (xmlctx->status == LYXML_ATTRIBUTE) {
822 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
823 }
824
825 if (!xmlctx->ws_only) {
826 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Unexpected value \"%.*s\" in the \"%s\" element.",
827 xmlctx->value_len, xmlctx->value, name);
828 ret = LY_EVALID;
829 goto cleanup;
830 }
831
832 /* parser next element */
833 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
834
835 /* create node */
836 ret = lyd_create_opaq(xmlctx->ctx, name, strlen(name), "", 0, NULL, LYD_XML, NULL, prefix, prefix_len, uri, envp);
837 LY_CHECK_GOTO(ret, cleanup);
838
839 /* assign atributes */
840 ((struct lyd_node_opaq *)(*envp))->attr = attr;
841 attr = NULL;
842
843cleanup:
844 ly_free_attr(xmlctx->ctx, attr, 1);
845 return ret;
846}
847
848LY_ERR
849lyd_parse_xml_rpc(const struct ly_ctx *ctx, const char *data, struct lyd_node **tree, struct lyd_node **op)
850{
851 LY_ERR ret = LY_SUCCESS;
852 struct lyd_xml_ctx lydctx = {0};
853 struct lyd_node *rpc_e = NULL, *act_e = NULL;
854
855 /* init */
856 LY_CHECK_GOTO(ret = lyxml_ctx_new(ctx, data, &lydctx.xmlctx), cleanup);
857 lydctx.options = LYD_OPT_PARSE_ONLY | LYD_OPT_STRICT;
858 lydctx.int_opts = LYD_INTOPT_RPC;
859 *tree = NULL;
Michal Vaskocc048b22020-03-27 15:52:38 +0100860 if (op) {
861 *op = NULL;
862 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100863
864 /* parse "rpc", if any */
865 LY_CHECK_GOTO(ret = lydxml_envelope(lydctx.xmlctx, "rpc", "urn:ietf:params:xml:ns:netconf:base:1.0", &rpc_e), cleanup);
866
867 if (rpc_e) {
868 /* parse "action", if any */
869 LY_CHECK_GOTO(ret = lydxml_envelope(lydctx.xmlctx, "action", "urn:ietf:params:xml:ns:yang:1", &act_e), cleanup);
870 }
871
872 /* parse the rest of data normally */
873 LY_CHECK_GOTO(ret = lydxml_data_r(&lydctx, NULL, tree), cleanup);
874
875 /* make sure we have parsed some operation */
876 if (!lydctx.op_ntf) {
877 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_DATA, "Missing the \"rpc\"/\"action\" node.");
878 ret = LY_EVALID;
879 goto cleanup;
880 }
881
882 /* finish XML parsing and check operation type */
883 if (act_e) {
884 if (lydctx.xmlctx->status != LYXML_ELEM_CLOSE) {
885 assert(lydctx.xmlctx->status == LYXML_ELEMENT);
886 LOGVAL(ctx, LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"action\".",
887 lydctx.xmlctx->name_len, lydctx.xmlctx->name);
888 ret = LY_EVALID;
889 goto cleanup;
890 } else if (lydctx.op_ntf->schema->nodetype != LYS_ACTION) {
891 LOGVAL(ctx, LY_VLOG_LYD, lydctx.op_ntf, LYVE_DATA, "Unexpected %s element, an \"action\" expected.",
892 lys_nodetype2str(lydctx.op_ntf->schema->nodetype));
893 ret = LY_EVALID;
894 goto cleanup;
895 }
896 LY_CHECK_GOTO(ret = lyxml_ctx_next(lydctx.xmlctx), cleanup);
897 }
898 if (rpc_e) {
899 if (lydctx.xmlctx->status != LYXML_ELEM_CLOSE) {
900 assert(lydctx.xmlctx->status == LYXML_ELEMENT);
901 LOGVAL(ctx, LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"rpc\".",
902 lydctx.xmlctx->name_len, lydctx.xmlctx->name);
903 ret = LY_EVALID;
904 goto cleanup;
905 } else if (!act_e && (lydctx.op_ntf->schema->nodetype != LYS_RPC)) {
906 LOGVAL(ctx, LY_VLOG_LYD, lydctx.op_ntf, LYVE_DATA, "Unexpected %s element, an \"rpc\" expected.",
907 lys_nodetype2str(lydctx.op_ntf->schema->nodetype));
908 ret = LY_EVALID;
909 goto cleanup;
910 }
911 LY_CHECK_GOTO(ret = lyxml_ctx_next(lydctx.xmlctx), cleanup);
912 }
913
Michal Vaskocc048b22020-03-27 15:52:38 +0100914 if (op) {
915 *op = lydctx.op_ntf;
916 }
Michal Vasko1bf09392020-03-27 12:38:10 +0100917 assert(*tree);
918 if (act_e) {
919 /* connect to the action */
920 lyd_insert_node(act_e, NULL, *tree);
921 *tree = act_e;
922 }
923 if (rpc_e) {
924 /* connect to the rpc */
925 lyd_insert_node(rpc_e, NULL, *tree);
926 *tree = rpc_e;
927 }
928
929cleanup:
930 /* we have used parse_only flag */
931 assert(!lydctx.unres_node_type.count && !lydctx.unres_meta_type.count && !lydctx.when_check.count);
932 lyxml_ctx_free(lydctx.xmlctx);
933 if (ret) {
934 lyd_free_all(*tree);
935 lyd_free_tree(act_e);
936 lyd_free_tree(rpc_e);
937 *tree = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100938 }
939 return ret;
940}
Michal Vaskoa8edff02020-03-27 14:47:01 +0100941
942static LY_ERR
943lydxml_notif_envelope(struct lyxml_ctx *xmlctx, struct lyd_node **envp)
944{
945 LY_ERR ret = LY_SUCCESS;
946 const struct lyxml_ns *ns = NULL;
947 struct ly_attr *attr = NULL;
948 struct lyd_node *et;
949 const char *prefix;
950 size_t prefix_len;
951
952 *envp = NULL;
953
954 /* container envelope */
955 LY_CHECK_GOTO(ret = lydxml_envelope(xmlctx, "notification", "urn:ietf:params:xml:ns:netconf:notification:1.0",
956 envp), cleanup);
957
958 /* no envelope, fine */
959 if (!*envp) {
960 goto cleanup;
961 }
962
963 /* child "eventTime" */
964 if ((xmlctx->status != LYXML_ELEMENT) || ly_strncmp("eventTime", xmlctx->name, xmlctx->name_len)) {
965 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Missing the \"eventTime\" element.");
966 ret = LY_EVALID;
967 goto cleanup;
968 }
969
970 prefix = xmlctx->prefix;
971 prefix_len = xmlctx->prefix_len;
972 ns = lyxml_ns_get(xmlctx, prefix, prefix_len);
973 if (!ns) {
974 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
975 prefix_len, prefix);
976 ret = LY_EVALID;
977 goto cleanup;
978 } else if (strcmp(ns->uri, "urn:ietf:params:xml:ns:netconf:notification:1.0")) {
979 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Invalid namespace \"%s\" of \"eventTime\".",
980 ns->uri);
981 ret = LY_EVALID;
982 goto cleanup;
983 }
984
985 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
986
987 /* create attributes */
988 if (xmlctx->status == LYXML_ATTRIBUTE) {
989 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
990 }
991
992 /* validate value */
993 /* TODO */
994 /*if (!xmlctx->ws_only) {
995 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Unexpected value \"%.*s\" in the \"%s\" element.",
996 xmlctx->value_len, xmlctx->value, name);
997 ret = LY_EVALID;
998 goto cleanup;
999 }*/
1000
1001 /* create node */
1002 ret = lyd_create_opaq(xmlctx->ctx, "eventTime", 9, xmlctx->value, xmlctx->value_len, NULL, LYD_XML, NULL,
1003 prefix, prefix_len, ns->uri, &et);
1004 LY_CHECK_GOTO(ret, cleanup);
1005
1006 /* assign atributes */
1007 ((struct lyd_node_opaq *)et)->attr = attr;
1008 attr = NULL;
1009
1010 /* insert */
1011 lyd_insert_node(*envp, NULL, et);
1012
1013 /* finish parsing */
1014 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
1015 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1016 assert(xmlctx->status == LYXML_ELEMENT);
1017 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"eventTime\".",
1018 xmlctx->name_len, xmlctx->name);
1019 ret = LY_EVALID;
1020 goto cleanup;
1021 }
1022 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
1023
1024cleanup:
1025 if (ret) {
1026 lyd_free_tree(*envp);
1027 ly_free_attr(xmlctx->ctx, attr, 1);
1028 }
1029 return ret;
1030}
1031
1032LY_ERR
1033lyd_parse_xml_notif(const struct ly_ctx *ctx, const char *data, struct lyd_node **tree, struct lyd_node **ntf)
1034{
1035 LY_ERR ret = LY_SUCCESS;
1036 struct lyd_xml_ctx lydctx = {0};
1037 struct lyd_node *ntf_e = NULL;
1038
1039 /* init */
1040 LY_CHECK_GOTO(ret = lyxml_ctx_new(ctx, data, &lydctx.xmlctx), cleanup);
1041 lydctx.options = LYD_OPT_PARSE_ONLY | LYD_OPT_STRICT;
1042 lydctx.int_opts = LYD_INTOPT_NOTIF;
1043 *tree = NULL;
Michal Vaskocc048b22020-03-27 15:52:38 +01001044 if (ntf) {
1045 *ntf = NULL;
1046 }
Michal Vaskoa8edff02020-03-27 14:47:01 +01001047
1048 /* parse "notification" and "eventTime", if present */
1049 LY_CHECK_GOTO(ret = lydxml_notif_envelope(lydctx.xmlctx, &ntf_e), cleanup);
1050
1051 /* parse the rest of data normally */
1052 LY_CHECK_GOTO(ret = lydxml_data_r(&lydctx, NULL, tree), cleanup);
1053
1054 /* make sure we have parsed some notification */
1055 if (!lydctx.op_ntf) {
1056 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_DATA, "Missing the \"notification\" node.");
1057 ret = LY_EVALID;
1058 goto cleanup;
1059 }
1060
1061 /* finish XML parsing */
1062 if (ntf_e) {
1063 if (lydctx.xmlctx->status != LYXML_ELEM_CLOSE) {
1064 assert(lydctx.xmlctx->status == LYXML_ELEMENT);
1065 LOGVAL(ctx, LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"notification\".",
1066 lydctx.xmlctx->name_len, lydctx.xmlctx->name);
1067 ret = LY_EVALID;
1068 goto cleanup;
1069 }
1070 LY_CHECK_GOTO(ret = lyxml_ctx_next(lydctx.xmlctx), cleanup);
1071 }
1072
Michal Vaskocc048b22020-03-27 15:52:38 +01001073 if (ntf) {
1074 *ntf = lydctx.op_ntf;
1075 }
Michal Vaskoa8edff02020-03-27 14:47:01 +01001076 assert(*tree);
1077 if (ntf_e) {
1078 /* connect to the notification */
1079 lyd_insert_node(ntf_e, NULL, *tree);
1080 *tree = ntf_e;
1081 }
1082
1083cleanup:
1084 /* we have used parse_only flag */
1085 assert(!lydctx.unres_node_type.count && !lydctx.unres_meta_type.count && !lydctx.when_check.count);
1086 lyxml_ctx_free(lydctx.xmlctx);
1087 if (ret) {
1088 lyd_free_all(*tree);
1089 lyd_free_tree(ntf_e);
1090 *tree = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001091 }
1092 return ret;
1093}
Michal Vasko1ce933a2020-03-30 12:38:22 +02001094
1095LY_ERR
1096lyd_parse_xml_reply(const struct lyd_node *request, const char *data, struct lyd_node **tree, struct lyd_node **op)
1097{
1098 LY_ERR ret = LY_SUCCESS;
1099 struct lyd_xml_ctx lydctx = {0};
1100 struct lyd_node *rpcr_e = NULL, *iter, *req_op, *rep_op;
1101
1102 /* init */
1103 LY_CHECK_GOTO(ret = lyxml_ctx_new(LYD_NODE_CTX(request), data, &lydctx.xmlctx), cleanup);
1104 lydctx.options = LYD_OPT_PARSE_ONLY | LYD_OPT_STRICT;
1105 lydctx.int_opts = LYD_INTOPT_REPLY;
1106 *tree = NULL;
1107 if (op) {
1108 *op = NULL;
1109 }
1110
1111 /* find request OP */
1112 LYD_TREE_DFS_BEGIN((struct lyd_node *)request, iter, req_op) {
1113 if (req_op->schema->nodetype & (LYS_RPC | LYS_ACTION)) {
1114 break;
1115 }
1116 LYD_TREE_DFS_END(request, iter, req_op);
1117 }
1118 if (!(req_op->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
1119 LOGERR(LYD_NODE_CTX(request), LY_EINVAL, "No RPC/action in the request found.");
1120 ret = LY_EINVAL;
1121 goto cleanup;
1122 }
1123
1124 /* duplicate request OP with parents */
1125 rep_op = lyd_dup(req_op, NULL, LYD_DUP_WITH_PARENTS);
1126 LY_CHECK_ERR_GOTO(!rep_op, ret = LY_EMEM, cleanup);
1127
1128 /* parse "rpc-reply", if any */
1129 LY_CHECK_GOTO(ret = lydxml_envelope(lydctx.xmlctx, "rpc-reply", "urn:ietf:params:xml:ns:netconf:base:1.0", &rpcr_e), cleanup);
1130
1131 /* parse the rest of data normally but connect them to the duplicated operation */
1132 LY_CHECK_GOTO(ret = lydxml_data_r(&lydctx, (struct lyd_node_inner *)rep_op, lyd_node_children_p(rep_op)), cleanup);
1133
1134 /* finish XML parsing and check operation type */
1135 if (rpcr_e) {
1136 if (lydctx.xmlctx->status != LYXML_ELEM_CLOSE) {
1137 assert(lydctx.xmlctx->status == LYXML_ELEMENT);
1138 LOGVAL(LYD_NODE_CTX(request), LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX,
1139 "Unexpected sibling element \"%.*s\" of \"rpc-reply\".", lydctx.xmlctx->name_len, lydctx.xmlctx->name);
1140 ret = LY_EVALID;
1141 goto cleanup;
1142 }
1143 LY_CHECK_GOTO(ret = lyxml_ctx_next(lydctx.xmlctx), cleanup);
1144 }
1145
1146 if (op) {
1147 *op = rep_op;
1148 }
1149 for (iter = rep_op; iter->parent; iter = (struct lyd_node *)iter->parent);
1150 *tree = iter;
1151 if (rpcr_e) {
1152 /* connect to the operation */
1153 lyd_insert_node(rpcr_e, NULL, *tree);
1154 *tree = rpcr_e;
1155 }
1156
1157cleanup:
1158 /* we have used parse_only flag */
1159 assert(!lydctx.unres_node_type.count && !lydctx.unres_meta_type.count && !lydctx.when_check.count);
1160 lyxml_ctx_free(lydctx.xmlctx);
1161 if (ret) {
1162 lyd_free_all(rep_op);
1163 lyd_free_tree(rpcr_e);
1164 }
1165 return ret;
1166}