blob: 141393007c332357c3879edb7d5a611d43b86a4f [file] [log] [blame]
Radek Krejci1721c012015-07-08 12:52:33 +02001/**
2 * @file xml.c
3 * @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 Krejci749190d2016-02-18 16:26:25 +010063 if (ly_strequal(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 Vasko8ea2b7f2015-09-29 14:30:53 +020078xml_get_value(struct lyd_node *node, struct lyxml_elem *xml, int options, struct unres_data *unres)
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;
Radek Krejci37b756f2016-01-18 10:15:03 +010081 int resolve;
Michal Vasko23b61ec2015-08-19 11:19:50 +020082
Michal Vasko8ea2b7f2015-09-29 14:30:53 +020083 assert(node && (node->schema->nodetype & (LYS_LEAFLIST | LYS_LEAF)) && xml && unres);
Radek Krejci5a988152015-07-15 11:16:26 +020084
85 leaf->value_str = xml->content;
86 xml->content = NULL;
Radek Krejcie4748472015-07-08 18:00:22 +020087
Michal Vasko8ea2b7f2015-09-29 14:30:53 +020088 /* will be changed in case of union */
Radek Krejci37b756f2016-01-18 10:15:03 +010089 leaf->value_type = ((struct lys_node_leaf *)node->schema)->type.base;
Radek Krejcie3c33142015-08-10 15:04:36 +020090
Radek Krejcie2cf7c12015-08-12 10:24:05 +020091 if ((options & LYD_OPT_FILTER) && !leaf->value_str) {
92 /* no value in filter (selection) node -> nothing more is needed */
93 return EXIT_SUCCESS;
94 }
95
Radek Krejci20cdf632015-11-09 14:44:58 +010096 if (options & (LYD_OPT_FILTER | LYD_OPT_EDIT | LYD_OPT_GET | LYD_OPT_GETCONFIG)) {
Michal Vasko8ea2b7f2015-09-29 14:30:53 +020097 resolve = 0;
98 } else {
99 resolve = 1;
100 }
Radek Krejci3e3affe2015-07-09 15:38:40 +0200101
Radek Krejci37b756f2016-01-18 10:15:03 +0100102 if ((leaf->value_type == LY_TYPE_IDENT) || (leaf->value_type == LY_TYPE_INST)) {
Michal Vaskofb0873c2015-08-21 09:00:07 +0200103 /* convert the path from the XML form using XML namespaces into the JSON format
104 * using module names as namespaces
105 */
106 xml->content = leaf->value_str;
Michal Vaskofba15262015-10-21 12:10:28 +0200107 leaf->value_str = transform_xml2json(leaf->schema->module->ctx, xml->content, xml, 1);
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200108 lydict_remove(leaf->schema->module->ctx, xml->content);
Michal Vaskofb0873c2015-08-21 09:00:07 +0200109 xml->content = NULL;
110 if (!leaf->value_str) {
111 return EXIT_FAILURE;
Radek Krejciac8aac62015-07-10 15:36:35 +0200112 }
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200113 }
Radek Krejciac8aac62015-07-10 15:36:35 +0200114
Radek Krejci37b756f2016-01-18 10:15:03 +0100115 if (lyp_parse_value(leaf, xml, resolve, unres, LOGLINE(xml))) {
Michal Vasko493bea72015-07-16 16:08:12 +0200116 return EXIT_FAILURE;
Radek Krejcie4748472015-07-08 18:00:22 +0200117 }
118
119 return EXIT_SUCCESS;
120}
121
Michal Vasko0d343d12015-08-24 14:57:36 +0200122/* logs directly */
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100123static int
Michal Vasko36ef6932015-12-01 14:30:17 +0100124xml_parse_data(struct ly_ctx *ctx, struct lyxml_elem *xml, const struct lys_node *schema_parent, struct lyd_node *parent,
125 struct lyd_node *prev, int options, struct unres_data *unres, struct lyd_node **result)
Radek Krejci1721c012015-07-08 12:52:33 +0200126{
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100127 struct lyd_node *diter, *dlast;
Radek Krejcieab784a2015-08-27 09:56:53 +0200128 struct lys_node *schema = NULL;
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100129 struct lyd_attr *dattr, *dattr_iter;
Radek Krejcia5241e52015-08-19 15:09:31 +0200130 struct lyxml_attr *attr;
Michal Vasko17cc7062015-12-10 14:31:48 +0100131 struct lyxml_elem *tmp_xml, *child, *next;
Radek Krejci9a5daea2016-03-02 16:49:40 +0100132 int i, havechildren, r, flag;
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100133 int ret = 0;
Radek Krejci1721c012015-07-08 12:52:33 +0200134
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100135 assert(xml);
136 assert(result);
137 *result = NULL;
138
Radek Krejci1721c012015-07-08 12:52:33 +0200139 if (!xml->ns || !xml->ns->value) {
Radek Krejci2342cf62016-01-29 16:48:23 +0100140 if (options & LYD_OPT_STRICT) {
Radek Krejciadb57612016-02-16 13:34:34 +0100141 LOGVAL(LYE_XML_MISS, LOGLINE(xml), LY_VLOG_XML, xml, "element's", "namespace");
Radek Krejci2342cf62016-01-29 16:48:23 +0100142 return -1;
143 } else {
144 return 0;
145 }
Radek Krejci1721c012015-07-08 12:52:33 +0200146 }
147
148 /* find schema node */
Michal Vasko36ef6932015-12-01 14:30:17 +0100149 if (schema_parent) {
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100150 schema = xml_data_search_schemanode(xml, schema_parent->child, options);
Michal Vasko36ef6932015-12-01 14:30:17 +0100151 } else if (!parent) {
Radek Krejci1721c012015-07-08 12:52:33 +0200152 /* starting in root */
153 for (i = 0; i < ctx->models.used; i++) {
154 /* match data model based on namespace */
Radek Krejci749190d2016-02-18 16:26:25 +0100155 if (ly_strequal(ctx->models.list[i]->ns, xml->ns->value, 1)) {
Radek Krejci1721c012015-07-08 12:52:33 +0200156 /* get the proper schema node */
157 LY_TREE_FOR(ctx->models.list[i]->data, schema) {
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100158 /* skip nodes in module's data which are not expected here according to options' data type */
159 if (options & LYD_OPT_RPC) {
160 if (schema->nodetype != LYS_RPC) {
161 continue;
162 }
163 } else if (options & LYD_OPT_NOTIF) {
164 if (schema->nodetype != LYS_NOTIF) {
165 continue;
166 }
167 } else if (!(options & LYD_OPT_RPCREPLY)) {
168 /* rest of the data types except RPCREPLY which cannot be here */
169 if (schema->nodetype & (LYS_RPC | LYS_NOTIF)) {
170 continue;
171 }
172 }
Radek Krejci749190d2016-02-18 16:26:25 +0100173 if (ly_strequal(schema->name, xml->name, 1)) {
Radek Krejci1721c012015-07-08 12:52:33 +0200174 break;
175 }
176 }
177 break;
178 }
179 }
180 } else {
181 /* parsing some internal node, we start with parent's schema pointer */
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100182 schema = xml_data_search_schemanode(xml, parent->schema->child, options);
Radek Krejci1721c012015-07-08 12:52:33 +0200183 }
184 if (!schema) {
Radek Krejci25b9fd32015-08-10 15:06:07 +0200185 if ((options & LYD_OPT_STRICT) || ly_ctx_get_module_by_ns(ctx, xml->ns->value, NULL)) {
Radek Krejciadb57612016-02-16 13:34:34 +0100186 LOGVAL(LYE_INELEM, LOGLINE(xml), LY_VLOG_LYD, parent, xml->name);
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100187 return -1;
Radek Krejci25b9fd32015-08-10 15:06:07 +0200188 } else {
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100189 return 0;
Radek Krejci25b9fd32015-08-10 15:06:07 +0200190 }
Radek Krejci1721c012015-07-08 12:52:33 +0200191 }
192
Radek Krejciadb57612016-02-16 13:34:34 +0100193 /* create the element structure */
Radek Krejcib9930252015-07-08 15:47:45 +0200194 switch (schema->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +0200195 case LYS_CONTAINER:
Radek Krejci27aaa732015-09-04 15:24:04 +0200196 case LYS_LIST:
Michal Vasko2f30e572015-10-01 16:00:38 +0200197 case LYS_NOTIF:
198 case LYS_RPC:
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100199 *result = calloc(1, sizeof **result);
Michal Vaskoab8e4402015-07-17 12:54:28 +0200200 havechildren = 1;
Radek Krejcib9930252015-07-08 15:47:45 +0200201 break;
Radek Krejci76512572015-08-04 09:47:08 +0200202 case LYS_LEAF:
Radek Krejci76512572015-08-04 09:47:08 +0200203 case LYS_LEAFLIST:
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100204 *result = calloc(1, sizeof(struct lyd_node_leaf_list));
Radek Krejcie4748472015-07-08 18:00:22 +0200205 havechildren = 0;
206 break;
Radek Krejci76512572015-08-04 09:47:08 +0200207 case LYS_ANYXML:
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100208 *result = calloc(1, sizeof(struct lyd_node_anyxml));
Michal Vaskoab8e4402015-07-17 12:54:28 +0200209 havechildren = 0;
210 break;
Radek Krejcib9930252015-07-08 15:47:45 +0200211 default:
Michal Vasko0c888fd2015-08-11 15:54:08 +0200212 LOGINT;
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100213 return -1;
Radek Krejcib9930252015-07-08 15:47:45 +0200214 }
Michal Vasko253035f2015-12-17 16:58:13 +0100215 if (!(*result)) {
216 LOGMEM;
217 return -1;
218 }
219
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100220 (*result)->parent = parent;
Radek Krejcic41bf8a2015-08-21 10:28:48 +0200221 if (parent && !parent->child) {
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100222 parent->child = *result;
Radek Krejcic41bf8a2015-08-21 10:28:48 +0200223 }
224 if (prev) {
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100225 (*result)->prev = prev;
226 prev->next = *result;
Radek Krejcic41bf8a2015-08-21 10:28:48 +0200227
228 /* fix the "last" pointer */
Radek Krejci93fab982016-02-03 15:58:19 +0100229 if (parent) {
230 diter = parent->child;
231 } else {
232 for (diter = prev; diter->prev != prev; diter = diter->prev);
233 }
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100234 diter->prev = *result;
Radek Krejcic41bf8a2015-08-21 10:28:48 +0200235 } else {
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100236 (*result)->prev = *result;
Radek Krejcic41bf8a2015-08-21 10:28:48 +0200237 }
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100238 (*result)->schema = schema;
Radek Krejcica7efb72016-01-18 13:06:01 +0100239 (*result)->validity = LYD_VAL_NOT;
Radek Krejci1721c012015-07-08 12:52:33 +0200240
Radek Krejciadb57612016-02-16 13:34:34 +0100241 /* check insert attribute and its values */
242 if (options & LYD_OPT_EDIT) {
243 i = 0;
244 for (attr = xml->attr; attr; attr = attr->next) {
245 if (attr->type != LYXML_ATTR_STD || !attr->ns ||
246 strcmp(attr->name, "insert") || strcmp(attr->ns->value, LY_NSYANG)) {
247 continue;
248 }
249
250 /* insert attribute present */
251 if (!(schema->flags & LYS_USERORDERED)) {
252 /* ... but it is not expected */
253 LOGVAL(LYE_INATTR, LOGLINE(xml), LY_VLOG_LYD, (*result), "insert", schema->name);
254 return -1;
255 }
256
257 if (i) {
258 LOGVAL(LYE_TOOMANY, LOGLINE(xml), LY_VLOG_LYD, (*result), "insert attributes", xml->name);
259 return -1;
260 }
261 if (!strcmp(attr->value, "first") || !strcmp(attr->value, "last")) {
262 i = 1;
263 } else if (!strcmp(attr->value, "before") || !strcmp(attr->value, "after")) {
264 i = 2;
265 } else {
266 LOGVAL(LYE_INARG, LOGLINE(xml), LY_VLOG_LYD, (*result), attr->value, attr->name);
267 return -1;
268 }
269 }
270
271 for (attr = xml->attr; attr; attr = attr->next) {
272 if (attr->type != LYXML_ATTR_STD || !attr->ns ||
273 strcmp(attr->name, "value") || strcmp(attr->ns->value, LY_NSYANG)) {
274 continue;
275 }
276
277 /* the value attribute is present */
278 if (i < 2) {
279 /* but it shouldn't */
280 LOGVAL(LYE_INATTR, LOGLINE(xml), LY_VLOG_LYD, (*result), "value", schema->name);
281 return -1;
282 }
283 i++;
284 }
285 if (i == 2) {
286 /* missing value attribute for "before" or "after" */
287 LOGVAL(LYE_MISSATTR, LOGLINE(xml), LY_VLOG_LYD, (*result), "value", xml->name);
288 return -1;
289 } else if (i > 3) {
290 /* more than one instance of the value attribute */
291 LOGVAL(LYE_TOOMANY, LOGLINE(xml), LY_VLOG_LYD, (*result), "value attributes", xml->name);
292 return -1;
293 }
294 }
295
296 /* first part of validation checks */
Radek Krejci93fab982016-02-03 15:58:19 +0100297 if (!(options & LYD_OPT_TRUSTED) && lyv_data_context(*result, options, LOGLINE(xml), unres)) {
Michal Vaskocf024702015-10-08 15:01:42 +0200298 goto error;
299 }
300
Radek Krejcib9930252015-07-08 15:47:45 +0200301 /* type specific processing */
Radek Krejci27aaa732015-09-04 15:24:04 +0200302 if (schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
Radek Krejcie4748472015-07-08 18:00:22 +0200303 /* type detection and assigning the value */
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100304 if (xml_get_value(*result, xml, options, unres)) {
Radek Krejci3e3affe2015-07-09 15:38:40 +0200305 goto error;
306 }
Radek Krejci1b0d01a2015-08-19 17:00:35 +0200307 } else if (schema->nodetype == LYS_ANYXML && !(options & LYD_OPT_FILTER)) {
Michal Vasko17cc7062015-12-10 14:31:48 +0100308 /* HACK unlink xml children and link them to a separate copy of xml */
309 tmp_xml = calloc(1, sizeof *tmp_xml);
Michal Vasko253035f2015-12-17 16:58:13 +0100310 if (!tmp_xml) {
311 LOGMEM;
312 goto error;
313 }
Michal Vasko17cc7062015-12-10 14:31:48 +0100314 memcpy(tmp_xml, xml, sizeof *tmp_xml);
315 /* keep attributes in the original */
316 tmp_xml->attr = NULL;
317 /* increase reference counters on strings */
318 tmp_xml->name = lydict_insert(ctx, tmp_xml->name, 0);
319 tmp_xml->content = lydict_insert(ctx, tmp_xml->content, 0);
320 xml->child = NULL;
321 /* xml is correct now */
Michal Vasko60beecb2015-09-03 14:24:09 +0200322
Michal Vasko17cc7062015-12-10 14:31:48 +0100323 LY_TREE_FOR(tmp_xml->child, child) {
324 child->parent = tmp_xml;
325 }
326 /* children are correct now */
327
Michal Vasko63fac9e2016-02-24 10:42:02 +0100328 /* unlink manually */
Michal Vasko17cc7062015-12-10 14:31:48 +0100329 tmp_xml->parent = NULL;
Michal Vasko63fac9e2016-02-24 10:42:02 +0100330 tmp_xml->next = NULL;
331 tmp_xml->prev = tmp_xml;
332
333 /* just to correct namespaces */
Michal Vasko17cc7062015-12-10 14:31:48 +0100334 lyxml_unlink_elem(ctx, tmp_xml, 1);
335 /* tmp_xml is correct now */
336
337 ((struct lyd_node_anyxml *)*result)->value = tmp_xml;
Michal Vasko60beecb2015-09-03 14:24:09 +0200338 /* we can safely continue with xml, it's like it was, only without children */
Radek Krejcib9930252015-07-08 15:47:45 +0200339 }
340
Radek Krejci998a7502015-10-26 15:54:33 +0100341 for (attr = xml->attr; attr; attr = attr->next) {
Radek Krejci9a5daea2016-03-02 16:49:40 +0100342 flag = 0;
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100343 if (attr->type != LYXML_ATTR_STD) {
344 continue;
345 } else if (!attr->ns) {
Radek Krejci9a5daea2016-03-02 16:49:40 +0100346 if ((*result)->schema->nodetype != LYS_ANYXML ||
347 !ly_strequal((*result)->schema->name, "filter", 0) ||
348 !ly_strequal((*result)->schema->module->name, "ietf-netconf", 0)) {
349 LOGWRN("Ignoring \"%s\" attribute in \"%s\" element.", attr->name, xml->name);
350 continue;
351 } else {
352 /* exception for filter's attributes */
353 flag = 1;
354 }
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100355 }
356
357 dattr = malloc(sizeof *dattr);
Michal Vasko253035f2015-12-17 16:58:13 +0100358 if (!dattr) {
359 goto error;
360 }
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100361 dattr->next = NULL;
362 dattr->name = attr->name;
Radek Krejci9a5daea2016-03-02 16:49:40 +0100363 if (flag && ly_strequal(attr->name, "select", 0)) {
364 dattr->value = transform_xml2json(ctx, attr->value, xml, 1);
365 if (!dattr->value) {
366 free(dattr);
367 goto error;
368 }
369 lydict_remove(ctx, attr->value);
370 } else {
371 dattr->value = attr->value;
372 }
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100373 attr->name = NULL;
374 attr->value = NULL;
375
Radek Krejci9a5daea2016-03-02 16:49:40 +0100376 if (!attr->ns) {
377 /* filter's attributes, it actually has no namespace, but we need some for internal representation */
378 dattr->module = (*result)->schema->module;
379 } else {
380 dattr->module = (struct lys_module *)ly_ctx_get_module_by_ns(ctx, attr->ns->value, NULL);
381 }
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100382 if (!dattr->module) {
383 LOGWRN("Attribute \"%s\" from unknown schema (\"%s\") - skipping.", attr->name, attr->ns->value);
384 free(dattr);
385 continue;
386 }
387
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100388 if (!(*result)->attr) {
389 (*result)->attr = dattr;
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100390 } else {
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100391 for (dattr_iter = (*result)->attr; dattr_iter->next; dattr_iter = dattr_iter->next);
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100392 dattr_iter->next = dattr;
Radek Krejci998a7502015-10-26 15:54:33 +0100393 }
394 }
Michal Vasko4ff7b072015-08-21 09:05:03 +0200395
Radek Krejci14c00092015-11-01 11:03:24 +0100396 /* process children */
397 if (havechildren && xml->child) {
398 diter = dlast = NULL;
399 LY_TREE_FOR_SAFE(xml->child, next, child) {
400 if (schema->nodetype & (LYS_RPC | LYS_NOTIF)) {
Michal Vasko36ef6932015-12-01 14:30:17 +0100401 r = xml_parse_data(ctx, child, NULL, *result, dlast, 0, unres, &diter);
Radek Krejci14c00092015-11-01 11:03:24 +0100402 } else {
Michal Vasko36ef6932015-12-01 14:30:17 +0100403 r = xml_parse_data(ctx, child, NULL, *result, dlast, options, unres, &diter);
Radek Krejci14c00092015-11-01 11:03:24 +0100404 }
Radek Krejci14c00092015-11-01 11:03:24 +0100405 if (r) {
406 goto error;
Radek Krejci86538212015-12-17 15:59:01 +0100407 } else if (options & LYD_OPT_DESTRUCT) {
408 lyxml_free(ctx, child);
Radek Krejci14c00092015-11-01 11:03:24 +0100409 }
410 if (diter) {
411 dlast = diter;
412 }
413 }
414 }
415
Radek Krejcicf509982015-12-15 09:22:44 +0100416 /* rest of validation checks */
Radek Krejcieab784a2015-08-27 09:56:53 +0200417 ly_errno = 0;
Radek Krejci93fab982016-02-03 15:58:19 +0100418 if (!(options & LYD_OPT_TRUSTED) && lyv_data_content(*result, options, LOGLINE(xml), unres)) {
Radek Krejcieab784a2015-08-27 09:56:53 +0200419 if (ly_errno) {
Radek Krejcib1c12512015-08-11 11:22:04 +0200420 goto error;
Radek Krejci1b0d01a2015-08-19 17:00:35 +0200421 } else {
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100422 goto clear;
Radek Krejcida374342015-08-19 13:33:22 +0200423 }
Radek Krejci78ce8612015-08-18 14:31:05 +0200424 }
425
Radek Krejcica7efb72016-01-18 13:06:01 +0100426 /* validation successful */
427 (*result)->validity = LYD_VAL_OK;
428
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100429 return ret;
Radek Krejci3e3affe2015-07-09 15:38:40 +0200430
431error:
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100432 ret--;
433
434clear:
Radek Krejcieab784a2015-08-27 09:56:53 +0200435 /* cleanup */
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100436 lyd_free(*result);
437 *result = NULL;
Radek Krejci1b0d01a2015-08-19 17:00:35 +0200438
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100439 return ret;
Radek Krejci1721c012015-07-08 12:52:33 +0200440}
441
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100442API struct lyd_node *
443lyd_parse_xml(struct ly_ctx *ctx, struct lyxml_elem **root, int options, ...)
Radek Krejcic6704c82015-10-06 11:12:45 +0200444{
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100445 va_list ap;
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100446 int r;
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100447 struct unres_data *unres = NULL;
448 const struct lys_node *rpc = NULL;
449 struct lyd_node *result = NULL, *next, *iter, *last;
450 struct lyxml_elem *xmlstart, *xmlelem, *xmlaux;
Radek Krejcic6704c82015-10-06 11:12:45 +0200451
Radek Krejci2342cf62016-01-29 16:48:23 +0100452 ly_errno = LY_SUCCESS;
453
Radek Krejcic6704c82015-10-06 11:12:45 +0200454 if (!ctx || !root) {
455 LOGERR(LY_EINVAL, "%s: Invalid parameter.", __func__);
456 return NULL;
457 }
458
Radek Krejci2342cf62016-01-29 16:48:23 +0100459 if (!(*root)) {
460 /* empty tree - no work is needed */
Radek Krejci1daa7a42016-02-10 13:09:59 +0100461 lyd_validate(NULL, options, ctx);
Radek Krejci2342cf62016-01-29 16:48:23 +0100462 return NULL;
463 }
464
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100465 if (lyp_check_options(options)) {
466 LOGERR(LY_EINVAL, "%s: Invalid options (multiple data type flags set).", __func__);
467 return NULL;
468 }
469
470 va_start(ap, options);
471 if (options & LYD_OPT_RPCREPLY) {
472 rpc = va_arg(ap, struct lys_node*);
473 if (!rpc || (rpc->nodetype != LYS_RPC)) {
474 LOGERR(LY_EINVAL, "%s: Invalid parameter.", __func__);
475 goto cleanup;
476 }
477 }
478
Radek Krejcic6704c82015-10-06 11:12:45 +0200479 unres = calloc(1, sizeof *unres);
Michal Vasko253035f2015-12-17 16:58:13 +0100480 if (!unres) {
481 LOGMEM;
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100482 goto cleanup;
Michal Vasko253035f2015-12-17 16:58:13 +0100483 }
Radek Krejcic6704c82015-10-06 11:12:45 +0200484
Radek Krejci86538212015-12-17 15:59:01 +0100485 if (!(options & LYD_OPT_NOSIBLINGS)) {
486 /* locate the first root to process */
487 if ((*root)->parent) {
488 xmlstart = (*root)->parent->child;
489 } else {
490 xmlstart = *root;
491 while(xmlstart->prev->next) {
492 xmlstart = xmlstart->prev;
493 }
Radek Krejci04b97de2015-10-31 23:09:15 +0100494 }
Radek Krejci86538212015-12-17 15:59:01 +0100495 } else {
496 xmlstart = *root;
497 }
498 iter = result = last = NULL;
499
500 LY_TREE_FOR_SAFE(xmlstart, xmlaux, xmlelem) {
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100501 r = xml_parse_data(ctx, xmlelem, rpc, NULL, last, options, unres, &iter);
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100502 if (r) {
503 LY_TREE_FOR_SAFE(result, next, iter) {
504 lyd_free(iter);
505 }
506 result = NULL;
507 goto cleanup;
Radek Krejci86538212015-12-17 15:59:01 +0100508 } else if (options & LYD_OPT_DESTRUCT) {
509 lyxml_free(ctx, xmlelem);
510 *root = xmlaux;
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100511 }
512 if (iter) {
513 last = iter;
514 }
515 if (!result) {
516 result = iter;
517 }
Radek Krejci86538212015-12-17 15:59:01 +0100518
519 if (options & LYD_OPT_NOSIBLINGS) {
520 /* stop after the first processed root */
521 break;
522 }
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100523 }
Radek Krejcic6704c82015-10-06 11:12:45 +0200524
525 /* check leafrefs and/or instids if any */
526 if (result && resolve_unres_data(unres)) {
527 /* leafref & instid checking failed */
528 LY_TREE_FOR_SAFE(result, next, iter) {
529 lyd_free(iter);
530 }
531 result = NULL;
532 }
533
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100534cleanup:
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100535 if (unres) {
536 free(unres->node);
537 free(unres->type);
Radek Krejcic6704c82015-10-06 11:12:45 +0200538#ifndef NDEBUG
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100539 free(unres->line);
Radek Krejcic6704c82015-10-06 11:12:45 +0200540#endif
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100541 free(unres);
542 }
543 va_end(ap);
Radek Krejcic6704c82015-10-06 11:12:45 +0200544
545 return result;
546}