blob: ccae5aa86e9d4756fd255211cd1c9b3f7cedc8aa [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>
Radek Krejci4a49bdf2016-01-12 17:17:01 +010025#include <stdarg.h>
Radek Krejci1721c012015-07-08 12:52:33 +020026#include <stdlib.h>
27#include <string.h>
Michal Vasko8bcdf292015-08-19 14:04:43 +020028#include <limits.h>
Radek Krejci1721c012015-07-08 12:52:33 +020029
Radek Krejci998a0b82015-08-17 13:14:36 +020030#include "libyang.h"
31#include "common.h"
32#include "context.h"
Michal Vaskob7982322015-10-16 13:56:12 +020033#include "parser.h"
Radek Krejci998a0b82015-08-17 13:14:36 +020034#include "tree_internal.h"
35#include "validation.h"
Michal Vaskofc5744d2015-10-22 12:09:34 +020036#include "xml_internal.h"
Radek Krejci1721c012015-07-08 12:52:33 +020037
Michal Vasko0d343d12015-08-24 14:57:36 +020038/* does not log */
Radek Krejci76512572015-08-04 09:47:08 +020039static struct lys_node *
Radek Krejci4a49bdf2016-01-12 17:17:01 +010040xml_data_search_schemanode(struct lyxml_elem *xml, struct lys_node *start, int options)
Radek Krejci1721c012015-07-08 12:52:33 +020041{
Radek Krejci76512572015-08-04 09:47:08 +020042 struct lys_node *result, *aux;
Radek Krejci1721c012015-07-08 12:52:33 +020043
44 LY_TREE_FOR(start, result) {
Radek Krejci4a49bdf2016-01-12 17:17:01 +010045 /* skip groupings ... */
Radek Krejci76512572015-08-04 09:47:08 +020046 if (result->nodetype == LYS_GROUPING) {
Radek Krejci1721c012015-07-08 12:52:33 +020047 continue;
Radek Krejci4a49bdf2016-01-12 17:17:01 +010048 /* ... and output in case of RPC ... */
49 } else if (result->nodetype == LYS_OUTPUT && (options & LYD_OPT_RPC)) {
50 continue;
51 /* ... and input in case of RPC reply */
52 } else if (result->nodetype == LYS_INPUT && (options & LYD_OPT_RPCREPLY)) {
53 continue;
Radek Krejci1721c012015-07-08 12:52:33 +020054 }
55
Radek Krejcifb54be42015-10-02 15:21:16 +020056 /* go into cases, choices, uses and in RPCs into input and output */
57 if (result->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES | LYS_INPUT | LYS_OUTPUT)) {
Radek Krejci4a49bdf2016-01-12 17:17:01 +010058 aux = xml_data_search_schemanode(xml, result->child, options);
Radek Krejci1721c012015-07-08 12:52:33 +020059 if (aux) {
60 /* we have matching result */
61 return aux;
62 }
63 /* else, continue with next schema node */
64 continue;
65 }
66
67 /* match data nodes */
68 if (result->name == xml->name) {
69 /* names matches, what about namespaces? */
70 if (result->module->ns == xml->ns->value) {
71 /* we have matching result */
72 return result;
73 }
74 /* else, continue with next schema node */
75 continue;
76 }
77 }
78
79 /* no match */
80 return NULL;
81}
82
Michal Vasko0d343d12015-08-24 14:57:36 +020083/* logs directly */
Radek Krejcie4748472015-07-08 18:00:22 +020084static int
Michal Vasko8ea2b7f2015-09-29 14:30:53 +020085xml_get_value(struct lyd_node *node, struct lyxml_elem *xml, int options, struct unres_data *unres)
Michal Vasko07471a52015-07-16 11:18:48 +020086{
Michal Vasko4c183312015-09-25 10:41:47 +020087 struct lyd_node_leaf_list *leaf = (struct lyd_node_leaf_list *)node;
Radek Krejci37b756f2016-01-18 10:15:03 +010088 int resolve;
Michal Vasko23b61ec2015-08-19 11:19:50 +020089
Michal Vasko8ea2b7f2015-09-29 14:30:53 +020090 assert(node && (node->schema->nodetype & (LYS_LEAFLIST | LYS_LEAF)) && xml && unres);
Radek Krejci5a988152015-07-15 11:16:26 +020091
92 leaf->value_str = xml->content;
93 xml->content = NULL;
Radek Krejcie4748472015-07-08 18:00:22 +020094
Michal Vasko8ea2b7f2015-09-29 14:30:53 +020095 /* will be changed in case of union */
Radek Krejci37b756f2016-01-18 10:15:03 +010096 leaf->value_type = ((struct lys_node_leaf *)node->schema)->type.base;
Radek Krejcie3c33142015-08-10 15:04:36 +020097
Radek Krejcie2cf7c12015-08-12 10:24:05 +020098 if ((options & LYD_OPT_FILTER) && !leaf->value_str) {
99 /* no value in filter (selection) node -> nothing more is needed */
100 return EXIT_SUCCESS;
101 }
102
Radek Krejci20cdf632015-11-09 14:44:58 +0100103 if (options & (LYD_OPT_FILTER | LYD_OPT_EDIT | LYD_OPT_GET | LYD_OPT_GETCONFIG)) {
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200104 resolve = 0;
105 } else {
106 resolve = 1;
107 }
Radek Krejci3e3affe2015-07-09 15:38:40 +0200108
Radek Krejci37b756f2016-01-18 10:15:03 +0100109 if ((leaf->value_type == LY_TYPE_IDENT) || (leaf->value_type == LY_TYPE_INST)) {
Michal Vaskofb0873c2015-08-21 09:00:07 +0200110 /* convert the path from the XML form using XML namespaces into the JSON format
111 * using module names as namespaces
112 */
113 xml->content = leaf->value_str;
Michal Vaskofba15262015-10-21 12:10:28 +0200114 leaf->value_str = transform_xml2json(leaf->schema->module->ctx, xml->content, xml, 1);
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200115 lydict_remove(leaf->schema->module->ctx, xml->content);
Michal Vaskofb0873c2015-08-21 09:00:07 +0200116 xml->content = NULL;
117 if (!leaf->value_str) {
118 return EXIT_FAILURE;
Radek Krejciac8aac62015-07-10 15:36:35 +0200119 }
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200120 }
Radek Krejciac8aac62015-07-10 15:36:35 +0200121
Radek Krejci37b756f2016-01-18 10:15:03 +0100122 if (lyp_parse_value(leaf, xml, resolve, unres, LOGLINE(xml))) {
Michal Vasko493bea72015-07-16 16:08:12 +0200123 return EXIT_FAILURE;
Radek Krejcie4748472015-07-08 18:00:22 +0200124 }
125
126 return EXIT_SUCCESS;
127}
128
Michal Vasko0d343d12015-08-24 14:57:36 +0200129/* logs directly */
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100130static int
Michal Vasko36ef6932015-12-01 14:30:17 +0100131xml_parse_data(struct ly_ctx *ctx, struct lyxml_elem *xml, const struct lys_node *schema_parent, struct lyd_node *parent,
132 struct lyd_node *prev, int options, struct unres_data *unres, struct lyd_node **result)
Radek Krejci1721c012015-07-08 12:52:33 +0200133{
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100134 struct lyd_node *diter, *dlast;
Radek Krejcieab784a2015-08-27 09:56:53 +0200135 struct lys_node *schema = NULL;
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100136 struct lyd_attr *dattr, *dattr_iter;
Radek Krejcia5241e52015-08-19 15:09:31 +0200137 struct lyxml_attr *attr;
Michal Vasko17cc7062015-12-10 14:31:48 +0100138 struct lyxml_elem *tmp_xml, *child, *next;
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100139 int i, havechildren, r;
140 int ret = 0;
Radek Krejci1721c012015-07-08 12:52:33 +0200141
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100142 assert(xml);
143 assert(result);
144 *result = NULL;
145
Radek Krejci1721c012015-07-08 12:52:33 +0200146 if (!xml->ns || !xml->ns->value) {
Michal Vaskoe7fc19c2015-08-05 16:24:39 +0200147 LOGVAL(LYE_XML_MISS, LOGLINE(xml), "element's", "namespace");
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100148 return -1;
Radek Krejci1721c012015-07-08 12:52:33 +0200149 }
150
151 /* find schema node */
Michal Vasko36ef6932015-12-01 14:30:17 +0100152 if (schema_parent) {
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100153 schema = xml_data_search_schemanode(xml, schema_parent->child, options);
Michal Vasko36ef6932015-12-01 14:30:17 +0100154 } else if (!parent) {
Radek Krejci1721c012015-07-08 12:52:33 +0200155 /* starting in root */
156 for (i = 0; i < ctx->models.used; i++) {
157 /* match data model based on namespace */
158 if (ctx->models.list[i]->ns == xml->ns->value) {
159 /* get the proper schema node */
160 LY_TREE_FOR(ctx->models.list[i]->data, schema) {
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100161 /* skip nodes in module's data which are not expected here according to options' data type */
162 if (options & LYD_OPT_RPC) {
163 if (schema->nodetype != LYS_RPC) {
164 continue;
165 }
166 } else if (options & LYD_OPT_NOTIF) {
167 if (schema->nodetype != LYS_NOTIF) {
168 continue;
169 }
170 } else if (!(options & LYD_OPT_RPCREPLY)) {
171 /* rest of the data types except RPCREPLY which cannot be here */
172 if (schema->nodetype & (LYS_RPC | LYS_NOTIF)) {
173 continue;
174 }
175 }
Radek Krejci1721c012015-07-08 12:52:33 +0200176 if (schema->name == xml->name) {
177 break;
178 }
179 }
180 break;
181 }
182 }
183 } else {
184 /* parsing some internal node, we start with parent's schema pointer */
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100185 schema = xml_data_search_schemanode(xml, parent->schema->child, options);
Radek Krejci1721c012015-07-08 12:52:33 +0200186 }
187 if (!schema) {
Radek Krejci25b9fd32015-08-10 15:06:07 +0200188 if ((options & LYD_OPT_STRICT) || ly_ctx_get_module_by_ns(ctx, xml->ns->value, NULL)) {
189 LOGVAL(LYE_INELEM, LOGLINE(xml), xml->name);
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100190 return -1;
Radek Krejci25b9fd32015-08-10 15:06:07 +0200191 } else {
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100192 return 0;
Radek Krejci25b9fd32015-08-10 15:06:07 +0200193 }
Radek Krejci1721c012015-07-08 12:52:33 +0200194 }
195
Radek Krejcia5241e52015-08-19 15:09:31 +0200196 /* check insert attribute and its values */
197 if (options & LYD_OPT_EDIT) {
198 i = 0;
199 for (attr = xml->attr; attr; attr = attr->next) {
200 if (attr->type != LYXML_ATTR_STD || !attr->ns ||
201 strcmp(attr->name, "insert") || strcmp(attr->ns->value, LY_NSYANG)) {
202 continue;
203 }
204
205 /* insert attribute present */
206 if (!(schema->flags & LYS_USERORDERED)) {
207 /* ... but it is not expected */
208 LOGVAL(LYE_INATTR, LOGLINE(xml), "insert", schema->name);
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100209 return -1;
Radek Krejcia5241e52015-08-19 15:09:31 +0200210 }
211
212 if (i) {
213 LOGVAL(LYE_TOOMANY, LOGLINE(xml), "insert attributes", xml->name);
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100214 return -1;
Radek Krejcia5241e52015-08-19 15:09:31 +0200215 }
216 if (!strcmp(attr->value, "first") || !strcmp(attr->value, "last")) {
217 i = 1;
218 } else if (!strcmp(attr->value, "before") || !strcmp(attr->value, "after")) {
219 i = 2;
220 } else {
221 LOGVAL(LYE_INARG, LOGLINE(xml), attr->value, attr->name);
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100222 return -1;
Radek Krejcia5241e52015-08-19 15:09:31 +0200223 }
224 }
225
226 for (attr = xml->attr; attr; attr = attr->next) {
227 if (attr->type != LYXML_ATTR_STD || !attr->ns ||
228 strcmp(attr->name, "value") || strcmp(attr->ns->value, LY_NSYANG)) {
229 continue;
230 }
231
232 /* the value attribute is present */
233 if (i < 2) {
234 /* but it shouldn't */
235 LOGVAL(LYE_INATTR, LOGLINE(xml), "value", schema->name);
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100236 return -1;
Radek Krejcia5241e52015-08-19 15:09:31 +0200237 }
238 i++;
239 }
240 if (i == 2) {
241 /* missing value attribute for "before" or "after" */
242 LOGVAL(LYE_MISSATTR, LOGLINE(xml), "value", xml->name);
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100243 return -1;
Radek Krejcia5241e52015-08-19 15:09:31 +0200244 } else if (i > 3) {
245 /* more than one instance of the value attribute */
246 LOGVAL(LYE_TOOMANY, LOGLINE(xml), "value attributes", xml->name);
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100247 return -1;
Radek Krejcia5241e52015-08-19 15:09:31 +0200248 }
Radek Krejci074bf852015-08-19 14:22:16 +0200249 }
250
Radek Krejcib9930252015-07-08 15:47:45 +0200251 switch (schema->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +0200252 case LYS_CONTAINER:
Radek Krejci27aaa732015-09-04 15:24:04 +0200253 case LYS_LIST:
Michal Vasko2f30e572015-10-01 16:00:38 +0200254 case LYS_NOTIF:
255 case LYS_RPC:
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100256 *result = calloc(1, sizeof **result);
Michal Vaskoab8e4402015-07-17 12:54:28 +0200257 havechildren = 1;
Radek Krejcib9930252015-07-08 15:47:45 +0200258 break;
Radek Krejci76512572015-08-04 09:47:08 +0200259 case LYS_LEAF:
Radek Krejci76512572015-08-04 09:47:08 +0200260 case LYS_LEAFLIST:
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100261 *result = calloc(1, sizeof(struct lyd_node_leaf_list));
Radek Krejcie4748472015-07-08 18:00:22 +0200262 havechildren = 0;
263 break;
Radek Krejci76512572015-08-04 09:47:08 +0200264 case LYS_ANYXML:
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100265 *result = calloc(1, sizeof(struct lyd_node_anyxml));
Michal Vaskoab8e4402015-07-17 12:54:28 +0200266 havechildren = 0;
267 break;
Radek Krejcib9930252015-07-08 15:47:45 +0200268 default:
Michal Vasko0c888fd2015-08-11 15:54:08 +0200269 LOGINT;
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100270 return -1;
Radek Krejcib9930252015-07-08 15:47:45 +0200271 }
Michal Vasko253035f2015-12-17 16:58:13 +0100272 if (!(*result)) {
273 LOGMEM;
274 return -1;
275 }
276
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100277 (*result)->parent = parent;
Radek Krejcic41bf8a2015-08-21 10:28:48 +0200278 if (parent && !parent->child) {
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100279 parent->child = *result;
Radek Krejcic41bf8a2015-08-21 10:28:48 +0200280 }
281 if (prev) {
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100282 (*result)->prev = prev;
283 prev->next = *result;
Radek Krejcic41bf8a2015-08-21 10:28:48 +0200284
285 /* fix the "last" pointer */
286 for (diter = prev; diter->prev != prev; diter = diter->prev);
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100287 diter->prev = *result;
Radek Krejcic41bf8a2015-08-21 10:28:48 +0200288 } else {
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100289 (*result)->prev = *result;
Radek Krejcic41bf8a2015-08-21 10:28:48 +0200290 }
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100291 (*result)->schema = schema;
Radek Krejcica7efb72016-01-18 13:06:01 +0100292 (*result)->validity = LYD_VAL_NOT;
Radek Krejci1721c012015-07-08 12:52:33 +0200293
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100294 if (lyv_data_context(*result, options, LOGLINE(xml), unres)) {
Michal Vaskocf024702015-10-08 15:01:42 +0200295 goto error;
296 }
297
Radek Krejcib9930252015-07-08 15:47:45 +0200298 /* type specific processing */
Radek Krejci27aaa732015-09-04 15:24:04 +0200299 if (schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
Radek Krejcie4748472015-07-08 18:00:22 +0200300 /* type detection and assigning the value */
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100301 if (xml_get_value(*result, xml, options, unres)) {
Radek Krejci3e3affe2015-07-09 15:38:40 +0200302 goto error;
303 }
Radek Krejci1b0d01a2015-08-19 17:00:35 +0200304 } else if (schema->nodetype == LYS_ANYXML && !(options & LYD_OPT_FILTER)) {
Michal Vasko17cc7062015-12-10 14:31:48 +0100305 /* HACK unlink xml children and link them to a separate copy of xml */
306 tmp_xml = calloc(1, sizeof *tmp_xml);
Michal Vasko253035f2015-12-17 16:58:13 +0100307 if (!tmp_xml) {
308 LOGMEM;
309 goto error;
310 }
Michal Vasko17cc7062015-12-10 14:31:48 +0100311 memcpy(tmp_xml, xml, sizeof *tmp_xml);
312 /* keep attributes in the original */
313 tmp_xml->attr = NULL;
314 /* increase reference counters on strings */
315 tmp_xml->name = lydict_insert(ctx, tmp_xml->name, 0);
316 tmp_xml->content = lydict_insert(ctx, tmp_xml->content, 0);
317 xml->child = NULL;
318 /* xml is correct now */
Michal Vasko60beecb2015-09-03 14:24:09 +0200319
Michal Vasko17cc7062015-12-10 14:31:48 +0100320 LY_TREE_FOR(tmp_xml->child, child) {
321 child->parent = tmp_xml;
322 }
323 /* children are correct now */
324
325 tmp_xml->parent = NULL;
326 lyxml_unlink_elem(ctx, tmp_xml, 1);
327 /* tmp_xml is correct now */
328
329 ((struct lyd_node_anyxml *)*result)->value = tmp_xml;
Michal Vasko60beecb2015-09-03 14:24:09 +0200330 /* we can safely continue with xml, it's like it was, only without children */
Radek Krejcib9930252015-07-08 15:47:45 +0200331 }
332
Radek Krejci998a7502015-10-26 15:54:33 +0100333 for (attr = xml->attr; attr; attr = attr->next) {
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100334 if (attr->type != LYXML_ATTR_STD) {
335 continue;
336 } else if (!attr->ns) {
337 LOGWRN("Ignoring \"%s\" attribute in \"%s\" element.", attr->name, xml->name);
338 continue;
339 }
340
341 dattr = malloc(sizeof *dattr);
Michal Vasko253035f2015-12-17 16:58:13 +0100342 if (!dattr) {
343 goto error;
344 }
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100345 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)) {
Michal Vasko36ef6932015-12-01 14:30:17 +0100371 r = xml_parse_data(ctx, child, NULL, *result, dlast, 0, unres, &diter);
Radek Krejci14c00092015-11-01 11:03:24 +0100372 } else {
Michal Vasko36ef6932015-12-01 14:30:17 +0100373 r = xml_parse_data(ctx, child, NULL, *result, dlast, options, unres, &diter);
Radek Krejci14c00092015-11-01 11:03:24 +0100374 }
Radek Krejci14c00092015-11-01 11:03:24 +0100375 if (r) {
376 goto error;
Radek Krejci86538212015-12-17 15:59:01 +0100377 } else if (options & LYD_OPT_DESTRUCT) {
378 lyxml_free(ctx, child);
Radek Krejci14c00092015-11-01 11:03:24 +0100379 }
380 if (diter) {
381 dlast = diter;
382 }
383 }
384 }
385
Radek Krejcicf509982015-12-15 09:22:44 +0100386 /* rest of validation checks */
Radek Krejcieab784a2015-08-27 09:56:53 +0200387 ly_errno = 0;
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100388 if (lyv_data_content(*result, options, LOGLINE(xml), unres)) {
Radek Krejcieab784a2015-08-27 09:56:53 +0200389 if (ly_errno) {
Radek Krejcib1c12512015-08-11 11:22:04 +0200390 goto error;
Radek Krejci1b0d01a2015-08-19 17:00:35 +0200391 } else {
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100392 goto clear;
Radek Krejcida374342015-08-19 13:33:22 +0200393 }
Radek Krejci78ce8612015-08-18 14:31:05 +0200394 }
395
Radek Krejcica7efb72016-01-18 13:06:01 +0100396 /* validation successful */
397 (*result)->validity = LYD_VAL_OK;
398
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100399 return ret;
Radek Krejci3e3affe2015-07-09 15:38:40 +0200400
401error:
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100402 ret--;
403
404clear:
Radek Krejcieab784a2015-08-27 09:56:53 +0200405 /* cleanup */
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100406 lyd_free(*result);
407 *result = NULL;
Radek Krejci1b0d01a2015-08-19 17:00:35 +0200408
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100409 return ret;
Radek Krejci1721c012015-07-08 12:52:33 +0200410}
411
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100412API struct lyd_node *
413lyd_parse_xml(struct ly_ctx *ctx, struct lyxml_elem **root, int options, ...)
Radek Krejcic6704c82015-10-06 11:12:45 +0200414{
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100415 va_list ap;
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100416 int r;
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100417 struct unres_data *unres = NULL;
418 const struct lys_node *rpc = NULL;
419 struct lyd_node *result = NULL, *next, *iter, *last;
420 struct lyxml_elem *xmlstart, *xmlelem, *xmlaux;
Radek Krejcic6704c82015-10-06 11:12:45 +0200421
422 if (!ctx || !root) {
423 LOGERR(LY_EINVAL, "%s: Invalid parameter.", __func__);
424 return NULL;
425 }
426
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100427 if (lyp_check_options(options)) {
428 LOGERR(LY_EINVAL, "%s: Invalid options (multiple data type flags set).", __func__);
429 return NULL;
430 }
431
432 va_start(ap, options);
433 if (options & LYD_OPT_RPCREPLY) {
434 rpc = va_arg(ap, struct lys_node*);
435 if (!rpc || (rpc->nodetype != LYS_RPC)) {
436 LOGERR(LY_EINVAL, "%s: Invalid parameter.", __func__);
437 goto cleanup;
438 }
439 }
440
Radek Krejcic6704c82015-10-06 11:12:45 +0200441 unres = calloc(1, sizeof *unres);
Michal Vasko253035f2015-12-17 16:58:13 +0100442 if (!unres) {
443 LOGMEM;
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100444 goto cleanup;
Michal Vasko253035f2015-12-17 16:58:13 +0100445 }
Radek Krejcic6704c82015-10-06 11:12:45 +0200446
Radek Krejci86538212015-12-17 15:59:01 +0100447 if (!(options & LYD_OPT_NOSIBLINGS)) {
448 /* locate the first root to process */
449 if ((*root)->parent) {
450 xmlstart = (*root)->parent->child;
451 } else {
452 xmlstart = *root;
453 while(xmlstart->prev->next) {
454 xmlstart = xmlstart->prev;
455 }
Radek Krejci04b97de2015-10-31 23:09:15 +0100456 }
Radek Krejci86538212015-12-17 15:59:01 +0100457 } else {
458 xmlstart = *root;
459 }
460 iter = result = last = NULL;
461
462 LY_TREE_FOR_SAFE(xmlstart, xmlaux, xmlelem) {
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100463 r = xml_parse_data(ctx, xmlelem, rpc, NULL, last, options, unres, &iter);
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100464 if (r) {
465 LY_TREE_FOR_SAFE(result, next, iter) {
466 lyd_free(iter);
467 }
468 result = NULL;
469 goto cleanup;
Radek Krejci86538212015-12-17 15:59:01 +0100470 } else if (options & LYD_OPT_DESTRUCT) {
471 lyxml_free(ctx, xmlelem);
472 *root = xmlaux;
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100473 }
474 if (iter) {
475 last = iter;
476 }
477 if (!result) {
478 result = iter;
479 }
Radek Krejci86538212015-12-17 15:59:01 +0100480
481 if (options & LYD_OPT_NOSIBLINGS) {
482 /* stop after the first processed root */
483 break;
484 }
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100485 }
Radek Krejcic6704c82015-10-06 11:12:45 +0200486
Michal Vaskoc1cf86f2015-11-04 09:54:51 +0100487 if (!result) {
488 LOGERR(LY_EVALID, "Model for the data to be linked with not found.");
489 goto cleanup;
490 }
491
Radek Krejcic6704c82015-10-06 11:12:45 +0200492 /* check leafrefs and/or instids if any */
493 if (result && resolve_unres_data(unres)) {
494 /* leafref & instid checking failed */
495 LY_TREE_FOR_SAFE(result, next, iter) {
496 lyd_free(iter);
497 }
498 result = NULL;
499 }
500
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100501cleanup:
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100502 if (unres) {
503 free(unres->node);
504 free(unres->type);
Radek Krejcic6704c82015-10-06 11:12:45 +0200505#ifndef NDEBUG
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100506 free(unres->line);
Radek Krejcic6704c82015-10-06 11:12:45 +0200507#endif
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100508 free(unres);
509 }
510 va_end(ap);
Radek Krejcic6704c82015-10-06 11:12:45 +0200511
512 return result;
513}