blob: 80b97c7f0541f1331b21507e7f1ec989b9d5737a [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 *
6 * Copyright (c) 2015 CESNET, z.s.p.o.
7 *
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 Vaskoe3886bb2017-01-02 11:33:28 +010078xml_get_value(struct lyd_node *node, struct lyxml_elem *xml, int editbits)
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 Krejci1fe9ac02016-09-23 09:38:21 +020086 if ((editbits & 0x10) && (node->schema->nodetype & LYS_LEAF) && (!leaf->value_str || !leaf->value_str[0])) {
87 /* 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 */
89 leaf->value_type = LY_TYPE_ERR;
90 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 */
Radek Krejcia571d942017-02-24 09:26:49 +010095 if (!lyp_parse_value(&((struct lys_node_leaf *)leaf->schema)->type, &leaf->value_str, xml, leaf, NULL, 1, 0)) {
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,
Michal Vaskob15cae22016-09-15 09:40:56 +0200106 struct lyd_node **act_notif)
Radek Krejci1721c012015-07-08 12:52:33 +0200107{
Michal Vaskof53187d2017-01-13 13:23:14 +0100108 const struct lys_module *mod = NULL;
Radek Krejcib1ef1872017-02-23 14:33:34 +0100109 const struct lys_submodule *submod;
Radek Krejcibd930122016-08-10 13:28:26 +0200110 struct lyd_node *diter, *dlast;
Michal Vasko5e523b62016-08-26 16:23:15 +0200111 struct lys_node *schema = NULL, *target;
112 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 Krejci532e5e92017-02-22 12:59:24 +0100116 int i, j, havechildren, r, pos, editbits = 0;
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100117 int ret = 0;
Radek Krejciabb7b582016-04-20 16:15:47 +0200118 const char *str = NULL;
Radek Krejci1721c012015-07-08 12:52:33 +0200119
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100120 assert(xml);
121 assert(result);
122 *result = NULL;
123
Radek Krejci1721c012015-07-08 12:52:33 +0200124 if (!xml->ns || !xml->ns->value) {
Radek Krejci2342cf62016-01-29 16:48:23 +0100125 if (options & LYD_OPT_STRICT) {
Radek Krejci48464ed2016-03-17 15:44:09 +0100126 LOGVAL(LYE_XML_MISS, LY_VLOG_XML, xml, "element's", "namespace");
Radek Krejci2342cf62016-01-29 16:48:23 +0100127 return -1;
128 } else {
129 return 0;
130 }
Radek Krejci1721c012015-07-08 12:52:33 +0200131 }
132
133 /* find schema node */
Michal Vaskob1b19442016-07-13 12:26:01 +0200134 if (!parent) {
Michal Vaskof53187d2017-01-13 13:23:14 +0100135 mod = ly_ctx_get_module_by_ns(ctx, xml->ns->value, NULL);
136 if (ctx->data_clb) {
137 if (!mod) {
138 mod = ctx->data_clb(ctx, NULL, xml->ns->value, 0, ctx->data_clb_data);
139 } else if (!mod->implemented) {
140 mod = ctx->data_clb(ctx, mod->name, mod->ns, LY_MODCLB_NOT_IMPLEMENTED, ctx->data_clb_data);
Radek Krejci27fe55e2016-09-13 17:13:35 +0200141 }
Michal Vaskof53187d2017-01-13 13:23:14 +0100142 }
143
144 /* get the proper schema node */
145 if (mod && mod->implemented && !mod->disabled) {
146 schema = xml_data_search_schemanode(xml, mod->data, options);
147 if (!schema) {
148 /* it still can be the specific case of this module containing an augment of another module
149 * top-level choice or top-level choice's case, bleh */
150 for (j = 0; j < mod->augment_size; ++j) {
151 aug = &mod->augment[j];
152 target = aug->target;
153 if (target->nodetype & (LYS_CHOICE | LYS_CASE)) {
154 /* 1) okay, the target is choice or case */
155 while (target && (target->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES))) {
156 target = lys_parent(target);
157 }
158 /* 2) now, the data node will be top-level, there are only non-data schema nodes */
159 if (!target) {
160 while ((schema = (struct lys_node *)lys_getnext(schema, (struct lys_node *)aug, NULL, 0))) {
161 /* 3) alright, even the name matches, we found our schema node */
162 if (ly_strequal(schema->name, xml->name, 1)) {
163 break;
Michal Vasko5e523b62016-08-26 16:23:15 +0200164 }
165 }
166 }
Michal Vaskof53187d2017-01-13 13:23:14 +0100167 }
Michal Vasko5e523b62016-08-26 16:23:15 +0200168
Michal Vaskof53187d2017-01-13 13:23:14 +0100169 if (schema) {
170 break;
Michal Vasko5e523b62016-08-26 16:23:15 +0200171 }
172 }
Radek Krejci1721c012015-07-08 12:52:33 +0200173 }
174 }
175 } else {
176 /* parsing some internal node, we start with parent's schema pointer */
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100177 schema = xml_data_search_schemanode(xml, parent->schema->child, options);
Michal Vaskof53187d2017-01-13 13:23:14 +0100178
179 if (schema) {
180 if (!lys_node_module(schema)->implemented && ctx->data_clb) {
Michal Vaskoad43c182017-01-23 09:55:28 +0100181 ctx->data_clb(ctx, lys_node_module(schema)->name, lys_node_module(schema)->ns,
182 LY_MODCLB_NOT_IMPLEMENTED, ctx->data_clb_data);
Michal Vaskof53187d2017-01-13 13:23:14 +0100183 }
Radek Krejci25b9fd32015-08-10 15:06:07 +0200184 }
Michal Vaskof53187d2017-01-13 13:23:14 +0100185 }
186
187 mod = lys_node_module(schema);
188 if (!mod || !mod->implemented || mod->disabled) {
Radek Krejci27fe55e2016-09-13 17:13:35 +0200189 if (options & LYD_OPT_STRICT) {
Michal Vaskof53187d2017-01-13 13:23:14 +0100190 LOGVAL(LYE_INELEM, (parent ? LY_VLOG_LYD : LY_VLOG_NONE), parent, xml->name);
Radek Krejci27fe55e2016-09-13 17:13:35 +0200191 return -1;
192 } else {
193 return 0;
194 }
Radek Krejci1721c012015-07-08 12:52:33 +0200195 }
196
Radek Krejciadb57612016-02-16 13:34:34 +0100197 /* create the element structure */
Radek Krejcib9930252015-07-08 15:47:45 +0200198 switch (schema->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +0200199 case LYS_CONTAINER:
Radek Krejci27aaa732015-09-04 15:24:04 +0200200 case LYS_LIST:
Michal Vasko2f30e572015-10-01 16:00:38 +0200201 case LYS_NOTIF:
202 case LYS_RPC:
Michal Vaskob1b19442016-07-13 12:26:01 +0200203 case LYS_ACTION:
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100204 *result = calloc(1, sizeof **result);
Michal Vaskoab8e4402015-07-17 12:54:28 +0200205 havechildren = 1;
Radek Krejcib9930252015-07-08 15:47:45 +0200206 break;
Radek Krejci76512572015-08-04 09:47:08 +0200207 case LYS_LEAF:
Radek Krejci76512572015-08-04 09:47:08 +0200208 case LYS_LEAFLIST:
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100209 *result = calloc(1, sizeof(struct lyd_node_leaf_list));
Radek Krejcie4748472015-07-08 18:00:22 +0200210 havechildren = 0;
211 break;
Radek Krejci76512572015-08-04 09:47:08 +0200212 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +0200213 case LYS_ANYDATA:
214 *result = calloc(1, sizeof(struct lyd_node_anydata));
Michal Vaskoab8e4402015-07-17 12:54:28 +0200215 havechildren = 0;
216 break;
Radek Krejcib9930252015-07-08 15:47:45 +0200217 default:
Michal Vasko0c888fd2015-08-11 15:54:08 +0200218 LOGINT;
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100219 return -1;
Radek Krejcib9930252015-07-08 15:47:45 +0200220 }
Michal Vasko253035f2015-12-17 16:58:13 +0100221 if (!(*result)) {
222 LOGMEM;
223 return -1;
224 }
225
Radek Krejci61767ca2016-09-19 14:21:55 +0200226 (*result)->prev = *result;
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100227 (*result)->schema = schema;
Radek Krejci61767ca2016-09-19 14:21:55 +0200228 (*result)->parent = parent;
229 diter = NULL;
230 if (parent && parent->child && schema->nodetype == LYS_LEAF && parent->schema->nodetype == LYS_LIST &&
231 (pos = lys_is_key((struct lys_node_list *)parent->schema, (struct lys_node_leaf *)schema))) {
232 /* it is key and we need to insert it into a correct place */
233 for (i = 0, diter = parent->child;
234 diter && i < (pos - 1) && diter->schema->nodetype == LYS_LEAF &&
235 lys_is_key((struct lys_node_list *)parent->schema, (struct lys_node_leaf *)diter->schema);
236 i++, diter = diter->next);
237 if (diter) {
238 /* out of order insertion - insert list's key to the correct position, before the diter */
239 if (options & LYD_OPT_STRICT) {
240 LOGVAL(LYE_INORDER, LY_VLOG_LYD, *result, schema->name, diter->schema->name);
Michal Vasko51e5c582017-01-19 14:16:39 +0100241 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Invalid position of the key \"%s\" in a list \"%s\".",
Radek Krejci61767ca2016-09-19 14:21:55 +0200242 schema->name, parent->schema->name);
243 free(*result);
244 *result = NULL;
245 return -1;
246 } else {
247 LOGWRN("Invalid position of the key \"%s\" in a list \"%s\".", schema->name, parent->schema->name)
248 }
249 if (parent->child == diter) {
250 parent->child = *result;
251 /* update first_sibling */
252 first_sibling = *result;
253 }
254 if (diter->prev->next) {
255 diter->prev->next = *result;
256 }
257 (*result)->prev = diter->prev;
258 diter->prev = *result;
259 (*result)->next = diter;
260 }
261 }
262 if (!diter) {
263 /* simplified (faster) insert as the last node */
264 if (parent && !parent->child) {
265 parent->child = *result;
266 }
267 if (prev) {
268 (*result)->prev = prev;
269 prev->next = *result;
270
271 /* fix the "last" pointer */
272 first_sibling->prev = *result;
273 } else {
274 (*result)->prev = *result;
275 first_sibling = *result;
276 }
277 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +0100278 (*result)->validity = ly_new_node_validity((*result)->schema);
Radek Krejci46165822016-08-26 14:06:27 +0200279 if (resolve_applies_when(schema, 0, NULL)) {
Radek Krejci0b7704f2016-03-18 12:16:14 +0100280 (*result)->when_status = LYD_WHEN;
281 }
Radek Krejci1721c012015-07-08 12:52:33 +0200282
Radek Krejciadb57612016-02-16 13:34:34 +0100283 /* check insert attribute and its values */
284 if (options & LYD_OPT_EDIT) {
Radek Krejci9bfcbde2016-04-07 16:30:15 +0200285 /* 0x01 - insert attribute present
286 * 0x02 - insert is relative (before or after)
287 * 0x04 - value attribute present
288 * 0x08 - key attribute present
289 * 0x10 - operation not allowing insert attribute
290 */
Radek Krejciadb57612016-02-16 13:34:34 +0100291 for (attr = xml->attr; attr; attr = attr->next) {
Radek Krejci9bfcbde2016-04-07 16:30:15 +0200292 if (attr->type != LYXML_ATTR_STD || !attr->ns) {
293 /* not interesting attribute or namespace declaration */
Radek Krejciadb57612016-02-16 13:34:34 +0100294 continue;
295 }
296
Radek Krejci9bfcbde2016-04-07 16:30:15 +0200297 if (!strcmp(attr->name, "operation") && !strcmp(attr->ns->value, LY_NSNC)) {
Radek Krejci1fe9ac02016-09-23 09:38:21 +0200298 if (editbits & 0x10) {
Radek Krejci72614bf2016-04-08 17:46:07 +0200299 LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, (*result), "operation attributes", xml->name);
300 return -1;
301 }
302
Radek Krejci9bfcbde2016-04-07 16:30:15 +0200303 if (!strcmp(attr->value, "delete") || !strcmp(attr->value, "remove")) {
Radek Krejci1fe9ac02016-09-23 09:38:21 +0200304 editbits |= 0x10;
Radek Krejci9bfcbde2016-04-07 16:30:15 +0200305 } else if (strcmp(attr->value, "create") &&
306 strcmp(attr->value, "merge") &&
307 strcmp(attr->value, "replace")) {
308 /* unknown operation */
309 LOGVAL(LYE_INVALATTR, LY_VLOG_LYD, (*result), attr->value, attr->name);
310 return -1;
311 }
312 } else if (!strcmp(attr->name, "insert") && !strcmp(attr->ns->value, LY_NSYANG)) {
313 /* 'insert' attribute present */
314 if (!(schema->flags & LYS_USERORDERED)) {
315 /* ... but it is not expected */
316 LOGVAL(LYE_INATTR, LY_VLOG_LYD, (*result), "insert", schema->name);
317 return -1;
318 }
Radek Krejciadb57612016-02-16 13:34:34 +0100319
Radek Krejci1fe9ac02016-09-23 09:38:21 +0200320 if (editbits & 0x01) {
Radek Krejci9bfcbde2016-04-07 16:30:15 +0200321 LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, (*result), "insert attributes", xml->name);
322 return -1;
323 }
324 if (!strcmp(attr->value, "first") || !strcmp(attr->value, "last")) {
Radek Krejci1fe9ac02016-09-23 09:38:21 +0200325 editbits |= 0x01;
Radek Krejci9bfcbde2016-04-07 16:30:15 +0200326 } else if (!strcmp(attr->value, "before") || !strcmp(attr->value, "after")) {
Radek Krejci1fe9ac02016-09-23 09:38:21 +0200327 editbits |= 0x01 | 0x02;
Radek Krejci9bfcbde2016-04-07 16:30:15 +0200328 } else {
329 LOGVAL(LYE_INVALATTR, LY_VLOG_LYD, (*result), attr->value, attr->name);
330 return -1;
331 }
332 str = attr->name;
333 } else if (!strcmp(attr->name, "value") && !strcmp(attr->ns->value, LY_NSYANG)) {
Radek Krejci1fe9ac02016-09-23 09:38:21 +0200334 if (editbits & 0x04) {
Radek Krejci9bfcbde2016-04-07 16:30:15 +0200335 LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, (*result), "value attributes", xml->name);
336 return -1;
337 } else if (schema->nodetype & LYS_LIST) {
338 LOGVAL(LYE_INATTR, LY_VLOG_LYD, (*result), attr->name, schema->name);
339 return -1;
340 }
Radek Krejci1fe9ac02016-09-23 09:38:21 +0200341 editbits |= 0x04;
Radek Krejci9bfcbde2016-04-07 16:30:15 +0200342 str = attr->name;
343 } else if (!strcmp(attr->name, "key") && !strcmp(attr->ns->value, LY_NSYANG)) {
Radek Krejci1fe9ac02016-09-23 09:38:21 +0200344 if (editbits & 0x08) {
Radek Krejci9bfcbde2016-04-07 16:30:15 +0200345 LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, (*result), "key attributes", xml->name);
346 return -1;
347 } else if (schema->nodetype & LYS_LEAFLIST) {
348 LOGVAL(LYE_INATTR, LY_VLOG_LYD, (*result), attr->name, schema->name);
349 return -1;
350 }
Radek Krejci1fe9ac02016-09-23 09:38:21 +0200351 editbits |= 0x08;
Radek Krejci9bfcbde2016-04-07 16:30:15 +0200352 str = attr->name;
Radek Krejciadb57612016-02-16 13:34:34 +0100353 }
Radek Krejciadb57612016-02-16 13:34:34 +0100354 }
355
Radek Krejci9bfcbde2016-04-07 16:30:15 +0200356 /* report errors */
Radek Krejci1fe9ac02016-09-23 09:38:21 +0200357 if (editbits > 0x10 || (editbits && editbits < 0x10 &&
Radek Krejcicced9382016-04-13 13:15:03 +0200358 (!(schema->nodetype & (LYS_LEAFLIST | LYS_LIST)) || !(schema->flags & LYS_USERORDERED)))) {
Radek Krejcid0df6902016-03-10 09:32:00 +0100359 /* attributes in wrong elements */
Radek Krejci48464ed2016-03-17 15:44:09 +0100360 LOGVAL(LYE_INATTR, LY_VLOG_LYD, (*result), str, xml->name);
Radek Krejcid0df6902016-03-10 09:32:00 +0100361 return -1;
Radek Krejci1fe9ac02016-09-23 09:38:21 +0200362 } else if (editbits == 3) {
Radek Krejci9bfcbde2016-04-07 16:30:15 +0200363 /* 0x01 | 0x02 - relative position, but value/key is missing */
364 if (schema->nodetype & LYS_LIST) {
365 LOGVAL(LYE_MISSATTR, LY_VLOG_LYD, (*result), "key", xml->name);
366 } else { /* LYS_LEAFLIST */
367 LOGVAL(LYE_MISSATTR, LY_VLOG_LYD, (*result), "value", xml->name);
368 }
Radek Krejciadb57612016-02-16 13:34:34 +0100369 return -1;
Radek Krejci1fe9ac02016-09-23 09:38:21 +0200370 } else if ((editbits & (0x04 | 0x08)) && !(editbits & 0x02)) {
Radek Krejci9bfcbde2016-04-07 16:30:15 +0200371 /* key/value without relative position */
Radek Krejci1fe9ac02016-09-23 09:38:21 +0200372 LOGVAL(LYE_INATTR, LY_VLOG_LYD, (*result), (editbits & 0x04) ? "value" : "key", schema->name);
Radek Krejciadb57612016-02-16 13:34:34 +0100373 return -1;
374 }
375 }
376
Radek Krejcib9930252015-07-08 15:47:45 +0200377 /* type specific processing */
Radek Krejci27aaa732015-09-04 15:24:04 +0200378 if (schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
Radek Krejcie4748472015-07-08 18:00:22 +0200379 /* type detection and assigning the value */
Michal Vaskoe3886bb2017-01-02 11:33:28 +0100380 if (xml_get_value(*result, xml, editbits)) {
Radek Krejci3e3affe2015-07-09 15:38:40 +0200381 goto error;
382 }
Radek Krejcibf2abff2016-08-23 15:51:52 +0200383 } else if (schema->nodetype & LYS_ANYDATA) {
Michal Vaskof748dbc2016-04-05 11:27:47 +0200384 /* store children values */
385 if (xml->child) {
386 child = xml->child;
387 /* manually unlink all siblings and correct namespaces */
388 xml->child = NULL;
389 LY_TREE_FOR(child, next) {
390 next->parent = NULL;
391 lyxml_correct_elem_ns(ctx, next, 1, 1);
392 }
393
Radek Krejci45826012016-08-24 15:07:57 +0200394 ((struct lyd_node_anydata *)*result)->value_type = LYD_ANYDATA_XML;
Radek Krejcibf2abff2016-08-23 15:51:52 +0200395 ((struct lyd_node_anydata *)*result)->value.xml = child;
Michal Vaskof748dbc2016-04-05 11:27:47 +0200396 } else {
Radek Krejci45826012016-08-24 15:07:57 +0200397 ((struct lyd_node_anydata *)*result)->value_type = LYD_ANYDATA_CONSTSTRING;
Radek Krejcibf2abff2016-08-23 15:51:52 +0200398 ((struct lyd_node_anydata *)*result)->value.str = lydict_insert(ctx, xml->content, 0);
Michal Vasko253035f2015-12-17 16:58:13 +0100399 }
Michal Vaskoafa7a642016-10-18 15:11:38 +0200400 } else if (schema->nodetype & (LYS_RPC | LYS_ACTION)) {
401 if (!(options & LYD_OPT_RPC) || *act_notif) {
402 LOGVAL(LYE_INELEM, LY_VLOG_LYD, (*result), schema->name);
Michal Vasko51e5c582017-01-19 14:16:39 +0100403 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Unexpected %s node \"%s\".",
Michal Vaskoafa7a642016-10-18 15:11:38 +0200404 (schema->nodetype == LYS_RPC ? "rpc" : "action"), schema->name);
405 goto error;
406 }
407 *act_notif = *result;
408 } else if (schema->nodetype == LYS_NOTIF) {
409 if (!(options & LYD_OPT_NOTIF) || *act_notif) {
410 LOGVAL(LYE_INELEM, LY_VLOG_LYD, (*result), schema->name);
Michal Vasko51e5c582017-01-19 14:16:39 +0100411 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Unexpected notification node \"%s\".", schema->name);
Michal Vaskoafa7a642016-10-18 15:11:38 +0200412 goto error;
413 }
414 *act_notif = *result;
Radek Krejcib9930252015-07-08 15:47:45 +0200415 }
416
Michal Vasko10e586f2016-05-18 13:25:30 +0200417 /* first part of validation checks */
Michal Vaskoe3886bb2017-01-02 11:33:28 +0100418 if (lyv_data_context(*result, options, unres)) {
Michal Vasko10e586f2016-05-18 13:25:30 +0200419 goto error;
420 }
421
Radek Krejci998a7502015-10-26 15:54:33 +0100422 for (attr = xml->attr; attr; attr = attr->next) {
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100423 if (attr->type != LYXML_ATTR_STD) {
424 continue;
425 } else if (!attr->ns) {
Radek Krejci9a5daea2016-03-02 16:49:40 +0100426 if ((*result)->schema->nodetype != LYS_ANYXML ||
427 !ly_strequal((*result)->schema->name, "filter", 0) ||
428 !ly_strequal((*result)->schema->module->name, "ietf-netconf", 0)) {
Radek Krejci0f721232016-05-03 14:52:29 +0200429 if (options & LYD_OPT_STRICT) {
430 LOGVAL(LYE_INATTR, LY_VLOG_LYD, (*result), attr->name, xml->name);
Michal Vasko51e5c582017-01-19 14:16:39 +0100431 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Attribute \"%s\" with no namespace (schema).",
Radek Krejci0f721232016-05-03 14:52:29 +0200432 attr->name);
433 goto error;
434 } else {
435 LOGWRN("Ignoring \"%s\" attribute in \"%s\" element.", attr->name, xml->name);
436 continue;
437 }
Radek Krejci9a5daea2016-03-02 16:49:40 +0100438 } else {
439 /* exception for filter's attributes */
Radek Krejci532e5e92017-02-22 12:59:24 +0100440 pos = -1;
441 }
442 } else if (!strcmp(attr->ns->value, LY_NSNC)) {
443 /* exception for edit-config's attributes */
444 pos = -1;
445 } else { /* regular annotation */
446 /* first, get module where the annotation should be defined */
447 mod = (struct lys_module*)ly_ctx_get_module_by_ns(ctx, attr->ns->value, NULL);
448 if (!mod) {
449 goto attr_error;
450 }
451
452 /* then, find the appropriate annotation definition */
Radek Krejcib1ef1872017-02-23 14:33:34 +0100453 submod = NULL;
Radek Krejci532e5e92017-02-22 12:59:24 +0100454 pos = lys_ext_instance_presence(&ctx->models.list[0]->extensions[0], mod->ext, mod->ext_size);
Radek Krejcib1ef1872017-02-23 14:33:34 +0100455 while(pos != -1 && ((unsigned int)(pos + 1) < mod->ext_size) &&
456 !ly_strequal(mod->ext[pos]->arg_value, attr->name, 1)) {
457 i = lys_ext_instance_presence(&ctx->models.list[0]->extensions[0],
458 &mod->ext[pos + 1], mod->ext_size - (pos + 1));
459 pos = (i == -1) ? -1 : pos + 1 + i;
460 }
461 /* try submodules */
462 for (j = 0; pos == -1 && j < mod->inc_size; j++) {
463 submod = mod->inc[j].submodule;
464 pos = lys_ext_instance_presence(&ctx->models.list[0]->extensions[0], submod->ext, submod->ext_size);
465 while (pos != -1 && ((unsigned int)(pos + 1) < submod->ext_size)
466 && !ly_strequal(submod->ext[pos]->arg_value, attr->name, 1)) {
467 i = lys_ext_instance_presence(&ctx->models.list[0]->extensions[0], &submod->ext[pos + 1],
468 submod->ext_size - (pos + 1));
469 pos = (i == -1) ? -1 : pos + 1 + i;
470 }
471 }
Radek Krejci532e5e92017-02-22 12:59:24 +0100472 if (pos == -1) {
473 goto attr_error;
Radek Krejci9a5daea2016-03-02 16:49:40 +0100474 }
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100475 }
476
Radek Krejci532e5e92017-02-22 12:59:24 +0100477 /* allocate and fill the data attribute structure */
Radek Krejcia571d942017-02-24 09:26:49 +0100478 dattr = calloc(1, sizeof *dattr);
Michal Vasko253035f2015-12-17 16:58:13 +0100479 if (!dattr) {
480 goto error;
481 }
Radek Krejci532e5e92017-02-22 12:59:24 +0100482 dattr->parent = (*result);
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100483 dattr->next = NULL;
Radek Krejci532e5e92017-02-22 12:59:24 +0100484
485 if (pos != -1) {
Radek Krejcib1ef1872017-02-23 14:33:34 +0100486 dattr->annotation = submod ? (struct lys_ext_instance_complex *)submod->ext[pos] :
487 (struct lys_ext_instance_complex *)mod->ext[pos];
Radek Krejci532e5e92017-02-22 12:59:24 +0100488 } else {
489 /* exception for NETCONF's edit-config and filter attributes */
490 dattr->annotation = NULL;
491 }
492
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100493 dattr->name = attr->name;
Radek Krejci532e5e92017-02-22 12:59:24 +0100494 attr->name = NULL;
495
Radek Krejcia571d942017-02-24 09:26:49 +0100496 dattr->value_str = attr->value;
497 attr->value = NULL;
498
499 /* the value is here converted to a JSON format if needed in case of LY_TYPE_IDENT and LY_TYPE_INST or to a
500 * canonical form of the value */
501 if (!lyp_parse_value(*((struct lys_type **)lys_ext_complex_get_substmt(LY_STMT_TYPE, dattr->annotation, NULL)),
502 &dattr->value_str, xml, NULL, dattr, 1, 0)) {
503 attr->value = dattr->value_str;
504 free(dattr);
505 goto error;
506 }
507
508#if 0
Radek Krejci532e5e92017-02-22 12:59:24 +0100509 ly_vlog_hide(1);
510 dattr->value = transform_xml2json(ctx, attr->value, xml, 0, 1);
511 ly_vlog_hide(0);
512 if (!dattr->value) {
513 if (ly_errno != LY_EVALID) {
514 /* fatal error, reprint the error message */
515 ly_err_repeat();
Radek Krejci9a5daea2016-03-02 16:49:40 +0100516 free(dattr);
517 goto error;
518 }
Radek Krejci532e5e92017-02-22 12:59:24 +0100519 /* problem with resolving value as xpath
520 * - ignore it and just store the value as it is */
521 ly_err_clean(1);
Radek Krejci9a5daea2016-03-02 16:49:40 +0100522 dattr->value = attr->value;
Radek Krejci532e5e92017-02-22 12:59:24 +0100523 attr->value = NULL;
Radek Krejci9a5daea2016-03-02 16:49:40 +0100524 } else {
Radek Krejci532e5e92017-02-22 12:59:24 +0100525 lydict_remove(ctx, attr->value);
526 attr->value = NULL;
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100527 }
Radek Krejcia571d942017-02-24 09:26:49 +0100528#endif
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100529
Radek Krejci532e5e92017-02-22 12:59:24 +0100530 /* insert into the data node */
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100531 if (!(*result)->attr) {
532 (*result)->attr = dattr;
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100533 } else {
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100534 for (dattr_iter = (*result)->attr; dattr_iter->next; dattr_iter = dattr_iter->next);
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100535 dattr_iter->next = dattr;
Radek Krejci998a7502015-10-26 15:54:33 +0100536 }
Radek Krejci532e5e92017-02-22 12:59:24 +0100537 continue;
538
539attr_error:
540 if (options & LYD_OPT_STRICT) {
541 LOGVAL(LYE_INATTR, LY_VLOG_LYD, (*result), attr->name, xml->name);
Radek Krejcib1ef1872017-02-23 14:33:34 +0100542 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Unknown metadata (%s:%s).", attr->ns->prefix, attr->name);
Radek Krejci532e5e92017-02-22 12:59:24 +0100543 goto error;
544 } else {
Radek Krejcib1ef1872017-02-23 14:33:34 +0100545 LOGWRN("Unknown metadata (%s:%s) - skipping.", attr->ns->prefix, attr->name);
Radek Krejci532e5e92017-02-22 12:59:24 +0100546 continue;
547 }
Radek Krejci998a7502015-10-26 15:54:33 +0100548 }
Michal Vasko4ff7b072015-08-21 09:05:03 +0200549
Radek Krejci14c00092015-11-01 11:03:24 +0100550 /* process children */
551 if (havechildren && xml->child) {
552 diter = dlast = NULL;
553 LY_TREE_FOR_SAFE(xml->child, next, child) {
554 if (schema->nodetype & (LYS_RPC | LYS_NOTIF)) {
Michal Vaskob15cae22016-09-15 09:40:56 +0200555 r = xml_parse_data(ctx, child, *result, (*result)->child, dlast, 0, unres, &diter, act_notif);
Radek Krejci14c00092015-11-01 11:03:24 +0100556 } else {
Michal Vaskob15cae22016-09-15 09:40:56 +0200557 r = xml_parse_data(ctx, child, *result, (*result)->child, dlast, options, unres, &diter, act_notif);
Radek Krejci14c00092015-11-01 11:03:24 +0100558 }
Radek Krejci14c00092015-11-01 11:03:24 +0100559 if (r) {
560 goto error;
Radek Krejci86538212015-12-17 15:59:01 +0100561 } else if (options & LYD_OPT_DESTRUCT) {
562 lyxml_free(ctx, child);
Radek Krejci14c00092015-11-01 11:03:24 +0100563 }
Radek Krejci61767ca2016-09-19 14:21:55 +0200564 if (diter && !diter->next) {
565 /* the child was parsed/created and it was placed as the last child. The child can be inserted
566 * 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 +0100567 dlast = diter;
568 }
569 }
570 }
571
Radek Krejcifb7156e2016-10-27 13:39:56 +0200572 /* if we have empty non-presence container, we keep it, but mark it as default */
Radek Krejci2537fd32016-09-07 16:22:41 +0200573 if (schema->nodetype == LYS_CONTAINER && !(*result)->child &&
Radek Krejcid3e73722016-05-23 12:24:55 +0200574 !(*result)->attr && !((struct lys_node_container *)schema)->presence) {
Radek Krejcifb7156e2016-10-27 13:39:56 +0200575 (*result)->dflt = 1;
Radek Krejci0c0086a2016-03-24 15:20:28 +0100576 }
577
Radek Krejcicf509982015-12-15 09:22:44 +0100578 /* rest of validation checks */
Radek Krejci00a0e712016-10-26 10:24:46 +0200579 ly_err_clean(1);
Michal Vaskoe3886bb2017-01-02 11:33:28 +0100580 if (lyv_data_content(*result, options, unres) ||
581 lyv_multicases(*result, NULL, prev ? &first_sibling : NULL, 0, NULL)) {
Radek Krejcieab784a2015-08-27 09:56:53 +0200582 if (ly_errno) {
Radek Krejcib1c12512015-08-11 11:22:04 +0200583 goto error;
Radek Krejci1b0d01a2015-08-19 17:00:35 +0200584 } else {
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100585 goto clear;
Radek Krejcida374342015-08-19 13:33:22 +0200586 }
Radek Krejci78ce8612015-08-18 14:31:05 +0200587 }
588
Radek Krejcica7efb72016-01-18 13:06:01 +0100589 /* validation successful */
Radek Krejci63b79c82016-08-10 10:09:33 +0200590 if ((*result)->schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
591 /* postpone checking when there will be all list/leaflist instances */
Michal Vaskoe3886bb2017-01-02 11:33:28 +0100592 (*result)->validity |= LYD_VAL_UNIQUE;
Radek Krejci63b79c82016-08-10 10:09:33 +0200593 }
Radek Krejcica7efb72016-01-18 13:06:01 +0100594
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100595 return ret;
Radek Krejci3e3affe2015-07-09 15:38:40 +0200596
597error:
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100598 ret--;
599
600clear:
Radek Krejcieab784a2015-08-27 09:56:53 +0200601 /* cleanup */
Radek Krejci0c0086a2016-03-24 15:20:28 +0100602 for (i = unres->count - 1; i >= 0; i--) {
603 /* remove unres items connected with the node being removed */
604 if (unres->node[i] == *result) {
605 unres_data_del(unres, i);
606 }
607 }
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100608 lyd_free(*result);
609 *result = NULL;
Radek Krejci1b0d01a2015-08-19 17:00:35 +0200610
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100611 return ret;
Radek Krejci1721c012015-07-08 12:52:33 +0200612}
613
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100614API struct lyd_node *
615lyd_parse_xml(struct ly_ctx *ctx, struct lyxml_elem **root, int options, ...)
Radek Krejcic6704c82015-10-06 11:12:45 +0200616{
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100617 va_list ap;
Radek Krejci63b79c82016-08-10 10:09:33 +0200618 int r, i;
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100619 struct unres_data *unres = NULL;
Michal Vasko945b96b2016-10-18 11:49:12 +0200620 const struct lyd_node *rpc_act = NULL, *data_tree = NULL;
621 struct lyd_node *result = NULL, *iter, *last, *reply_parent = NULL, *reply_top = NULL, *act_notif = NULL;
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100622 struct lyxml_elem *xmlstart, *xmlelem, *xmlaux;
Radek Krejci63b79c82016-08-10 10:09:33 +0200623 struct ly_set *set;
Radek Krejcic6704c82015-10-06 11:12:45 +0200624
Radek Krejci00a0e712016-10-26 10:24:46 +0200625 ly_err_clean(1);
Radek Krejci2342cf62016-01-29 16:48:23 +0100626
Radek Krejcic6704c82015-10-06 11:12:45 +0200627 if (!ctx || !root) {
628 LOGERR(LY_EINVAL, "%s: Invalid parameter.", __func__);
629 return NULL;
630 }
631
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100632 if (lyp_check_options(options)) {
633 LOGERR(LY_EINVAL, "%s: Invalid options (multiple data type flags set).", __func__);
634 return NULL;
635 }
636
Radek Krejcia6939c32016-03-24 15:19:09 +0100637 if (!(*root)) {
638 /* empty tree - no work is needed */
639 lyd_validate(&result, options, ctx);
640 return result;
641 }
642
Michal Vasko24d982f2016-04-18 15:13:58 +0200643 unres = calloc(1, sizeof *unres);
644 if (!unres) {
645 LOGMEM;
646 return NULL;
647 }
648
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100649 va_start(ap, options);
650 if (options & LYD_OPT_RPCREPLY) {
Michal Vasko945b96b2016-10-18 11:49:12 +0200651 rpc_act = va_arg(ap, const struct lyd_node *);
652 if (!rpc_act || rpc_act->parent || !(rpc_act->schema->nodetype & (LYS_RPC | LYS_LIST | LYS_CONTAINER))) {
653 LOGERR(LY_EINVAL, "%s: invalid variable parameter (const struct lyd_node *rpc_act).", __func__);
Michal Vasko24d982f2016-04-18 15:13:58 +0200654 goto error;
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100655 }
Michal Vasko945b96b2016-10-18 11:49:12 +0200656 if (rpc_act->schema->nodetype == LYS_RPC) {
657 /* RPC request */
658 reply_top = reply_parent = _lyd_new(NULL, rpc_act->schema, 0);
659 } else {
660 /* action request */
661 reply_top = lyd_dup(rpc_act, 1);
662 LY_TREE_DFS_BEGIN(reply_top, iter, reply_parent) {
663 if (reply_parent->schema->nodetype == LYS_ACTION) {
664 break;
665 }
666 LY_TREE_DFS_END(reply_top, iter, reply_parent);
667 }
668 if (!reply_parent) {
669 LOGERR(LY_EINVAL, "%s: invalid variable parameter (const struct lyd_node *rpc_act).", __func__);
670 lyd_free_withsiblings(reply_top);
671 goto error;
672 }
673 lyd_free_withsiblings(reply_parent->child);
674 }
Michal Vasko45e23652016-09-21 11:24:32 +0200675 }
676 if (options & (LYD_OPT_RPC | LYD_OPT_NOTIF | LYD_OPT_RPCREPLY)) {
Michal Vasko945b96b2016-10-18 11:49:12 +0200677 data_tree = va_arg(ap, const struct lyd_node *);
Michal Vasko6b44d712016-09-12 16:25:46 +0200678 if (data_tree) {
Michal Vasko945b96b2016-10-18 11:49:12 +0200679 LY_TREE_FOR((struct lyd_node *)data_tree, iter) {
Michal Vasko6b44d712016-09-12 16:25:46 +0200680 if (iter->parent) {
681 /* a sibling is not top-level */
682 LOGERR(LY_EINVAL, "%s: invalid variable parameter (const struct lyd_node *data_tree).", __func__);
683 goto error;
684 }
685 }
686
687 /* move it to the beginning */
688 for (; data_tree->prev->next; data_tree = data_tree->prev);
689
690 /* LYD_OPT_NOSIBLINGS cannot be set in this case */
691 if (options & LYD_OPT_NOSIBLINGS) {
692 LOGERR(LY_EINVAL, "%s: invalid parameter (variable arg const struct lyd_node *data_tree with LYD_OPT_NOSIBLINGS).", __func__);
693 goto error;
694 }
695 }
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100696 }
697
Radek Krejci86538212015-12-17 15:59:01 +0100698 if (!(options & LYD_OPT_NOSIBLINGS)) {
699 /* locate the first root to process */
700 if ((*root)->parent) {
701 xmlstart = (*root)->parent->child;
702 } else {
703 xmlstart = *root;
704 while(xmlstart->prev->next) {
705 xmlstart = xmlstart->prev;
706 }
Radek Krejci04b97de2015-10-31 23:09:15 +0100707 }
Radek Krejci86538212015-12-17 15:59:01 +0100708 } else {
709 xmlstart = *root;
710 }
Radek Krejci86538212015-12-17 15:59:01 +0100711
Michal Vaskob1b19442016-07-13 12:26:01 +0200712 if ((options & LYD_OPT_RPC)
713 && !strcmp(xmlstart->name, "action") && !strcmp(xmlstart->ns->value, "urn:ietf:params:xml:ns:yang:1")) {
714 /* it's an action, not a simple RPC */
715 xmlstart = xmlstart->child;
Michal Vaskob1b19442016-07-13 12:26:01 +0200716 }
717
718 iter = last = NULL;
Radek Krejci86538212015-12-17 15:59:01 +0100719 LY_TREE_FOR_SAFE(xmlstart, xmlaux, xmlelem) {
Michal Vaskob15cae22016-09-15 09:40:56 +0200720 r = xml_parse_data(ctx, xmlelem, reply_parent, result, last, options, unres, &iter, &act_notif);
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100721 if (r) {
Michal Vasko945b96b2016-10-18 11:49:12 +0200722 if (reply_top) {
723 result = reply_top;
Pavol Vican8a552f62016-09-05 11:20:57 +0200724 }
Michal Vasko24d982f2016-04-18 15:13:58 +0200725 goto error;
Radek Krejci86538212015-12-17 15:59:01 +0100726 } else if (options & LYD_OPT_DESTRUCT) {
727 lyxml_free(ctx, xmlelem);
728 *root = xmlaux;
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100729 }
730 if (iter) {
731 last = iter;
732 }
733 if (!result) {
734 result = iter;
735 }
Radek Krejci86538212015-12-17 15:59:01 +0100736
737 if (options & LYD_OPT_NOSIBLINGS) {
738 /* stop after the first processed root */
739 break;
740 }
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100741 }
Radek Krejcic6704c82015-10-06 11:12:45 +0200742
Michal Vasko945b96b2016-10-18 11:49:12 +0200743 if (reply_top) {
744 result = reply_top;
Michal Vaskoe45aff52016-08-25 09:01:09 +0200745 }
746
Michal Vasko945b96b2016-10-18 11:49:12 +0200747 if ((options & LYD_OPT_RPCREPLY) && (rpc_act->schema->nodetype != LYS_RPC)) {
748 /* action reply */
749 act_notif = reply_parent;
Michal Vaskoafa7a642016-10-18 15:11:38 +0200750 } else if ((options & (LYD_OPT_RPC | LYD_OPT_NOTIF)) && !act_notif) {
751 ly_vecode = LYVE_INELEM;
752 LOGVAL(LYE_SPEC, LY_VLOG_LYD, result, "Missing %s node.", (options & LYD_OPT_RPC ? "action" : "notification"));
753 goto error;
Radek Krejcib45b3082016-09-09 16:08:51 +0200754 }
755
Radek Krejci63b79c82016-08-10 10:09:33 +0200756 /* check for uniquness of top-level lists/leaflists because
757 * only the inner instances were tested in lyv_data_content() */
758 set = ly_set_new();
759 LY_TREE_FOR(result, iter) {
760 if (!(iter->schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) || !(iter->validity & LYD_VAL_UNIQUE)) {
761 continue;
762 }
763
764 /* check each list/leaflist only once */
765 i = set->number;
766 if (ly_set_add(set, iter->schema, 0) != i) {
767 /* already checked */
768 continue;
769 }
770
771 if (lyv_data_unique(iter, result)) {
772 ly_set_free(set);
773 goto error;
774 }
775 }
776 ly_set_free(set);
777
Radek Krejcib45b3082016-09-09 16:08:51 +0200778 /* add default values, resolve unres and check for mandatory nodes in final tree */
Michal Vaskob15cae22016-09-15 09:40:56 +0200779 if (lyd_defaults_add_unres(&result, options, ctx, data_tree, act_notif, unres)) {
Michal Vasko6b44d712016-09-12 16:25:46 +0200780 goto error;
781 }
Michal Vaskoad2e44a2017-01-03 10:31:35 +0100782 if (!(options & (LYD_OPT_TRUSTED | LYD_OPT_NOTIF_FILTER))
783 && lyd_check_mandatory_tree((act_notif ? act_notif : result), ctx, options)) {
Michal Vaskoafa7a642016-10-18 15:11:38 +0200784 goto error;
Radek Krejci46165822016-08-26 14:06:27 +0200785 }
786
Michal Vasko24d982f2016-04-18 15:13:58 +0200787 free(unres->node);
788 free(unres->type);
789 free(unres);
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100790 va_end(ap);
Radek Krejcic6704c82015-10-06 11:12:45 +0200791
792 return result;
Michal Vasko24d982f2016-04-18 15:13:58 +0200793
794error:
795 lyd_free_withsiblings(result);
796 free(unres->node);
797 free(unres->type);
798 free(unres);
799 va_end(ap);
800
801 return NULL;
Radek Krejcic6704c82015-10-06 11:12:45 +0200802}