blob: f8c5683f616acbd6a887a6c124e20ce3c4be5c3a [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
Radek Krejcibd930122016-08-10 13:28:26 +0200119xml_parse_data(struct ly_ctx *ctx, struct lyxml_elem *xml, struct lyd_node *parent, struct lyd_node *first_sibling,
120 struct lyd_node *prev, int options, struct unres_data *unres, struct lyd_node **result,
121 struct lyd_node **action)
Radek Krejci1721c012015-07-08 12:52:33 +0200122{
Radek Krejcibd930122016-08-10 13:28:26 +0200123 struct lyd_node *diter, *dlast;
Michal Vasko5e523b62016-08-26 16:23:15 +0200124 struct lys_node *schema = NULL, *target;
125 struct lys_node_augment *aug;
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100126 struct lyd_attr *dattr, *dattr_iter;
Radek Krejcia5241e52015-08-19 15:09:31 +0200127 struct lyxml_attr *attr;
Michal Vaskof748dbc2016-04-05 11:27:47 +0200128 struct lyxml_elem *child, *next;
Michal Vasko5e523b62016-08-26 16:23:15 +0200129 int i, j, havechildren, r, flag;
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100130 int ret = 0;
Radek Krejciabb7b582016-04-20 16:15:47 +0200131 const char *str = NULL;
Radek Krejci1721c012015-07-08 12:52:33 +0200132
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100133 assert(xml);
134 assert(result);
135 *result = NULL;
136
Radek Krejci1721c012015-07-08 12:52:33 +0200137 if (!xml->ns || !xml->ns->value) {
Radek Krejci2342cf62016-01-29 16:48:23 +0100138 if (options & LYD_OPT_STRICT) {
Radek Krejci48464ed2016-03-17 15:44:09 +0100139 LOGVAL(LYE_XML_MISS, LY_VLOG_XML, xml, "element's", "namespace");
Radek Krejci2342cf62016-01-29 16:48:23 +0100140 return -1;
141 } else {
142 return 0;
143 }
Radek Krejci1721c012015-07-08 12:52:33 +0200144 }
145
146 /* find schema node */
Michal Vaskob1b19442016-07-13 12:26:01 +0200147 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 */
Radek Krejci919a9242016-07-27 08:17:13 +0200153 schema = xml_data_search_schemanode(xml, ctx->models.list[i]->data, options);
Michal Vasko5e523b62016-08-26 16:23:15 +0200154 if (!schema) {
155 /* it still can be the specific case of this module containing an augment of another module
156 * top-level choice or top-level choice's case, bleh */
157 for (j = 0; j < ctx->models.list[i]->augment_size; ++j) {
158 aug = &ctx->models.list[i]->augment[j];
159 target = aug->target;
160 if (target->nodetype & (LYS_CHOICE | LYS_CASE)) {
161 /* 1) okay, the target is choice or case */
162 while (target && (target->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES))) {
163 target = lys_parent(target);
164 }
165 /* 2) now, the data node will be top-level, there are only non-data schema nodes */
166 if (!target) {
167 while ((schema = (struct lys_node *)lys_getnext(schema, (struct lys_node *)aug, NULL, 0))) {
168 /* 3) alright, even the name matches, we found our schema node */
169 if (ly_strequal(schema->name, xml->name, 1)) {
170 break;
171 }
172 }
173 }
174 }
175
176 if (schema) {
177 break;
178 }
179 }
180 }
Radek Krejci1721c012015-07-08 12:52:33 +0200181 break;
182 }
183 }
184 } else {
185 /* parsing some internal node, we start with parent's schema pointer */
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100186 schema = xml_data_search_schemanode(xml, parent->schema->child, options);
Radek Krejci1721c012015-07-08 12:52:33 +0200187 }
188 if (!schema) {
Radek Krejci25b9fd32015-08-10 15:06:07 +0200189 if ((options & LYD_OPT_STRICT) || ly_ctx_get_module_by_ns(ctx, xml->ns->value, NULL)) {
Radek Krejci48464ed2016-03-17 15:44:09 +0100190 LOGVAL(LYE_INELEM, LY_VLOG_LYD, parent, xml->name);
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100191 return -1;
Radek Krejci25b9fd32015-08-10 15:06:07 +0200192 } else {
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100193 return 0;
Radek Krejci25b9fd32015-08-10 15:06:07 +0200194 }
Radek Krejci1721c012015-07-08 12:52:33 +0200195 }
196
Radek Krejciadb57612016-02-16 13:34:34 +0100197 /* create the element structure */
Radek Krejcib9930252015-07-08 15:47:45 +0200198 switch (schema->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +0200199 case LYS_CONTAINER:
Radek Krejci27aaa732015-09-04 15:24:04 +0200200 case LYS_LIST:
Michal Vasko2f30e572015-10-01 16:00:38 +0200201 case LYS_NOTIF:
202 case LYS_RPC:
Michal Vaskob1b19442016-07-13 12:26:01 +0200203 case LYS_ACTION:
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100204 *result = calloc(1, sizeof **result);
Michal Vaskoab8e4402015-07-17 12:54:28 +0200205 havechildren = 1;
Radek Krejcib9930252015-07-08 15:47:45 +0200206 break;
Radek Krejci76512572015-08-04 09:47:08 +0200207 case LYS_LEAF:
Radek Krejci76512572015-08-04 09:47:08 +0200208 case LYS_LEAFLIST:
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100209 *result = calloc(1, sizeof(struct lyd_node_leaf_list));
Radek Krejcie4748472015-07-08 18:00:22 +0200210 havechildren = 0;
211 break;
Radek Krejci76512572015-08-04 09:47:08 +0200212 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +0200213 case LYS_ANYDATA:
214 *result = calloc(1, sizeof(struct lyd_node_anydata));
Michal Vaskoab8e4402015-07-17 12:54:28 +0200215 havechildren = 0;
216 break;
Radek Krejcib9930252015-07-08 15:47:45 +0200217 default:
Michal Vasko0c888fd2015-08-11 15:54:08 +0200218 LOGINT;
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100219 return -1;
Radek Krejcib9930252015-07-08 15:47:45 +0200220 }
Michal Vasko253035f2015-12-17 16:58:13 +0100221 if (!(*result)) {
222 LOGMEM;
223 return -1;
224 }
225
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100226 (*result)->parent = parent;
Radek Krejcic41bf8a2015-08-21 10:28:48 +0200227 if (parent && !parent->child) {
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100228 parent->child = *result;
Radek Krejcic41bf8a2015-08-21 10:28:48 +0200229 }
230 if (prev) {
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100231 (*result)->prev = prev;
232 prev->next = *result;
Radek Krejcic41bf8a2015-08-21 10:28:48 +0200233
234 /* fix the "last" pointer */
Radek Krejcibd930122016-08-10 13:28:26 +0200235 first_sibling->prev = *result;
Radek Krejcic41bf8a2015-08-21 10:28:48 +0200236 } else {
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100237 (*result)->prev = *result;
Radek Krejci2d5525d2016-04-04 15:43:30 +0200238 first_sibling = *result;
Radek Krejcic41bf8a2015-08-21 10:28:48 +0200239 }
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100240 (*result)->schema = schema;
Radek Krejcica7efb72016-01-18 13:06:01 +0100241 (*result)->validity = LYD_VAL_NOT;
Radek Krejci46165822016-08-26 14:06:27 +0200242 if (resolve_applies_when(schema, 0, NULL)) {
Radek Krejci0b7704f2016-03-18 12:16:14 +0100243 (*result)->when_status = LYD_WHEN;
244 }
Radek Krejci1721c012015-07-08 12:52:33 +0200245
Radek Krejciadb57612016-02-16 13:34:34 +0100246 /* check insert attribute and its values */
247 if (options & LYD_OPT_EDIT) {
Radek Krejci9bfcbde2016-04-07 16:30:15 +0200248 /* 0x01 - insert attribute present
249 * 0x02 - insert is relative (before or after)
250 * 0x04 - value attribute present
251 * 0x08 - key attribute present
252 * 0x10 - operation not allowing insert attribute
253 */
Radek Krejciadb57612016-02-16 13:34:34 +0100254 i = 0;
255 for (attr = xml->attr; attr; attr = attr->next) {
Radek Krejci9bfcbde2016-04-07 16:30:15 +0200256 if (attr->type != LYXML_ATTR_STD || !attr->ns) {
257 /* not interesting attribute or namespace declaration */
Radek Krejciadb57612016-02-16 13:34:34 +0100258 continue;
259 }
260
Radek Krejci9bfcbde2016-04-07 16:30:15 +0200261 if (!strcmp(attr->name, "operation") && !strcmp(attr->ns->value, LY_NSNC)) {
Radek Krejci72614bf2016-04-08 17:46:07 +0200262 if (i & 0x10) {
263 LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, (*result), "operation attributes", xml->name);
264 return -1;
265 }
266
Radek Krejci9bfcbde2016-04-07 16:30:15 +0200267 if (!strcmp(attr->value, "delete") || !strcmp(attr->value, "remove")) {
268 i |= 0x10;
269 } else if (strcmp(attr->value, "create") &&
270 strcmp(attr->value, "merge") &&
271 strcmp(attr->value, "replace")) {
272 /* unknown operation */
273 LOGVAL(LYE_INVALATTR, LY_VLOG_LYD, (*result), attr->value, attr->name);
274 return -1;
275 }
276 } else if (!strcmp(attr->name, "insert") && !strcmp(attr->ns->value, LY_NSYANG)) {
277 /* 'insert' attribute present */
278 if (!(schema->flags & LYS_USERORDERED)) {
279 /* ... but it is not expected */
280 LOGVAL(LYE_INATTR, LY_VLOG_LYD, (*result), "insert", schema->name);
281 return -1;
282 }
Radek Krejciadb57612016-02-16 13:34:34 +0100283
Radek Krejci9bfcbde2016-04-07 16:30:15 +0200284 if (i & 0x01) {
285 LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, (*result), "insert attributes", xml->name);
286 return -1;
287 }
288 if (!strcmp(attr->value, "first") || !strcmp(attr->value, "last")) {
289 i |= 0x01;
290 } else if (!strcmp(attr->value, "before") || !strcmp(attr->value, "after")) {
291 i |= 0x01 | 0x02;
292 } else {
293 LOGVAL(LYE_INVALATTR, LY_VLOG_LYD, (*result), attr->value, attr->name);
294 return -1;
295 }
296 str = attr->name;
297 } else if (!strcmp(attr->name, "value") && !strcmp(attr->ns->value, LY_NSYANG)) {
298 if (i & 0x04) {
299 LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, (*result), "value attributes", xml->name);
300 return -1;
301 } else if (schema->nodetype & LYS_LIST) {
302 LOGVAL(LYE_INATTR, LY_VLOG_LYD, (*result), attr->name, schema->name);
303 return -1;
304 }
305 i |= 0x04;
306 str = attr->name;
307 } else if (!strcmp(attr->name, "key") && !strcmp(attr->ns->value, LY_NSYANG)) {
308 if (i & 0x08) {
309 LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, (*result), "key attributes", xml->name);
310 return -1;
311 } else if (schema->nodetype & LYS_LEAFLIST) {
312 LOGVAL(LYE_INATTR, LY_VLOG_LYD, (*result), attr->name, schema->name);
313 return -1;
314 }
315 i |= 0x08;
316 str = attr->name;
Radek Krejciadb57612016-02-16 13:34:34 +0100317 }
Radek Krejciadb57612016-02-16 13:34:34 +0100318 }
319
Radek Krejci9bfcbde2016-04-07 16:30:15 +0200320 /* report errors */
Radek Krejcicced9382016-04-13 13:15:03 +0200321 if (i > 0x10 || (i && i < 0x10 &&
322 (!(schema->nodetype & (LYS_LEAFLIST | LYS_LIST)) || !(schema->flags & LYS_USERORDERED)))) {
Radek Krejcid0df6902016-03-10 09:32:00 +0100323 /* attributes in wrong elements */
Radek Krejci48464ed2016-03-17 15:44:09 +0100324 LOGVAL(LYE_INATTR, LY_VLOG_LYD, (*result), str, xml->name);
Radek Krejcid0df6902016-03-10 09:32:00 +0100325 return -1;
Radek Krejci9bfcbde2016-04-07 16:30:15 +0200326 } else if (i == 3) {
327 /* 0x01 | 0x02 - relative position, but value/key is missing */
328 if (schema->nodetype & LYS_LIST) {
329 LOGVAL(LYE_MISSATTR, LY_VLOG_LYD, (*result), "key", xml->name);
330 } else { /* LYS_LEAFLIST */
331 LOGVAL(LYE_MISSATTR, LY_VLOG_LYD, (*result), "value", xml->name);
332 }
Radek Krejciadb57612016-02-16 13:34:34 +0100333 return -1;
Radek Krejci9bfcbde2016-04-07 16:30:15 +0200334 } else if ((i & (0x04 | 0x08)) && !(i & 0x02)) {
335 /* key/value without relative position */
336 LOGVAL(LYE_INATTR, LY_VLOG_LYD, (*result), (i & 0x04) ? "value" : "key", schema->name);
Radek Krejciadb57612016-02-16 13:34:34 +0100337 return -1;
338 }
339 }
340
Radek Krejcib9930252015-07-08 15:47:45 +0200341 /* type specific processing */
Radek Krejci27aaa732015-09-04 15:24:04 +0200342 if (schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
Radek Krejcie4748472015-07-08 18:00:22 +0200343 /* type detection and assigning the value */
Radek Krejci0b7704f2016-03-18 12:16:14 +0100344 if (xml_get_value(*result, xml, options)) {
Radek Krejci3e3affe2015-07-09 15:38:40 +0200345 goto error;
346 }
Radek Krejcibf2abff2016-08-23 15:51:52 +0200347 } else if (schema->nodetype & LYS_ANYDATA) {
Michal Vaskof748dbc2016-04-05 11:27:47 +0200348 /* store children values */
349 if (xml->child) {
350 child = xml->child;
351 /* manually unlink all siblings and correct namespaces */
352 xml->child = NULL;
353 LY_TREE_FOR(child, next) {
354 next->parent = NULL;
355 lyxml_correct_elem_ns(ctx, next, 1, 1);
356 }
357
Radek Krejci45826012016-08-24 15:07:57 +0200358 ((struct lyd_node_anydata *)*result)->value_type = LYD_ANYDATA_XML;
Radek Krejcibf2abff2016-08-23 15:51:52 +0200359 ((struct lyd_node_anydata *)*result)->value.xml = child;
Michal Vaskof748dbc2016-04-05 11:27:47 +0200360 } else {
Radek Krejci45826012016-08-24 15:07:57 +0200361 ((struct lyd_node_anydata *)*result)->value_type = LYD_ANYDATA_CONSTSTRING;
Radek Krejcibf2abff2016-08-23 15:51:52 +0200362 ((struct lyd_node_anydata *)*result)->value.str = lydict_insert(ctx, xml->content, 0);
Michal Vasko253035f2015-12-17 16:58:13 +0100363 }
Michal Vaskob1b19442016-07-13 12:26:01 +0200364 } else if (schema->nodetype == LYS_ACTION) {
365 options &= ~LYS_ACTION;
366 options |= LYS_RPC;
Radek Krejcib9930252015-07-08 15:47:45 +0200367 }
368
Michal Vasko10e586f2016-05-18 13:25:30 +0200369 /* first part of validation checks */
370 if (!(options & LYD_OPT_TRUSTED) && lyv_data_context(*result, options, unres)) {
371 goto error;
372 }
373
Radek Krejci998a7502015-10-26 15:54:33 +0100374 for (attr = xml->attr; attr; attr = attr->next) {
Radek Krejci9a5daea2016-03-02 16:49:40 +0100375 flag = 0;
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100376 if (attr->type != LYXML_ATTR_STD) {
377 continue;
378 } else if (!attr->ns) {
Radek Krejci9a5daea2016-03-02 16:49:40 +0100379 if ((*result)->schema->nodetype != LYS_ANYXML ||
380 !ly_strequal((*result)->schema->name, "filter", 0) ||
381 !ly_strequal((*result)->schema->module->name, "ietf-netconf", 0)) {
Radek Krejci0f721232016-05-03 14:52:29 +0200382 if (options & LYD_OPT_STRICT) {
383 LOGVAL(LYE_INATTR, LY_VLOG_LYD, (*result), attr->name, xml->name);
384 LOGVAL(LYE_SPEC, LY_VLOG_LYD, (*result), "Attribute \"%s\" with no namespace (schema).",
385 attr->name);
386 goto error;
387 } else {
388 LOGWRN("Ignoring \"%s\" attribute in \"%s\" element.", attr->name, xml->name);
389 continue;
390 }
Radek Krejci9a5daea2016-03-02 16:49:40 +0100391 } else {
392 /* exception for filter's attributes */
393 flag = 1;
394 }
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100395 }
396
397 dattr = malloc(sizeof *dattr);
Michal Vasko253035f2015-12-17 16:58:13 +0100398 if (!dattr) {
399 goto error;
400 }
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100401 dattr->next = NULL;
402 dattr->name = attr->name;
Radek Krejci9a5daea2016-03-02 16:49:40 +0100403 if (flag && ly_strequal(attr->name, "select", 0)) {
404 dattr->value = transform_xml2json(ctx, attr->value, xml, 1);
405 if (!dattr->value) {
406 free(dattr);
407 goto error;
408 }
409 lydict_remove(ctx, attr->value);
410 } else {
411 dattr->value = attr->value;
412 }
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100413 attr->name = NULL;
414 attr->value = NULL;
415
Radek Krejci9a5daea2016-03-02 16:49:40 +0100416 if (!attr->ns) {
417 /* filter's attributes, it actually has no namespace, but we need some for internal representation */
418 dattr->module = (*result)->schema->module;
419 } else {
420 dattr->module = (struct lys_module *)ly_ctx_get_module_by_ns(ctx, attr->ns->value, NULL);
421 }
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100422 if (!dattr->module) {
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100423 free(dattr);
Radek Krejci0f721232016-05-03 14:52:29 +0200424 if (options & LYD_OPT_STRICT) {
425 LOGVAL(LYE_INATTR, LY_VLOG_LYD, (*result), attr->name, xml->name);
426 LOGVAL(LYE_SPEC, LY_VLOG_LYD, (*result), "Attribute \"%s\" from unknown schema (\"%s\").",
427 attr->name, attr->ns->value);
428 goto error;
429 } else {
430 LOGWRN("Attribute \"%s\" from unknown schema (\"%s\") - skipping.", attr->name, attr->ns->value);
431 continue;
432 }
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100433 }
434
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100435 if (!(*result)->attr) {
436 (*result)->attr = dattr;
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100437 } else {
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100438 for (dattr_iter = (*result)->attr; dattr_iter->next; dattr_iter = dattr_iter->next);
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100439 dattr_iter->next = dattr;
Radek Krejci998a7502015-10-26 15:54:33 +0100440 }
441 }
Michal Vasko4ff7b072015-08-21 09:05:03 +0200442
Michal Vaskob1b19442016-07-13 12:26:01 +0200443 if ((*result)->schema->nodetype == LYS_ACTION) {
444 if (!(options & LYD_OPT_ACTION) || *action) {
Radek Krejcib45b3082016-09-09 16:08:51 +0200445 LOGVAL(LYE_INACT, LY_VLOG_LYD, (*result), "action", (*result)->schema->name);
Michal Vaskob1b19442016-07-13 12:26:01 +0200446 LOGVAL(LYE_SPEC, LY_VLOG_LYD, (*result), "Unexpected action node \"%s\".", (*result)->schema->name);
447 goto error;
448 }
449 *action = *result;
450 }
451
Radek Krejci14c00092015-11-01 11:03:24 +0100452 /* process children */
453 if (havechildren && xml->child) {
454 diter = dlast = NULL;
455 LY_TREE_FOR_SAFE(xml->child, next, child) {
456 if (schema->nodetype & (LYS_RPC | LYS_NOTIF)) {
Radek Krejcibd930122016-08-10 13:28:26 +0200457 r = xml_parse_data(ctx, child, *result, (*result)->child, dlast, 0, unres, &diter, action);
Radek Krejci14c00092015-11-01 11:03:24 +0100458 } else {
Radek Krejcibd930122016-08-10 13:28:26 +0200459 r = xml_parse_data(ctx, child, *result, (*result)->child, dlast, options, unres, &diter, action);
Radek Krejci14c00092015-11-01 11:03:24 +0100460 }
Radek Krejci14c00092015-11-01 11:03:24 +0100461 if (r) {
462 goto error;
Radek Krejci86538212015-12-17 15:59:01 +0100463 } else if (options & LYD_OPT_DESTRUCT) {
464 lyxml_free(ctx, child);
Radek Krejci14c00092015-11-01 11:03:24 +0100465 }
466 if (diter) {
467 dlast = diter;
468 }
469 }
470 }
471
Radek Krejci0c0086a2016-03-24 15:20:28 +0100472 /* if we have empty non-presence container, we can remove it */
Radek Krejci2537fd32016-09-07 16:22:41 +0200473 if (schema->nodetype == LYS_CONTAINER && !(*result)->child &&
Radek Krejcid3e73722016-05-23 12:24:55 +0200474 !(*result)->attr && !((struct lys_node_container *)schema)->presence) {
Radek Krejci0c0086a2016-03-24 15:20:28 +0100475 goto clear;
476 }
477
Radek Krejcicf509982015-12-15 09:22:44 +0100478 /* rest of validation checks */
Radek Krejcieab784a2015-08-27 09:56:53 +0200479 ly_errno = 0;
Radek Krejci2d5525d2016-04-04 15:43:30 +0200480 if (!(options & LYD_OPT_TRUSTED) &&
481 (lyv_data_content(*result, options, unres) ||
Radek Krejcia1c33bf2016-09-07 12:38:49 +0200482 lyv_multicases(*result, NULL, first_sibling == *result ? NULL : &first_sibling, 0, NULL))) {
Radek Krejcieab784a2015-08-27 09:56:53 +0200483 if (ly_errno) {
Radek Krejcib1c12512015-08-11 11:22:04 +0200484 goto error;
Radek Krejci1b0d01a2015-08-19 17:00:35 +0200485 } else {
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100486 goto clear;
Radek Krejcida374342015-08-19 13:33:22 +0200487 }
Radek Krejci78ce8612015-08-18 14:31:05 +0200488 }
489
Radek Krejcica7efb72016-01-18 13:06:01 +0100490 /* validation successful */
Radek Krejci63b79c82016-08-10 10:09:33 +0200491 if ((*result)->schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
492 /* postpone checking when there will be all list/leaflist instances */
493 (*result)->validity = LYD_VAL_UNIQUE;
494 } else {
495 (*result)->validity = LYD_VAL_OK;
496 }
Radek Krejcica7efb72016-01-18 13:06:01 +0100497
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100498 return ret;
Radek Krejci3e3affe2015-07-09 15:38:40 +0200499
500error:
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100501 ret--;
502
503clear:
Radek Krejcieab784a2015-08-27 09:56:53 +0200504 /* cleanup */
Radek Krejci0c0086a2016-03-24 15:20:28 +0100505 for (i = unres->count - 1; i >= 0; i--) {
506 /* remove unres items connected with the node being removed */
507 if (unres->node[i] == *result) {
508 unres_data_del(unres, i);
509 }
510 }
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100511 lyd_free(*result);
512 *result = NULL;
Radek Krejci1b0d01a2015-08-19 17:00:35 +0200513
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100514 return ret;
Radek Krejci1721c012015-07-08 12:52:33 +0200515}
516
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100517API struct lyd_node *
518lyd_parse_xml(struct ly_ctx *ctx, struct lyxml_elem **root, int options, ...)
Radek Krejcic6704c82015-10-06 11:12:45 +0200519{
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100520 va_list ap;
Radek Krejci63b79c82016-08-10 10:09:33 +0200521 int r, i;
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100522 struct unres_data *unres = NULL;
Michal Vasko6b44d712016-09-12 16:25:46 +0200523 const struct lys_node *rpc_act = NULL;
524 struct lyd_node *result = NULL, *iter, *last, *reply_parent = NULL, *action = NULL, *data_tree = NULL;
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100525 struct lyxml_elem *xmlstart, *xmlelem, *xmlaux;
Radek Krejci63b79c82016-08-10 10:09:33 +0200526 struct ly_set *set;
Radek Krejcic6704c82015-10-06 11:12:45 +0200527
Radek Krejci2342cf62016-01-29 16:48:23 +0100528 ly_errno = LY_SUCCESS;
529
Radek Krejcic6704c82015-10-06 11:12:45 +0200530 if (!ctx || !root) {
531 LOGERR(LY_EINVAL, "%s: Invalid parameter.", __func__);
532 return NULL;
533 }
534
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100535 if (lyp_check_options(options)) {
536 LOGERR(LY_EINVAL, "%s: Invalid options (multiple data type flags set).", __func__);
537 return NULL;
538 }
539
Radek Krejcia6939c32016-03-24 15:19:09 +0100540 if (!(*root)) {
541 /* empty tree - no work is needed */
542 lyd_validate(&result, options, ctx);
543 return result;
544 }
545
Michal Vasko24d982f2016-04-18 15:13:58 +0200546 unres = calloc(1, sizeof *unres);
547 if (!unres) {
548 LOGMEM;
549 return NULL;
550 }
551
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100552 va_start(ap, options);
553 if (options & LYD_OPT_RPCREPLY) {
Michal Vasko6b44d712016-09-12 16:25:46 +0200554 rpc_act = va_arg(ap, const struct lys_node *);
Michal Vaskob1b19442016-07-13 12:26:01 +0200555 if (!rpc_act || !(rpc_act->nodetype & (LYS_RPC | LYS_ACTION))) {
Michal Vasko6b44d712016-09-12 16:25:46 +0200556 LOGERR(LY_EINVAL, "%s: invalid variable parameter (const struct lys_node *rpc_act).", __func__);
Michal Vasko24d982f2016-04-18 15:13:58 +0200557 goto error;
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100558 }
Radek Krejci47fd5cb2016-09-01 16:50:22 +0200559 reply_parent = _lyd_new(NULL, rpc_act, 0);
Michal Vasko6b44d712016-09-12 16:25:46 +0200560
561 data_tree = va_arg(ap, struct lyd_node *);
562 if (data_tree) {
563 LY_TREE_FOR(data_tree, iter) {
564 if (iter->parent) {
565 /* a sibling is not top-level */
566 LOGERR(LY_EINVAL, "%s: invalid variable parameter (const struct lyd_node *data_tree).", __func__);
567 goto error;
568 }
569 }
570
571 /* move it to the beginning */
572 for (; data_tree->prev->next; data_tree = data_tree->prev);
573
574 /* LYD_OPT_NOSIBLINGS cannot be set in this case */
575 if (options & LYD_OPT_NOSIBLINGS) {
576 LOGERR(LY_EINVAL, "%s: invalid parameter (variable arg const struct lyd_node *data_tree with LYD_OPT_NOSIBLINGS).", __func__);
577 goto error;
578 }
579 }
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100580 }
581
Radek Krejci86538212015-12-17 15:59:01 +0100582 if (!(options & LYD_OPT_NOSIBLINGS)) {
583 /* locate the first root to process */
584 if ((*root)->parent) {
585 xmlstart = (*root)->parent->child;
586 } else {
587 xmlstart = *root;
588 while(xmlstart->prev->next) {
589 xmlstart = xmlstart->prev;
590 }
Radek Krejci04b97de2015-10-31 23:09:15 +0100591 }
Radek Krejci86538212015-12-17 15:59:01 +0100592 } else {
593 xmlstart = *root;
594 }
Radek Krejci86538212015-12-17 15:59:01 +0100595
Michal Vaskob1b19442016-07-13 12:26:01 +0200596 if ((options & LYD_OPT_RPC)
597 && !strcmp(xmlstart->name, "action") && !strcmp(xmlstart->ns->value, "urn:ietf:params:xml:ns:yang:1")) {
598 /* it's an action, not a simple RPC */
599 xmlstart = xmlstart->child;
600 options &= ~LYD_OPT_RPC;
601 options |= LYD_OPT_ACTION;
602 }
603
604 iter = last = NULL;
Radek Krejci86538212015-12-17 15:59:01 +0100605 LY_TREE_FOR_SAFE(xmlstart, xmlaux, xmlelem) {
Radek Krejcibd930122016-08-10 13:28:26 +0200606 r = xml_parse_data(ctx, xmlelem, reply_parent, result, last, options, unres, &iter, &action);
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100607 if (r) {
Pavol Vican8a552f62016-09-05 11:20:57 +0200608 if (reply_parent) {
609 result = reply_parent;
610 }
Michal Vasko24d982f2016-04-18 15:13:58 +0200611 goto error;
Radek Krejci86538212015-12-17 15:59:01 +0100612 } else if (options & LYD_OPT_DESTRUCT) {
613 lyxml_free(ctx, xmlelem);
614 *root = xmlaux;
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100615 }
616 if (iter) {
617 last = iter;
618 }
619 if (!result) {
620 result = iter;
621 }
Radek Krejci86538212015-12-17 15:59:01 +0100622
623 if (options & LYD_OPT_NOSIBLINGS) {
624 /* stop after the first processed root */
625 break;
626 }
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100627 }
Radek Krejcic6704c82015-10-06 11:12:45 +0200628
Michal Vaskoe45aff52016-08-25 09:01:09 +0200629 if (reply_parent) {
630 result = reply_parent;
631 }
632
Michal Vasko6b44d712016-09-12 16:25:46 +0200633 if (options & LYD_OPT_ACTION) {
634 if (!action) {
635 ly_vecode = LYVE_INACT;
636 LOGVAL(LYE_SPEC, LY_VLOG_LYD, result, "Missing action node.");
637 goto error;
638 }
639 options &= ~LYD_OPT_ACTION;
640 options |= LYD_OPT_RPC;
Radek Krejcib45b3082016-09-09 16:08:51 +0200641 }
642
Radek Krejci63b79c82016-08-10 10:09:33 +0200643 /* check for uniquness of top-level lists/leaflists because
644 * only the inner instances were tested in lyv_data_content() */
645 set = ly_set_new();
646 LY_TREE_FOR(result, iter) {
647 if (!(iter->schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) || !(iter->validity & LYD_VAL_UNIQUE)) {
648 continue;
649 }
650
651 /* check each list/leaflist only once */
652 i = set->number;
653 if (ly_set_add(set, iter->schema, 0) != i) {
654 /* already checked */
655 continue;
656 }
657
658 if (lyv_data_unique(iter, result)) {
659 ly_set_free(set);
660 goto error;
661 }
662 }
663 ly_set_free(set);
664
Radek Krejcib45b3082016-09-09 16:08:51 +0200665 /* add default values, resolve unres and check for mandatory nodes in final tree */
Michal Vasko6b44d712016-09-12 16:25:46 +0200666 if (lyd_defaults_add_unres(&result, options, ctx, data_tree, action, unres)) {
667 goto error;
668 }
669 if (!(options & LYD_OPT_TRUSTED)) {
670 if (lyd_check_mandatory_tree((action ? action : result), ctx, options)) {
Michal Vaskob1b19442016-07-13 12:26:01 +0200671 goto error;
672 }
Radek Krejci46165822016-08-26 14:06:27 +0200673 }
674
Michal Vasko24d982f2016-04-18 15:13:58 +0200675 free(unres->node);
676 free(unres->type);
677 free(unres);
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100678 va_end(ap);
Radek Krejcic6704c82015-10-06 11:12:45 +0200679
680 return result;
Michal Vasko24d982f2016-04-18 15:13:58 +0200681
682error:
683 lyd_free_withsiblings(result);
684 free(unres->node);
685 free(unres->type);
686 free(unres);
687 va_end(ap);
688
689 return NULL;
Radek Krejcic6704c82015-10-06 11:12:45 +0200690}