blob: bfd82b28cabeea406c6531ab396b922d616c71e3 [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) {
Radek Krejci2efc45b2020-12-22 16:25:44 +010082 LOGVAL(xmlctx->ctx, 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 */
Radek Krejci2efc45b2020-12-22 16:25:44 +010098 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", xmlctx->prefix_len, xmlctx->prefix);
Radek Krejci28681fa2019-09-06 13:08:45 +020099 goto cleanup;
100 }
Michal Vasko52927e22020-03-16 17:26:14 +0100101 mod = ly_ctx_get_module_implemented_ns(xmlctx->ctx, ns->uri);
Radek Krejci28681fa2019-09-06 13:08:45 +0200102 if (!mod) {
103 /* module is not implemented or not present in the schema */
Radek Krejci1798aae2020-07-14 13:26:06 +0200104 if (lydctx->parse_options & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100105 LOGVAL(xmlctx->ctx, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +0200106 "Unknown (or not implemented) YANG module with namespace \"%s\" for metadata \"%.*s%s%.*s\".",
107 ns->uri, xmlctx->prefix_len, xmlctx->prefix, xmlctx->prefix_len ? ":" : "", xmlctx->name_len,
108 xmlctx->name);
Michal Vaskob36053d2020-03-26 15:49:30 +0100109 goto cleanup;
Radek Krejci28681fa2019-09-06 13:08:45 +0200110 }
111 goto skip_attr;
112 }
113
Michal Vasko60ea6352020-06-29 13:39:39 +0200114 /* remember meta name and get its content */
Michal Vaskob36053d2020-03-26 15:49:30 +0100115 name = xmlctx->name;
116 name_len = xmlctx->name_len;
117 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
118 assert(xmlctx->status == LYXML_ATTR_CONTENT);
119
120 /* create metadata */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200121 ret = lyd_parser_create_meta((struct lyd_ctx *)lydctx, NULL, meta, mod, name, name_len, xmlctx->value,
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200122 xmlctx->value_len, &xmlctx->dynamic, LY_PREF_XML, &xmlctx->ns, LYD_HINT_DATA);
Radek Krejci1798aae2020-07-14 13:26:06 +0200123 LY_CHECK_GOTO(ret, cleanup);
Michal Vaskob36053d2020-03-26 15:49:30 +0100124
125 /* next attribute */
126 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200127 }
Michal Vasko52927e22020-03-16 17:26:14 +0100128
Radek Krejci28681fa2019-09-06 13:08:45 +0200129 ret = LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200130
131cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100132 if (ret) {
Michal Vasko3a41dff2020-07-15 14:30:28 +0200133 lyd_free_meta_siblings(*meta);
Michal Vaskob36053d2020-03-26 15:49:30 +0100134 *meta = NULL;
Radek Krejci38d85362019-09-05 16:26:38 +0200135 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200136 return ret;
137}
138
Michal Vasko52927e22020-03-16 17:26:14 +0100139static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200140lydxml_attrs(struct lyxml_ctx *xmlctx, struct lyd_attr **attr)
Michal Vasko52927e22020-03-16 17:26:14 +0100141{
142 LY_ERR ret = LY_SUCCESS;
143 const struct lyxml_ns *ns;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100144 void *val_prefix_data;
145 LY_PREFIX_FORMAT format;
Radek Krejci1798aae2020-07-14 13:26:06 +0200146 struct lyd_attr *attr2;
Michal Vaskob36053d2020-03-26 15:49:30 +0100147 const char *name, *prefix;
148 size_t name_len, prefix_len;
Michal Vasko52927e22020-03-16 17:26:14 +0100149
150 assert(attr);
Michal Vaskob36053d2020-03-26 15:49:30 +0100151 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100152
Michal Vaskob36053d2020-03-26 15:49:30 +0100153 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vasko52927e22020-03-16 17:26:14 +0100154 ns = NULL;
Michal Vaskob36053d2020-03-26 15:49:30 +0100155 if (xmlctx->prefix_len) {
Michal Vasko52927e22020-03-16 17:26:14 +0100156 /* get namespace of the attribute */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200157 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
Michal Vasko52927e22020-03-16 17:26:14 +0100158 if (!ns) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100159 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", xmlctx->prefix_len, xmlctx->prefix);
Michal Vasko52927e22020-03-16 17:26:14 +0100160 ret = LY_EVALID;
161 goto cleanup;
162 }
163 }
164
165 if (*attr) {
166 attr2 = *attr;
167 } else {
168 attr2 = NULL;
169 }
170
Michal Vaskob36053d2020-03-26 15:49:30 +0100171 /* remember attr prefix, name, and get its content */
172 prefix = xmlctx->prefix;
173 prefix_len = xmlctx->prefix_len;
174 name = xmlctx->name;
175 name_len = xmlctx->name_len;
176 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
177 assert(xmlctx->status == LYXML_ATTR_CONTENT);
178
Michal Vasko52927e22020-03-16 17:26:14 +0100179 /* get value prefixes */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100180 LY_CHECK_GOTO(ret = ly_store_prefix_data(xmlctx->ctx, xmlctx->value, xmlctx->value_len, LY_PREF_XML,
181 &xmlctx->ns, &format, &val_prefix_data), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100182
183 /* attr2 is always changed to the created attribute */
Michal Vasko501af032020-11-11 20:27:44 +0100184 ret = lyd_create_attr(NULL, &attr2, xmlctx->ctx, name, name_len, prefix, prefix_len, ns ? ns->uri : NULL,
185 ns ? strlen(ns->uri) : 0, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic, format, val_prefix_data, 0);
Michal Vasko52927e22020-03-16 17:26:14 +0100186 LY_CHECK_GOTO(ret, cleanup);
187
188 if (!*attr) {
189 *attr = attr2;
190 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100191
192 /* next attribute */
193 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100194 }
195
196cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100197 if (ret) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200198 lyd_free_attr_siblings(xmlctx->ctx, *attr);
Michal Vaskob36053d2020-03-26 15:49:30 +0100199 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100200 }
Michal Vasko52927e22020-03-16 17:26:14 +0100201 return ret;
202}
203
Michal Vasko44685da2020-03-17 15:38:06 +0100204static LY_ERR
Michal Vaskob36053d2020-03-26 15:49:30 +0100205lydxml_check_list(struct lyxml_ctx *xmlctx, const struct lysc_node *list)
Michal Vasko44685da2020-03-17 15:38:06 +0100206{
Michal Vaskob36053d2020-03-26 15:49:30 +0100207 LY_ERR ret = LY_SUCCESS, r;
208 enum LYXML_PARSER_STATUS next;
Michal Vasko44685da2020-03-17 15:38:06 +0100209 struct ly_set key_set = {0};
210 const struct lysc_node *snode;
Michal Vaskob36053d2020-03-26 15:49:30 +0100211 uint32_t i, parents_count;
Michal Vasko44685da2020-03-17 15:38:06 +0100212
213 assert(list && (list->nodetype == LYS_LIST));
214
215 /* get all keys into a set (keys do not have if-features or anything) */
216 snode = NULL;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100217 while ((snode = lys_getnext(snode, list, NULL, 0)) && (snode->flags & LYS_KEY)) {
Radek Krejci3d92e442020-10-12 12:48:13 +0200218 ret = ly_set_add(&key_set, (void *)snode, 1, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200219 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100220 }
221
Michal Vaskob36053d2020-03-26 15:49:30 +0100222 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vasko44685da2020-03-17 15:38:06 +0100223 /* find key definition */
224 for (i = 0; i < key_set.count; ++i) {
225 snode = (const struct lysc_node *)key_set.objs[i];
Michal Vaskob36053d2020-03-26 15:49:30 +0100226 if (!ly_strncmp(snode->name, xmlctx->name, xmlctx->name_len)) {
Michal Vasko44685da2020-03-17 15:38:06 +0100227 break;
228 }
229 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100230 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100231
232 /* skip attributes */
233 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100234 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
235 assert(xmlctx->status == LYXML_ATTR_CONTENT);
236 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100237 }
238
Michal Vaskob36053d2020-03-26 15:49:30 +0100239 assert(xmlctx->status == LYXML_ELEM_CONTENT);
240 if (i < key_set.count) {
241 /* validate the value */
Michal Vasko713148b2020-11-12 13:10:13 +0100242 r = _lys_value_validate(NULL, snode, xmlctx->value, xmlctx->value_len, LY_PREF_XML, &xmlctx->ns);
Michal Vaskob36053d2020-03-26 15:49:30 +0100243 if (!r) {
244 /* key with a valid value, remove from the set */
245 ly_set_rm_index(&key_set, i, NULL);
Michal Vasko44685da2020-03-17 15:38:06 +0100246 }
247 }
248
Michal Vaskob36053d2020-03-26 15:49:30 +0100249 /* parser next */
250 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100251
Michal Vaskob36053d2020-03-26 15:49:30 +0100252 /* skip any children, resursively */
253 parents_count = xmlctx->elements.count;
254 while ((parents_count < xmlctx->elements.count) || (xmlctx->status == LYXML_ELEMENT)) {
255 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
256 }
257
258 /* parser next, but do not parse closing element of the list because it would remove its namespaces */
259 assert(xmlctx->status == LYXML_ELEM_CLOSE);
260 LY_CHECK_GOTO(ret = lyxml_ctx_peek(xmlctx, &next), cleanup);
261 if (next != LYXML_ELEM_CLOSE) {
262 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
263 }
Michal Vasko44685da2020-03-17 15:38:06 +0100264 }
265
266 if (key_set.count) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100267 /* some keys are missing/did not validate */
Michal Vasko44685da2020-03-17 15:38:06 +0100268 ret = LY_ENOT;
Michal Vasko44685da2020-03-17 15:38:06 +0100269 }
270
271cleanup:
272 ly_set_erase(&key_set, NULL);
273 return ret;
274}
275
Michal Vasko1bf09392020-03-27 12:38:10 +0100276static LY_ERR
277lydxml_data_skip(struct lyxml_ctx *xmlctx)
278{
279 uint32_t parents_count;
280
281 /* remember current number of parents */
282 parents_count = xmlctx->elements.count;
283
284 /* skip after the content */
285 while (xmlctx->status != LYXML_ELEM_CONTENT) {
286 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
287 }
288 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
289
290 /* skip all children elements, recursively, if any */
291 while (parents_count < xmlctx->elements.count) {
292 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
293 }
294
295 /* close element */
296 assert(xmlctx->status == LYXML_ELEM_CLOSE);
297 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
298
299 return LY_SUCCESS;
300}
301
302static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200303lydxml_data_check_opaq(struct lyd_xml_ctx *lydctx, const struct lysc_node **snode)
Michal Vasko1bf09392020-03-27 12:38:10 +0100304{
305 LY_ERR ret = LY_SUCCESS;
306 enum LYXML_PARSER_STATUS prev_status;
Michal Vasko63f3d842020-07-08 10:10:14 +0200307 const char *prev_current, *pname, *pprefix;
Michal Vasko1bf09392020-03-27 12:38:10 +0100308 size_t pprefix_len, pname_len;
309 struct lyxml_ctx *xmlctx = lydctx->xmlctx;
310
Radek Krejci1798aae2020-07-14 13:26:06 +0200311 if ((lydctx->parse_options & LYD_PARSE_OPAQ) && ((*snode)->nodetype & (LYD_NODE_TERM | LYS_LIST))) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100312 /* backup parser */
313 prev_status = xmlctx->status;
314 pprefix = xmlctx->prefix;
315 pprefix_len = xmlctx->prefix_len;
316 pname = xmlctx->name;
317 pname_len = xmlctx->name_len;
Michal Vasko63f3d842020-07-08 10:10:14 +0200318 prev_current = xmlctx->in->current;
Michal Vasko1bf09392020-03-27 12:38:10 +0100319 if ((xmlctx->status == LYXML_ELEM_CONTENT) && xmlctx->dynamic) {
320 /* it was backed up, do not free */
321 xmlctx->dynamic = 0;
322 }
323
324 /* skip attributes */
325 while (xmlctx->status == LYXML_ATTRIBUTE) {
326 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
327 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
328 }
329
330 if ((*snode)->nodetype & LYD_NODE_TERM) {
331 /* value may not be valid in which case we parse it as an opaque node */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200332 if (_lys_value_validate(NULL, *snode, xmlctx->value, xmlctx->value_len, LY_PREF_XML, &xmlctx->ns)) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100333 *snode = NULL;
334 }
335 } else {
336 /* skip content */
337 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
338
339 if (lydxml_check_list(xmlctx, *snode)) {
340 /* invalid list, parse as opaque if it missing/has invalid some keys */
341 *snode = NULL;
342 }
343 }
344
345restore:
346 /* restore parser */
347 if (xmlctx->dynamic) {
348 free((char *)xmlctx->value);
349 }
350 xmlctx->status = prev_status;
351 xmlctx->prefix = pprefix;
352 xmlctx->prefix_len = pprefix_len;
353 xmlctx->name = pname;
354 xmlctx->name_len = pname_len;
Michal Vasko63f3d842020-07-08 10:10:14 +0200355 xmlctx->in->current = prev_current;
Michal Vasko1bf09392020-03-27 12:38:10 +0100356 }
357
358 return ret;
359}
360
Radek Krejcie7b95092019-05-15 11:03:07 +0200361/**
Michal Vaskoa5da3292020-08-12 13:10:50 +0200362 * @brief Parse XML subtree.
Radek Krejcie7b95092019-05-15 11:03:07 +0200363 *
Michal Vaskob36053d2020-03-26 15:49:30 +0100364 * @param[in] lydctx XML YANG data parser context.
Radek Krejcie7b95092019-05-15 11:03:07 +0200365 * @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 +0200366 * @param[out] node Resulting list of the parsed nodes.
Michal Vasko9b368d32020-02-14 13:53:31 +0100367 * @return LY_ERR value.
Radek Krejcie7b95092019-05-15 11:03:07 +0200368 */
369static LY_ERR
Michal Vaskoa5da3292020-08-12 13:10:50 +0200370lydxml_subtree_r(struct lyd_xml_ctx *lydctx, struct lyd_node_inner *parent, struct lyd_node **first_p)
Radek Krejcie7b95092019-05-15 11:03:07 +0200371{
Michal Vaskob36053d2020-03-26 15:49:30 +0100372 LY_ERR ret = LY_SUCCESS;
Michal Vasko1bf09392020-03-27 12:38:10 +0100373 const char *prefix, *name;
374 size_t prefix_len, name_len;
Michal Vaskob36053d2020-03-26 15:49:30 +0100375 struct lyxml_ctx *xmlctx;
376 const struct ly_ctx *ctx;
Radek Krejcie7b95092019-05-15 11:03:07 +0200377 const struct lyxml_ns *ns;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200378 struct lyd_meta *meta = NULL;
379 struct lyd_attr *attr = NULL;
Radek Krejcie7b95092019-05-15 11:03:07 +0200380 const struct lysc_node *snode;
381 struct lys_module *mod;
Michal Vasko1bf09392020-03-27 12:38:10 +0100382 uint32_t prev_opts;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200383 struct lyd_node *node = NULL, *anchor;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100384 void *val_prefix_data;
385 LY_PREFIX_FORMAT format;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200386 uint32_t getnext_opts;
Radek Krejcie7b95092019-05-15 11:03:07 +0200387
Michal Vaskob36053d2020-03-26 15:49:30 +0100388 xmlctx = lydctx->xmlctx;
389 ctx = xmlctx->ctx;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100390 getnext_opts = lydctx->int_opts & LYD_INTOPT_REPLY ? LYS_GETNEXT_OUTPUT : 0;
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100391
Michal Vaskoa5da3292020-08-12 13:10:50 +0200392 assert(xmlctx->status == LYXML_ELEMENT);
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200393
Michal Vaskoa5da3292020-08-12 13:10:50 +0200394 /* remember element prefix and name */
395 prefix = xmlctx->prefix;
396 prefix_len = xmlctx->prefix_len;
397 name = xmlctx->name;
398 name_len = xmlctx->name_len;
399
400 /* get the element module */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200401 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200402 if (!ns) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100403 LOGVAL(ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", prefix_len, prefix);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200404 ret = LY_EVALID;
405 goto error;
406 }
407 mod = ly_ctx_get_module_implemented_ns(ctx, ns->uri);
408 if (!mod) {
409 if (lydctx->parse_options & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100410 LOGVAL(ctx, LYVE_REFERENCE, "No module with namespace \"%s\" in the context.", ns->uri);
Michal Vasko90932a92020-02-12 14:33:03 +0100411 ret = LY_EVALID;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200412 goto error;
Radek Krejcie7b95092019-05-15 11:03:07 +0200413 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200414 if (!(lydctx->parse_options & LYD_PARSE_OPAQ)) {
415 /* skip element with children */
416 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
417 return LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200418 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200419 }
420
Michal Vaskoa5da3292020-08-12 13:10:50 +0200421 /* parser next */
422 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
Michal Vasko90932a92020-02-12 14:33:03 +0100423
Michal Vaskoa5da3292020-08-12 13:10:50 +0200424 /* get the schema node */
425 snode = NULL;
426 if (mod && (!parent || parent->schema)) {
427 snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
428 if (!snode) {
429 if (lydctx->parse_options & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100430 LOGVAL(ctx, LYVE_REFERENCE, "Element \"%.*s\" not found in the \"%s\" module.", name_len, name, mod->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200431 ret = LY_EVALID;
432 goto error;
433 } else if (!(lydctx->parse_options & LYD_PARSE_OPAQ)) {
434 /* skip element with children */
435 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
436 return LY_SUCCESS;
437 }
438 } else {
439 /* check that schema node is valid and can be used */
440 LY_CHECK_GOTO(ret = lyd_parser_check_schema((struct lyd_ctx *)lydctx, snode), error);
441 LY_CHECK_GOTO(ret = lydxml_data_check_opaq(lydctx, &snode), error);
442 }
443 }
444
445 /* create metadata/attributes */
446 if (xmlctx->status == LYXML_ATTRIBUTE) {
447 if (snode) {
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200448 ret = lydxml_metadata(lydctx, &meta);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200449 LY_CHECK_GOTO(ret, error);
450 } else {
451 assert(lydctx->parse_options & LYD_PARSE_OPAQ);
452 ret = lydxml_attrs(xmlctx, &attr);
453 LY_CHECK_GOTO(ret, error);
454 }
455 }
456
457 assert(xmlctx->status == LYXML_ELEM_CONTENT);
458 if (!snode) {
459 assert(lydctx->parse_options & LYD_PARSE_OPAQ);
460
461 if (xmlctx->ws_only) {
462 /* ignore WS-only value */
463 xmlctx->value_len = 0;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100464 val_prefix_data = NULL;
465 format = LY_PREF_XML;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200466 } else {
467 /* get value prefixes */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100468 ret = ly_store_prefix_data(xmlctx->ctx, xmlctx->value, xmlctx->value_len, LY_PREF_XML,
469 &xmlctx->ns, &format, &val_prefix_data);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200470 LY_CHECK_GOTO(ret, error);
471 }
472
473 /* create node */
Michal Vasko501af032020-11-11 20:27:44 +0100474 ret = lyd_create_opaq(ctx, name, name_len, prefix, prefix_len, ns->uri, strlen(ns->uri), xmlctx->value,
475 xmlctx->value_len, &xmlctx->dynamic, format, val_prefix_data, LYD_HINT_DATA, &node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200476 LY_CHECK_GOTO(ret, error);
477
478 /* parser next */
479 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
480
481 /* process children */
482 while (xmlctx->status == LYXML_ELEMENT) {
483 ret = lydxml_subtree_r(lydctx, (struct lyd_node_inner *)node, lyd_node_children_p(node));
484 LY_CHECK_GOTO(ret, error);
485 }
486 } else if (snode->nodetype & LYD_NODE_TERM) {
487 /* create node */
Michal Vasko22df3f02020-08-24 13:29:22 +0200488 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 +0200489 &xmlctx->dynamic, LY_PREF_XML, &xmlctx->ns, LYD_HINT_DATA, &node), error);
Radek Krejciddace2c2021-01-08 11:30:56 +0100490 LOG_LOCSET(snode, node, NULL, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200491
492 if (parent && (node->schema->flags & LYS_KEY)) {
493 /* check the key order, the anchor must never be a key */
494 anchor = lyd_insert_get_next_anchor(parent->child, node);
495 if (anchor && (anchor->schema->flags & LYS_KEY)) {
496 if (lydctx->parse_options & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100497 LOGVAL(ctx, LYVE_DATA, "Invalid position of the key \"%s\" in a list.", node->schema->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200498 ret = LY_EVALID;
499 goto error;
500 } else {
501 LOGWRN(ctx, "Invalid position of the key \"%s\" in a list.", node->schema->name);
502 }
503 }
504 }
505
506 /* parser next */
507 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
508
509 /* no children expected */
510 if (xmlctx->status == LYXML_ELEMENT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100511 LOGVAL(ctx, LYVE_SYNTAX, "Child element \"%.*s\" inside a terminal node \"%s\" found.",
Michal Vasko69730152020-10-09 16:30:07 +0200512 xmlctx->name_len, xmlctx->name, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200513 ret = LY_EVALID;
514 goto error;
515 }
516 } else if (snode->nodetype & LYD_NODE_INNER) {
517 if (!xmlctx->ws_only) {
518 /* value in inner node */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100519 LOGVAL(ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an inner node \"%s\" found.",
Michal Vasko69730152020-10-09 16:30:07 +0200520 xmlctx->value_len, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200521 ret = LY_EVALID;
522 goto error;
523 }
524
525 /* create node */
526 ret = lyd_create_inner(snode, &node);
527 LY_CHECK_GOTO(ret, error);
528
Radek Krejciddace2c2021-01-08 11:30:56 +0100529 LOG_LOCSET(snode, node, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100530
Michal Vaskoa5da3292020-08-12 13:10:50 +0200531 /* parser next */
532 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
533
534 /* process children */
535 while (xmlctx->status == LYXML_ELEMENT) {
536 ret = lydxml_subtree_r(lydctx, (struct lyd_node_inner *)node, lyd_node_children_p(node));
537 LY_CHECK_GOTO(ret, error);
538 }
539
540 if (snode->nodetype == LYS_LIST) {
541 /* check all keys exist */
542 LY_CHECK_GOTO(ret = lyd_parse_check_keys(node), error);
543 }
544
545 if (!(lydctx->parse_options & LYD_PARSE_ONLY)) {
546 /* new node validation, autodelete CANNOT occur, all nodes are new */
547 ret = lyd_validate_new(lyd_node_children_p(node), snode, NULL, NULL);
548 LY_CHECK_GOTO(ret, error);
549
550 /* add any missing default children */
Michal Vasko49c39d82020-11-06 17:20:27 +0100551 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 +0200552 (lydctx->validate_options & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200553 LY_CHECK_GOTO(ret, error);
554 }
555
556 if (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
557 /* rememeber the RPC/action/notification */
558 lydctx->op_node = node;
559 }
560 } else if (snode->nodetype & LYD_NODE_ANY) {
561 if (!xmlctx->ws_only) {
562 /* value in inner node */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100563 LOGVAL(ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an any node \"%s\" found.",
Michal Vasko69730152020-10-09 16:30:07 +0200564 xmlctx->value_len, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200565 ret = LY_EVALID;
566 goto error;
567 }
568
569 /* parser next */
570 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
571
572 /* parse any data tree with correct options */
573 prev_opts = lydctx->parse_options;
574 lydctx->parse_options &= ~LYD_PARSE_STRICT;
575 lydctx->parse_options |= LYD_PARSE_OPAQ;
576 anchor = NULL;
577 while (xmlctx->status == LYXML_ELEMENT) {
578 ret = lydxml_subtree_r(lydctx, NULL, &anchor);
579 LY_CHECK_ERR_GOTO(ret, lydctx->parse_options = prev_opts, error);
580 }
581 lydctx->parse_options = prev_opts;
582
583 /* create node */
Michal Vasko366a4a12020-12-04 16:23:57 +0100584 ret = lyd_create_any(snode, anchor, LYD_ANYDATA_DATATREE, 1, &node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200585 LY_CHECK_GOTO(ret, error);
586 }
587 assert(node);
588
589 /* add/correct flags */
590 if (snode) {
Michal Vasko49c39d82020-11-06 17:20:27 +0100591 lyd_parse_set_data_flags(node, &lydctx->node_when, &meta, lydctx->parse_options);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200592 }
593
594 /* parser next */
595 assert(xmlctx->status == LYXML_ELEM_CLOSE);
596 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
597
598 /* add metadata/attributes */
599 if (snode) {
Michal Vasko871a0252020-11-11 18:35:24 +0100600 lyd_insert_meta(node, meta, 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200601 } else {
602 lyd_insert_attr(node, attr);
603 }
604
605 /* insert, keep first pointer correct */
606 lyd_insert_node((struct lyd_node *)parent, first_p, node);
607 while (!parent && (*first_p)->prev->next) {
608 *first_p = (*first_p)->prev;
609 }
610
Radek Krejciddace2c2021-01-08 11:30:56 +0100611 LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200612 return LY_SUCCESS;
613
614error:
Radek Krejciddace2c2021-01-08 11:30:56 +0100615 LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
Michal Vasko3a41dff2020-07-15 14:30:28 +0200616 lyd_free_meta_siblings(meta);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200617 lyd_free_attr_siblings(ctx, attr);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200618 lyd_free_tree(node);
Radek Krejcie7b95092019-05-15 11:03:07 +0200619 return ret;
620}
621
622LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +0200623lyd_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 +0200624 struct lyd_node **tree_p, struct lyd_ctx **lydctx_p)
Radek Krejcie7b95092019-05-15 11:03:07 +0200625{
Radek Krejci18a57d92019-07-25 14:01:42 +0200626 LY_ERR ret = LY_SUCCESS;
Radek Krejci1798aae2020-07-14 13:26:06 +0200627 struct lyd_xml_ctx *lydctx;
Radek Krejcie7b95092019-05-15 11:03:07 +0200628
Radek Krejci7931b192020-06-25 17:05:03 +0200629 assert(!(parse_options & ~LYD_PARSE_OPTS_MASK));
630 assert(!(validate_options & ~LYD_VALIDATE_OPTS_MASK));
631
Radek Krejci1798aae2020-07-14 13:26:06 +0200632 /* init context */
633 lydctx = calloc(1, sizeof *lydctx);
634 LY_CHECK_ERR_RET(!lydctx, LOGMEM(ctx), LY_EMEM);
635 LY_CHECK_GOTO(ret = lyxml_ctx_new(ctx, in, &lydctx->xmlctx), cleanup);
636 lydctx->parse_options = parse_options;
637 lydctx->validate_options = validate_options;
638 lydctx->free = lyd_xml_ctx_free;
Radek Krejcif3b6fec2019-07-24 15:53:11 +0200639
Michal Vaskob1b5c262020-03-05 14:29:47 +0100640 /* parse XML data */
Michal Vaskoa5da3292020-08-12 13:10:50 +0200641 while (lydctx->xmlctx->status == LYXML_ELEMENT) {
642 LY_CHECK_GOTO(ret = lydxml_subtree_r(lydctx, NULL, tree_p), cleanup);
643 }
Michal Vaskocde73ac2019-11-14 16:10:27 +0100644
Michal Vaskocde73ac2019-11-14 16:10:27 +0100645cleanup:
Michal Vasko49c39d82020-11-06 17:20:27 +0100646 /* there should be no unres stored if validation should be skipped */
647 assert(!(parse_options & LYD_PARSE_ONLY) || (!lydctx->node_types.count && !lydctx->meta_types.count &&
648 !lydctx->node_when.count));
Michal Vasko9b368d32020-02-14 13:53:31 +0100649
Michal Vasko9f96a052020-03-10 09:41:45 +0100650 if (ret) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200651 lyd_xml_ctx_free((struct lyd_ctx *)lydctx);
652 lyd_free_all(*tree_p);
653 *tree_p = NULL;
654 } else {
655 *lydctx_p = (struct lyd_ctx *)lydctx;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100656
657 /* the XML context is no more needed, freeing it also stops logging line numbers which would be confusing now */
658 lyxml_ctx_free(lydctx->xmlctx);
659 lydctx->xmlctx = NULL;
Michal Vasko9f96a052020-03-10 09:41:45 +0100660 }
661 return ret;
662}
Michal Vasko1bf09392020-03-27 12:38:10 +0100663
Michal Vasko2552ea32020-12-08 15:32:34 +0100664#if 0
Michal Vasko1bf09392020-03-27 12:38:10 +0100665static LY_ERR
666lydxml_envelope(struct lyxml_ctx *xmlctx, const char *name, const char *uri, struct lyd_node **envp)
667{
668 LY_ERR ret = LY_SUCCESS;
669 const struct lyxml_ns *ns = NULL;
Radek Krejci1798aae2020-07-14 13:26:06 +0200670 struct lyd_attr *attr = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100671 const char *prefix;
672 size_t prefix_len;
673
674 *envp = NULL;
675
676 assert(xmlctx->status == LYXML_ELEMENT);
677 if (ly_strncmp(name, xmlctx->name, xmlctx->name_len)) {
678 /* not the expected element */
679 return LY_SUCCESS;
680 }
681
682 prefix = xmlctx->prefix;
683 prefix_len = xmlctx->prefix_len;
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200684 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vasko1bf09392020-03-27 12:38:10 +0100685 if (!ns) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100686 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".",
Michal Vasko69730152020-10-09 16:30:07 +0200687 prefix_len, prefix);
Michal Vasko1bf09392020-03-27 12:38:10 +0100688 return LY_EVALID;
689 } else if (strcmp(ns->uri, uri)) {
690 /* different namespace */
691 return LY_SUCCESS;
692 }
693
694 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
695
696 /* create attributes */
697 if (xmlctx->status == LYXML_ATTRIBUTE) {
698 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
699 }
700
701 if (!xmlctx->ws_only) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100702 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected value \"%.*s\" in the \"%s\" element.",
Michal Vasko69730152020-10-09 16:30:07 +0200703 xmlctx->value_len, xmlctx->value, name);
Michal Vasko1bf09392020-03-27 12:38:10 +0100704 ret = LY_EVALID;
705 goto cleanup;
706 }
707
708 /* parser next element */
709 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
710
711 /* create node */
Michal Vasko501af032020-11-11 20:27:44 +0100712 ret = lyd_create_opaq(xmlctx->ctx, name, strlen(name), prefix, prefix_len, uri, strlen(uri), "", 0, NULL,
713 LY_PREF_XML, NULL, LYD_NODEHINT_ENVELOPE, envp);
Michal Vasko1bf09392020-03-27 12:38:10 +0100714 LY_CHECK_GOTO(ret, cleanup);
715
716 /* assign atributes */
717 ((struct lyd_node_opaq *)(*envp))->attr = attr;
718 attr = NULL;
719
720cleanup:
Radek Krejci011e4aa2020-09-04 15:22:31 +0200721 lyd_free_attr_siblings(xmlctx->ctx, attr);
Michal Vasko1bf09392020-03-27 12:38:10 +0100722 return ret;
723}
Michal Vasko79135ae2020-12-16 10:08:35 +0100724
Michal Vasko2552ea32020-12-08 15:32:34 +0100725#endif
Michal Vasko1bf09392020-03-27 12:38:10 +0100726
727LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200728lyd_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 +0100729{
730 LY_ERR ret = LY_SUCCESS;
731 struct lyd_xml_ctx lydctx = {0};
Radek Krejci1798aae2020-07-14 13:26:06 +0200732 struct lyd_node *tree = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100733
734 /* init */
Michal Vasko63f3d842020-07-08 10:10:14 +0200735 LY_CHECK_GOTO(ret = lyxml_ctx_new(ctx, in, &lydctx.xmlctx), cleanup);
Radek Krejci1798aae2020-07-14 13:26:06 +0200736 lydctx.parse_options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
Michal Vasko1bf09392020-03-27 12:38:10 +0100737 lydctx.int_opts = LYD_INTOPT_RPC;
Michal Vasko1bf09392020-03-27 12:38:10 +0100738
Michal Vasko2552ea32020-12-08 15:32:34 +0100739#if 0
Michal Vasko1bf09392020-03-27 12:38:10 +0100740 /* parse "rpc", if any */
741 LY_CHECK_GOTO(ret = lydxml_envelope(lydctx.xmlctx, "rpc", "urn:ietf:params:xml:ns:netconf:base:1.0", &rpc_e), cleanup);
742
743 if (rpc_e) {
744 /* parse "action", if any */
745 LY_CHECK_GOTO(ret = lydxml_envelope(lydctx.xmlctx, "action", "urn:ietf:params:xml:ns:yang:1", &act_e), cleanup);
746 }
Michal Vasko2552ea32020-12-08 15:32:34 +0100747#endif
Michal Vasko1bf09392020-03-27 12:38:10 +0100748
749 /* parse the rest of data normally */
Michal Vaskocf770e22020-08-12 13:21:43 +0200750 LY_CHECK_GOTO(ret = lydxml_subtree_r(&lydctx, NULL, &tree), cleanup);
Michal Vasko1bf09392020-03-27 12:38:10 +0100751
Michal Vaskocf770e22020-08-12 13:21:43 +0200752 /* make sure we have parsed some operation and it is the only subtree */
Radek Krejci1798aae2020-07-14 13:26:06 +0200753 if (!lydctx.op_node) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100754 LOGVAL(ctx, LYVE_DATA, "Missing the \"rpc\"/\"action\" node.");
Michal Vasko1bf09392020-03-27 12:38:10 +0100755 ret = LY_EVALID;
756 goto cleanup;
Michal Vaskocf770e22020-08-12 13:21:43 +0200757 } else if (lydctx.xmlctx->status == LYXML_ELEMENT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100758 LOGVAL(ctx, LYVE_SYNTAX, "Unexpected sibling element of \"%s\".",
Michal Vasko69730152020-10-09 16:30:07 +0200759 tree->schema->name);
Michal Vaskocf770e22020-08-12 13:21:43 +0200760 ret = LY_EVALID;
761 goto cleanup;
Michal Vasko1bf09392020-03-27 12:38:10 +0100762 }
763
Radek Krejci1798aae2020-07-14 13:26:06 +0200764 if (op_p) {
765 *op_p = lydctx.op_node;
Michal Vaskocc048b22020-03-27 15:52:38 +0100766 }
Radek Krejci1798aae2020-07-14 13:26:06 +0200767 assert(tree);
Michal Vasko4189c0f2020-08-13 09:05:22 +0200768 if (tree_p) {
769 *tree_p = tree;
Michal Vasko1bf09392020-03-27 12:38:10 +0100770 }
771
772cleanup:
773 /* we have used parse_only flag */
Michal Vasko49c39d82020-11-06 17:20:27 +0100774 assert(!lydctx.node_types.count && !lydctx.meta_types.count && !lydctx.node_when.count);
Michal Vasko1bf09392020-03-27 12:38:10 +0100775 lyxml_ctx_free(lydctx.xmlctx);
776 if (ret) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200777 lyd_free_all(tree);
Michal Vasko1bf09392020-03-27 12:38:10 +0100778 }
779 return ret;
780}
Michal Vaskoa8edff02020-03-27 14:47:01 +0100781
Michal Vasko2552ea32020-12-08 15:32:34 +0100782#if 0
Michal Vaskoa8edff02020-03-27 14:47:01 +0100783static LY_ERR
784lydxml_notif_envelope(struct lyxml_ctx *xmlctx, struct lyd_node **envp)
785{
786 LY_ERR ret = LY_SUCCESS;
787 const struct lyxml_ns *ns = NULL;
Radek Krejci1798aae2020-07-14 13:26:06 +0200788 struct lyd_attr *attr = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100789 struct lyd_node *et;
790 const char *prefix;
791 size_t prefix_len;
792
793 *envp = NULL;
794
795 /* container envelope */
796 LY_CHECK_GOTO(ret = lydxml_envelope(xmlctx, "notification", "urn:ietf:params:xml:ns:netconf:notification:1.0",
Michal Vasko69730152020-10-09 16:30:07 +0200797 envp), cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100798
799 /* no envelope, fine */
800 if (!*envp) {
801 goto cleanup;
802 }
803
804 /* child "eventTime" */
805 if ((xmlctx->status != LYXML_ELEMENT) || ly_strncmp("eventTime", xmlctx->name, xmlctx->name_len)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100806 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Missing the \"eventTime\" element.");
Michal Vaskoa8edff02020-03-27 14:47:01 +0100807 ret = LY_EVALID;
808 goto cleanup;
809 }
810
811 prefix = xmlctx->prefix;
812 prefix_len = xmlctx->prefix_len;
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200813 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100814 if (!ns) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100815 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", prefix_len, prefix);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100816 ret = LY_EVALID;
817 goto cleanup;
818 } else if (strcmp(ns->uri, "urn:ietf:params:xml:ns:netconf:notification:1.0")) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100819 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid namespace \"%s\" of \"eventTime\".", ns->uri);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100820 ret = LY_EVALID;
821 goto cleanup;
822 }
823
824 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
825
826 /* create attributes */
827 if (xmlctx->status == LYXML_ATTRIBUTE) {
828 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
829 }
830
831 /* validate value */
832 /* TODO */
833 /*if (!xmlctx->ws_only) {
834 LOGVAL(xmlctx->ctx, LY_VLOG_LINE, &xmlctx->line, LYVE_SYNTAX, "Unexpected value \"%.*s\" in the \"%s\" element.",
835 xmlctx->value_len, xmlctx->value, name);
836 ret = LY_EVALID;
837 goto cleanup;
838 }*/
839
840 /* create node */
Radek Krejcif13b87b2020-12-01 22:02:17 +0100841 ret = lyd_create_opaq(xmlctx->ctx, "eventTime", ly_strlen_const("eventTime"), prefix, prefix_len,
842 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 +0100843 LY_CHECK_GOTO(ret, cleanup);
844
845 /* assign atributes */
846 ((struct lyd_node_opaq *)et)->attr = attr;
847 attr = NULL;
848
849 /* insert */
850 lyd_insert_node(*envp, NULL, et);
851
852 /* finish parsing */
853 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
854 if (xmlctx->status != LYXML_ELEM_CLOSE) {
855 assert(xmlctx->status == LYXML_ELEMENT);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100856 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"eventTime\".",
Michal Vasko69730152020-10-09 16:30:07 +0200857 xmlctx->name_len, xmlctx->name);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100858 ret = LY_EVALID;
859 goto cleanup;
860 }
861 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
862
863cleanup:
864 if (ret) {
865 lyd_free_tree(*envp);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200866 lyd_free_attr_siblings(xmlctx->ctx, attr);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100867 }
868 return ret;
869}
Michal Vasko79135ae2020-12-16 10:08:35 +0100870
Michal Vasko2552ea32020-12-08 15:32:34 +0100871#endif
Michal Vaskoa8edff02020-03-27 14:47:01 +0100872
873LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200874lyd_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 +0100875{
876 LY_ERR ret = LY_SUCCESS;
877 struct lyd_xml_ctx lydctx = {0};
Radek Krejci1798aae2020-07-14 13:26:06 +0200878 struct lyd_node *tree = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100879
880 /* init */
Michal Vasko63f3d842020-07-08 10:10:14 +0200881 LY_CHECK_GOTO(ret = lyxml_ctx_new(ctx, in, &lydctx.xmlctx), cleanup);
Radek Krejci1798aae2020-07-14 13:26:06 +0200882 lydctx.parse_options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100883 lydctx.int_opts = LYD_INTOPT_NOTIF;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100884
Michal Vasko2552ea32020-12-08 15:32:34 +0100885#if 0
Michal Vaskoa8edff02020-03-27 14:47:01 +0100886 /* parse "notification" and "eventTime", if present */
887 LY_CHECK_GOTO(ret = lydxml_notif_envelope(lydctx.xmlctx, &ntf_e), cleanup);
Michal Vasko2552ea32020-12-08 15:32:34 +0100888#endif
Michal Vaskoa8edff02020-03-27 14:47:01 +0100889
890 /* parse the rest of data normally */
Michal Vaskocf770e22020-08-12 13:21:43 +0200891 LY_CHECK_GOTO(ret = lydxml_subtree_r(&lydctx, NULL, &tree), cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100892
893 /* make sure we have parsed some notification */
Radek Krejci1798aae2020-07-14 13:26:06 +0200894 if (!lydctx.op_node) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100895 LOGVAL(ctx, LYVE_DATA, "Missing the \"notification\" node.");
Michal Vaskoa8edff02020-03-27 14:47:01 +0100896 ret = LY_EVALID;
897 goto cleanup;
Michal Vaskocf770e22020-08-12 13:21:43 +0200898 } else if (lydctx.xmlctx->status == LYXML_ELEMENT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100899 LOGVAL(ctx, LYVE_SYNTAX, "Unexpected sibling element of \"%s\".",
Michal Vasko69730152020-10-09 16:30:07 +0200900 tree->schema->name);
Michal Vaskocf770e22020-08-12 13:21:43 +0200901 ret = LY_EVALID;
902 goto cleanup;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100903 }
904
Radek Krejci1798aae2020-07-14 13:26:06 +0200905 if (ntf_p) {
906 *ntf_p = lydctx.op_node;
Michal Vaskocc048b22020-03-27 15:52:38 +0100907 }
Radek Krejci1798aae2020-07-14 13:26:06 +0200908 assert(tree);
Michal Vasko2552ea32020-12-08 15:32:34 +0100909 if (tree_p) {
910 *tree_p = tree;
911 }
912
913cleanup:
914 /* we have used parse_only flag */
915 assert(!lydctx.node_types.count && !lydctx.meta_types.count && !lydctx.node_when.count);
916 lyxml_ctx_free(lydctx.xmlctx);
917 if (ret) {
918 lyd_free_all(tree);
919 }
920 return ret;
921}
922
923LY_ERR
924lyd_parse_xml_reply(const struct ly_ctx *ctx, struct ly_in *in, struct lyd_node **tree_p, struct lyd_node **op_p)
925{
926 LY_ERR ret = LY_SUCCESS;
927 struct lyd_xml_ctx lydctx = {0};
928 struct lyd_node *tree = NULL;
929
930 /* init */
931 LY_CHECK_GOTO(ret = lyxml_ctx_new(ctx, in, &lydctx.xmlctx), cleanup);
932 lydctx.parse_options = LYD_PARSE_ONLY | LYD_PARSE_STRICT;
933 lydctx.int_opts = LYD_INTOPT_REPLY;
934
935#if 0
936 /* parse "rpc-reply", if any */
937 LY_CHECK_GOTO(ret = lydxml_envelope(lydctx.xmlctx, "rpc-reply", "urn:ietf:params:xml:ns:netconf:base:1.0", &rpcr_e),
938 cleanup);
939#endif
940
941 /* parse the rest of data normally but connect them to the duplicated operation */
942 while (lydctx.xmlctx->status == LYXML_ELEMENT) {
943 ret = lydxml_subtree_r(&lydctx, NULL, &tree);
944 LY_CHECK_GOTO(ret, cleanup);
945 }
946
947 if (op_p) {
Michal Vasko79135ae2020-12-16 10:08:35 +0100948 *op_p = lydctx.op_node;
Michal Vasko4189c0f2020-08-13 09:05:22 +0200949 }
950 if (tree_p) {
951 *tree_p = tree;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100952 }
953
954cleanup:
955 /* we have used parse_only flag */
Michal Vasko49c39d82020-11-06 17:20:27 +0100956 assert(!lydctx.node_types.count && !lydctx.meta_types.count && !lydctx.node_when.count);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100957 lyxml_ctx_free(lydctx.xmlctx);
958 if (ret) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200959 lyd_free_all(tree);
Michal Vasko1ce933a2020-03-30 12:38:22 +0200960 }
961 return ret;
962}