blob: 1d2a0f208f3406bef31c44b6cd8986633ca6b22e [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 Krejci1721c012015-07-08 12:52:33 +0200292
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100293 if (lyv_data_context(*result, options, LOGLINE(xml), unres)) {
Michal Vaskocf024702015-10-08 15:01:42 +0200294 goto error;
295 }
296
Radek Krejcib9930252015-07-08 15:47:45 +0200297 /* type specific processing */
Radek Krejci27aaa732015-09-04 15:24:04 +0200298 if (schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
Radek Krejcie4748472015-07-08 18:00:22 +0200299 /* type detection and assigning the value */
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100300 if (xml_get_value(*result, xml, options, unres)) {
Radek Krejci3e3affe2015-07-09 15:38:40 +0200301 goto error;
302 }
Radek Krejci1b0d01a2015-08-19 17:00:35 +0200303 } else if (schema->nodetype == LYS_ANYXML && !(options & LYD_OPT_FILTER)) {
Michal Vasko17cc7062015-12-10 14:31:48 +0100304 /* HACK unlink xml children and link them to a separate copy of xml */
305 tmp_xml = calloc(1, sizeof *tmp_xml);
Michal Vasko253035f2015-12-17 16:58:13 +0100306 if (!tmp_xml) {
307 LOGMEM;
308 goto error;
309 }
Michal Vasko17cc7062015-12-10 14:31:48 +0100310 memcpy(tmp_xml, xml, sizeof *tmp_xml);
311 /* keep attributes in the original */
312 tmp_xml->attr = NULL;
313 /* increase reference counters on strings */
314 tmp_xml->name = lydict_insert(ctx, tmp_xml->name, 0);
315 tmp_xml->content = lydict_insert(ctx, tmp_xml->content, 0);
316 xml->child = NULL;
317 /* xml is correct now */
Michal Vasko60beecb2015-09-03 14:24:09 +0200318
Michal Vasko17cc7062015-12-10 14:31:48 +0100319 LY_TREE_FOR(tmp_xml->child, child) {
320 child->parent = tmp_xml;
321 }
322 /* children are correct now */
323
324 tmp_xml->parent = NULL;
325 lyxml_unlink_elem(ctx, tmp_xml, 1);
326 /* tmp_xml is correct now */
327
328 ((struct lyd_node_anyxml *)*result)->value = tmp_xml;
Michal Vasko60beecb2015-09-03 14:24:09 +0200329 /* we can safely continue with xml, it's like it was, only without children */
Radek Krejcib9930252015-07-08 15:47:45 +0200330 }
331
Radek Krejci998a7502015-10-26 15:54:33 +0100332 for (attr = xml->attr; attr; attr = attr->next) {
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100333 if (attr->type != LYXML_ATTR_STD) {
334 continue;
335 } else if (!attr->ns) {
336 LOGWRN("Ignoring \"%s\" attribute in \"%s\" element.", attr->name, xml->name);
337 continue;
338 }
339
340 dattr = malloc(sizeof *dattr);
Michal Vasko253035f2015-12-17 16:58:13 +0100341 if (!dattr) {
342 goto error;
343 }
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100344 dattr->next = NULL;
345 dattr->name = attr->name;
346 dattr->value = attr->value;
347 attr->name = NULL;
348 attr->value = NULL;
349
Michal Vasko1e62a092015-12-01 12:27:20 +0100350 dattr->module = (struct lys_module *)ly_ctx_get_module_by_ns(ctx, attr->ns->value, NULL);
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100351 if (!dattr->module) {
352 LOGWRN("Attribute \"%s\" from unknown schema (\"%s\") - skipping.", attr->name, attr->ns->value);
353 free(dattr);
354 continue;
355 }
356
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100357 if (!(*result)->attr) {
358 (*result)->attr = dattr;
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100359 } else {
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100360 for (dattr_iter = (*result)->attr; dattr_iter->next; dattr_iter = dattr_iter->next);
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100361 dattr_iter->next = dattr;
Radek Krejci998a7502015-10-26 15:54:33 +0100362 }
363 }
Michal Vasko4ff7b072015-08-21 09:05:03 +0200364
Radek Krejci14c00092015-11-01 11:03:24 +0100365 /* process children */
366 if (havechildren && xml->child) {
367 diter = dlast = NULL;
368 LY_TREE_FOR_SAFE(xml->child, next, child) {
369 if (schema->nodetype & (LYS_RPC | LYS_NOTIF)) {
Michal Vasko36ef6932015-12-01 14:30:17 +0100370 r = xml_parse_data(ctx, child, NULL, *result, dlast, 0, unres, &diter);
Radek Krejci14c00092015-11-01 11:03:24 +0100371 } else {
Michal Vasko36ef6932015-12-01 14:30:17 +0100372 r = xml_parse_data(ctx, child, NULL, *result, dlast, options, unres, &diter);
Radek Krejci14c00092015-11-01 11:03:24 +0100373 }
Radek Krejci14c00092015-11-01 11:03:24 +0100374 if (r) {
375 goto error;
Radek Krejci86538212015-12-17 15:59:01 +0100376 } else if (options & LYD_OPT_DESTRUCT) {
377 lyxml_free(ctx, child);
Radek Krejci14c00092015-11-01 11:03:24 +0100378 }
379 if (diter) {
380 dlast = diter;
381 }
382 }
383 }
384
Radek Krejcicf509982015-12-15 09:22:44 +0100385 /* rest of validation checks */
Radek Krejcieab784a2015-08-27 09:56:53 +0200386 ly_errno = 0;
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100387 if (lyv_data_content(*result, options, LOGLINE(xml), unres)) {
Radek Krejcieab784a2015-08-27 09:56:53 +0200388 if (ly_errno) {
Radek Krejcib1c12512015-08-11 11:22:04 +0200389 goto error;
Radek Krejci1b0d01a2015-08-19 17:00:35 +0200390 } else {
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100391 goto clear;
Radek Krejcida374342015-08-19 13:33:22 +0200392 }
Radek Krejci78ce8612015-08-18 14:31:05 +0200393 }
394
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100395 return ret;
Radek Krejci3e3affe2015-07-09 15:38:40 +0200396
397error:
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100398 ret--;
399
400clear:
Radek Krejcieab784a2015-08-27 09:56:53 +0200401 /* cleanup */
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100402 lyd_free(*result);
403 *result = NULL;
Radek Krejci1b0d01a2015-08-19 17:00:35 +0200404
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100405 return ret;
Radek Krejci1721c012015-07-08 12:52:33 +0200406}
407
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100408API struct lyd_node *
409lyd_parse_xml(struct ly_ctx *ctx, struct lyxml_elem **root, int options, ...)
Radek Krejcic6704c82015-10-06 11:12:45 +0200410{
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100411 va_list ap;
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100412 int r;
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100413 struct unres_data *unres = NULL;
414 const struct lys_node *rpc = NULL;
415 struct lyd_node *result = NULL, *next, *iter, *last;
416 struct lyxml_elem *xmlstart, *xmlelem, *xmlaux;
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
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100423 if (lyp_check_options(options)) {
424 LOGERR(LY_EINVAL, "%s: Invalid options (multiple data type flags set).", __func__);
425 return NULL;
426 }
427
428 va_start(ap, options);
429 if (options & LYD_OPT_RPCREPLY) {
430 rpc = va_arg(ap, struct lys_node*);
431 if (!rpc || (rpc->nodetype != LYS_RPC)) {
432 LOGERR(LY_EINVAL, "%s: Invalid parameter.", __func__);
433 goto cleanup;
434 }
435 }
436
Radek Krejcic6704c82015-10-06 11:12:45 +0200437 unres = calloc(1, sizeof *unres);
Michal Vasko253035f2015-12-17 16:58:13 +0100438 if (!unres) {
439 LOGMEM;
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100440 goto cleanup;
Michal Vasko253035f2015-12-17 16:58:13 +0100441 }
Radek Krejcic6704c82015-10-06 11:12:45 +0200442
Radek Krejci86538212015-12-17 15:59:01 +0100443 if (!(options & LYD_OPT_NOSIBLINGS)) {
444 /* locate the first root to process */
445 if ((*root)->parent) {
446 xmlstart = (*root)->parent->child;
447 } else {
448 xmlstart = *root;
449 while(xmlstart->prev->next) {
450 xmlstart = xmlstart->prev;
451 }
Radek Krejci04b97de2015-10-31 23:09:15 +0100452 }
Radek Krejci86538212015-12-17 15:59:01 +0100453 } else {
454 xmlstart = *root;
455 }
456 iter = result = last = NULL;
457
458 LY_TREE_FOR_SAFE(xmlstart, xmlaux, xmlelem) {
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100459 r = xml_parse_data(ctx, xmlelem, rpc, NULL, last, options, unres, &iter);
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100460 if (r) {
461 LY_TREE_FOR_SAFE(result, next, iter) {
462 lyd_free(iter);
463 }
464 result = NULL;
465 goto cleanup;
Radek Krejci86538212015-12-17 15:59:01 +0100466 } else if (options & LYD_OPT_DESTRUCT) {
467 lyxml_free(ctx, xmlelem);
468 *root = xmlaux;
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100469 }
470 if (iter) {
471 last = iter;
472 }
473 if (!result) {
474 result = iter;
475 }
Radek Krejci86538212015-12-17 15:59:01 +0100476
477 if (options & LYD_OPT_NOSIBLINGS) {
478 /* stop after the first processed root */
479 break;
480 }
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100481 }
Radek Krejcic6704c82015-10-06 11:12:45 +0200482
Michal Vaskoc1cf86f2015-11-04 09:54:51 +0100483 if (!result) {
484 LOGERR(LY_EVALID, "Model for the data to be linked with not found.");
485 goto cleanup;
486 }
487
Radek Krejcic6704c82015-10-06 11:12:45 +0200488 /* check leafrefs and/or instids if any */
489 if (result && resolve_unres_data(unres)) {
490 /* leafref & instid checking failed */
491 LY_TREE_FOR_SAFE(result, next, iter) {
492 lyd_free(iter);
493 }
494 result = NULL;
495 }
496
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100497cleanup:
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100498 if (unres) {
499 free(unres->node);
500 free(unres->type);
Radek Krejcic6704c82015-10-06 11:12:45 +0200501#ifndef NDEBUG
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100502 free(unres->line);
Radek Krejcic6704c82015-10-06 11:12:45 +0200503#endif
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100504 free(unres);
505 }
506 va_end(ap);
Radek Krejcic6704c82015-10-06 11:12:45 +0200507
508 return result;
509}