blob: e3fb11697c9265a6107f3bf36a8256b9c4ff98d0 [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
Radek Krejci0b7704f2016-03-18 12:16:14 +010078xml_get_value(struct lyd_node *node, struct lyxml_elem *xml, int options)
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
Radek Krejci0b7704f2016-03-18 12:16:14 +010083 assert(node && (node->schema->nodetype & (LYS_LEAFLIST | LYS_LEAF)) && xml);
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 Krejci92ece002016-04-04 15:45:05 +020091 if (options & (LYD_OPT_EDIT | LYD_OPT_GET | LYD_OPT_GETCONFIG)) {
Michal Vasko8ea2b7f2015-09-29 14:30:53 +020092 resolve = 0;
93 } else {
94 resolve = 1;
95 }
Radek Krejci3e3affe2015-07-09 15:38:40 +020096
Radek Krejci37b756f2016-01-18 10:15:03 +010097 if ((leaf->value_type == LY_TYPE_IDENT) || (leaf->value_type == LY_TYPE_INST)) {
Michal Vaskofb0873c2015-08-21 09:00:07 +020098 /* convert the path from the XML form using XML namespaces into the JSON format
99 * using module names as namespaces
100 */
101 xml->content = leaf->value_str;
Michal Vaskofba15262015-10-21 12:10:28 +0200102 leaf->value_str = transform_xml2json(leaf->schema->module->ctx, xml->content, xml, 1);
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200103 lydict_remove(leaf->schema->module->ctx, xml->content);
Michal Vaskofb0873c2015-08-21 09:00:07 +0200104 xml->content = NULL;
105 if (!leaf->value_str) {
106 return EXIT_FAILURE;
Radek Krejciac8aac62015-07-10 15:36:35 +0200107 }
Michal Vasko8ea2b7f2015-09-29 14:30:53 +0200108 }
Radek Krejciac8aac62015-07-10 15:36:35 +0200109
Radek Krejci0b7704f2016-03-18 12:16:14 +0100110 if (lyp_parse_value(leaf, xml, resolve)) {
Michal Vasko493bea72015-07-16 16:08:12 +0200111 return EXIT_FAILURE;
Radek Krejcie4748472015-07-08 18:00:22 +0200112 }
113
114 return EXIT_SUCCESS;
115}
116
Michal Vasko0d343d12015-08-24 14:57:36 +0200117/* logs directly */
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100118static int
Michal Vasko36ef6932015-12-01 14:30:17 +0100119xml_parse_data(struct ly_ctx *ctx, struct lyxml_elem *xml, const struct lys_node *schema_parent, struct lyd_node *parent,
120 struct lyd_node *prev, int options, struct unres_data *unres, struct lyd_node **result)
Radek Krejci1721c012015-07-08 12:52:33 +0200121{
Radek Krejci2d5525d2016-04-04 15:43:30 +0200122 struct lyd_node *diter, *dlast, *first_sibling;
Radek Krejcieab784a2015-08-27 09:56:53 +0200123 struct lys_node *schema = NULL;
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100124 struct lyd_attr *dattr, *dattr_iter;
Radek Krejcia5241e52015-08-19 15:09:31 +0200125 struct lyxml_attr *attr;
Michal Vaskof748dbc2016-04-05 11:27:47 +0200126 struct lyxml_elem *child, *next;
Radek Krejci9a5daea2016-03-02 16:49:40 +0100127 int i, havechildren, r, flag;
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100128 int ret = 0;
Radek Krejciabb7b582016-04-20 16:15:47 +0200129 const char *str = NULL;
Radek Krejci1721c012015-07-08 12:52:33 +0200130
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100131 assert(xml);
132 assert(result);
133 *result = NULL;
134
Radek Krejci1721c012015-07-08 12:52:33 +0200135 if (!xml->ns || !xml->ns->value) {
Radek Krejci2342cf62016-01-29 16:48:23 +0100136 if (options & LYD_OPT_STRICT) {
Radek Krejci48464ed2016-03-17 15:44:09 +0100137 LOGVAL(LYE_XML_MISS, LY_VLOG_XML, xml, "element's", "namespace");
Radek Krejci2342cf62016-01-29 16:48:23 +0100138 return -1;
139 } else {
140 return 0;
141 }
Radek Krejci1721c012015-07-08 12:52:33 +0200142 }
143
144 /* find schema node */
Michal Vasko36ef6932015-12-01 14:30:17 +0100145 if (schema_parent) {
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100146 schema = xml_data_search_schemanode(xml, schema_parent->child, options);
Michal Vasko36ef6932015-12-01 14:30:17 +0100147 } else if (!parent) {
Radek Krejci1721c012015-07-08 12:52:33 +0200148 /* starting in root */
149 for (i = 0; i < ctx->models.used; i++) {
150 /* match data model based on namespace */
Radek Krejci749190d2016-02-18 16:26:25 +0100151 if (ly_strequal(ctx->models.list[i]->ns, xml->ns->value, 1)) {
Radek Krejci1721c012015-07-08 12:52:33 +0200152 /* get the proper schema node */
153 LY_TREE_FOR(ctx->models.list[i]->data, schema) {
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100154 /* skip nodes in module's data which are not expected here according to options' data type */
155 if (options & LYD_OPT_RPC) {
156 if (schema->nodetype != LYS_RPC) {
157 continue;
158 }
159 } else if (options & LYD_OPT_NOTIF) {
160 if (schema->nodetype != LYS_NOTIF) {
161 continue;
162 }
163 } else if (!(options & LYD_OPT_RPCREPLY)) {
164 /* rest of the data types except RPCREPLY which cannot be here */
165 if (schema->nodetype & (LYS_RPC | LYS_NOTIF)) {
166 continue;
167 }
168 }
Radek Krejci749190d2016-02-18 16:26:25 +0100169 if (ly_strequal(schema->name, xml->name, 1)) {
Radek Krejci1721c012015-07-08 12:52:33 +0200170 break;
171 }
172 }
173 break;
174 }
175 }
176 } else {
177 /* parsing some internal node, we start with parent's schema pointer */
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100178 schema = xml_data_search_schemanode(xml, parent->schema->child, options);
Radek Krejci1721c012015-07-08 12:52:33 +0200179 }
180 if (!schema) {
Radek Krejci25b9fd32015-08-10 15:06:07 +0200181 if ((options & LYD_OPT_STRICT) || ly_ctx_get_module_by_ns(ctx, xml->ns->value, NULL)) {
Radek Krejci48464ed2016-03-17 15:44:09 +0100182 LOGVAL(LYE_INELEM, LY_VLOG_LYD, parent, xml->name);
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100183 return -1;
Radek Krejci25b9fd32015-08-10 15:06:07 +0200184 } else {
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100185 return 0;
Radek Krejci25b9fd32015-08-10 15:06:07 +0200186 }
Radek Krejci1721c012015-07-08 12:52:33 +0200187 }
188
Radek Krejciadb57612016-02-16 13:34:34 +0100189 /* create the element structure */
Radek Krejcib9930252015-07-08 15:47:45 +0200190 switch (schema->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +0200191 case LYS_CONTAINER:
Radek Krejci27aaa732015-09-04 15:24:04 +0200192 case LYS_LIST:
Michal Vasko2f30e572015-10-01 16:00:38 +0200193 case LYS_NOTIF:
194 case LYS_RPC:
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100195 *result = calloc(1, sizeof **result);
Michal Vaskoab8e4402015-07-17 12:54:28 +0200196 havechildren = 1;
Radek Krejcib9930252015-07-08 15:47:45 +0200197 break;
Radek Krejci76512572015-08-04 09:47:08 +0200198 case LYS_LEAF:
Radek Krejci76512572015-08-04 09:47:08 +0200199 case LYS_LEAFLIST:
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100200 *result = calloc(1, sizeof(struct lyd_node_leaf_list));
Radek Krejcie4748472015-07-08 18:00:22 +0200201 havechildren = 0;
202 break;
Radek Krejci76512572015-08-04 09:47:08 +0200203 case LYS_ANYXML:
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100204 *result = calloc(1, sizeof(struct lyd_node_anyxml));
Michal Vaskoab8e4402015-07-17 12:54:28 +0200205 havechildren = 0;
206 break;
Radek Krejcib9930252015-07-08 15:47:45 +0200207 default:
Michal Vasko0c888fd2015-08-11 15:54:08 +0200208 LOGINT;
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100209 return -1;
Radek Krejcib9930252015-07-08 15:47:45 +0200210 }
Michal Vasko253035f2015-12-17 16:58:13 +0100211 if (!(*result)) {
212 LOGMEM;
213 return -1;
214 }
215
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100216 (*result)->parent = parent;
Radek Krejcic41bf8a2015-08-21 10:28:48 +0200217 if (parent && !parent->child) {
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100218 parent->child = *result;
Radek Krejcic41bf8a2015-08-21 10:28:48 +0200219 }
220 if (prev) {
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100221 (*result)->prev = prev;
222 prev->next = *result;
Radek Krejcic41bf8a2015-08-21 10:28:48 +0200223
224 /* fix the "last" pointer */
Radek Krejci93fab982016-02-03 15:58:19 +0100225 if (parent) {
226 diter = parent->child;
227 } else {
228 for (diter = prev; diter->prev != prev; diter = diter->prev);
229 }
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100230 diter->prev = *result;
Radek Krejci2d5525d2016-04-04 15:43:30 +0200231 first_sibling = diter;
Radek Krejcic41bf8a2015-08-21 10:28:48 +0200232 } else {
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100233 (*result)->prev = *result;
Radek Krejci2d5525d2016-04-04 15:43:30 +0200234 first_sibling = *result;
Radek Krejcic41bf8a2015-08-21 10:28:48 +0200235 }
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100236 (*result)->schema = schema;
Radek Krejcica7efb72016-01-18 13:06:01 +0100237 (*result)->validity = LYD_VAL_NOT;
Radek Krejci0b7704f2016-03-18 12:16:14 +0100238 if (resolve_applies_when(*result)) {
239 (*result)->when_status = LYD_WHEN;
240 }
Radek Krejci1721c012015-07-08 12:52:33 +0200241
Radek Krejciadb57612016-02-16 13:34:34 +0100242 /* check insert attribute and its values */
243 if (options & LYD_OPT_EDIT) {
Radek Krejci9bfcbde2016-04-07 16:30:15 +0200244 /* 0x01 - insert attribute present
245 * 0x02 - insert is relative (before or after)
246 * 0x04 - value attribute present
247 * 0x08 - key attribute present
248 * 0x10 - operation not allowing insert attribute
249 */
Radek Krejciadb57612016-02-16 13:34:34 +0100250 i = 0;
251 for (attr = xml->attr; attr; attr = attr->next) {
Radek Krejci9bfcbde2016-04-07 16:30:15 +0200252 if (attr->type != LYXML_ATTR_STD || !attr->ns) {
253 /* not interesting attribute or namespace declaration */
Radek Krejciadb57612016-02-16 13:34:34 +0100254 continue;
255 }
256
Radek Krejci9bfcbde2016-04-07 16:30:15 +0200257 if (!strcmp(attr->name, "operation") && !strcmp(attr->ns->value, LY_NSNC)) {
Radek Krejci72614bf2016-04-08 17:46:07 +0200258 if (i & 0x10) {
259 LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, (*result), "operation attributes", xml->name);
260 return -1;
261 }
262
Radek Krejci9bfcbde2016-04-07 16:30:15 +0200263 if (!strcmp(attr->value, "delete") || !strcmp(attr->value, "remove")) {
264 i |= 0x10;
265 } else if (strcmp(attr->value, "create") &&
266 strcmp(attr->value, "merge") &&
267 strcmp(attr->value, "replace")) {
268 /* unknown operation */
269 LOGVAL(LYE_INVALATTR, LY_VLOG_LYD, (*result), attr->value, attr->name);
270 return -1;
271 }
272 } else if (!strcmp(attr->name, "insert") && !strcmp(attr->ns->value, LY_NSYANG)) {
273 /* 'insert' attribute present */
274 if (!(schema->flags & LYS_USERORDERED)) {
275 /* ... but it is not expected */
276 LOGVAL(LYE_INATTR, LY_VLOG_LYD, (*result), "insert", schema->name);
277 return -1;
278 }
Radek Krejciadb57612016-02-16 13:34:34 +0100279
Radek Krejci9bfcbde2016-04-07 16:30:15 +0200280 if (i & 0x01) {
281 LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, (*result), "insert attributes", xml->name);
282 return -1;
283 }
284 if (!strcmp(attr->value, "first") || !strcmp(attr->value, "last")) {
285 i |= 0x01;
286 } else if (!strcmp(attr->value, "before") || !strcmp(attr->value, "after")) {
287 i |= 0x01 | 0x02;
288 } else {
289 LOGVAL(LYE_INVALATTR, LY_VLOG_LYD, (*result), attr->value, attr->name);
290 return -1;
291 }
292 str = attr->name;
293 } else if (!strcmp(attr->name, "value") && !strcmp(attr->ns->value, LY_NSYANG)) {
294 if (i & 0x04) {
295 LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, (*result), "value attributes", xml->name);
296 return -1;
297 } else if (schema->nodetype & LYS_LIST) {
298 LOGVAL(LYE_INATTR, LY_VLOG_LYD, (*result), attr->name, schema->name);
299 return -1;
300 }
301 i |= 0x04;
302 str = attr->name;
303 } else if (!strcmp(attr->name, "key") && !strcmp(attr->ns->value, LY_NSYANG)) {
304 if (i & 0x08) {
305 LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, (*result), "key attributes", xml->name);
306 return -1;
307 } else if (schema->nodetype & LYS_LEAFLIST) {
308 LOGVAL(LYE_INATTR, LY_VLOG_LYD, (*result), attr->name, schema->name);
309 return -1;
310 }
311 i |= 0x08;
312 str = attr->name;
Radek Krejciadb57612016-02-16 13:34:34 +0100313 }
Radek Krejciadb57612016-02-16 13:34:34 +0100314 }
315
Radek Krejci9bfcbde2016-04-07 16:30:15 +0200316 /* report errors */
Radek Krejcicced9382016-04-13 13:15:03 +0200317 if (i > 0x10 || (i && i < 0x10 &&
318 (!(schema->nodetype & (LYS_LEAFLIST | LYS_LIST)) || !(schema->flags & LYS_USERORDERED)))) {
Radek Krejcid0df6902016-03-10 09:32:00 +0100319 /* attributes in wrong elements */
Radek Krejci48464ed2016-03-17 15:44:09 +0100320 LOGVAL(LYE_INATTR, LY_VLOG_LYD, (*result), str, xml->name);
Radek Krejcid0df6902016-03-10 09:32:00 +0100321 return -1;
Radek Krejci9bfcbde2016-04-07 16:30:15 +0200322 } else if (i == 3) {
323 /* 0x01 | 0x02 - relative position, but value/key is missing */
324 if (schema->nodetype & LYS_LIST) {
325 LOGVAL(LYE_MISSATTR, LY_VLOG_LYD, (*result), "key", xml->name);
326 } else { /* LYS_LEAFLIST */
327 LOGVAL(LYE_MISSATTR, LY_VLOG_LYD, (*result), "value", xml->name);
328 }
Radek Krejciadb57612016-02-16 13:34:34 +0100329 return -1;
Radek Krejci9bfcbde2016-04-07 16:30:15 +0200330 } else if ((i & (0x04 | 0x08)) && !(i & 0x02)) {
331 /* key/value without relative position */
332 LOGVAL(LYE_INATTR, LY_VLOG_LYD, (*result), (i & 0x04) ? "value" : "key", schema->name);
Radek Krejciadb57612016-02-16 13:34:34 +0100333 return -1;
334 }
335 }
336
Radek Krejcib9930252015-07-08 15:47:45 +0200337 /* type specific processing */
Radek Krejci27aaa732015-09-04 15:24:04 +0200338 if (schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
Radek Krejcie4748472015-07-08 18:00:22 +0200339 /* type detection and assigning the value */
Radek Krejci0b7704f2016-03-18 12:16:14 +0100340 if (xml_get_value(*result, xml, options)) {
Radek Krejci3e3affe2015-07-09 15:38:40 +0200341 goto error;
342 }
Radek Krejci92ece002016-04-04 15:45:05 +0200343 } else if (schema->nodetype == LYS_ANYXML) {
Michal Vaskof748dbc2016-04-05 11:27:47 +0200344 /* store children values */
345 if (xml->child) {
346 child = xml->child;
347 /* manually unlink all siblings and correct namespaces */
348 xml->child = NULL;
349 LY_TREE_FOR(child, next) {
350 next->parent = NULL;
351 lyxml_correct_elem_ns(ctx, next, 1, 1);
352 }
353
354 ((struct lyd_node_anyxml *)*result)->xml_struct = 1;
355 ((struct lyd_node_anyxml *)*result)->value.xml = child;
356 } else {
357 ((struct lyd_node_anyxml *)*result)->xml_struct = 0;
358 ((struct lyd_node_anyxml *)*result)->value.str = lydict_insert(ctx, xml->content, 0);
Michal Vasko253035f2015-12-17 16:58:13 +0100359 }
Radek Krejcib9930252015-07-08 15:47:45 +0200360 }
361
Michal Vasko10e586f2016-05-18 13:25:30 +0200362 /* first part of validation checks */
363 if (!(options & LYD_OPT_TRUSTED) && lyv_data_context(*result, options, unres)) {
364 goto error;
365 }
366
Radek Krejci998a7502015-10-26 15:54:33 +0100367 for (attr = xml->attr; attr; attr = attr->next) {
Radek Krejci9a5daea2016-03-02 16:49:40 +0100368 flag = 0;
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100369 if (attr->type != LYXML_ATTR_STD) {
370 continue;
371 } else if (!attr->ns) {
Radek Krejci9a5daea2016-03-02 16:49:40 +0100372 if ((*result)->schema->nodetype != LYS_ANYXML ||
373 !ly_strequal((*result)->schema->name, "filter", 0) ||
374 !ly_strequal((*result)->schema->module->name, "ietf-netconf", 0)) {
Radek Krejci0f721232016-05-03 14:52:29 +0200375 if (options & LYD_OPT_STRICT) {
376 LOGVAL(LYE_INATTR, LY_VLOG_LYD, (*result), attr->name, xml->name);
377 LOGVAL(LYE_SPEC, LY_VLOG_LYD, (*result), "Attribute \"%s\" with no namespace (schema).",
378 attr->name);
379 goto error;
380 } else {
381 LOGWRN("Ignoring \"%s\" attribute in \"%s\" element.", attr->name, xml->name);
382 continue;
383 }
Radek Krejci9a5daea2016-03-02 16:49:40 +0100384 } else {
385 /* exception for filter's attributes */
386 flag = 1;
387 }
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100388 }
389
390 dattr = malloc(sizeof *dattr);
Michal Vasko253035f2015-12-17 16:58:13 +0100391 if (!dattr) {
392 goto error;
393 }
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100394 dattr->next = NULL;
395 dattr->name = attr->name;
Radek Krejci9a5daea2016-03-02 16:49:40 +0100396 if (flag && ly_strequal(attr->name, "select", 0)) {
397 dattr->value = transform_xml2json(ctx, attr->value, xml, 1);
398 if (!dattr->value) {
399 free(dattr);
400 goto error;
401 }
402 lydict_remove(ctx, attr->value);
403 } else {
404 dattr->value = attr->value;
405 }
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100406 attr->name = NULL;
407 attr->value = NULL;
408
Radek Krejci9a5daea2016-03-02 16:49:40 +0100409 if (!attr->ns) {
410 /* filter's attributes, it actually has no namespace, but we need some for internal representation */
411 dattr->module = (*result)->schema->module;
412 } else {
413 dattr->module = (struct lys_module *)ly_ctx_get_module_by_ns(ctx, attr->ns->value, NULL);
414 }
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100415 if (!dattr->module) {
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100416 free(dattr);
Radek Krejci0f721232016-05-03 14:52:29 +0200417 if (options & LYD_OPT_STRICT) {
418 LOGVAL(LYE_INATTR, LY_VLOG_LYD, (*result), attr->name, xml->name);
419 LOGVAL(LYE_SPEC, LY_VLOG_LYD, (*result), "Attribute \"%s\" from unknown schema (\"%s\").",
420 attr->name, attr->ns->value);
421 goto error;
422 } else {
423 LOGWRN("Attribute \"%s\" from unknown schema (\"%s\") - skipping.", attr->name, attr->ns->value);
424 continue;
425 }
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100426 }
427
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100428 if (!(*result)->attr) {
429 (*result)->attr = dattr;
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100430 } else {
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100431 for (dattr_iter = (*result)->attr; dattr_iter->next; dattr_iter = dattr_iter->next);
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100432 dattr_iter->next = dattr;
Radek Krejci998a7502015-10-26 15:54:33 +0100433 }
434 }
Michal Vasko4ff7b072015-08-21 09:05:03 +0200435
Radek Krejci14c00092015-11-01 11:03:24 +0100436 /* process children */
437 if (havechildren && xml->child) {
438 diter = dlast = NULL;
439 LY_TREE_FOR_SAFE(xml->child, next, child) {
440 if (schema->nodetype & (LYS_RPC | LYS_NOTIF)) {
Michal Vasko36ef6932015-12-01 14:30:17 +0100441 r = xml_parse_data(ctx, child, NULL, *result, dlast, 0, unres, &diter);
Radek Krejci14c00092015-11-01 11:03:24 +0100442 } else {
Michal Vasko36ef6932015-12-01 14:30:17 +0100443 r = xml_parse_data(ctx, child, NULL, *result, dlast, options, unres, &diter);
Radek Krejci14c00092015-11-01 11:03:24 +0100444 }
Radek Krejci14c00092015-11-01 11:03:24 +0100445 if (r) {
446 goto error;
Radek Krejci86538212015-12-17 15:59:01 +0100447 } else if (options & LYD_OPT_DESTRUCT) {
448 lyxml_free(ctx, child);
Radek Krejci14c00092015-11-01 11:03:24 +0100449 }
450 if (diter) {
451 dlast = diter;
452 }
453 }
454 }
455
Radek Krejci0c0086a2016-03-24 15:20:28 +0100456 /* if we have empty non-presence container, we can remove it */
457 if (!(options & LYD_OPT_KEEPEMPTYCONT) && schema->nodetype == LYS_CONTAINER && !(*result)->child &&
Radek Krejcid3e73722016-05-23 12:24:55 +0200458 !(*result)->attr && !((struct lys_node_container *)schema)->presence) {
Radek Krejci0c0086a2016-03-24 15:20:28 +0100459 goto clear;
460 }
461
Radek Krejcicf509982015-12-15 09:22:44 +0100462 /* rest of validation checks */
Radek Krejcieab784a2015-08-27 09:56:53 +0200463 ly_errno = 0;
Radek Krejci2d5525d2016-04-04 15:43:30 +0200464 if (!(options & LYD_OPT_TRUSTED) &&
465 (lyv_data_content(*result, options, unres) ||
Radek Krejci76fed2b2016-04-11 14:55:23 +0200466 lyv_multicases(*result, NULL, first_sibling == *result ? NULL : first_sibling, 0, NULL))) {
Radek Krejcieab784a2015-08-27 09:56:53 +0200467 if (ly_errno) {
Radek Krejcib1c12512015-08-11 11:22:04 +0200468 goto error;
Radek Krejci1b0d01a2015-08-19 17:00:35 +0200469 } else {
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100470 goto clear;
Radek Krejcida374342015-08-19 13:33:22 +0200471 }
Radek Krejci78ce8612015-08-18 14:31:05 +0200472 }
473
Radek Krejcica7efb72016-01-18 13:06:01 +0100474 /* validation successful */
475 (*result)->validity = LYD_VAL_OK;
476
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100477 return ret;
Radek Krejci3e3affe2015-07-09 15:38:40 +0200478
479error:
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100480 ret--;
481
482clear:
Radek Krejcieab784a2015-08-27 09:56:53 +0200483 /* cleanup */
Radek Krejci0c0086a2016-03-24 15:20:28 +0100484 for (i = unres->count - 1; i >= 0; i--) {
485 /* remove unres items connected with the node being removed */
486 if (unres->node[i] == *result) {
487 unres_data_del(unres, i);
488 }
489 }
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100490 lyd_free(*result);
491 *result = NULL;
Radek Krejci1b0d01a2015-08-19 17:00:35 +0200492
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100493 return ret;
Radek Krejci1721c012015-07-08 12:52:33 +0200494}
495
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100496API struct lyd_node *
497lyd_parse_xml(struct ly_ctx *ctx, struct lyxml_elem **root, int options, ...)
Radek Krejcic6704c82015-10-06 11:12:45 +0200498{
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100499 va_list ap;
Michal Vasko24d982f2016-04-18 15:13:58 +0200500 int r;
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100501 struct unres_data *unres = NULL;
Michal Vasko0a073da2016-05-10 15:48:40 +0200502 struct lys_node *rpc = NULL;
Michal Vasko24d982f2016-04-18 15:13:58 +0200503 struct lyd_node *result = NULL, *iter, *last;
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100504 struct lyxml_elem *xmlstart, *xmlelem, *xmlaux;
Radek Krejcic6704c82015-10-06 11:12:45 +0200505
Radek Krejci2342cf62016-01-29 16:48:23 +0100506 ly_errno = LY_SUCCESS;
507
Radek Krejcic6704c82015-10-06 11:12:45 +0200508 if (!ctx || !root) {
509 LOGERR(LY_EINVAL, "%s: Invalid parameter.", __func__);
510 return NULL;
511 }
512
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100513 if (lyp_check_options(options)) {
514 LOGERR(LY_EINVAL, "%s: Invalid options (multiple data type flags set).", __func__);
515 return NULL;
516 }
517
Radek Krejcia6939c32016-03-24 15:19:09 +0100518 if (!(*root)) {
519 /* empty tree - no work is needed */
520 lyd_validate(&result, options, ctx);
521 return result;
522 }
523
Michal Vasko24d982f2016-04-18 15:13:58 +0200524 unres = calloc(1, sizeof *unres);
525 if (!unres) {
526 LOGMEM;
527 return NULL;
528 }
529
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100530 va_start(ap, options);
531 if (options & LYD_OPT_RPCREPLY) {
532 rpc = va_arg(ap, struct lys_node*);
533 if (!rpc || (rpc->nodetype != LYS_RPC)) {
534 LOGERR(LY_EINVAL, "%s: Invalid parameter.", __func__);
Michal Vasko24d982f2016-04-18 15:13:58 +0200535 goto error;
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100536 }
537 }
538
Radek Krejci86538212015-12-17 15:59:01 +0100539 if (!(options & LYD_OPT_NOSIBLINGS)) {
540 /* locate the first root to process */
541 if ((*root)->parent) {
542 xmlstart = (*root)->parent->child;
543 } else {
544 xmlstart = *root;
545 while(xmlstart->prev->next) {
546 xmlstart = xmlstart->prev;
547 }
Radek Krejci04b97de2015-10-31 23:09:15 +0100548 }
Radek Krejci86538212015-12-17 15:59:01 +0100549 } else {
550 xmlstart = *root;
551 }
552 iter = result = last = NULL;
553
554 LY_TREE_FOR_SAFE(xmlstart, xmlaux, xmlelem) {
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100555 r = xml_parse_data(ctx, xmlelem, rpc, NULL, last, options, unres, &iter);
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100556 if (r) {
Michal Vasko24d982f2016-04-18 15:13:58 +0200557 goto error;
Radek Krejci86538212015-12-17 15:59:01 +0100558 } else if (options & LYD_OPT_DESTRUCT) {
559 lyxml_free(ctx, xmlelem);
560 *root = xmlaux;
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100561 }
562 if (iter) {
563 last = iter;
564 }
565 if (!result) {
566 result = iter;
567 }
Radek Krejci86538212015-12-17 15:59:01 +0100568
569 if (options & LYD_OPT_NOSIBLINGS) {
570 /* stop after the first processed root */
571 break;
572 }
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100573 }
Radek Krejcic6704c82015-10-06 11:12:45 +0200574
Michal Vaskob8029b52016-05-11 16:26:16 +0200575 if (options & LYD_OPT_RPCREPLY) {
Michal Vasko79450fb2016-05-23 11:26:55 +0200576 last = result;
Michal Vaskob8029b52016-05-11 16:26:16 +0200577 result = lyd_new_output(NULL, lys_node_module(rpc), rpc->name);
Michal Vasko79450fb2016-05-23 11:26:55 +0200578 /* insert all the output parameters into RPC */
579 do {
580 iter = last;
581 last = iter->next;
582 if (lyd_insert(result, iter)) {
583 LOGINT;
584 lyd_free_withsiblings(last);
585 goto error;
586 }
587 } while (last);
Michal Vaskob8029b52016-05-11 16:26:16 +0200588 }
589
Michal Vasko24d982f2016-04-18 15:13:58 +0200590 /* check for missing top level mandatory nodes */
Michal Vasko98a5a742016-05-11 11:02:56 +0200591 if (lyd_check_topmandatory(result, ctx, options)) {
Michal Vasko24d982f2016-04-18 15:13:58 +0200592 goto error;
Radek Krejci5c162452016-03-23 13:36:01 +0100593 }
594
Michal Vasko24d982f2016-04-18 15:13:58 +0200595 /* add/validate default values, unres */
Michal Vaskocd5dbe12016-05-12 10:56:38 +0200596 if (lyd_defaults_add_unres(&result, options, ctx, unres)) {
Michal Vasko24d982f2016-04-18 15:13:58 +0200597 goto error;
Radek Krejci5c162452016-03-23 13:36:01 +0100598 }
599
Michal Vasko24d982f2016-04-18 15:13:58 +0200600 free(unres->node);
601 free(unres->type);
602 free(unres);
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100603 va_end(ap);
Radek Krejcic6704c82015-10-06 11:12:45 +0200604
605 return result;
Michal Vasko24d982f2016-04-18 15:13:58 +0200606
607error:
608 lyd_free_withsiblings(result);
609 free(unres->node);
610 free(unres->type);
611 free(unres);
612 va_end(ap);
613
614 return NULL;
Radek Krejcic6704c82015-10-06 11:12:45 +0200615}