blob: cb4fb82ff15404f07c3a4152e749ab4f10676a1f [file] [log] [blame]
Radek Krejcie7b95092019-05-15 11:03:07 +02001/**
2 * @file parser_xml.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief XML data parser for libyang
5 *
6 * Copyright (c) 2019 CESNET, z.s.p.o.
7 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
14
Michal Vasko69730152020-10-09 16:30:07 +020015#include <assert.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020016#include <stdint.h>
17#include <stdlib.h>
18#include <string.h>
19
Radek Krejci535ea9f2020-05-29 16:01:05 +020020#include "common.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020021#include "context.h"
Michal Vaskoafac7822020-10-20 14:22:26 +020022#include "in_internal.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020023#include "log.h"
Radek Krejci7931b192020-06-25 17:05:03 +020024#include "parser_data.h"
25#include "parser_internal.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020026#include "set.h"
Radek Krejci47fab892020-11-05 17:02:41 +010027#include "tree_data.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020028#include "tree_data_internal.h"
29#include "tree_schema.h"
Michal Vaskocde73ac2019-11-14 16:10:27 +010030#include "validation.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020031#include "xml.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 Krejci1798aae2020-07-14 13:26:06 +020035 *
36 * Note that the structure maps to the lyd_ctx which is common for all the data parsers
Radek Krejcie7b95092019-05-15 11:03:07 +020037 */
38struct lyd_xml_ctx {
Radek Krejci1798aae2020-07-14 13:26:06 +020039 uint32_t parse_options; /**< various @ref dataparseroptions. */
40 uint32_t validate_options; /**< various @ref datavalidationoptions. */
41 uint32_t int_opts; /**< internal data parser options */
42 uint32_t path_len; /**< used bytes in the path buffer */
43 char path[LYD_PARSER_BUFSIZE]; /**< buffer for the generated path */
Michal Vasko49c39d82020-11-06 17:20:27 +010044 struct ly_set node_types; /**< set of nodes validated with LY_EINCOMPLETE result */
45 struct ly_set meta_types; /**< set of metadata validated with LY_EINCOMPLETE result */
46 struct ly_set node_when; /**< set of nodes with "when" conditions */
Radek Krejci1798aae2020-07-14 13:26:06 +020047 struct lyd_node *op_node; /**< if an RPC/action/notification is being parsed, store the pointer to it */
Radek Krejcie7b95092019-05-15 11:03:07 +020048
Radek Krejci1798aae2020-07-14 13:26:06 +020049 /* callbacks */
50 lyd_ctx_free_clb free; /* destructor */
Radek Krejci1798aae2020-07-14 13:26:06 +020051
52 struct lyxml_ctx *xmlctx; /**< XML context */
Radek Krejcie7b95092019-05-15 11:03:07 +020053};
54
Radek Krejci1798aae2020-07-14 13:26:06 +020055void
56lyd_xml_ctx_free(struct lyd_ctx *lydctx)
57{
58 struct lyd_xml_ctx *ctx = (struct lyd_xml_ctx *)lydctx;
59
60 lyd_ctx_free(lydctx);
61 lyxml_ctx_free(ctx->xmlctx);
62 free(ctx);
63}
64
Radek Krejcie7b95092019-05-15 11:03:07 +020065static LY_ERR
Michal Vaskofeca4fb2020-10-05 08:58:40 +020066lydxml_metadata(struct lyd_xml_ctx *lydctx, struct lyd_meta **meta)
Radek Krejcie7b95092019-05-15 11:03:07 +020067{
Michal Vaskob36053d2020-03-26 15:49:30 +010068 LY_ERR ret = LY_EVALID;
Radek Krejci28681fa2019-09-06 13:08:45 +020069 const struct lyxml_ns *ns;
70 struct lys_module *mod;
Michal Vaskob36053d2020-03-26 15:49:30 +010071 const char *name;
72 size_t name_len;
Radek Krejci1798aae2020-07-14 13:26:06 +020073 struct lyxml_ctx *xmlctx = lydctx->xmlctx;
Radek Krejci28681fa2019-09-06 13:08:45 +020074
Michal Vaskob36053d2020-03-26 15:49:30 +010075 *meta = NULL;
Radek Krejci28681fa2019-09-06 13:08:45 +020076
Michal Vaskob36053d2020-03-26 15:49:30 +010077 while (xmlctx->status == LYXML_ATTRIBUTE) {
78 if (!xmlctx->prefix_len) {
Radek Krejci28681fa2019-09-06 13:08:45 +020079 /* in XML, all attributes must be prefixed
80 * TODO exception for NETCONF filters which are supposed to map to the ietf-netconf without prefix */
Radek Krejci1798aae2020-07-14 13:26:06 +020081 if (lydctx->parse_options & LYD_PARSE_STRICT) {
Michal Vasko52927e22020-03-16 17:26:14 +010082 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Missing mandatory prefix for XML metadata \"%.*s\".",
Michal Vasko69730152020-10-09 16:30:07 +020083 xmlctx->name_len, xmlctx->name);
Michal Vaskob36053d2020-03-26 15:49:30 +010084 goto cleanup;
Radek Krejci28681fa2019-09-06 13:08:45 +020085 }
Michal Vaskob36053d2020-03-26 15:49:30 +010086
Radek Krejci28681fa2019-09-06 13:08:45 +020087skip_attr:
Michal Vaskob36053d2020-03-26 15:49:30 +010088 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
89 assert(xmlctx->status == LYXML_ATTR_CONTENT);
90 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejci28681fa2019-09-06 13:08:45 +020091 continue;
92 }
93
94 /* get namespace of the attribute to find its annotation definition */
Michal Vaskoc8a230d2020-08-14 12:17:10 +020095 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
Radek Krejci28681fa2019-09-06 13:08:45 +020096 if (!ns) {
Michal Vasko52927e22020-03-16 17:26:14 +010097 /* unknown namespace, XML error */
98 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
Michal Vasko69730152020-10-09 16:30:07 +020099 xmlctx->prefix_len, xmlctx->prefix);
Radek Krejci28681fa2019-09-06 13:08:45 +0200100 goto cleanup;
101 }
Michal Vasko52927e22020-03-16 17:26:14 +0100102 mod = ly_ctx_get_module_implemented_ns(xmlctx->ctx, ns->uri);
Radek Krejci28681fa2019-09-06 13:08:45 +0200103 if (!mod) {
104 /* module is not implemented or not present in the schema */
Radek Krejci1798aae2020-07-14 13:26:06 +0200105 if (lydctx->parse_options & LYD_PARSE_STRICT) {
Michal Vasko52927e22020-03-16 17:26:14 +0100106 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +0200107 "Unknown (or not implemented) YANG module with namespace \"%s\" for metadata \"%.*s%s%.*s\".",
108 ns->uri, xmlctx->prefix_len, xmlctx->prefix, xmlctx->prefix_len ? ":" : "", xmlctx->name_len,
109 xmlctx->name);
Michal Vaskob36053d2020-03-26 15:49:30 +0100110 goto cleanup;
Radek Krejci28681fa2019-09-06 13:08:45 +0200111 }
112 goto skip_attr;
113 }
114
Michal Vasko60ea6352020-06-29 13:39:39 +0200115 /* remember meta name and get its content */
Michal Vaskob36053d2020-03-26 15:49:30 +0100116 name = xmlctx->name;
117 name_len = xmlctx->name_len;
118 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
119 assert(xmlctx->status == LYXML_ATTR_CONTENT);
120
121 /* create metadata */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200122 ret = lyd_parser_create_meta((struct lyd_ctx *)lydctx, NULL, meta, mod, name, name_len, xmlctx->value,
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200123 xmlctx->value_len, &xmlctx->dynamic, LY_PREF_XML, &xmlctx->ns, LYD_HINT_DATA);
Radek Krejci1798aae2020-07-14 13:26:06 +0200124 LY_CHECK_GOTO(ret, cleanup);
Michal Vaskob36053d2020-03-26 15:49:30 +0100125
126 /* next attribute */
127 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200128 }
Michal Vasko52927e22020-03-16 17:26:14 +0100129
Radek Krejci28681fa2019-09-06 13:08:45 +0200130 ret = LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200131
132cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100133 if (ret) {
Michal Vasko3a41dff2020-07-15 14:30:28 +0200134 lyd_free_meta_siblings(*meta);
Michal Vaskob36053d2020-03-26 15:49:30 +0100135 *meta = NULL;
Radek Krejci38d85362019-09-05 16:26:38 +0200136 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200137 return ret;
138}
139
Michal Vasko52927e22020-03-16 17:26:14 +0100140static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200141lydxml_attrs(struct lyxml_ctx *xmlctx, struct lyd_attr **attr)
Michal Vasko52927e22020-03-16 17:26:14 +0100142{
143 LY_ERR ret = LY_SUCCESS;
144 const struct lyxml_ns *ns;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100145 void *val_prefix_data;
146 LY_PREFIX_FORMAT format;
Radek Krejci1798aae2020-07-14 13:26:06 +0200147 struct lyd_attr *attr2;
Michal Vaskob36053d2020-03-26 15:49:30 +0100148 const char *name, *prefix;
149 size_t name_len, prefix_len;
Michal Vasko52927e22020-03-16 17:26:14 +0100150
151 assert(attr);
Michal Vaskob36053d2020-03-26 15:49:30 +0100152 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100153
Michal Vaskob36053d2020-03-26 15:49:30 +0100154 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vasko52927e22020-03-16 17:26:14 +0100155 ns = NULL;
Michal Vaskob36053d2020-03-26 15:49:30 +0100156 if (xmlctx->prefix_len) {
Michal Vasko52927e22020-03-16 17:26:14 +0100157 /* get namespace of the attribute */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200158 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
Michal Vasko52927e22020-03-16 17:26:14 +0100159 if (!ns) {
160 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
Michal Vasko69730152020-10-09 16:30:07 +0200161 xmlctx->prefix_len, xmlctx->prefix);
Michal Vasko52927e22020-03-16 17:26:14 +0100162 ret = LY_EVALID;
163 goto cleanup;
164 }
165 }
166
167 if (*attr) {
168 attr2 = *attr;
169 } else {
170 attr2 = NULL;
171 }
172
Michal Vaskob36053d2020-03-26 15:49:30 +0100173 /* remember attr prefix, name, and get its content */
174 prefix = xmlctx->prefix;
175 prefix_len = xmlctx->prefix_len;
176 name = xmlctx->name;
177 name_len = xmlctx->name_len;
178 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
179 assert(xmlctx->status == LYXML_ATTR_CONTENT);
180
Michal Vasko52927e22020-03-16 17:26:14 +0100181 /* get value prefixes */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100182 LY_CHECK_GOTO(ret = ly_store_prefix_data(xmlctx->ctx, xmlctx->value, xmlctx->value_len, LY_PREF_XML,
183 &xmlctx->ns, &format, &val_prefix_data), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100184
185 /* attr2 is always changed to the created attribute */
Michal Vasko501af032020-11-11 20:27:44 +0100186 ret = lyd_create_attr(NULL, &attr2, xmlctx->ctx, name, name_len, prefix, prefix_len, ns ? ns->uri : NULL,
187 ns ? strlen(ns->uri) : 0, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic, format, val_prefix_data, 0);
Michal Vasko52927e22020-03-16 17:26:14 +0100188 LY_CHECK_GOTO(ret, cleanup);
189
190 if (!*attr) {
191 *attr = attr2;
192 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100193
194 /* next attribute */
195 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100196 }
197
198cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100199 if (ret) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200200 lyd_free_attr_siblings(xmlctx->ctx, *attr);
Michal Vaskob36053d2020-03-26 15:49:30 +0100201 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100202 }
Michal Vasko52927e22020-03-16 17:26:14 +0100203 return ret;
204}
205
Michal Vasko44685da2020-03-17 15:38:06 +0100206static LY_ERR
Michal Vaskob36053d2020-03-26 15:49:30 +0100207lydxml_check_list(struct lyxml_ctx *xmlctx, const struct lysc_node *list)
Michal Vasko44685da2020-03-17 15:38:06 +0100208{
Michal Vaskob36053d2020-03-26 15:49:30 +0100209 LY_ERR ret = LY_SUCCESS, r;
210 enum LYXML_PARSER_STATUS next;
Michal Vasko44685da2020-03-17 15:38:06 +0100211 struct ly_set key_set = {0};
212 const struct lysc_node *snode;
Michal Vaskob36053d2020-03-26 15:49:30 +0100213 uint32_t i, parents_count;
Michal Vasko44685da2020-03-17 15:38:06 +0100214
215 assert(list && (list->nodetype == LYS_LIST));
216
217 /* get all keys into a set (keys do not have if-features or anything) */
218 snode = NULL;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100219 while ((snode = lys_getnext(snode, list, NULL, 0)) && (snode->flags & LYS_KEY)) {
Radek Krejci3d92e442020-10-12 12:48:13 +0200220 ret = ly_set_add(&key_set, (void *)snode, 1, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200221 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100222 }
223
Michal Vaskob36053d2020-03-26 15:49:30 +0100224 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vasko44685da2020-03-17 15:38:06 +0100225 /* find key definition */
226 for (i = 0; i < key_set.count; ++i) {
227 snode = (const struct lysc_node *)key_set.objs[i];
Michal Vaskob36053d2020-03-26 15:49:30 +0100228 if (!ly_strncmp(snode->name, xmlctx->name, xmlctx->name_len)) {
Michal Vasko44685da2020-03-17 15:38:06 +0100229 break;
230 }
231 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100232 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100233
234 /* skip attributes */
235 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100236 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
237 assert(xmlctx->status == LYXML_ATTR_CONTENT);
238 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100239 }
240
Michal Vaskob36053d2020-03-26 15:49:30 +0100241 assert(xmlctx->status == LYXML_ELEM_CONTENT);
242 if (i < key_set.count) {
243 /* validate the value */
Michal Vasko713148b2020-11-12 13:10:13 +0100244 r = _lys_value_validate(NULL, snode, xmlctx->value, xmlctx->value_len, LY_PREF_XML, &xmlctx->ns);
Michal Vaskob36053d2020-03-26 15:49:30 +0100245 if (!r) {
246 /* key with a valid value, remove from the set */
247 ly_set_rm_index(&key_set, i, NULL);
Michal Vasko44685da2020-03-17 15:38:06 +0100248 }
249 }
250
Michal Vaskob36053d2020-03-26 15:49:30 +0100251 /* parser next */
252 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100253
Michal Vaskob36053d2020-03-26 15:49:30 +0100254 /* skip any children, resursively */
255 parents_count = xmlctx->elements.count;
256 while ((parents_count < xmlctx->elements.count) || (xmlctx->status == LYXML_ELEMENT)) {
257 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
258 }
259
260 /* parser next, but do not parse closing element of the list because it would remove its namespaces */
261 assert(xmlctx->status == LYXML_ELEM_CLOSE);
262 LY_CHECK_GOTO(ret = lyxml_ctx_peek(xmlctx, &next), cleanup);
263 if (next != LYXML_ELEM_CLOSE) {
264 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
265 }
Michal Vasko44685da2020-03-17 15:38:06 +0100266 }
267
268 if (key_set.count) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100269 /* some keys are missing/did not validate */
Michal Vasko44685da2020-03-17 15:38:06 +0100270 ret = LY_ENOT;
Michal Vasko44685da2020-03-17 15:38:06 +0100271 }
272
273cleanup:
274 ly_set_erase(&key_set, NULL);
275 return ret;
276}
277
Michal Vasko1bf09392020-03-27 12:38:10 +0100278static LY_ERR
279lydxml_data_skip(struct lyxml_ctx *xmlctx)
280{
281 uint32_t parents_count;
282
283 /* remember current number of parents */
284 parents_count = xmlctx->elements.count;
285
286 /* skip after the content */
287 while (xmlctx->status != LYXML_ELEM_CONTENT) {
288 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
289 }
290 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
291
292 /* skip all children elements, recursively, if any */
293 while (parents_count < xmlctx->elements.count) {
294 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
295 }
296
297 /* close element */
298 assert(xmlctx->status == LYXML_ELEM_CLOSE);
299 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
300
301 return LY_SUCCESS;
302}
303
304static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200305lydxml_data_check_opaq(struct lyd_xml_ctx *lydctx, const struct lysc_node **snode)
Michal Vasko1bf09392020-03-27 12:38:10 +0100306{
307 LY_ERR ret = LY_SUCCESS;
308 enum LYXML_PARSER_STATUS prev_status;
Michal Vasko63f3d842020-07-08 10:10:14 +0200309 const char *prev_current, *pname, *pprefix;
Michal Vasko1bf09392020-03-27 12:38:10 +0100310 size_t pprefix_len, pname_len;
311 struct lyxml_ctx *xmlctx = lydctx->xmlctx;
312
Radek Krejci1798aae2020-07-14 13:26:06 +0200313 if ((lydctx->parse_options & LYD_PARSE_OPAQ) && ((*snode)->nodetype & (LYD_NODE_TERM | LYS_LIST))) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100314 /* backup parser */
315 prev_status = xmlctx->status;
316 pprefix = xmlctx->prefix;
317 pprefix_len = xmlctx->prefix_len;
318 pname = xmlctx->name;
319 pname_len = xmlctx->name_len;
Michal Vasko63f3d842020-07-08 10:10:14 +0200320 prev_current = xmlctx->in->current;
Michal Vasko1bf09392020-03-27 12:38:10 +0100321 if ((xmlctx->status == LYXML_ELEM_CONTENT) && xmlctx->dynamic) {
322 /* it was backed up, do not free */
323 xmlctx->dynamic = 0;
324 }
325
326 /* skip attributes */
327 while (xmlctx->status == LYXML_ATTRIBUTE) {
328 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
329 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
330 }
331
332 if ((*snode)->nodetype & LYD_NODE_TERM) {
333 /* value may not be valid in which case we parse it as an opaque node */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200334 if (_lys_value_validate(NULL, *snode, xmlctx->value, xmlctx->value_len, LY_PREF_XML, &xmlctx->ns)) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100335 *snode = NULL;
336 }
337 } else {
338 /* skip content */
339 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
340
341 if (lydxml_check_list(xmlctx, *snode)) {
342 /* invalid list, parse as opaque if it missing/has invalid some keys */
343 *snode = NULL;
344 }
345 }
346
347restore:
348 /* restore parser */
349 if (xmlctx->dynamic) {
350 free((char *)xmlctx->value);
351 }
352 xmlctx->status = prev_status;
353 xmlctx->prefix = pprefix;
354 xmlctx->prefix_len = pprefix_len;
355 xmlctx->name = pname;
356 xmlctx->name_len = pname_len;
Michal Vasko63f3d842020-07-08 10:10:14 +0200357 xmlctx->in->current = prev_current;
Michal Vasko1bf09392020-03-27 12:38:10 +0100358 }
359
360 return ret;
361}
362
Radek Krejcie7b95092019-05-15 11:03:07 +0200363/**
Michal Vaskoa5da3292020-08-12 13:10:50 +0200364 * @brief Parse XML subtree.
Radek Krejcie7b95092019-05-15 11:03:07 +0200365 *
Michal Vaskob36053d2020-03-26 15:49:30 +0100366 * @param[in] lydctx XML YANG data parser context.
Radek Krejcie7b95092019-05-15 11:03:07 +0200367 * @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 +0200368 * @param[out] node Resulting list of the parsed nodes.
Michal Vasko9b368d32020-02-14 13:53:31 +0100369 * @return LY_ERR value.
Radek Krejcie7b95092019-05-15 11:03:07 +0200370 */
371static LY_ERR
Michal Vaskoa5da3292020-08-12 13:10:50 +0200372lydxml_subtree_r(struct lyd_xml_ctx *lydctx, struct lyd_node_inner *parent, struct lyd_node **first_p)
Radek Krejcie7b95092019-05-15 11:03:07 +0200373{
Michal Vaskob36053d2020-03-26 15:49:30 +0100374 LY_ERR ret = LY_SUCCESS;
Michal Vasko1bf09392020-03-27 12:38:10 +0100375 const char *prefix, *name;
376 size_t prefix_len, name_len;
Michal Vaskob36053d2020-03-26 15:49:30 +0100377 struct lyxml_ctx *xmlctx;
378 const struct ly_ctx *ctx;
Radek Krejcie7b95092019-05-15 11:03:07 +0200379 const struct lyxml_ns *ns;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200380 struct lyd_meta *meta = NULL;
381 struct lyd_attr *attr = NULL;
Radek Krejcie7b95092019-05-15 11:03:07 +0200382 const struct lysc_node *snode;
383 struct lys_module *mod;
Michal Vasko1bf09392020-03-27 12:38:10 +0100384 uint32_t prev_opts;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200385 struct lyd_node *node = NULL, *anchor;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100386 void *val_prefix_data;
387 LY_PREFIX_FORMAT format;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200388 uint32_t getnext_opts;
Radek Krejcie7b95092019-05-15 11:03:07 +0200389
Michal Vaskob36053d2020-03-26 15:49:30 +0100390 xmlctx = lydctx->xmlctx;
391 ctx = xmlctx->ctx;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100392 getnext_opts = lydctx->int_opts & LYD_INTOPT_REPLY ? LYS_GETNEXT_OUTPUT : 0;
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100393
Michal Vaskoa5da3292020-08-12 13:10:50 +0200394 assert(xmlctx->status == LYXML_ELEMENT);
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200395
Michal Vaskoa5da3292020-08-12 13:10:50 +0200396 /* remember element prefix and name */
397 prefix = xmlctx->prefix;
398 prefix_len = xmlctx->prefix_len;
399 name = xmlctx->name;
400 name_len = xmlctx->name_len;
401
402 /* get the element module */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200403 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200404 if (!ns) {
405 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
Michal Vasko69730152020-10-09 16:30:07 +0200406 prefix_len, prefix);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200407 ret = LY_EVALID;
408 goto error;
409 }
410 mod = ly_ctx_get_module_implemented_ns(ctx, ns->uri);
411 if (!mod) {
412 if (lydctx->parse_options & LYD_PARSE_STRICT) {
413 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "No module with namespace \"%s\" in the context.",
Michal Vasko69730152020-10-09 16:30:07 +0200414 ns->uri);
Michal Vasko90932a92020-02-12 14:33:03 +0100415 ret = LY_EVALID;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200416 goto error;
Radek Krejcie7b95092019-05-15 11:03:07 +0200417 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200418 if (!(lydctx->parse_options & LYD_PARSE_OPAQ)) {
419 /* skip element with children */
420 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
421 return LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200422 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200423 }
424
Michal Vaskoa5da3292020-08-12 13:10:50 +0200425 /* parser next */
426 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
Michal Vasko90932a92020-02-12 14:33:03 +0100427
Michal Vaskoa5da3292020-08-12 13:10:50 +0200428 /* get the schema node */
429 snode = NULL;
430 if (mod && (!parent || parent->schema)) {
431 snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
432 if (!snode) {
433 if (lydctx->parse_options & LYD_PARSE_STRICT) {
434 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Element \"%.*s\" not found in the \"%s\" module.",
Michal Vasko69730152020-10-09 16:30:07 +0200435 name_len, name, mod->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200436 ret = LY_EVALID;
437 goto error;
438 } else if (!(lydctx->parse_options & LYD_PARSE_OPAQ)) {
439 /* skip element with children */
440 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
441 return LY_SUCCESS;
442 }
443 } else {
444 /* check that schema node is valid and can be used */
445 LY_CHECK_GOTO(ret = lyd_parser_check_schema((struct lyd_ctx *)lydctx, snode), error);
446 LY_CHECK_GOTO(ret = lydxml_data_check_opaq(lydctx, &snode), error);
447 }
448 }
449
450 /* create metadata/attributes */
451 if (xmlctx->status == LYXML_ATTRIBUTE) {
452 if (snode) {
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200453 ret = lydxml_metadata(lydctx, &meta);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200454 LY_CHECK_GOTO(ret, error);
455 } else {
456 assert(lydctx->parse_options & LYD_PARSE_OPAQ);
457 ret = lydxml_attrs(xmlctx, &attr);
458 LY_CHECK_GOTO(ret, error);
459 }
460 }
461
462 assert(xmlctx->status == LYXML_ELEM_CONTENT);
463 if (!snode) {
464 assert(lydctx->parse_options & LYD_PARSE_OPAQ);
465
466 if (xmlctx->ws_only) {
467 /* ignore WS-only value */
468 xmlctx->value_len = 0;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100469 val_prefix_data = NULL;
470 format = LY_PREF_XML;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200471 } else {
472 /* get value prefixes */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100473 ret = ly_store_prefix_data(xmlctx->ctx, xmlctx->value, xmlctx->value_len, LY_PREF_XML,
474 &xmlctx->ns, &format, &val_prefix_data);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200475 LY_CHECK_GOTO(ret, error);
476 }
477
478 /* create node */
Michal Vasko501af032020-11-11 20:27:44 +0100479 ret = lyd_create_opaq(ctx, name, name_len, prefix, prefix_len, ns->uri, strlen(ns->uri), xmlctx->value,
480 xmlctx->value_len, &xmlctx->dynamic, format, val_prefix_data, LYD_HINT_DATA, &node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200481 LY_CHECK_GOTO(ret, error);
482
483 /* parser next */
484 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
485
486 /* process children */
487 while (xmlctx->status == LYXML_ELEMENT) {
488 ret = lydxml_subtree_r(lydctx, (struct lyd_node_inner *)node, lyd_node_children_p(node));
489 LY_CHECK_GOTO(ret, error);
490 }
491 } else if (snode->nodetype & LYD_NODE_TERM) {
492 /* create node */
Michal Vasko22df3f02020-08-24 13:29:22 +0200493 LY_CHECK_GOTO(ret = lyd_parser_create_term((struct lyd_ctx *)lydctx, snode, xmlctx->value, xmlctx->value_len,
Michal Vasko69730152020-10-09 16:30:07 +0200494 &xmlctx->dynamic, LY_PREF_XML, &xmlctx->ns, LYD_HINT_DATA, &node), error);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200495
496 if (parent && (node->schema->flags & LYS_KEY)) {
497 /* check the key order, the anchor must never be a key */
498 anchor = lyd_insert_get_next_anchor(parent->child, node);
499 if (anchor && (anchor->schema->flags & LYS_KEY)) {
500 if (lydctx->parse_options & LYD_PARSE_STRICT) {
501 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_DATA, "Invalid position of the key \"%s\" in a list.",
Michal Vasko69730152020-10-09 16:30:07 +0200502 node->schema->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200503 ret = LY_EVALID;
504 goto error;
505 } else {
506 LOGWRN(ctx, "Invalid position of the key \"%s\" in a list.", node->schema->name);
507 }
508 }
509 }
510
511 /* parser next */
512 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
513
514 /* no children expected */
515 if (xmlctx->status == LYXML_ELEMENT) {
516 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Child element \"%.*s\" inside a terminal node \"%s\" found.",
Michal Vasko69730152020-10-09 16:30:07 +0200517 xmlctx->name_len, xmlctx->name, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200518 ret = LY_EVALID;
519 goto error;
520 }
521 } else if (snode->nodetype & LYD_NODE_INNER) {
522 if (!xmlctx->ws_only) {
523 /* value in inner node */
524 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Text value \"%.*s\" inside an inner node \"%s\" found.",
Michal Vasko69730152020-10-09 16:30:07 +0200525 xmlctx->value_len, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200526 ret = LY_EVALID;
527 goto error;
528 }
529
530 /* create node */
531 ret = lyd_create_inner(snode, &node);
532 LY_CHECK_GOTO(ret, error);
533
534 /* parser next */
535 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
536
537 /* process children */
538 while (xmlctx->status == LYXML_ELEMENT) {
539 ret = lydxml_subtree_r(lydctx, (struct lyd_node_inner *)node, lyd_node_children_p(node));
540 LY_CHECK_GOTO(ret, error);
541 }
542
543 if (snode->nodetype == LYS_LIST) {
544 /* check all keys exist */
545 LY_CHECK_GOTO(ret = lyd_parse_check_keys(node), error);
546 }
547
548 if (!(lydctx->parse_options & LYD_PARSE_ONLY)) {
549 /* new node validation, autodelete CANNOT occur, all nodes are new */
550 ret = lyd_validate_new(lyd_node_children_p(node), snode, NULL, NULL);
551 LY_CHECK_GOTO(ret, error);
552
553 /* add any missing default children */
Michal Vasko49c39d82020-11-06 17:20:27 +0100554 ret = lyd_new_implicit_r(node, lyd_node_children_p(node), NULL, NULL, &lydctx->node_types, &lydctx->node_when,
Michal Vasko69730152020-10-09 16:30:07 +0200555 (lydctx->validate_options & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200556 LY_CHECK_GOTO(ret, error);
557 }
558
559 if (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
560 /* rememeber the RPC/action/notification */
561 lydctx->op_node = node;
562 }
563 } else if (snode->nodetype & LYD_NODE_ANY) {
564 if (!xmlctx->ws_only) {
565 /* value in inner node */
566 LOGVAL(ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Text value \"%.*s\" inside an any node \"%s\" found.",
Michal Vasko69730152020-10-09 16:30:07 +0200567 xmlctx->value_len, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200568 ret = LY_EVALID;
569 goto error;
570 }
571
572 /* parser next */
573 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
574
575 /* parse any data tree with correct options */
576 prev_opts = lydctx->parse_options;
577 lydctx->parse_options &= ~LYD_PARSE_STRICT;
578 lydctx->parse_options |= LYD_PARSE_OPAQ;
579 anchor = NULL;
580 while (xmlctx->status == LYXML_ELEMENT) {
581 ret = lydxml_subtree_r(lydctx, NULL, &anchor);
582 LY_CHECK_ERR_GOTO(ret, lydctx->parse_options = prev_opts, error);
583 }
584 lydctx->parse_options = prev_opts;
585
586 /* create node */
Michal Vasko366a4a12020-12-04 16:23:57 +0100587 ret = lyd_create_any(snode, anchor, LYD_ANYDATA_DATATREE, 1, &node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200588 LY_CHECK_GOTO(ret, error);
589 }
590 assert(node);
591
592 /* add/correct flags */
593 if (snode) {
Michal Vasko49c39d82020-11-06 17:20:27 +0100594 lyd_parse_set_data_flags(node, &lydctx->node_when, &meta, lydctx->parse_options);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200595 }
596
597 /* parser next */
598 assert(xmlctx->status == LYXML_ELEM_CLOSE);
599 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
600
601 /* add metadata/attributes */
602 if (snode) {
Michal Vasko871a0252020-11-11 18:35:24 +0100603 lyd_insert_meta(node, meta, 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200604 } else {
605 lyd_insert_attr(node, attr);
606 }
607
608 /* insert, keep first pointer correct */
609 lyd_insert_node((struct lyd_node *)parent, first_p, node);
610 while (!parent && (*first_p)->prev->next) {
611 *first_p = (*first_p)->prev;
612 }
613
614 return LY_SUCCESS;
615
616error:
Michal Vasko3a41dff2020-07-15 14:30:28 +0200617 lyd_free_meta_siblings(meta);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200618 lyd_free_attr_siblings(ctx, attr);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200619 lyd_free_tree(node);
Radek Krejcie7b95092019-05-15 11:03:07 +0200620 return ret;
621}
622
623LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +0200624lyd_parse_xml_data(const struct ly_ctx *ctx, struct ly_in *in, uint32_t parse_options, uint32_t validate_options,
Radek Krejci0f969882020-08-21 16:56:47 +0200625 struct lyd_node **tree_p, struct lyd_ctx **lydctx_p)
Radek Krejcie7b95092019-05-15 11:03:07 +0200626{
Radek Krejci18a57d92019-07-25 14:01:42 +0200627 LY_ERR ret = LY_SUCCESS;
Radek Krejci1798aae2020-07-14 13:26:06 +0200628 struct lyd_xml_ctx *lydctx;
Radek Krejcie7b95092019-05-15 11:03:07 +0200629
Radek Krejci7931b192020-06-25 17:05:03 +0200630 assert(!(parse_options & ~LYD_PARSE_OPTS_MASK));
631 assert(!(validate_options & ~LYD_VALIDATE_OPTS_MASK));
632
Radek Krejci1798aae2020-07-14 13:26:06 +0200633 /* init context */
634 lydctx = calloc(1, sizeof *lydctx);
635 LY_CHECK_ERR_RET(!lydctx, LOGMEM(ctx), LY_EMEM);
636 LY_CHECK_GOTO(ret = lyxml_ctx_new(ctx, in, &lydctx->xmlctx), cleanup);
637 lydctx->parse_options = parse_options;
638 lydctx->validate_options = validate_options;
639 lydctx->free = lyd_xml_ctx_free;
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200640
Michal Vaskob1b5c262020-03-05 14:29:47 +0100641 /* parse XML data */
Michal Vaskoa5da3292020-08-12 13:10:50 +0200642 while (lydctx->xmlctx->status == LYXML_ELEMENT) {
643 LY_CHECK_GOTO(ret = lydxml_subtree_r(lydctx, NULL, tree_p), cleanup);
644 }
Michal Vaskocde73ac2019-11-14 16:10:27 +0100645
Michal Vaskocde73ac2019-11-14 16:10:27 +0100646cleanup:
Michal Vasko49c39d82020-11-06 17:20:27 +0100647 /* there should be no unres stored if validation should be skipped */
648 assert(!(parse_options & LYD_PARSE_ONLY) || (!lydctx->node_types.count && !lydctx->meta_types.count &&
649 !lydctx->node_when.count));
Michal Vasko9b368d32020-02-14 13:53:31 +0100650
Michal Vasko9f96a052020-03-10 09:41:45 +0100651 if (ret) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200652 lyd_xml_ctx_free((struct lyd_ctx *)lydctx);
653 lyd_free_all(*tree_p);
654 *tree_p = NULL;
655 } else {
656 *lydctx_p = (struct lyd_ctx *)lydctx;
Michal Vasko9f96a052020-03-10 09:41:45 +0100657 }
658 return ret;
659}
Michal Vasko1bf09392020-03-27 12:38:10 +0100660
Michal Vasko2552ea32020-12-08 15:32:34 +0100661#if 0
Michal Vasko1bf09392020-03-27 12:38:10 +0100662static LY_ERR
663lydxml_envelope(struct lyxml_ctx *xmlctx, const char *name, const char *uri, struct lyd_node **envp)
664{
665 LY_ERR ret = LY_SUCCESS;
666 const struct lyxml_ns *ns = NULL;
Radek Krejci1798aae2020-07-14 13:26:06 +0200667 struct lyd_attr *attr = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100668 const char *prefix;
669 size_t prefix_len;
670
671 *envp = NULL;
672
673 assert(xmlctx->status == LYXML_ELEMENT);
674 if (ly_strncmp(name, xmlctx->name, xmlctx->name_len)) {
675 /* not the expected element */
676 return LY_SUCCESS;
677 }
678
679 prefix = xmlctx->prefix;
680 prefix_len = xmlctx->prefix_len;
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200681 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vasko1bf09392020-03-27 12:38:10 +0100682 if (!ns) {
683 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
Michal Vasko69730152020-10-09 16:30:07 +0200684 prefix_len, prefix);
Michal Vasko1bf09392020-03-27 12:38:10 +0100685 return LY_EVALID;
686 } else if (strcmp(ns->uri, uri)) {
687 /* different namespace */
688 return LY_SUCCESS;
689 }
690
691 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
692
693 /* create attributes */
694 if (xmlctx->status == LYXML_ATTRIBUTE) {
695 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
696 }
697
698 if (!xmlctx->ws_only) {
699 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Unexpected value \"%.*s\" in the \"%s\" element.",
Michal Vasko69730152020-10-09 16:30:07 +0200700 xmlctx->value_len, xmlctx->value, name);
Michal Vasko1bf09392020-03-27 12:38:10 +0100701 ret = LY_EVALID;
702 goto cleanup;
703 }
704
705 /* parser next element */
706 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
707
708 /* create node */
Michal Vasko501af032020-11-11 20:27:44 +0100709 ret = lyd_create_opaq(xmlctx->ctx, name, strlen(name), prefix, prefix_len, uri, strlen(uri), "", 0, NULL,
710 LY_PREF_XML, NULL, LYD_NODEHINT_ENVELOPE, envp);
Michal Vasko1bf09392020-03-27 12:38:10 +0100711 LY_CHECK_GOTO(ret, cleanup);
712
713 /* assign atributes */
714 ((struct lyd_node_opaq *)(*envp))->attr = attr;
715 attr = NULL;
716
717cleanup:
Radek Krejci011e4aa2020-09-04 15:22:31 +0200718 lyd_free_attr_siblings(xmlctx->ctx, attr);
Michal Vasko1bf09392020-03-27 12:38:10 +0100719 return ret;
720}
Michal Vasko2552ea32020-12-08 15:32:34 +0100721#endif
Michal Vasko1bf09392020-03-27 12:38:10 +0100722
723LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200724lyd_parse_xml_rpc(const struct ly_ctx *ctx, struct ly_in *in, struct lyd_node **tree_p, struct lyd_node **op_p)
Michal Vasko1bf09392020-03-27 12:38:10 +0100725{
726 LY_ERR ret = LY_SUCCESS;
727 struct lyd_xml_ctx lydctx = {0};
Radek Krejci1798aae2020-07-14 13:26:06 +0200728 struct lyd_node *tree = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100729
730 /* init */
Michal Vasko63f3d842020-07-08 10:10:14 +0200731 LY_CHECK_GOTO(ret = lyxml_ctx_new(ctx, in, &lydctx.xmlctx), cleanup);
Radek Krejci1798aae2020-07-14 13:26:06 +0200732 lydctx.parse_options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
Michal Vasko1bf09392020-03-27 12:38:10 +0100733 lydctx.int_opts = LYD_INTOPT_RPC;
Michal Vasko1bf09392020-03-27 12:38:10 +0100734
Michal Vasko2552ea32020-12-08 15:32:34 +0100735#if 0
Michal Vasko1bf09392020-03-27 12:38:10 +0100736 /* parse "rpc", if any */
737 LY_CHECK_GOTO(ret = lydxml_envelope(lydctx.xmlctx, "rpc", "urn:ietf:params:xml:ns:netconf:base:1.0", &rpc_e), cleanup);
738
739 if (rpc_e) {
740 /* parse "action", if any */
741 LY_CHECK_GOTO(ret = lydxml_envelope(lydctx.xmlctx, "action", "urn:ietf:params:xml:ns:yang:1", &act_e), cleanup);
742 }
Michal Vasko2552ea32020-12-08 15:32:34 +0100743#endif
Michal Vasko1bf09392020-03-27 12:38:10 +0100744
745 /* parse the rest of data normally */
Michal Vaskocf770e22020-08-12 13:21:43 +0200746 LY_CHECK_GOTO(ret = lydxml_subtree_r(&lydctx, NULL, &tree), cleanup);
Michal Vasko1bf09392020-03-27 12:38:10 +0100747
Michal Vaskocf770e22020-08-12 13:21:43 +0200748 /* make sure we have parsed some operation and it is the only subtree */
Radek Krejci1798aae2020-07-14 13:26:06 +0200749 if (!lydctx.op_node) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100750 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_DATA, "Missing the \"rpc\"/\"action\" node.");
751 ret = LY_EVALID;
752 goto cleanup;
Michal Vaskocf770e22020-08-12 13:21:43 +0200753 } else if (lydctx.xmlctx->status == LYXML_ELEMENT) {
754 LOGVAL(ctx, LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element of \"%s\".",
Michal Vasko69730152020-10-09 16:30:07 +0200755 tree->schema->name);
Michal Vaskocf770e22020-08-12 13:21:43 +0200756 ret = LY_EVALID;
757 goto cleanup;
Michal Vasko1bf09392020-03-27 12:38:10 +0100758 }
759
Radek Krejci1798aae2020-07-14 13:26:06 +0200760 if (op_p) {
761 *op_p = lydctx.op_node;
Michal Vaskocc048b22020-03-27 15:52:38 +0100762 }
Radek Krejci1798aae2020-07-14 13:26:06 +0200763 assert(tree);
Michal Vasko4189c0f2020-08-13 09:05:22 +0200764 if (tree_p) {
765 *tree_p = tree;
Michal Vasko1bf09392020-03-27 12:38:10 +0100766 }
767
768cleanup:
769 /* we have used parse_only flag */
Michal Vasko49c39d82020-11-06 17:20:27 +0100770 assert(!lydctx.node_types.count && !lydctx.meta_types.count && !lydctx.node_when.count);
Michal Vasko1bf09392020-03-27 12:38:10 +0100771 lyxml_ctx_free(lydctx.xmlctx);
772 if (ret) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200773 lyd_free_all(tree);
Michal Vasko1bf09392020-03-27 12:38:10 +0100774 }
775 return ret;
776}
Michal Vaskoa8edff02020-03-27 14:47:01 +0100777
Michal Vasko2552ea32020-12-08 15:32:34 +0100778#if 0
Michal Vaskoa8edff02020-03-27 14:47:01 +0100779static LY_ERR
780lydxml_notif_envelope(struct lyxml_ctx *xmlctx, struct lyd_node **envp)
781{
782 LY_ERR ret = LY_SUCCESS;
783 const struct lyxml_ns *ns = NULL;
Radek Krejci1798aae2020-07-14 13:26:06 +0200784 struct lyd_attr *attr = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100785 struct lyd_node *et;
786 const char *prefix;
787 size_t prefix_len;
788
789 *envp = NULL;
790
791 /* container envelope */
792 LY_CHECK_GOTO(ret = lydxml_envelope(xmlctx, "notification", "urn:ietf:params:xml:ns:netconf:notification:1.0",
Michal Vasko69730152020-10-09 16:30:07 +0200793 envp), cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100794
795 /* no envelope, fine */
796 if (!*envp) {
797 goto cleanup;
798 }
799
800 /* child "eventTime" */
801 if ((xmlctx->status != LYXML_ELEMENT) || ly_strncmp("eventTime", xmlctx->name, xmlctx->name_len)) {
802 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Missing the \"eventTime\" element.");
803 ret = LY_EVALID;
804 goto cleanup;
805 }
806
807 prefix = xmlctx->prefix;
808 prefix_len = xmlctx->prefix_len;
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200809 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100810 if (!ns) {
811 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
Michal Vasko69730152020-10-09 16:30:07 +0200812 prefix_len, prefix);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100813 ret = LY_EVALID;
814 goto cleanup;
815 } else if (strcmp(ns->uri, "urn:ietf:params:xml:ns:netconf:notification:1.0")) {
816 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_REFERENCE, "Invalid namespace \"%s\" of \"eventTime\".",
Michal Vasko69730152020-10-09 16:30:07 +0200817 ns->uri);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100818 ret = LY_EVALID;
819 goto cleanup;
820 }
821
822 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
823
824 /* create attributes */
825 if (xmlctx->status == LYXML_ATTRIBUTE) {
826 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
827 }
828
829 /* validate value */
830 /* TODO */
831 /*if (!xmlctx->ws_only) {
832 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Unexpected value \"%.*s\" in the \"%s\" element.",
833 xmlctx->value_len, xmlctx->value, name);
834 ret = LY_EVALID;
835 goto cleanup;
836 }*/
837
838 /* create node */
Radek Krejcif13b87b2020-12-01 22:02:17 +0100839 ret = lyd_create_opaq(xmlctx->ctx, "eventTime", ly_strlen_const("eventTime"), prefix, prefix_len,
840 ns->uri, strlen(ns->uri), xmlctx->value, xmlctx->value_len, NULL, LY_PREF_XML, NULL, LYD_NODEHINT_ENVELOPE, &et);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100841 LY_CHECK_GOTO(ret, cleanup);
842
843 /* assign atributes */
844 ((struct lyd_node_opaq *)et)->attr = attr;
845 attr = NULL;
846
847 /* insert */
848 lyd_insert_node(*envp, NULL, et);
849
850 /* finish parsing */
851 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
852 if (xmlctx->status != LYXML_ELEM_CLOSE) {
853 assert(xmlctx->status == LYXML_ELEMENT);
854 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"eventTime\".",
Michal Vasko69730152020-10-09 16:30:07 +0200855 xmlctx->name_len, xmlctx->name);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100856 ret = LY_EVALID;
857 goto cleanup;
858 }
859 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
860
861cleanup:
862 if (ret) {
863 lyd_free_tree(*envp);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200864 lyd_free_attr_siblings(xmlctx->ctx, attr);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100865 }
866 return ret;
867}
Michal Vasko2552ea32020-12-08 15:32:34 +0100868#endif
Michal Vaskoa8edff02020-03-27 14:47:01 +0100869
870LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200871lyd_parse_xml_notif(const struct ly_ctx *ctx, struct ly_in *in, struct lyd_node **tree_p, struct lyd_node **ntf_p)
Michal Vaskoa8edff02020-03-27 14:47:01 +0100872{
873 LY_ERR ret = LY_SUCCESS;
874 struct lyd_xml_ctx lydctx = {0};
Radek Krejci1798aae2020-07-14 13:26:06 +0200875 struct lyd_node *tree = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100876
877 /* init */
Michal Vasko63f3d842020-07-08 10:10:14 +0200878 LY_CHECK_GOTO(ret = lyxml_ctx_new(ctx, in, &lydctx.xmlctx), cleanup);
Radek Krejci1798aae2020-07-14 13:26:06 +0200879 lydctx.parse_options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100880 lydctx.int_opts = LYD_INTOPT_NOTIF;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100881
Michal Vasko2552ea32020-12-08 15:32:34 +0100882#if 0
Michal Vaskoa8edff02020-03-27 14:47:01 +0100883 /* parse "notification" and "eventTime", if present */
884 LY_CHECK_GOTO(ret = lydxml_notif_envelope(lydctx.xmlctx, &ntf_e), cleanup);
Michal Vasko2552ea32020-12-08 15:32:34 +0100885#endif
Michal Vaskoa8edff02020-03-27 14:47:01 +0100886
887 /* parse the rest of data normally */
Michal Vaskocf770e22020-08-12 13:21:43 +0200888 LY_CHECK_GOTO(ret = lydxml_subtree_r(&lydctx, NULL, &tree), cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100889
890 /* make sure we have parsed some notification */
Radek Krejci1798aae2020-07-14 13:26:06 +0200891 if (!lydctx.op_node) {
Michal Vaskoa8edff02020-03-27 14:47:01 +0100892 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_DATA, "Missing the \"notification\" node.");
893 ret = LY_EVALID;
894 goto cleanup;
Michal Vaskocf770e22020-08-12 13:21:43 +0200895 } else if (lydctx.xmlctx->status == LYXML_ELEMENT) {
896 LOGVAL(ctx, LY_VLOG_LINE, &lydctx.xmlctx->line, LYVE_SYNTAX, "Unexpected sibling element of \"%s\".",
Michal Vasko69730152020-10-09 16:30:07 +0200897 tree->schema->name);
Michal Vaskocf770e22020-08-12 13:21:43 +0200898 ret = LY_EVALID;
899 goto cleanup;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100900 }
901
Radek Krejci1798aae2020-07-14 13:26:06 +0200902 if (ntf_p) {
903 *ntf_p = lydctx.op_node;
Michal Vaskocc048b22020-03-27 15:52:38 +0100904 }
Radek Krejci1798aae2020-07-14 13:26:06 +0200905 assert(tree);
Michal Vasko2552ea32020-12-08 15:32:34 +0100906 if (tree_p) {
907 *tree_p = tree;
908 }
909
910cleanup:
911 /* we have used parse_only flag */
912 assert(!lydctx.node_types.count && !lydctx.meta_types.count && !lydctx.node_when.count);
913 lyxml_ctx_free(lydctx.xmlctx);
914 if (ret) {
915 lyd_free_all(tree);
916 }
917 return ret;
918}
919
920LY_ERR
921lyd_parse_xml_reply(const struct ly_ctx *ctx, struct ly_in *in, struct lyd_node **tree_p, struct lyd_node **op_p)
922{
923 LY_ERR ret = LY_SUCCESS;
924 struct lyd_xml_ctx lydctx = {0};
925 struct lyd_node *tree = NULL;
926
927 /* init */
928 LY_CHECK_GOTO(ret = lyxml_ctx_new(ctx, in, &lydctx.xmlctx), cleanup);
929 lydctx.parse_options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
930 lydctx.int_opts = LYD_INTOPT_REPLY;
931
932#if 0
933 /* parse "rpc-reply", if any */
934 LY_CHECK_GOTO(ret = lydxml_envelope(lydctx.xmlctx, "rpc-reply", "urn:ietf:params:xml:ns:netconf:base:1.0", &rpcr_e),
935 cleanup);
936#endif
937
938 /* parse the rest of data normally but connect them to the duplicated operation */
939 while (lydctx.xmlctx->status == LYXML_ELEMENT) {
940 ret = lydxml_subtree_r(&lydctx, NULL, &tree);
941 LY_CHECK_GOTO(ret, cleanup);
942 }
943
944 if (op_p) {
945 *op_p = lydctx.op_node;
Michal Vasko4189c0f2020-08-13 09:05:22 +0200946 }
947 if (tree_p) {
948 *tree_p = tree;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100949 }
950
951cleanup:
952 /* we have used parse_only flag */
Michal Vasko49c39d82020-11-06 17:20:27 +0100953 assert(!lydctx.node_types.count && !lydctx.meta_types.count && !lydctx.node_when.count);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100954 lyxml_ctx_free(lydctx.xmlctx);
955 if (ret) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200956 lyd_free_all(tree);
Michal Vasko1ce933a2020-03-30 12:38:22 +0200957 }
958 return ret;
959}