blob: be565bbcd412fc48b3076f0f97dbb7a4a0fc9a49 [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 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of the Company nor the names of its contributors
18 * may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 */
21
22#include <assert.h>
Radek Krejci3e3affe2015-07-09 15:38:40 +020023#include <ctype.h>
Radek Krejci1721c012015-07-08 12:52:33 +020024#include <errno.h>
25#include <stdlib.h>
26#include <string.h>
Michal Vasko8bcdf292015-08-19 14:04:43 +020027#include <limits.h>
Radek Krejci1721c012015-07-08 12:52:33 +020028
Radek Krejci998a0b82015-08-17 13:14:36 +020029#include "libyang.h"
30#include "common.h"
31#include "context.h"
Michal Vaskob7982322015-10-16 13:56:12 +020032#include "parser.h"
Radek Krejci998a0b82015-08-17 13:14:36 +020033#include "tree_internal.h"
34#include "validation.h"
Michal Vaskofc5744d2015-10-22 12:09:34 +020035#include "xml_internal.h"
Radek Krejci1721c012015-07-08 12:52:33 +020036
Michal Vasko0d343d12015-08-24 14:57:36 +020037/* does not log */
Radek Krejci76512572015-08-04 09:47:08 +020038static struct lys_node *
39xml_data_search_schemanode(struct lyxml_elem *xml, struct lys_node *start)
Radek Krejci1721c012015-07-08 12:52:33 +020040{
Radek Krejci76512572015-08-04 09:47:08 +020041 struct lys_node *result, *aux;
Radek Krejci1721c012015-07-08 12:52:33 +020042
43 LY_TREE_FOR(start, result) {
44 /* skip groupings */
Radek Krejci76512572015-08-04 09:47:08 +020045 if (result->nodetype == LYS_GROUPING) {
Radek Krejci1721c012015-07-08 12:52:33 +020046 continue;
47 }
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 Krejci1721c012015-07-08 12:52:33 +020051 aux = xml_data_search_schemanode(xml, result->child);
52 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 */
61 if (result->name == xml->name) {
62 /* names matches, what about namespaces? */
63 if (result->module->ns == xml->ns->value) {
64 /* 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;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +020081 struct lys_type *type, *stype;
82 int resolve, found;
Michal Vasko23b61ec2015-08-19 11:19:50 +020083
Michal Vasko8ea2b7f2015-09-29 14:30:53 +020084 assert(node && (node->schema->nodetype & (LYS_LEAFLIST | LYS_LEAF)) && xml && unres);
Radek Krejci5a988152015-07-15 11:16:26 +020085
Michal Vasko8ea2b7f2015-09-29 14:30:53 +020086 stype = &((struct lys_node_leaf *)node->schema)->type;
Radek Krejci5a988152015-07-15 11:16:26 +020087 leaf->value_str = xml->content;
88 xml->content = NULL;
Radek Krejcie4748472015-07-08 18:00:22 +020089
Michal Vasko8ea2b7f2015-09-29 14:30:53 +020090 /* will be changed in case of union */
91 leaf->value_type = stype->base;
Radek Krejcie3c33142015-08-10 15:04:36 +020092
Radek Krejcie2cf7c12015-08-12 10:24:05 +020093 if ((options & LYD_OPT_FILTER) && !leaf->value_str) {
94 /* no value in filter (selection) node -> nothing more is needed */
95 return EXIT_SUCCESS;
96 }
97
Radek Krejci20cdf632015-11-09 14:44:58 +010098 if (options & (LYD_OPT_FILTER | LYD_OPT_EDIT | LYD_OPT_GET | LYD_OPT_GETCONFIG)) {
Michal Vasko8ea2b7f2015-09-29 14:30:53 +020099 resolve = 0;
100 } else {
101 resolve = 1;
102 }
Radek Krejci3e3affe2015-07-09 15:38:40 +0200103
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200104 if ((stype->base == LY_TYPE_IDENT) || (stype->base == LY_TYPE_INST)) {
Michal Vaskofb0873c2015-08-21 09:00:07 +0200105 /* convert the path from the XML form using XML namespaces into the JSON format
106 * using module names as namespaces
107 */
108 xml->content = leaf->value_str;
Michal Vaskofba15262015-10-21 12:10:28 +0200109 leaf->value_str = transform_xml2json(leaf->schema->module->ctx, xml->content, xml, 1);
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200110 lydict_remove(leaf->schema->module->ctx, xml->content);
Michal Vaskofb0873c2015-08-21 09:00:07 +0200111 xml->content = NULL;
112 if (!leaf->value_str) {
113 return EXIT_FAILURE;
Radek Krejciac8aac62015-07-10 15:36:35 +0200114 }
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200115 }
Radek Krejciac8aac62015-07-10 15:36:35 +0200116
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200117 if (stype->base == LY_TYPE_UNION) {
Michal Vasko07471a52015-07-16 11:18:48 +0200118 found = 0;
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200119 type = lyp_get_next_union_type(stype, NULL, &found);
120 while (type) {
121 leaf->value_type = type->base;
Michal Vasko9f9ea082015-10-16 13:41:25 +0200122
123 /* in these cases we use JSON format */
124 if ((type->base == LY_TYPE_IDENT) || (type->base == LY_TYPE_INST)) {
125 xml->content = leaf->value_str;
Michal Vaskofba15262015-10-21 12:10:28 +0200126 leaf->value_str = transform_xml2json(leaf->schema->module->ctx, xml->content, xml, 0);
Michal Vasko9f9ea082015-10-16 13:41:25 +0200127 if (!leaf->value_str) {
128 leaf->value_str = xml->content;
129 xml->content = NULL;
130
131 found = 0;
132 type = lyp_get_next_union_type(stype, type, &found);
133 continue;
134 }
135 }
136
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200137 if (!lyp_parse_value(leaf, type, resolve, unres, UINT_MAX)) {
Michal Vasko07471a52015-07-16 11:18:48 +0200138 break;
139 }
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200140
Michal Vasko9f9ea082015-10-16 13:41:25 +0200141 if ((type->base == LY_TYPE_IDENT) || (type->base == LY_TYPE_INST)) {
142 lydict_remove(leaf->schema->module->ctx, leaf->value_str);
143 leaf->value_str = xml->content;
144 xml->content = NULL;
145 }
146
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200147 found = 0;
148 type = lyp_get_next_union_type(stype, type, &found);
Michal Vasko07471a52015-07-16 11:18:48 +0200149 }
150
151 if (!type) {
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200152 LOGVAL(LYE_INVAL, LOGLINE(xml), (leaf->value_str ? leaf->value_str : ""), xml->name);
Michal Vasko07471a52015-07-16 11:18:48 +0200153 return EXIT_FAILURE;
154 }
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200155 } else if (lyp_parse_value(leaf, stype, resolve, unres, LOGLINE(xml))) {
Michal Vasko493bea72015-07-16 16:08:12 +0200156 return EXIT_FAILURE;
Radek Krejcie4748472015-07-08 18:00:22 +0200157 }
158
159 return EXIT_SUCCESS;
160}
161
Michal Vasko0d343d12015-08-24 14:57:36 +0200162/* logs directly */
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100163static int
Michal Vasko493bea72015-07-16 16:08:12 +0200164xml_parse_data(struct ly_ctx *ctx, struct lyxml_elem *xml, struct lyd_node *parent, struct lyd_node *prev,
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100165 int options, struct unres_data *unres, struct lyd_node **result)
Radek Krejci1721c012015-07-08 12:52:33 +0200166{
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100167 struct lyd_node *diter, *dlast;
Radek Krejcieab784a2015-08-27 09:56:53 +0200168 struct lys_node *schema = NULL;
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100169 struct lyd_attr *dattr, *dattr_iter;
Radek Krejcia5241e52015-08-19 15:09:31 +0200170 struct lyxml_attr *attr;
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100171 struct lyxml_elem *first_child, *last_child, *child, *next;
172 int i, havechildren, r;
173 int ret = 0;
Radek Krejci1721c012015-07-08 12:52:33 +0200174
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100175 assert(xml);
176 assert(result);
177 *result = NULL;
178
Radek Krejci1721c012015-07-08 12:52:33 +0200179 if (!xml->ns || !xml->ns->value) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +0200180 LOGVAL(LYE_XML_MISS, LOGLINE(xml), "element's", "namespace");
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100181 return -1;
Radek Krejci1721c012015-07-08 12:52:33 +0200182 }
183
184 /* find schema node */
185 if (!parent) {
186 /* starting in root */
187 for (i = 0; i < ctx->models.used; i++) {
188 /* match data model based on namespace */
189 if (ctx->models.list[i]->ns == xml->ns->value) {
190 /* get the proper schema node */
191 LY_TREE_FOR(ctx->models.list[i]->data, schema) {
192 if (schema->name == xml->name) {
193 break;
194 }
195 }
196 break;
197 }
198 }
199 } else {
200 /* parsing some internal node, we start with parent's schema pointer */
201 schema = xml_data_search_schemanode(xml, parent->schema->child);
202 }
203 if (!schema) {
Radek Krejci25b9fd32015-08-10 15:06:07 +0200204 if ((options & LYD_OPT_STRICT) || ly_ctx_get_module_by_ns(ctx, xml->ns->value, NULL)) {
205 LOGVAL(LYE_INELEM, LOGLINE(xml), xml->name);
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100206 return -1;
Radek Krejci25b9fd32015-08-10 15:06:07 +0200207 } else {
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100208 return 0;
Radek Krejci25b9fd32015-08-10 15:06:07 +0200209 }
Radek Krejci1721c012015-07-08 12:52:33 +0200210 }
211
Radek Krejcia5241e52015-08-19 15:09:31 +0200212 /* check insert attribute and its values */
213 if (options & LYD_OPT_EDIT) {
214 i = 0;
215 for (attr = xml->attr; attr; attr = attr->next) {
216 if (attr->type != LYXML_ATTR_STD || !attr->ns ||
217 strcmp(attr->name, "insert") || strcmp(attr->ns->value, LY_NSYANG)) {
218 continue;
219 }
220
221 /* insert attribute present */
222 if (!(schema->flags & LYS_USERORDERED)) {
223 /* ... but it is not expected */
224 LOGVAL(LYE_INATTR, LOGLINE(xml), "insert", schema->name);
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100225 return -1;
Radek Krejcia5241e52015-08-19 15:09:31 +0200226 }
227
228 if (i) {
229 LOGVAL(LYE_TOOMANY, LOGLINE(xml), "insert attributes", xml->name);
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100230 return -1;
Radek Krejcia5241e52015-08-19 15:09:31 +0200231 }
232 if (!strcmp(attr->value, "first") || !strcmp(attr->value, "last")) {
233 i = 1;
234 } else if (!strcmp(attr->value, "before") || !strcmp(attr->value, "after")) {
235 i = 2;
236 } else {
237 LOGVAL(LYE_INARG, LOGLINE(xml), attr->value, attr->name);
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100238 return -1;
Radek Krejcia5241e52015-08-19 15:09:31 +0200239 }
240 }
241
242 for (attr = xml->attr; attr; attr = attr->next) {
243 if (attr->type != LYXML_ATTR_STD || !attr->ns ||
244 strcmp(attr->name, "value") || strcmp(attr->ns->value, LY_NSYANG)) {
245 continue;
246 }
247
248 /* the value attribute is present */
249 if (i < 2) {
250 /* but it shouldn't */
251 LOGVAL(LYE_INATTR, LOGLINE(xml), "value", schema->name);
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100252 return -1;
Radek Krejcia5241e52015-08-19 15:09:31 +0200253 }
254 i++;
255 }
256 if (i == 2) {
257 /* missing value attribute for "before" or "after" */
258 LOGVAL(LYE_MISSATTR, LOGLINE(xml), "value", xml->name);
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100259 return -1;
Radek Krejcia5241e52015-08-19 15:09:31 +0200260 } else if (i > 3) {
261 /* more than one instance of the value attribute */
262 LOGVAL(LYE_TOOMANY, LOGLINE(xml), "value attributes", xml->name);
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100263 return -1;
Radek Krejcia5241e52015-08-19 15:09:31 +0200264 }
Radek Krejci074bf852015-08-19 14:22:16 +0200265 }
266
Radek Krejcib9930252015-07-08 15:47:45 +0200267 switch (schema->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +0200268 case LYS_CONTAINER:
Radek Krejci27aaa732015-09-04 15:24:04 +0200269 case LYS_LIST:
Michal Vasko2f30e572015-10-01 16:00:38 +0200270 case LYS_NOTIF:
271 case LYS_RPC:
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100272 *result = calloc(1, sizeof **result);
Michal Vaskoab8e4402015-07-17 12:54:28 +0200273 havechildren = 1;
Radek Krejcib9930252015-07-08 15:47:45 +0200274 break;
Radek Krejci76512572015-08-04 09:47:08 +0200275 case LYS_LEAF:
Radek Krejci76512572015-08-04 09:47:08 +0200276 case LYS_LEAFLIST:
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100277 *result = calloc(1, sizeof(struct lyd_node_leaf_list));
Radek Krejcie4748472015-07-08 18:00:22 +0200278 havechildren = 0;
279 break;
Radek Krejci76512572015-08-04 09:47:08 +0200280 case LYS_ANYXML:
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100281 *result = calloc(1, sizeof(struct lyd_node_anyxml));
Michal Vaskoab8e4402015-07-17 12:54:28 +0200282 havechildren = 0;
283 break;
Radek Krejcib9930252015-07-08 15:47:45 +0200284 default:
Michal Vasko0c888fd2015-08-11 15:54:08 +0200285 LOGINT;
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100286 return -1;
Radek Krejcib9930252015-07-08 15:47:45 +0200287 }
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100288 (*result)->parent = parent;
Radek Krejcic41bf8a2015-08-21 10:28:48 +0200289 if (parent && !parent->child) {
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100290 parent->child = *result;
Radek Krejcic41bf8a2015-08-21 10:28:48 +0200291 }
292 if (prev) {
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100293 (*result)->prev = prev;
294 prev->next = *result;
Radek Krejcic41bf8a2015-08-21 10:28:48 +0200295
296 /* fix the "last" pointer */
297 for (diter = prev; diter->prev != prev; diter = diter->prev);
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100298 diter->prev = *result;
Radek Krejcic41bf8a2015-08-21 10:28:48 +0200299 } else {
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100300 (*result)->prev = *result;
Radek Krejcic41bf8a2015-08-21 10:28:48 +0200301 }
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100302 (*result)->schema = schema;
Radek Krejci1721c012015-07-08 12:52:33 +0200303
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100304 if (lyv_data_context(*result, options, LOGLINE(xml), unres)) {
Michal Vaskocf024702015-10-08 15:01:42 +0200305 goto error;
306 }
307
Radek Krejcib9930252015-07-08 15:47:45 +0200308 /* type specific processing */
Radek Krejci27aaa732015-09-04 15:24:04 +0200309 if (schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
Radek Krejcie4748472015-07-08 18:00:22 +0200310 /* type detection and assigning the value */
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100311 if (xml_get_value(*result, xml, options, unres)) {
Radek Krejci3e3affe2015-07-09 15:38:40 +0200312 goto error;
313 }
Radek Krejci1b0d01a2015-08-19 17:00:35 +0200314 } else if (schema->nodetype == LYS_ANYXML && !(options & LYD_OPT_FILTER)) {
Michal Vasko9f1ef592015-09-29 14:57:51 +0200315 /* unlink xml children, they will be the anyxml value */
Radek Krejcie4e4d722015-10-05 16:53:50 +0200316 first_child = last_child = NULL;
Michal Vasko9f1ef592015-09-29 14:57:51 +0200317 LY_TREE_FOR(xml->child, child) {
318 lyxml_unlink_elem(ctx, child, 1);
319 if (!first_child) {
320 first_child = child;
321 last_child = child;
322 } else {
323 last_child->next = child;
324 child->prev = last_child;
325 last_child = child;
326 }
Michal Vasko60beecb2015-09-03 14:24:09 +0200327 }
Radek Krejcie4e4d722015-10-05 16:53:50 +0200328 if (first_child) {
329 first_child->prev = last_child;
330 }
Michal Vasko60beecb2015-09-03 14:24:09 +0200331
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100332 ((struct lyd_node_anyxml *)(*result))->value = first_child;
Michal Vasko60beecb2015-09-03 14:24:09 +0200333 /* we can safely continue with xml, it's like it was, only without children */
Radek Krejcib9930252015-07-08 15:47:45 +0200334 }
335
Radek Krejci998a7502015-10-26 15:54:33 +0100336 for (attr = xml->attr; attr; attr = attr->next) {
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100337 if (attr->type != LYXML_ATTR_STD) {
338 continue;
339 } else if (!attr->ns) {
340 LOGWRN("Ignoring \"%s\" attribute in \"%s\" element.", attr->name, xml->name);
341 continue;
342 }
343
344 dattr = malloc(sizeof *dattr);
345 dattr->next = NULL;
346 dattr->name = attr->name;
347 dattr->value = attr->value;
348 attr->name = NULL;
349 attr->value = NULL;
350
Michal Vasko1e62a092015-12-01 12:27:20 +0100351 dattr->module = (struct lys_module *)ly_ctx_get_module_by_ns(ctx, attr->ns->value, NULL);
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100352 if (!dattr->module) {
353 LOGWRN("Attribute \"%s\" from unknown schema (\"%s\") - skipping.", attr->name, attr->ns->value);
354 free(dattr);
355 continue;
356 }
357
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100358 if (!(*result)->attr) {
359 (*result)->attr = dattr;
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100360 } else {
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100361 for (dattr_iter = (*result)->attr; dattr_iter->next; dattr_iter = dattr_iter->next);
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100362 dattr_iter->next = dattr;
Radek Krejci998a7502015-10-26 15:54:33 +0100363 }
364 }
Michal Vasko4ff7b072015-08-21 09:05:03 +0200365
Radek Krejci14c00092015-11-01 11:03:24 +0100366 /* process children */
367 if (havechildren && xml->child) {
368 diter = dlast = NULL;
369 LY_TREE_FOR_SAFE(xml->child, next, child) {
370 if (schema->nodetype & (LYS_RPC | LYS_NOTIF)) {
371 r = xml_parse_data(ctx, child, *result, dlast, 0, unres, &diter);
372 } else {
373 r = xml_parse_data(ctx, child, *result, dlast, options, unres, &diter);
374 }
375 if (options & LYD_OPT_DESTRUCT) {
376 lyxml_free_elem(ctx, child);
377 }
378 if (r) {
379 goto error;
380 }
381 if (diter) {
382 dlast = diter;
383 }
384 }
385 }
386
Radek Krejcib1c12512015-08-11 11:22:04 +0200387 /* various validation checks */
Radek Krejcieab784a2015-08-27 09:56:53 +0200388 ly_errno = 0;
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100389 if (lyv_data_content(*result, options, LOGLINE(xml), unres)) {
Radek Krejcieab784a2015-08-27 09:56:53 +0200390 if (ly_errno) {
Radek Krejcib1c12512015-08-11 11:22:04 +0200391 goto error;
Radek Krejci1b0d01a2015-08-19 17:00:35 +0200392 } else {
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100393 goto clear;
Radek Krejcida374342015-08-19 13:33:22 +0200394 }
Radek Krejci78ce8612015-08-18 14:31:05 +0200395 }
396
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100397 return ret;
Radek Krejci3e3affe2015-07-09 15:38:40 +0200398
399error:
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100400 ret--;
401
402clear:
Radek Krejcieab784a2015-08-27 09:56:53 +0200403 /* cleanup */
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100404 lyd_free(*result);
405 *result = NULL;
Radek Krejci1b0d01a2015-08-19 17:00:35 +0200406
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100407 return ret;
Radek Krejci1721c012015-07-08 12:52:33 +0200408}
409
Radek Krejcic6704c82015-10-06 11:12:45 +0200410API struct lyd_node *
411lyd_parse_xml(struct ly_ctx *ctx, struct lyxml_elem *root, int options)
412{
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100413 struct lyd_node *result, *next, *iter, *last;
414 struct lyxml_elem *xmlelem, *xmlaux;
Radek Krejcic6704c82015-10-06 11:12:45 +0200415 struct unres_data *unres = NULL;
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100416 int r;
Radek Krejcic6704c82015-10-06 11:12:45 +0200417
418 if (!ctx || !root) {
419 LOGERR(LY_EINVAL, "%s: Invalid parameter.", __func__);
420 return NULL;
421 }
422
423 unres = calloc(1, sizeof *unres);
424
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100425 iter = result = last = NULL;
426 LY_TREE_FOR_SAFE(root->child, xmlaux, xmlelem) {
427 r = xml_parse_data(ctx, xmlelem, NULL, last, options, unres, &iter);
Radek Krejci04b97de2015-10-31 23:09:15 +0100428 if (options & LYD_OPT_DESTRUCT) {
429 lyxml_free_elem(ctx, xmlelem);
430 }
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100431 if (r) {
432 LY_TREE_FOR_SAFE(result, next, iter) {
433 lyd_free(iter);
434 }
435 result = NULL;
436 goto cleanup;
437 }
438 if (iter) {
439 last = iter;
440 }
441 if (!result) {
442 result = iter;
443 }
444 }
Radek Krejcic6704c82015-10-06 11:12:45 +0200445
Michal Vaskoc1cf86f2015-11-04 09:54:51 +0100446 if (!result) {
447 LOGERR(LY_EVALID, "Model for the data to be linked with not found.");
448 goto cleanup;
449 }
450
Radek Krejcic6704c82015-10-06 11:12:45 +0200451 /* check leafrefs and/or instids if any */
452 if (result && resolve_unres_data(unres)) {
453 /* leafref & instid checking failed */
454 LY_TREE_FOR_SAFE(result, next, iter) {
455 lyd_free(iter);
456 }
457 result = NULL;
458 }
459
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100460cleanup:
Michal Vaskocf024702015-10-08 15:01:42 +0200461 free(unres->node);
462 free(unres->type);
Radek Krejcic6704c82015-10-06 11:12:45 +0200463#ifndef NDEBUG
464 free(unres->line);
465#endif
466 free(unres);
467
468 return result;
469}