blob: a5f145a26ed4f809ce367df109fdcc9da4e18847 [file] [log] [blame]
Radek Krejci1721c012015-07-08 12:52:33 +02001/**
Michal Vasko45a0ef32016-09-22 11:07:38 +02002 * @file parser_xml.c
Radek Krejci1721c012015-07-08 12:52:33 +02003 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief XML data parser for libyang
5 *
Michal Vasko7675c622017-03-02 10:50:07 +01006 * Copyright (c) 2015 - 2017 CESNET, z.s.p.o.
Radek Krejci1721c012015-07-08 12:52:33 +02007 *
Radek Krejci54f6fb32016-02-24 12:56:39 +01008 * 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
Michal Vasko8de098c2016-02-26 10:00:25 +010011 *
Radek Krejci54f6fb32016-02-24 12:56:39 +010012 * https://opensource.org/licenses/BSD-3-Clause
Radek Krejci1721c012015-07-08 12:52:33 +020013 */
14
15#include <assert.h>
Radek Krejci3e3affe2015-07-09 15:38:40 +020016#include <ctype.h>
Radek Krejci1721c012015-07-08 12:52:33 +020017#include <errno.h>
Radek Krejci4a49bdf2016-01-12 17:17:01 +010018#include <stdarg.h>
Radek Krejci1721c012015-07-08 12:52:33 +020019#include <stdlib.h>
20#include <string.h>
Michal Vasko8bcdf292015-08-19 14:04:43 +020021#include <limits.h>
Radek Krejci1721c012015-07-08 12:52:33 +020022
Radek Krejci998a0b82015-08-17 13:14:36 +020023#include "libyang.h"
24#include "common.h"
25#include "context.h"
Michal Vaskob7982322015-10-16 13:56:12 +020026#include "parser.h"
Radek Krejci998a0b82015-08-17 13:14:36 +020027#include "tree_internal.h"
28#include "validation.h"
Michal Vaskofc5744d2015-10-22 12:09:34 +020029#include "xml_internal.h"
Radek Krejci1721c012015-07-08 12:52:33 +020030
Michal Vasko0d343d12015-08-24 14:57:36 +020031/* does not log */
Radek Krejci76512572015-08-04 09:47:08 +020032static struct lys_node *
Radek Krejci4a49bdf2016-01-12 17:17:01 +010033xml_data_search_schemanode(struct lyxml_elem *xml, struct lys_node *start, int options)
Radek Krejci1721c012015-07-08 12:52:33 +020034{
Radek Krejci76512572015-08-04 09:47:08 +020035 struct lys_node *result, *aux;
Radek Krejci1721c012015-07-08 12:52:33 +020036
37 LY_TREE_FOR(start, result) {
Radek Krejci4a49bdf2016-01-12 17:17:01 +010038 /* skip groupings ... */
Radek Krejci76512572015-08-04 09:47:08 +020039 if (result->nodetype == LYS_GROUPING) {
Radek Krejci1721c012015-07-08 12:52:33 +020040 continue;
Radek Krejci4a49bdf2016-01-12 17:17:01 +010041 /* ... and output in case of RPC ... */
42 } else if (result->nodetype == LYS_OUTPUT && (options & LYD_OPT_RPC)) {
43 continue;
44 /* ... and input in case of RPC reply */
45 } else if (result->nodetype == LYS_INPUT && (options & LYD_OPT_RPCREPLY)) {
46 continue;
Radek Krejci1721c012015-07-08 12:52:33 +020047 }
48
Radek Krejcifb54be42015-10-02 15:21:16 +020049 /* go into cases, choices, uses and in RPCs into input and output */
50 if (result->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES | LYS_INPUT | LYS_OUTPUT)) {
Radek Krejci4a49bdf2016-01-12 17:17:01 +010051 aux = xml_data_search_schemanode(xml, result->child, options);
Radek Krejci1721c012015-07-08 12:52:33 +020052 if (aux) {
53 /* we have matching result */
54 return aux;
55 }
56 /* else, continue with next schema node */
57 continue;
58 }
59
60 /* match data nodes */
Radek Krejci749190d2016-02-18 16:26:25 +010061 if (ly_strequal(result->name, xml->name, 1)) {
Radek Krejci1721c012015-07-08 12:52:33 +020062 /* names matches, what about namespaces? */
Radek Krejci1a6303d2016-11-04 12:42:46 +010063 if (ly_strequal(lys_main_module(result->module)->ns, xml->ns->value, 1)) {
Radek Krejci1721c012015-07-08 12:52:33 +020064 /* we have matching result */
65 return result;
66 }
67 /* else, continue with next schema node */
68 continue;
69 }
70 }
71
72 /* no match */
73 return NULL;
74}
75
Michal Vasko0d343d12015-08-24 14:57:36 +020076/* logs directly */
Radek Krejcie4748472015-07-08 18:00:22 +020077static int
Michal Vasko35f46a82018-05-30 10:44:11 +020078xml_get_value(struct lyd_node *node, struct lyxml_elem *xml, int editbits, int trusted)
Michal Vasko07471a52015-07-16 11:18:48 +020079{
Michal Vasko4c183312015-09-25 10:41:47 +020080 struct lyd_node_leaf_list *leaf = (struct lyd_node_leaf_list *)node;
Michal Vasko23b61ec2015-08-19 11:19:50 +020081
Radek Krejci0b7704f2016-03-18 12:16:14 +010082 assert(node && (node->schema->nodetype & (LYS_LEAFLIST | LYS_LEAF)) && xml);
Radek Krejci5a988152015-07-15 11:16:26 +020083
Michal Vaskod27602c2016-12-20 11:11:17 +010084 leaf->value_str = lydict_insert(node->schema->module->ctx, xml->content, 0);
Radek Krejcie4748472015-07-08 18:00:22 +020085
Radek Krejci06b45272017-02-24 16:15:02 +010086 if ((editbits & 0x20) && (node->schema->nodetype & LYS_LEAF) && (!leaf->value_str || !leaf->value_str[0])) {
Radek Krejci1fe9ac02016-09-23 09:38:21 +020087 /* we have edit-config leaf/leaf-list with delete operation and no (empty) value,
88 * this is not a bug since the node is just used as a kind of selection node */
Michal Vasko70bf8e52018-03-26 11:32:33 +020089 leaf->value_type = LY_TYPE_UNKNOWN;
Radek Krejci1fe9ac02016-09-23 09:38:21 +020090 return EXIT_SUCCESS;
91 }
92
Radek Krejci1899d6a2016-11-03 13:48:07 +010093 /* the value is here converted to a JSON format if needed in case of LY_TYPE_IDENT and LY_TYPE_INST or to a
94 * canonical form of the value */
Michal Vasko35f46a82018-05-30 10:44:11 +020095 if (!lyp_parse_value(&((struct lys_node_leaf *)leaf->schema)->type, &leaf->value_str, xml, leaf, NULL, NULL, 1, 0, trusted)) {
Michal Vasko493bea72015-07-16 16:08:12 +020096 return EXIT_FAILURE;
Radek Krejcie4748472015-07-08 18:00:22 +020097 }
98
99 return EXIT_SUCCESS;
100}
101
Michal Vasko0d343d12015-08-24 14:57:36 +0200102/* logs directly */
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100103static int
Radek Krejcibd930122016-08-10 13:28:26 +0200104xml_parse_data(struct ly_ctx *ctx, struct lyxml_elem *xml, struct lyd_node *parent, struct lyd_node *first_sibling,
105 struct lyd_node *prev, int options, struct unres_data *unres, struct lyd_node **result,
PavolVican832f5432018-02-21 00:54:45 +0100106 struct lyd_node **act_notif, const char *yang_data_name)
Radek Krejci1721c012015-07-08 12:52:33 +0200107{
Michal Vaskof53187d2017-01-13 13:23:14 +0100108 const struct lys_module *mod = NULL;
Radek Krejcibd930122016-08-10 13:28:26 +0200109 struct lyd_node *diter, *dlast;
Michal Vasko5e523b62016-08-26 16:23:15 +0200110 struct lys_node *schema = NULL, *target;
PavolVican832f5432018-02-21 00:54:45 +0100111 const struct lys_node *ext_node;
Michal Vasko5e523b62016-08-26 16:23:15 +0200112 struct lys_node_augment *aug;
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100113 struct lyd_attr *dattr, *dattr_iter;
Radek Krejcia5241e52015-08-19 15:09:31 +0200114 struct lyxml_attr *attr;
Michal Vaskof748dbc2016-04-05 11:27:47 +0200115 struct lyxml_elem *child, *next;
Radek Krejci65aca412018-01-24 11:23:06 +0100116 int i, j, havechildren, r, editbits = 0, filterflag = 0, found;
117 uint8_t pos;
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100118 int ret = 0;
Radek Krejciabb7b582016-04-20 16:15:47 +0200119 const char *str = NULL;
Michal Vasko5bf8e212018-01-19 09:04:41 +0100120 char *msg;
Radek Krejci1721c012015-07-08 12:52:33 +0200121
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100122 assert(xml);
123 assert(result);
124 *result = NULL;
125
Radek Krejcie1bacd72017-03-01 13:18:46 +0100126 if (xml->flags & LYXML_ELEM_MIXED) {
127 if (options & LYD_OPT_STRICT) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100128 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_XML, xml, "XML element with mixed content");
Radek Krejcie1bacd72017-03-01 13:18:46 +0100129 return -1;
130 } else {
131 return 0;
132 }
133 }
134
Radek Krejci1721c012015-07-08 12:52:33 +0200135 if (!xml->ns || !xml->ns->value) {
Radek Krejci2342cf62016-01-29 16:48:23 +0100136 if (options & LYD_OPT_STRICT) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100137 LOGVAL(ctx, LYE_XML_MISS, LY_VLOG_XML, xml, "element's", "namespace");
Radek Krejci2342cf62016-01-29 16:48:23 +0100138 return -1;
139 } else {
140 return 0;
141 }
Radek Krejci1721c012015-07-08 12:52:33 +0200142 }
143
144 /* find schema node */
Michal Vaskob1b19442016-07-13 12:26:01 +0200145 if (!parent) {
Michal Vasko03b0a672018-06-15 09:58:30 +0200146 mod = ly_ctx_get_module_by_ns(ctx, xml->ns->value, NULL, 0);
Michal Vaskof53187d2017-01-13 13:23:14 +0100147 if (ctx->data_clb) {
148 if (!mod) {
149 mod = ctx->data_clb(ctx, NULL, xml->ns->value, 0, ctx->data_clb_data);
150 } else if (!mod->implemented) {
151 mod = ctx->data_clb(ctx, mod->name, mod->ns, LY_MODCLB_NOT_IMPLEMENTED, ctx->data_clb_data);
Radek Krejci27fe55e2016-09-13 17:13:35 +0200152 }
Michal Vaskof53187d2017-01-13 13:23:14 +0100153 }
154
155 /* get the proper schema node */
156 if (mod && mod->implemented && !mod->disabled) {
PavolVican832f5432018-02-21 00:54:45 +0100157 if (options & LYD_OPT_DATA_TEMPLATE) {
Michal Vaskod60a1a32018-05-23 16:31:22 +0200158 if (yang_data_name) {
159 ext_node = lyp_get_yang_data_template(mod, yang_data_name, strlen(yang_data_name));
160 if (ext_node) {
161 schema = *((struct lys_node **) lys_ext_complex_get_substmt(LY_STMT_CONTAINER, (struct lys_ext_instance_complex *)ext_node, NULL));
162 schema = xml_data_search_schemanode(xml, schema, options);
163 }
PavolVican832f5432018-02-21 00:54:45 +0100164 }
165 } else {
166 schema = xml_data_search_schemanode(xml, mod->data, options);
167 if (!schema) {
168 /* it still can be the specific case of this module containing an augment of another module
169 * top-level choice or top-level choice's case, bleh */
170 for (j = 0; j < mod->augment_size; ++j) {
171 aug = &mod->augment[j];
172 target = aug->target;
173 if (target->nodetype & (LYS_CHOICE | LYS_CASE)) {
174 /* 1) okay, the target is choice or case */
175 while (target && (target->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES))) {
176 target = lys_parent(target);
177 }
178 /* 2) now, the data node will be top-level, there are only non-data schema nodes */
179 if (!target) {
Michal Vasko8829c112018-06-15 09:59:00 +0200180 while ((schema = (struct lys_node *) lys_getnext(schema, (struct lys_node *) aug, NULL, 0))) {
PavolVican832f5432018-02-21 00:54:45 +0100181 /* 3) alright, even the name matches, we found our schema node */
182 if (ly_strequal(schema->name, xml->name, 1)) {
183 break;
184 }
Michal Vasko5e523b62016-08-26 16:23:15 +0200185 }
186 }
187 }
188
PavolVican832f5432018-02-21 00:54:45 +0100189 if (schema) {
190 break;
191 }
Michal Vasko5e523b62016-08-26 16:23:15 +0200192 }
193 }
Radek Krejci1721c012015-07-08 12:52:33 +0200194 }
195 }
196 } else {
197 /* parsing some internal node, we start with parent's schema pointer */
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100198 schema = xml_data_search_schemanode(xml, parent->schema->child, options);
Michal Vaskof53187d2017-01-13 13:23:14 +0100199
Michal Vaskoa358f942017-05-09 10:45:33 +0200200 if (ctx->data_clb) {
201 if (schema && !lys_node_module(schema)->implemented) {
Michal Vaskoad43c182017-01-23 09:55:28 +0100202 ctx->data_clb(ctx, lys_node_module(schema)->name, lys_node_module(schema)->ns,
203 LY_MODCLB_NOT_IMPLEMENTED, ctx->data_clb_data);
Michal Vaskoa358f942017-05-09 10:45:33 +0200204 } else if (!schema) {
205 if (ctx->data_clb(ctx, NULL, xml->ns->value, 0, ctx->data_clb_data)) {
206 /* context was updated, so try to find the schema node again */
207 schema = xml_data_search_schemanode(xml, parent->schema->child, options);
208 }
Michal Vaskof53187d2017-01-13 13:23:14 +0100209 }
Radek Krejci25b9fd32015-08-10 15:06:07 +0200210 }
Michal Vaskof53187d2017-01-13 13:23:14 +0100211 }
212
213 mod = lys_node_module(schema);
214 if (!mod || !mod->implemented || mod->disabled) {
Radek Krejci27fe55e2016-09-13 17:13:35 +0200215 if (options & LYD_OPT_STRICT) {
Michal Vaskoaf8ec362018-03-28 09:08:09 +0200216 LOGVAL(ctx, LYE_INELEM, (parent ? LY_VLOG_LYD : LY_VLOG_STR), (parent ? (void *)parent : (void *)"/") , xml->name);
Radek Krejci27fe55e2016-09-13 17:13:35 +0200217 return -1;
218 } else {
219 return 0;
220 }
Radek Krejci1721c012015-07-08 12:52:33 +0200221 }
222
Radek Krejciadb57612016-02-16 13:34:34 +0100223 /* create the element structure */
Radek Krejcib9930252015-07-08 15:47:45 +0200224 switch (schema->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +0200225 case LYS_CONTAINER:
Radek Krejci27aaa732015-09-04 15:24:04 +0200226 case LYS_LIST:
Michal Vasko2f30e572015-10-01 16:00:38 +0200227 case LYS_NOTIF:
228 case LYS_RPC:
Michal Vaskob1b19442016-07-13 12:26:01 +0200229 case LYS_ACTION:
Michal Vasko0fd75a22018-01-30 15:40:18 +0100230 for (i = 0; xml->content && xml->content[i]; ++i) {
231 if (!is_xmlws(xml->content[i])) {
232 msg = malloc(22 + strlen(xml->content) + 1);
Michal Vasko53b7da02018-02-13 15:28:42 +0100233 LY_CHECK_ERR_RETURN(!msg, LOGMEM(ctx), -1);
Michal Vasko0fd75a22018-01-30 15:40:18 +0100234 sprintf(msg, "node with text data \"%s\"", xml->content);
Michal Vasko53b7da02018-02-13 15:28:42 +0100235 LOGVAL(ctx, LYE_XML_INVAL, LY_VLOG_XML, xml, msg);
Michal Vasko0fd75a22018-01-30 15:40:18 +0100236 free(msg);
237 return -1;
238 }
Radek Krejci3096a802017-11-09 12:47:11 +0100239 }
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100240 *result = calloc(1, sizeof **result);
Michal Vaskoab8e4402015-07-17 12:54:28 +0200241 havechildren = 1;
Radek Krejcib9930252015-07-08 15:47:45 +0200242 break;
Radek Krejci76512572015-08-04 09:47:08 +0200243 case LYS_LEAF:
Radek Krejci76512572015-08-04 09:47:08 +0200244 case LYS_LEAFLIST:
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100245 *result = calloc(1, sizeof(struct lyd_node_leaf_list));
Radek Krejcie4748472015-07-08 18:00:22 +0200246 havechildren = 0;
247 break;
Radek Krejci76512572015-08-04 09:47:08 +0200248 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +0200249 case LYS_ANYDATA:
250 *result = calloc(1, sizeof(struct lyd_node_anydata));
Michal Vaskoab8e4402015-07-17 12:54:28 +0200251 havechildren = 0;
252 break;
Radek Krejcib9930252015-07-08 15:47:45 +0200253 default:
Michal Vasko53b7da02018-02-13 15:28:42 +0100254 LOGINT(ctx);
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100255 return -1;
Radek Krejcib9930252015-07-08 15:47:45 +0200256 }
Michal Vasko53b7da02018-02-13 15:28:42 +0100257 LY_CHECK_ERR_RETURN(!(*result), LOGMEM(ctx), -1);
Michal Vasko253035f2015-12-17 16:58:13 +0100258
Radek Krejci61767ca2016-09-19 14:21:55 +0200259 (*result)->prev = *result;
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100260 (*result)->schema = schema;
Radek Krejci61767ca2016-09-19 14:21:55 +0200261 (*result)->parent = parent;
262 diter = NULL;
Radek Krejci65aca412018-01-24 11:23:06 +0100263 if (schema->nodetype == LYS_LEAF && lys_is_key((struct lys_node_leaf *)schema, &pos)) {
Michal Vasko80389542018-02-08 14:35:32 +0100264 /* it is key and we need to insert it into a correct place (a key must have a parent list) */
265 assert(parent);
Radek Krejci61767ca2016-09-19 14:21:55 +0200266 for (i = 0, diter = parent->child;
Radek Krejci65aca412018-01-24 11:23:06 +0100267 diter && i < pos && diter->schema->nodetype == LYS_LEAF && lys_is_key((struct lys_node_leaf *)diter->schema, NULL);
Radek Krejci61767ca2016-09-19 14:21:55 +0200268 i++, diter = diter->next);
269 if (diter) {
270 /* out of order insertion - insert list's key to the correct position, before the diter */
271 if (options & LYD_OPT_STRICT) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100272 LOGVAL(ctx, LYE_INORDER, LY_VLOG_LYD, *result, schema->name, diter->schema->name);
273 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Invalid position of the key \"%s\" in a list \"%s\".",
Radek Krejci61767ca2016-09-19 14:21:55 +0200274 schema->name, parent->schema->name);
275 free(*result);
276 *result = NULL;
277 return -1;
278 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +0100279 LOGWRN(ctx, "Invalid position of the key \"%s\" in a list \"%s\".", schema->name, parent->schema->name)
Radek Krejci61767ca2016-09-19 14:21:55 +0200280 }
281 if (parent->child == diter) {
282 parent->child = *result;
283 /* update first_sibling */
284 first_sibling = *result;
285 }
286 if (diter->prev->next) {
287 diter->prev->next = *result;
288 }
289 (*result)->prev = diter->prev;
290 diter->prev = *result;
291 (*result)->next = diter;
292 }
293 }
294 if (!diter) {
295 /* simplified (faster) insert as the last node */
296 if (parent && !parent->child) {
297 parent->child = *result;
298 }
299 if (prev) {
300 (*result)->prev = prev;
301 prev->next = *result;
302
303 /* fix the "last" pointer */
304 first_sibling->prev = *result;
305 } else {
306 (*result)->prev = *result;
307 first_sibling = *result;
308 }
309 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +0100310 (*result)->validity = ly_new_node_validity((*result)->schema);
Radek Krejci46165822016-08-26 14:06:27 +0200311 if (resolve_applies_when(schema, 0, NULL)) {
Radek Krejci0b7704f2016-03-18 12:16:14 +0100312 (*result)->when_status = LYD_WHEN;
313 }
Radek Krejci1721c012015-07-08 12:52:33 +0200314
Radek Krejci146e3fc2017-02-24 13:41:00 +0100315 /* process attributes */
Radek Krejci998a7502015-10-26 15:54:33 +0100316 for (attr = xml->attr; attr; attr = attr->next) {
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100317 if (attr->type != LYXML_ATTR_STD) {
318 continue;
319 } else if (!attr->ns) {
Radek Krejcia68ddeb2017-02-24 12:49:44 +0100320 if ((*result)->schema->nodetype == LYS_ANYXML &&
321 ly_strequal((*result)->schema->name, "filter", 0) &&
Michal Vaskoaa98eb72017-03-24 11:23:34 +0100322 (ly_strequal((*result)->schema->module->name, "ietf-netconf", 0) ||
323 ly_strequal((*result)->schema->module->name, "notifications", 0))) {
Radek Krejcia68ddeb2017-02-24 12:49:44 +0100324 /* NETCONF filter's attributes, which we implement as non-standard annotations,
325 * they are unqualified (no namespace), but we know that we have internally defined
Michal Vaskoaa98eb72017-03-24 11:23:34 +0100326 * them in the ietf-netconf module */
327 str = "urn:ietf:params:xml:ns:netconf:base:1.0";
Radek Krejci598dbcb2017-02-24 15:14:15 +0100328 filterflag = 1;
Radek Krejci9a5daea2016-03-02 16:49:40 +0100329 } else {
Radek Krejcia68ddeb2017-02-24 12:49:44 +0100330 /* garbage */
331 goto attr_error;
Radek Krejci532e5e92017-02-22 12:59:24 +0100332 }
Michal Vasko7675c622017-03-02 10:50:07 +0100333 } else {
334 str = attr->ns->value;
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100335 }
336
Michal Vasko35f46a82018-05-30 10:44:11 +0200337 r = lyp_fill_attr(ctx, *result, str, NULL, attr->name, attr->value, xml, options, &dattr);
Michal Vasko7675c622017-03-02 10:50:07 +0100338 if (r == -1) {
Michal Vaskoa6af3652018-08-29 12:15:20 +0200339 goto unlink_node_error;
Michal Vasko7675c622017-03-02 10:50:07 +0100340 } else if (r == 1) {
341attr_error:
342 if (options & LYD_OPT_STRICT) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100343 LOGVAL(ctx, LYE_INATTR, LY_VLOG_LYD, *result, attr->name);
Michal Vaskoa6af3652018-08-29 12:15:20 +0200344 goto unlink_node_error;
Michal Vasko7675c622017-03-02 10:50:07 +0100345 }
346
Michal Vasko53b7da02018-02-13 15:28:42 +0100347 LOGWRN(ctx, "Unknown \"%s:%s\" metadata with value \"%s\", ignoring.",
Michal Vasko7675c622017-03-02 10:50:07 +0100348 (attr->ns ? attr->ns->prefix : "<none>"), attr->name, attr->value);
349 continue;
Michal Vasko253035f2015-12-17 16:58:13 +0100350 }
Radek Krejci532e5e92017-02-22 12:59:24 +0100351
Michal Vasko7675c622017-03-02 10:50:07 +0100352 /* special case of xpath in the value, we want to convert it to JSON */
353 if (filterflag && !strcmp(attr->name, "select")) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100354 dattr->value.string = transform_xml2json(ctx, dattr->value_str, xml, 0, 0);
Radek Krejci598dbcb2017-02-24 15:14:15 +0100355 if (!dattr->value.string) {
356 /* problem with resolving value as xpath */
Michal Vasko7675c622017-03-02 10:50:07 +0100357 dattr->value.string = dattr->value_str;
Michal Vaskoa6af3652018-08-29 12:15:20 +0200358 goto unlink_node_error;
Radek Krejci598dbcb2017-02-24 15:14:15 +0100359 }
360 lydict_remove(ctx, dattr->value_str);
361 dattr->value_str = dattr->value.string;
Radek Krejcia571d942017-02-24 09:26:49 +0100362 }
363
Radek Krejci532e5e92017-02-22 12:59:24 +0100364 /* insert into the data node */
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100365 if (!(*result)->attr) {
366 (*result)->attr = dattr;
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100367 } else {
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100368 for (dattr_iter = (*result)->attr; dattr_iter->next; dattr_iter = dattr_iter->next);
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100369 dattr_iter->next = dattr;
Radek Krejci998a7502015-10-26 15:54:33 +0100370 }
Radek Krejci532e5e92017-02-22 12:59:24 +0100371 continue;
Radek Krejci998a7502015-10-26 15:54:33 +0100372 }
Michal Vasko4ff7b072015-08-21 09:05:03 +0200373
Radek Krejci146e3fc2017-02-24 13:41:00 +0100374 /* check insert attribute and its values */
375 if (options & LYD_OPT_EDIT) {
Michal Vasko7675c622017-03-02 10:50:07 +0100376 if (lyp_check_edit_attr(ctx, (*result)->attr, *result, &editbits)) {
Michal Vaskoa6af3652018-08-29 12:15:20 +0200377 goto unlink_node_error;
Michal Vasko7675c622017-03-02 10:50:07 +0100378 }
Radek Krejci146e3fc2017-02-24 13:41:00 +0100379
Michal Vasko7675c622017-03-02 10:50:07 +0100380 /* check correct filter extension attributes */
381 } else if (filterflag) {
382 found = 0; /* 0 - nothing, 1 - type subtree, 2 - type xpath, 3 - select, 4 - type xpath + select */
383 LY_TREE_FOR((*result)->attr, dattr_iter) {
384 if (!strcmp(dattr_iter->name, "type")) {
385 if ((found == 1) || (found == 2) || (found == 4)) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100386 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_LYD, (*result), "type", xml->name);
Michal Vaskoa6af3652018-08-29 12:15:20 +0200387 goto unlink_node_error;
Radek Krejci146e3fc2017-02-24 13:41:00 +0100388 }
Michal Vasko7675c622017-03-02 10:50:07 +0100389 switch (dattr_iter->value.enm->value) {
390 case 0:
391 /* subtree */
392 if (found == 3) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100393 LOGVAL(ctx, LYE_INATTR, LY_VLOG_LYD, (*result), dattr_iter->name);
Michal Vaskoa6af3652018-08-29 12:15:20 +0200394 goto unlink_node_error;
Michal Vasko7675c622017-03-02 10:50:07 +0100395 }
Radek Krejci06b45272017-02-24 16:15:02 +0100396
Michal Vasko7675c622017-03-02 10:50:07 +0100397 assert(!found);
398 found = 1;
399 break;
400 case 1:
401 /* xpath */
402 if (found == 3) {
403 found = 4;
404 } else {
405 assert(!found);
406 found = 2;
407 }
408 break;
409 default:
Michal Vasko53b7da02018-02-13 15:28:42 +0100410 LOGINT(ctx);
Michal Vaskoa6af3652018-08-29 12:15:20 +0200411 goto unlink_node_error;
Radek Krejci146e3fc2017-02-24 13:41:00 +0100412 }
Michal Vasko7675c622017-03-02 10:50:07 +0100413 } else if (!strcmp(dattr_iter->name, "select")) {
414 switch (found) {
415 case 0:
416 found = 3;
417 break;
418 case 1:
Michal Vasko53b7da02018-02-13 15:28:42 +0100419 LOGVAL(ctx, LYE_INATTR, LY_VLOG_LYD, (*result), dattr_iter->name);
Michal Vaskoa6af3652018-08-29 12:15:20 +0200420 goto unlink_node_error;
Michal Vasko7675c622017-03-02 10:50:07 +0100421 case 2:
422 found = 4;
423 break;
424 case 3:
425 case 4:
Michal Vasko53b7da02018-02-13 15:28:42 +0100426 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_LYD, (*result), "select", xml->name);
Michal Vaskoa6af3652018-08-29 12:15:20 +0200427 goto unlink_node_error;
Michal Vasko7675c622017-03-02 10:50:07 +0100428 default:
Michal Vasko53b7da02018-02-13 15:28:42 +0100429 LOGINT(ctx);
Michal Vaskoa6af3652018-08-29 12:15:20 +0200430 goto unlink_node_error;
Radek Krejci146e3fc2017-02-24 13:41:00 +0100431 }
Radek Krejci146e3fc2017-02-24 13:41:00 +0100432 }
433 }
434
Michal Vasko7675c622017-03-02 10:50:07 +0100435 /* check if what we found is correct */
436 switch (found) {
437 case 1:
438 case 4:
439 /* ok */
440 break;
441 case 2:
Michal Vasko53b7da02018-02-13 15:28:42 +0100442 LOGVAL(ctx, LYE_MISSATTR, LY_VLOG_LYD, (*result), "select", xml->name);
Michal Vaskoa6af3652018-08-29 12:15:20 +0200443 goto unlink_node_error;
Michal Vasko7675c622017-03-02 10:50:07 +0100444 case 3:
Michal Vasko53b7da02018-02-13 15:28:42 +0100445 LOGVAL(ctx, LYE_MISSATTR, LY_VLOG_LYD, (*result), "type", xml->name);
Michal Vaskoa6af3652018-08-29 12:15:20 +0200446 goto unlink_node_error;
Michal Vasko7675c622017-03-02 10:50:07 +0100447 default:
Michal Vasko53b7da02018-02-13 15:28:42 +0100448 LOGINT(ctx);
Michal Vaskoa6af3652018-08-29 12:15:20 +0200449 goto unlink_node_error;
Radek Krejci146e3fc2017-02-24 13:41:00 +0100450 }
451 }
452
Michal Vaskoe342d9f2018-08-07 12:22:08 +0200453 /* type specific processing */
454 if (schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
455 /* type detection and assigning the value */
456 if (xml_get_value(*result, xml, editbits, options & LYD_OPT_TRUSTED)) {
Michal Vaskoa6af3652018-08-29 12:15:20 +0200457 goto unlink_node_error;
Michal Vaskoe342d9f2018-08-07 12:22:08 +0200458 }
459 } else if (schema->nodetype & LYS_ANYDATA) {
460 /* store children values */
461 if (xml->child) {
462 child = xml->child;
463 /* manually unlink all siblings and correct namespaces */
464 xml->child = NULL;
465 LY_TREE_FOR(child, next) {
466 next->parent = NULL;
467 lyxml_correct_elem_ns(ctx, next, 1, 1);
468 }
469
470 ((struct lyd_node_anydata *)*result)->value_type = LYD_ANYDATA_XML;
471 ((struct lyd_node_anydata *)*result)->value.xml = child;
472 } else {
473 ((struct lyd_node_anydata *)*result)->value_type = LYD_ANYDATA_CONSTSTRING;
474 ((struct lyd_node_anydata *)*result)->value.str = lydict_insert(ctx, xml->content, 0);
475 }
476 } else if (schema->nodetype & (LYS_RPC | LYS_ACTION)) {
477 if (!(options & LYD_OPT_RPC) || *act_notif) {
478 LOGVAL(ctx, LYE_INELEM, LY_VLOG_LYD, (*result), schema->name);
479 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Unexpected %s node \"%s\".",
480 (schema->nodetype == LYS_RPC ? "rpc" : "action"), schema->name);
Michal Vaskoa6af3652018-08-29 12:15:20 +0200481 goto unlink_node_error;
Michal Vaskoe342d9f2018-08-07 12:22:08 +0200482 }
483 *act_notif = *result;
484 } else if (schema->nodetype == LYS_NOTIF) {
485 if (!(options & LYD_OPT_NOTIF) || *act_notif) {
486 LOGVAL(ctx, LYE_INELEM, LY_VLOG_LYD, (*result), schema->name);
487 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Unexpected notification node \"%s\".", schema->name);
Michal Vaskoa6af3652018-08-29 12:15:20 +0200488 goto unlink_node_error;
Michal Vaskoe342d9f2018-08-07 12:22:08 +0200489 }
490 *act_notif = *result;
491 }
492
493#ifdef LY_ENABLED_CACHE
494 /* calculate the hash and insert it into parent (list with keys is handled when its keys are inserted) */
495 if (((*result)->schema->nodetype != LYS_LIST) || !((struct lys_node_list *)(*result)->schema)->keys_size) {
496 lyd_hash(*result);
497 lyd_insert_hash(*result);
498 }
499#endif
500
Radek Krejci146e3fc2017-02-24 13:41:00 +0100501 /* first part of validation checks */
502 if (lyv_data_context(*result, options, unres)) {
503 goto error;
504 }
505
Radek Krejci14c00092015-11-01 11:03:24 +0100506 /* process children */
507 if (havechildren && xml->child) {
508 diter = dlast = NULL;
509 LY_TREE_FOR_SAFE(xml->child, next, child) {
PavolVican832f5432018-02-21 00:54:45 +0100510 r = xml_parse_data(ctx, child, *result, (*result)->child, dlast, options, unres, &diter, act_notif, yang_data_name);
Radek Krejci14c00092015-11-01 11:03:24 +0100511 if (r) {
512 goto error;
Radek Krejci86538212015-12-17 15:59:01 +0100513 } else if (options & LYD_OPT_DESTRUCT) {
514 lyxml_free(ctx, child);
Radek Krejci14c00092015-11-01 11:03:24 +0100515 }
Radek Krejci61767ca2016-09-19 14:21:55 +0200516 if (diter && !diter->next) {
517 /* the child was parsed/created and it was placed as the last child. The child can be inserted
518 * out of order (not as the last one) in case it is a list's key present out of the correct order */
Radek Krejci14c00092015-11-01 11:03:24 +0100519 dlast = diter;
520 }
521 }
522 }
523
Radek Krejcifb7156e2016-10-27 13:39:56 +0200524 /* if we have empty non-presence container, we keep it, but mark it as default */
Radek Krejci2537fd32016-09-07 16:22:41 +0200525 if (schema->nodetype == LYS_CONTAINER && !(*result)->child &&
Radek Krejcid3e73722016-05-23 12:24:55 +0200526 !(*result)->attr && !((struct lys_node_container *)schema)->presence) {
Radek Krejcifb7156e2016-10-27 13:39:56 +0200527 (*result)->dflt = 1;
Radek Krejci0c0086a2016-03-24 15:20:28 +0100528 }
529
Radek Krejcicf509982015-12-15 09:22:44 +0100530 /* rest of validation checks */
Michal Vaskoe3886bb2017-01-02 11:33:28 +0100531 if (lyv_data_content(*result, options, unres) ||
Michal Vasko53b7da02018-02-13 15:28:42 +0100532 lyv_multicases(*result, NULL, prev ? &first_sibling : NULL, 0, NULL)) {
533 goto error;
Radek Krejci78ce8612015-08-18 14:31:05 +0200534 }
535
Radek Krejcica7efb72016-01-18 13:06:01 +0100536 /* validation successful */
Radek Krejci63b79c82016-08-10 10:09:33 +0200537 if ((*result)->schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
538 /* postpone checking when there will be all list/leaflist instances */
Michal Vasko185b5272018-09-13 14:26:12 +0200539 (*result)->validity |= LYD_VAL_DUP;
Radek Krejci63b79c82016-08-10 10:09:33 +0200540 }
Radek Krejcica7efb72016-01-18 13:06:01 +0100541
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100542 return ret;
Radek Krejci3e3affe2015-07-09 15:38:40 +0200543
Michal Vaskoa6af3652018-08-29 12:15:20 +0200544unlink_node_error:
545 lyd_unlink_internal(*result, 2);
Radek Krejci3e3affe2015-07-09 15:38:40 +0200546error:
Radek Krejcieab784a2015-08-27 09:56:53 +0200547 /* cleanup */
Radek Krejci0c0086a2016-03-24 15:20:28 +0100548 for (i = unres->count - 1; i >= 0; i--) {
549 /* remove unres items connected with the node being removed */
550 if (unres->node[i] == *result) {
551 unres_data_del(unres, i);
552 }
553 }
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100554 lyd_free(*result);
555 *result = NULL;
Michal Vasko53b7da02018-02-13 15:28:42 +0100556 return -1;
Radek Krejci1721c012015-07-08 12:52:33 +0200557}
558
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100559API struct lyd_node *
560lyd_parse_xml(struct ly_ctx *ctx, struct lyxml_elem **root, int options, ...)
Radek Krejcic6704c82015-10-06 11:12:45 +0200561{
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100562 va_list ap;
Michal Vasko185b5272018-09-13 14:26:12 +0200563 int r;
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100564 struct unres_data *unres = NULL;
Michal Vasko945b96b2016-10-18 11:49:12 +0200565 const struct lyd_node *rpc_act = NULL, *data_tree = NULL;
566 struct lyd_node *result = NULL, *iter, *last, *reply_parent = NULL, *reply_top = NULL, *act_notif = NULL;
Michal Vaskoa8756562017-05-03 14:42:23 +0200567 struct lyxml_elem *xmlstart, *xmlelem, *xmlaux, *xmlfree = NULL;
PavolVican832f5432018-02-21 00:54:45 +0100568 const char *yang_data_name = NULL;
Radek Krejci2342cf62016-01-29 16:48:23 +0100569
Radek Krejcic6704c82015-10-06 11:12:45 +0200570 if (!ctx || !root) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100571 LOGARG;
Radek Krejcic6704c82015-10-06 11:12:45 +0200572 return NULL;
573 }
574
Michal Vasko53b7da02018-02-13 15:28:42 +0100575 if (lyp_data_check_options(ctx, options, __func__)) {
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100576 return NULL;
577 }
578
Radek Krejci19dbedb2017-08-08 13:54:31 +0200579 if (!(*root) && !(options & LYD_OPT_RPCREPLY)) {
580 /* empty tree */
581 if (options & (LYD_OPT_RPC | LYD_OPT_NOTIF)) {
582 /* error, top level node identify RPC and Notification */
Michal Vasko53b7da02018-02-13 15:28:42 +0100583 LOGERR(ctx, LY_EINVAL, "%s: *root identifies RPC/Notification so it cannot be NULL.", __func__);
Radek Krejci19dbedb2017-08-08 13:54:31 +0200584 return NULL;
585 } else if (!(options & LYD_OPT_RPCREPLY)) {
586 /* others - no work is needed, just check for missing mandatory nodes */
587 lyd_validate(&result, options, ctx);
Michal Vasko53b7da02018-02-13 15:28:42 +0100588 return result;
Radek Krejci19dbedb2017-08-08 13:54:31 +0200589 }
590 /* continue with empty RPC reply, for which we need RPC */
Radek Krejcia6939c32016-03-24 15:19:09 +0100591 }
592
Michal Vasko24d982f2016-04-18 15:13:58 +0200593 unres = calloc(1, sizeof *unres);
Michal Vasko53b7da02018-02-13 15:28:42 +0100594 LY_CHECK_ERR_RETURN(!unres, LOGMEM(ctx), NULL);
Michal Vasko24d982f2016-04-18 15:13:58 +0200595
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100596 va_start(ap, options);
597 if (options & LYD_OPT_RPCREPLY) {
Michal Vasko945b96b2016-10-18 11:49:12 +0200598 rpc_act = va_arg(ap, const struct lyd_node *);
599 if (!rpc_act || rpc_act->parent || !(rpc_act->schema->nodetype & (LYS_RPC | LYS_LIST | LYS_CONTAINER))) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100600 LOGERR(ctx, LY_EINVAL, "%s: invalid variable parameter (const struct lyd_node *rpc_act).", __func__);
Michal Vasko24d982f2016-04-18 15:13:58 +0200601 goto error;
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100602 }
Michal Vasko945b96b2016-10-18 11:49:12 +0200603 if (rpc_act->schema->nodetype == LYS_RPC) {
604 /* RPC request */
605 reply_top = reply_parent = _lyd_new(NULL, rpc_act->schema, 0);
606 } else {
607 /* action request */
608 reply_top = lyd_dup(rpc_act, 1);
609 LY_TREE_DFS_BEGIN(reply_top, iter, reply_parent) {
610 if (reply_parent->schema->nodetype == LYS_ACTION) {
611 break;
612 }
613 LY_TREE_DFS_END(reply_top, iter, reply_parent);
614 }
615 if (!reply_parent) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100616 LOGERR(ctx, LY_EINVAL, "%s: invalid variable parameter (const struct lyd_node *rpc_act).", __func__);
Michal Vasko945b96b2016-10-18 11:49:12 +0200617 lyd_free_withsiblings(reply_top);
618 goto error;
619 }
620 lyd_free_withsiblings(reply_parent->child);
621 }
Michal Vasko45e23652016-09-21 11:24:32 +0200622 }
623 if (options & (LYD_OPT_RPC | LYD_OPT_NOTIF | LYD_OPT_RPCREPLY)) {
Michal Vasko945b96b2016-10-18 11:49:12 +0200624 data_tree = va_arg(ap, const struct lyd_node *);
Michal Vasko6b44d712016-09-12 16:25:46 +0200625 if (data_tree) {
Michal Vaskod6a48062017-08-11 14:28:56 +0200626 if (options & LYD_OPT_NOEXTDEPS) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100627 LOGERR(ctx, LY_EINVAL, "%s: invalid parameter (variable arg const struct lyd_node *data_tree and LYD_OPT_NOEXTDEPS set).",
Michal Vaskod6a48062017-08-11 14:28:56 +0200628 __func__);
Michal Vaskodfbac232017-08-11 14:39:02 +0200629 goto error;
Michal Vaskod6a48062017-08-11 14:28:56 +0200630 }
631
Michal Vasko945b96b2016-10-18 11:49:12 +0200632 LY_TREE_FOR((struct lyd_node *)data_tree, iter) {
Michal Vasko6b44d712016-09-12 16:25:46 +0200633 if (iter->parent) {
634 /* a sibling is not top-level */
Michal Vasko53b7da02018-02-13 15:28:42 +0100635 LOGERR(ctx, LY_EINVAL, "%s: invalid variable parameter (const struct lyd_node *data_tree).", __func__);
Michal Vasko6b44d712016-09-12 16:25:46 +0200636 goto error;
637 }
638 }
639
640 /* move it to the beginning */
641 for (; data_tree->prev->next; data_tree = data_tree->prev);
642
643 /* LYD_OPT_NOSIBLINGS cannot be set in this case */
644 if (options & LYD_OPT_NOSIBLINGS) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100645 LOGERR(ctx, LY_EINVAL, "%s: invalid parameter (variable arg const struct lyd_node *data_tree with LYD_OPT_NOSIBLINGS).", __func__);
Michal Vasko6b44d712016-09-12 16:25:46 +0200646 goto error;
647 }
648 }
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100649 }
PavolVican832f5432018-02-21 00:54:45 +0100650 if (options & LYD_OPT_DATA_TEMPLATE) {
651 yang_data_name = va_arg(ap, const char *);
652 }
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100653
Radek Krejci19dbedb2017-08-08 13:54:31 +0200654 if ((*root) && !(options & LYD_OPT_NOSIBLINGS)) {
Radek Krejci86538212015-12-17 15:59:01 +0100655 /* locate the first root to process */
656 if ((*root)->parent) {
657 xmlstart = (*root)->parent->child;
658 } else {
659 xmlstart = *root;
660 while(xmlstart->prev->next) {
661 xmlstart = xmlstart->prev;
662 }
Radek Krejci04b97de2015-10-31 23:09:15 +0100663 }
Radek Krejci86538212015-12-17 15:59:01 +0100664 } else {
665 xmlstart = *root;
666 }
Radek Krejci86538212015-12-17 15:59:01 +0100667
Michal Vaskob1b19442016-07-13 12:26:01 +0200668 if ((options & LYD_OPT_RPC)
669 && !strcmp(xmlstart->name, "action") && !strcmp(xmlstart->ns->value, "urn:ietf:params:xml:ns:yang:1")) {
670 /* it's an action, not a simple RPC */
671 xmlstart = xmlstart->child;
Michal Vaskoa8756562017-05-03 14:42:23 +0200672 if (options & LYD_OPT_DESTRUCT) {
673 /* free it later */
674 xmlfree = xmlstart->parent;
675 }
Michal Vaskob1b19442016-07-13 12:26:01 +0200676 }
677
678 iter = last = NULL;
Radek Krejci86538212015-12-17 15:59:01 +0100679 LY_TREE_FOR_SAFE(xmlstart, xmlaux, xmlelem) {
PavolVican832f5432018-02-21 00:54:45 +0100680 r = xml_parse_data(ctx, xmlelem, reply_parent, result, last, options, unres, &iter, &act_notif, yang_data_name);
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100681 if (r) {
Michal Vasko945b96b2016-10-18 11:49:12 +0200682 if (reply_top) {
683 result = reply_top;
Pavol Vican8a552f62016-09-05 11:20:57 +0200684 }
Michal Vasko24d982f2016-04-18 15:13:58 +0200685 goto error;
Radek Krejci86538212015-12-17 15:59:01 +0100686 } else if (options & LYD_OPT_DESTRUCT) {
687 lyxml_free(ctx, xmlelem);
688 *root = xmlaux;
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100689 }
690 if (iter) {
691 last = iter;
Radek Krejcidfb00d62017-09-06 09:39:35 +0200692 if ((options & LYD_OPT_DATA_ADD_YANGLIB) && iter->schema->module == ctx->models.list[ctx->internal_module_count - 1]) {
Radek Krejci06f8bb92017-08-02 15:36:25 +0200693 /* ietf-yang-library data present, so ignore the option to add them */
694 options &= ~LYD_OPT_DATA_ADD_YANGLIB;
695 }
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100696 }
697 if (!result) {
698 result = iter;
699 }
Radek Krejci86538212015-12-17 15:59:01 +0100700
701 if (options & LYD_OPT_NOSIBLINGS) {
702 /* stop after the first processed root */
703 break;
704 }
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100705 }
Radek Krejcic6704c82015-10-06 11:12:45 +0200706
Michal Vasko945b96b2016-10-18 11:49:12 +0200707 if (reply_top) {
708 result = reply_top;
Michal Vaskoe45aff52016-08-25 09:01:09 +0200709 }
710
Michal Vasko945b96b2016-10-18 11:49:12 +0200711 if ((options & LYD_OPT_RPCREPLY) && (rpc_act->schema->nodetype != LYS_RPC)) {
712 /* action reply */
713 act_notif = reply_parent;
Michal Vaskoafa7a642016-10-18 15:11:38 +0200714 } else if ((options & (LYD_OPT_RPC | LYD_OPT_NOTIF)) && !act_notif) {
Michal Vaskod60a1a32018-05-23 16:31:22 +0200715 LOGVAL(ctx, LYE_INELEM, (result ? LY_VLOG_LYD : LY_VLOG_NONE), result, (options & LYD_OPT_RPC ? "action" : "notification"));
Michal Vaskoafa7a642016-10-18 15:11:38 +0200716 goto error;
Radek Krejcib45b3082016-09-09 16:08:51 +0200717 }
718
Radek Krejci06f8bb92017-08-02 15:36:25 +0200719 /* add missing ietf-yang-library if requested */
720 if (options & LYD_OPT_DATA_ADD_YANGLIB) {
721 if (!result) {
722 result = ly_ctx_info(ctx);
723 } else if (lyd_merge(result, ly_ctx_info(ctx), LYD_OPT_DESTRUCT | LYD_OPT_EXPLICIT)) {
Michal Vasko53b7da02018-02-13 15:28:42 +0100724 LOGERR(ctx, LY_EINT, "Adding ietf-yang-library data failed.");
Radek Krejci06f8bb92017-08-02 15:36:25 +0200725 goto error;
726 }
727 }
728
729 /* check for uniqueness of top-level lists/leaflists because
Radek Krejci63b79c82016-08-10 10:09:33 +0200730 * only the inner instances were tested in lyv_data_content() */
Radek Krejci63b79c82016-08-10 10:09:33 +0200731 LY_TREE_FOR(result, iter) {
Michal Vasko185b5272018-09-13 14:26:12 +0200732 if (!(iter->schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) || !(iter->validity & LYD_VAL_DUP)) {
Radek Krejci63b79c82016-08-10 10:09:33 +0200733 continue;
734 }
735
Michal Vasko185b5272018-09-13 14:26:12 +0200736 if (lyv_data_dup(iter, result)) {
Radek Krejci63b79c82016-08-10 10:09:33 +0200737 goto error;
738 }
739 }
Radek Krejci63b79c82016-08-10 10:09:33 +0200740
Radek Krejcib45b3082016-09-09 16:08:51 +0200741 /* add default values, resolve unres and check for mandatory nodes in final tree */
Michal Vasko993af1e2018-12-10 12:05:17 +0100742 if (lyd_defaults_add_unres(&result, options, ctx, NULL, 0, data_tree, act_notif, unres, 1)) {
Michal Vasko6b44d712016-09-12 16:25:46 +0200743 goto error;
744 }
Michal Vaskoad2e44a2017-01-03 10:31:35 +0100745 if (!(options & (LYD_OPT_TRUSTED | LYD_OPT_NOTIF_FILTER))
Michal Vasko993af1e2018-12-10 12:05:17 +0100746 && lyd_check_mandatory_tree((act_notif ? act_notif : result), ctx, NULL, 0, options)) {
Michal Vaskoafa7a642016-10-18 15:11:38 +0200747 goto error;
Radek Krejci46165822016-08-26 14:06:27 +0200748 }
749
Michal Vaskoa8756562017-05-03 14:42:23 +0200750 if (xmlfree) {
751 lyxml_free(ctx, xmlfree);
752 }
Michal Vasko24d982f2016-04-18 15:13:58 +0200753 free(unres->node);
754 free(unres->type);
755 free(unres);
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100756 va_end(ap);
Radek Krejcic6704c82015-10-06 11:12:45 +0200757 return result;
Michal Vasko24d982f2016-04-18 15:13:58 +0200758
759error:
760 lyd_free_withsiblings(result);
Michal Vaskoa8756562017-05-03 14:42:23 +0200761 if (xmlfree) {
762 lyxml_free(ctx, xmlfree);
763 }
Michal Vasko24d982f2016-04-18 15:13:58 +0200764 free(unres->node);
765 free(unres->type);
766 free(unres);
767 va_end(ap);
Michal Vasko24d982f2016-04-18 15:13:58 +0200768 return NULL;
Radek Krejcic6704c82015-10-06 11:12:45 +0200769}