blob: ad1da1acddab4b6a608e30f5713f148a9e509f6f [file] [log] [blame]
Radek Krejci1721c012015-07-08 12:52:33 +02001/**
Michal Vasko45a0ef32016-09-22 11:07:38 +02002 * @file parser_xml.c
Radek Krejci1721c012015-07-08 12:52:33 +02003 * @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 Krejci1a6303d2016-11-04 12:42:46 +010063 if (ly_strequal(lys_main_module(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 Krejci1fe9ac02016-09-23 09:38:21 +020078xml_get_value(struct lyd_node *node, struct lyxml_elem *xml, int options, int editbits)
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 Krejci1899d6a2016-11-03 13:48:07 +010081 int resolvable;
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
Radek Krejci1899d6a2016-11-03 13:48:07 +010085 if (options & (LYD_OPT_EDIT | LYD_OPT_GET | LYD_OPT_GETCONFIG)) {
86 resolvable = 0;
87 } else {
88 resolvable = 1;
89 }
90
Michal Vaskod27602c2016-12-20 11:11:17 +010091 leaf->value_str = lydict_insert(node->schema->module->ctx, xml->content, 0);
Radek Krejcie4748472015-07-08 18:00:22 +020092
Radek Krejci1fe9ac02016-09-23 09:38:21 +020093 if ((editbits & 0x10) && (node->schema->nodetype & LYS_LEAF) && (!leaf->value_str || !leaf->value_str[0])) {
94 /* we have edit-config leaf/leaf-list with delete operation and no (empty) value,
95 * this is not a bug since the node is just used as a kind of selection node */
96 leaf->value_type = LY_TYPE_ERR;
97 return EXIT_SUCCESS;
98 }
99
Radek Krejci1899d6a2016-11-03 13:48:07 +0100100 /* the value is here converted to a JSON format if needed in case of LY_TYPE_IDENT and LY_TYPE_INST or to a
101 * canonical form of the value */
Radek Krejcibb1ce0f2016-12-05 13:24:33 +0100102 if (!lyp_parse_value(&((struct lys_node_leaf *)leaf->schema)->type, &leaf->value_str, xml, NULL, leaf, 1,
Radek Krejci1899d6a2016-11-03 13:48:07 +0100103 resolvable, 0)) {
Michal Vasko493bea72015-07-16 16:08:12 +0200104 return EXIT_FAILURE;
Radek Krejcie4748472015-07-08 18:00:22 +0200105 }
106
107 return EXIT_SUCCESS;
108}
109
Michal Vasko0d343d12015-08-24 14:57:36 +0200110/* logs directly */
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100111static int
Radek Krejcibd930122016-08-10 13:28:26 +0200112xml_parse_data(struct ly_ctx *ctx, struct lyxml_elem *xml, struct lyd_node *parent, struct lyd_node *first_sibling,
113 struct lyd_node *prev, int options, struct unres_data *unres, struct lyd_node **result,
Michal Vaskob15cae22016-09-15 09:40:56 +0200114 struct lyd_node **act_notif)
Radek Krejci1721c012015-07-08 12:52:33 +0200115{
Radek Krejcibd930122016-08-10 13:28:26 +0200116 struct lyd_node *diter, *dlast;
Michal Vasko5e523b62016-08-26 16:23:15 +0200117 struct lys_node *schema = NULL, *target;
118 struct lys_node_augment *aug;
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100119 struct lyd_attr *dattr, *dattr_iter;
Radek Krejcia5241e52015-08-19 15:09:31 +0200120 struct lyxml_attr *attr;
Michal Vaskof748dbc2016-04-05 11:27:47 +0200121 struct lyxml_elem *child, *next;
Radek Krejci1fe9ac02016-09-23 09:38:21 +0200122 int i, j, havechildren, r, flag, pos, editbits = 0;
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100123 int ret = 0;
Radek Krejciabb7b582016-04-20 16:15:47 +0200124 const char *str = NULL;
Radek Krejci1721c012015-07-08 12:52:33 +0200125
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100126 assert(xml);
127 assert(result);
128 *result = NULL;
129
Radek Krejci1721c012015-07-08 12:52:33 +0200130 if (!xml->ns || !xml->ns->value) {
Radek Krejci2342cf62016-01-29 16:48:23 +0100131 if (options & LYD_OPT_STRICT) {
Radek Krejci48464ed2016-03-17 15:44:09 +0100132 LOGVAL(LYE_XML_MISS, LY_VLOG_XML, xml, "element's", "namespace");
Radek Krejci2342cf62016-01-29 16:48:23 +0100133 return -1;
134 } else {
135 return 0;
136 }
Radek Krejci1721c012015-07-08 12:52:33 +0200137 }
138
139 /* find schema node */
Michal Vaskob1b19442016-07-13 12:26:01 +0200140 if (!parent) {
Radek Krejci1721c012015-07-08 12:52:33 +0200141 /* starting in root */
142 for (i = 0; i < ctx->models.used; i++) {
Radek Krejci0ec51da2016-12-14 16:42:03 +0100143 /* skip just imported modules, data can be coupled only with the implemented modules,
144 * also skip the disabled modules */
145 if (!ctx->models.list[i]->implemented || ctx->models.list[i]->disabled) {
Radek Krejci27fe55e2016-09-13 17:13:35 +0200146 continue;
147 }
Radek Krejci1721c012015-07-08 12:52:33 +0200148 /* match data model based on namespace */
Radek Krejci749190d2016-02-18 16:26:25 +0100149 if (ly_strequal(ctx->models.list[i]->ns, xml->ns->value, 1)) {
Radek Krejci1721c012015-07-08 12:52:33 +0200150 /* get the proper schema node */
Radek Krejci919a9242016-07-27 08:17:13 +0200151 schema = xml_data_search_schemanode(xml, ctx->models.list[i]->data, options);
Michal Vasko5e523b62016-08-26 16:23:15 +0200152 if (!schema) {
153 /* it still can be the specific case of this module containing an augment of another module
154 * top-level choice or top-level choice's case, bleh */
155 for (j = 0; j < ctx->models.list[i]->augment_size; ++j) {
156 aug = &ctx->models.list[i]->augment[j];
157 target = aug->target;
158 if (target->nodetype & (LYS_CHOICE | LYS_CASE)) {
159 /* 1) okay, the target is choice or case */
160 while (target && (target->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES))) {
161 target = lys_parent(target);
162 }
163 /* 2) now, the data node will be top-level, there are only non-data schema nodes */
164 if (!target) {
165 while ((schema = (struct lys_node *)lys_getnext(schema, (struct lys_node *)aug, NULL, 0))) {
166 /* 3) alright, even the name matches, we found our schema node */
167 if (ly_strequal(schema->name, xml->name, 1)) {
168 break;
169 }
170 }
171 }
172 }
173
174 if (schema) {
175 break;
176 }
177 }
178 }
Radek Krejci1721c012015-07-08 12:52:33 +0200179 break;
180 }
181 }
182 } else {
183 /* parsing some internal node, we start with parent's schema pointer */
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100184 schema = xml_data_search_schemanode(xml, parent->schema->child, options);
Radek Krejci1721c012015-07-08 12:52:33 +0200185 }
186 if (!schema) {
Radek Krejci25b9fd32015-08-10 15:06:07 +0200187 if ((options & LYD_OPT_STRICT) || ly_ctx_get_module_by_ns(ctx, xml->ns->value, NULL)) {
Radek Krejci48464ed2016-03-17 15:44:09 +0100188 LOGVAL(LYE_INELEM, LY_VLOG_LYD, parent, xml->name);
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100189 return -1;
Radek Krejci25b9fd32015-08-10 15:06:07 +0200190 } else {
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100191 return 0;
Radek Krejci25b9fd32015-08-10 15:06:07 +0200192 }
Radek Krejci27fe55e2016-09-13 17:13:35 +0200193 } else if (!lys_node_module(schema)->implemented) {
194 if (options & LYD_OPT_STRICT) {
195 LOGVAL(LYE_INELEM, LY_VLOG_LYD, parent, xml->name);
196 return -1;
197 } else {
198 return 0;
199 }
Radek Krejci1721c012015-07-08 12:52:33 +0200200 }
201
Radek Krejciadb57612016-02-16 13:34:34 +0100202 /* create the element structure */
Radek Krejcib9930252015-07-08 15:47:45 +0200203 switch (schema->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +0200204 case LYS_CONTAINER:
Radek Krejci27aaa732015-09-04 15:24:04 +0200205 case LYS_LIST:
Michal Vasko2f30e572015-10-01 16:00:38 +0200206 case LYS_NOTIF:
207 case LYS_RPC:
Michal Vaskob1b19442016-07-13 12:26:01 +0200208 case LYS_ACTION:
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100209 *result = calloc(1, sizeof **result);
Michal Vaskoab8e4402015-07-17 12:54:28 +0200210 havechildren = 1;
Radek Krejcib9930252015-07-08 15:47:45 +0200211 break;
Radek Krejci76512572015-08-04 09:47:08 +0200212 case LYS_LEAF:
Radek Krejci76512572015-08-04 09:47:08 +0200213 case LYS_LEAFLIST:
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100214 *result = calloc(1, sizeof(struct lyd_node_leaf_list));
Radek Krejcie4748472015-07-08 18:00:22 +0200215 havechildren = 0;
216 break;
Radek Krejci76512572015-08-04 09:47:08 +0200217 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +0200218 case LYS_ANYDATA:
219 *result = calloc(1, sizeof(struct lyd_node_anydata));
Michal Vaskoab8e4402015-07-17 12:54:28 +0200220 havechildren = 0;
221 break;
Radek Krejcib9930252015-07-08 15:47:45 +0200222 default:
Michal Vasko0c888fd2015-08-11 15:54:08 +0200223 LOGINT;
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100224 return -1;
Radek Krejcib9930252015-07-08 15:47:45 +0200225 }
Michal Vasko253035f2015-12-17 16:58:13 +0100226 if (!(*result)) {
227 LOGMEM;
228 return -1;
229 }
230
Radek Krejci61767ca2016-09-19 14:21:55 +0200231 (*result)->prev = *result;
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100232 (*result)->schema = schema;
Radek Krejci61767ca2016-09-19 14:21:55 +0200233 (*result)->parent = parent;
234 diter = NULL;
235 if (parent && parent->child && schema->nodetype == LYS_LEAF && parent->schema->nodetype == LYS_LIST &&
236 (pos = lys_is_key((struct lys_node_list *)parent->schema, (struct lys_node_leaf *)schema))) {
237 /* it is key and we need to insert it into a correct place */
238 for (i = 0, diter = parent->child;
239 diter && i < (pos - 1) && diter->schema->nodetype == LYS_LEAF &&
240 lys_is_key((struct lys_node_list *)parent->schema, (struct lys_node_leaf *)diter->schema);
241 i++, diter = diter->next);
242 if (diter) {
243 /* out of order insertion - insert list's key to the correct position, before the diter */
244 if (options & LYD_OPT_STRICT) {
245 LOGVAL(LYE_INORDER, LY_VLOG_LYD, *result, schema->name, diter->schema->name);
246 LOGVAL(LYE_SPEC, LY_VLOG_LYD, *result, "Invalid position of the key \"%s\" in a list \"%s\".",
247 schema->name, parent->schema->name);
248 free(*result);
249 *result = NULL;
250 return -1;
251 } else {
252 LOGWRN("Invalid position of the key \"%s\" in a list \"%s\".", schema->name, parent->schema->name)
253 }
254 if (parent->child == diter) {
255 parent->child = *result;
256 /* update first_sibling */
257 first_sibling = *result;
258 }
259 if (diter->prev->next) {
260 diter->prev->next = *result;
261 }
262 (*result)->prev = diter->prev;
263 diter->prev = *result;
264 (*result)->next = diter;
265 }
266 }
267 if (!diter) {
268 /* simplified (faster) insert as the last node */
269 if (parent && !parent->child) {
270 parent->child = *result;
271 }
272 if (prev) {
273 (*result)->prev = prev;
274 prev->next = *result;
275
276 /* fix the "last" pointer */
277 first_sibling->prev = *result;
278 } else {
279 (*result)->prev = *result;
280 first_sibling = *result;
281 }
282 }
Radek Krejcica7efb72016-01-18 13:06:01 +0100283 (*result)->validity = LYD_VAL_NOT;
Radek Krejci46165822016-08-26 14:06:27 +0200284 if (resolve_applies_when(schema, 0, NULL)) {
Radek Krejci0b7704f2016-03-18 12:16:14 +0100285 (*result)->when_status = LYD_WHEN;
286 }
Radek Krejci1721c012015-07-08 12:52:33 +0200287
Radek Krejciadb57612016-02-16 13:34:34 +0100288 /* check insert attribute and its values */
289 if (options & LYD_OPT_EDIT) {
Radek Krejci9bfcbde2016-04-07 16:30:15 +0200290 /* 0x01 - insert attribute present
291 * 0x02 - insert is relative (before or after)
292 * 0x04 - value attribute present
293 * 0x08 - key attribute present
294 * 0x10 - operation not allowing insert attribute
295 */
Radek Krejciadb57612016-02-16 13:34:34 +0100296 for (attr = xml->attr; attr; attr = attr->next) {
Radek Krejci9bfcbde2016-04-07 16:30:15 +0200297 if (attr->type != LYXML_ATTR_STD || !attr->ns) {
298 /* not interesting attribute or namespace declaration */
Radek Krejciadb57612016-02-16 13:34:34 +0100299 continue;
300 }
301
Radek Krejci9bfcbde2016-04-07 16:30:15 +0200302 if (!strcmp(attr->name, "operation") && !strcmp(attr->ns->value, LY_NSNC)) {
Radek Krejci1fe9ac02016-09-23 09:38:21 +0200303 if (editbits & 0x10) {
Radek Krejci72614bf2016-04-08 17:46:07 +0200304 LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, (*result), "operation attributes", xml->name);
305 return -1;
306 }
307
Radek Krejci9bfcbde2016-04-07 16:30:15 +0200308 if (!strcmp(attr->value, "delete") || !strcmp(attr->value, "remove")) {
Radek Krejci1fe9ac02016-09-23 09:38:21 +0200309 editbits |= 0x10;
Radek Krejci9bfcbde2016-04-07 16:30:15 +0200310 } else if (strcmp(attr->value, "create") &&
311 strcmp(attr->value, "merge") &&
312 strcmp(attr->value, "replace")) {
313 /* unknown operation */
314 LOGVAL(LYE_INVALATTR, LY_VLOG_LYD, (*result), attr->value, attr->name);
315 return -1;
316 }
317 } else if (!strcmp(attr->name, "insert") && !strcmp(attr->ns->value, LY_NSYANG)) {
318 /* 'insert' attribute present */
319 if (!(schema->flags & LYS_USERORDERED)) {
320 /* ... but it is not expected */
321 LOGVAL(LYE_INATTR, LY_VLOG_LYD, (*result), "insert", schema->name);
322 return -1;
323 }
Radek Krejciadb57612016-02-16 13:34:34 +0100324
Radek Krejci1fe9ac02016-09-23 09:38:21 +0200325 if (editbits & 0x01) {
Radek Krejci9bfcbde2016-04-07 16:30:15 +0200326 LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, (*result), "insert attributes", xml->name);
327 return -1;
328 }
329 if (!strcmp(attr->value, "first") || !strcmp(attr->value, "last")) {
Radek Krejci1fe9ac02016-09-23 09:38:21 +0200330 editbits |= 0x01;
Radek Krejci9bfcbde2016-04-07 16:30:15 +0200331 } else if (!strcmp(attr->value, "before") || !strcmp(attr->value, "after")) {
Radek Krejci1fe9ac02016-09-23 09:38:21 +0200332 editbits |= 0x01 | 0x02;
Radek Krejci9bfcbde2016-04-07 16:30:15 +0200333 } else {
334 LOGVAL(LYE_INVALATTR, LY_VLOG_LYD, (*result), attr->value, attr->name);
335 return -1;
336 }
337 str = attr->name;
338 } else if (!strcmp(attr->name, "value") && !strcmp(attr->ns->value, LY_NSYANG)) {
Radek Krejci1fe9ac02016-09-23 09:38:21 +0200339 if (editbits & 0x04) {
Radek Krejci9bfcbde2016-04-07 16:30:15 +0200340 LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, (*result), "value attributes", xml->name);
341 return -1;
342 } else if (schema->nodetype & LYS_LIST) {
343 LOGVAL(LYE_INATTR, LY_VLOG_LYD, (*result), attr->name, schema->name);
344 return -1;
345 }
Radek Krejci1fe9ac02016-09-23 09:38:21 +0200346 editbits |= 0x04;
Radek Krejci9bfcbde2016-04-07 16:30:15 +0200347 str = attr->name;
348 } else if (!strcmp(attr->name, "key") && !strcmp(attr->ns->value, LY_NSYANG)) {
Radek Krejci1fe9ac02016-09-23 09:38:21 +0200349 if (editbits & 0x08) {
Radek Krejci9bfcbde2016-04-07 16:30:15 +0200350 LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, (*result), "key attributes", xml->name);
351 return -1;
352 } else if (schema->nodetype & LYS_LEAFLIST) {
353 LOGVAL(LYE_INATTR, LY_VLOG_LYD, (*result), attr->name, schema->name);
354 return -1;
355 }
Radek Krejci1fe9ac02016-09-23 09:38:21 +0200356 editbits |= 0x08;
Radek Krejci9bfcbde2016-04-07 16:30:15 +0200357 str = attr->name;
Radek Krejciadb57612016-02-16 13:34:34 +0100358 }
Radek Krejciadb57612016-02-16 13:34:34 +0100359 }
360
Radek Krejci9bfcbde2016-04-07 16:30:15 +0200361 /* report errors */
Radek Krejci1fe9ac02016-09-23 09:38:21 +0200362 if (editbits > 0x10 || (editbits && editbits < 0x10 &&
Radek Krejcicced9382016-04-13 13:15:03 +0200363 (!(schema->nodetype & (LYS_LEAFLIST | LYS_LIST)) || !(schema->flags & LYS_USERORDERED)))) {
Radek Krejcid0df6902016-03-10 09:32:00 +0100364 /* attributes in wrong elements */
Radek Krejci48464ed2016-03-17 15:44:09 +0100365 LOGVAL(LYE_INATTR, LY_VLOG_LYD, (*result), str, xml->name);
Radek Krejcid0df6902016-03-10 09:32:00 +0100366 return -1;
Radek Krejci1fe9ac02016-09-23 09:38:21 +0200367 } else if (editbits == 3) {
Radek Krejci9bfcbde2016-04-07 16:30:15 +0200368 /* 0x01 | 0x02 - relative position, but value/key is missing */
369 if (schema->nodetype & LYS_LIST) {
370 LOGVAL(LYE_MISSATTR, LY_VLOG_LYD, (*result), "key", xml->name);
371 } else { /* LYS_LEAFLIST */
372 LOGVAL(LYE_MISSATTR, LY_VLOG_LYD, (*result), "value", xml->name);
373 }
Radek Krejciadb57612016-02-16 13:34:34 +0100374 return -1;
Radek Krejci1fe9ac02016-09-23 09:38:21 +0200375 } else if ((editbits & (0x04 | 0x08)) && !(editbits & 0x02)) {
Radek Krejci9bfcbde2016-04-07 16:30:15 +0200376 /* key/value without relative position */
Radek Krejci1fe9ac02016-09-23 09:38:21 +0200377 LOGVAL(LYE_INATTR, LY_VLOG_LYD, (*result), (editbits & 0x04) ? "value" : "key", schema->name);
Radek Krejciadb57612016-02-16 13:34:34 +0100378 return -1;
379 }
380 }
381
Radek Krejcib9930252015-07-08 15:47:45 +0200382 /* type specific processing */
Radek Krejci27aaa732015-09-04 15:24:04 +0200383 if (schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
Radek Krejcie4748472015-07-08 18:00:22 +0200384 /* type detection and assigning the value */
Radek Krejci1fe9ac02016-09-23 09:38:21 +0200385 if (xml_get_value(*result, xml, options, editbits)) {
Radek Krejci3e3affe2015-07-09 15:38:40 +0200386 goto error;
387 }
Radek Krejcibf2abff2016-08-23 15:51:52 +0200388 } else if (schema->nodetype & LYS_ANYDATA) {
Michal Vaskof748dbc2016-04-05 11:27:47 +0200389 /* store children values */
390 if (xml->child) {
391 child = xml->child;
392 /* manually unlink all siblings and correct namespaces */
393 xml->child = NULL;
394 LY_TREE_FOR(child, next) {
395 next->parent = NULL;
396 lyxml_correct_elem_ns(ctx, next, 1, 1);
397 }
398
Radek Krejci45826012016-08-24 15:07:57 +0200399 ((struct lyd_node_anydata *)*result)->value_type = LYD_ANYDATA_XML;
Radek Krejcibf2abff2016-08-23 15:51:52 +0200400 ((struct lyd_node_anydata *)*result)->value.xml = child;
Michal Vaskof748dbc2016-04-05 11:27:47 +0200401 } else {
Radek Krejci45826012016-08-24 15:07:57 +0200402 ((struct lyd_node_anydata *)*result)->value_type = LYD_ANYDATA_CONSTSTRING;
Radek Krejcibf2abff2016-08-23 15:51:52 +0200403 ((struct lyd_node_anydata *)*result)->value.str = lydict_insert(ctx, xml->content, 0);
Michal Vasko253035f2015-12-17 16:58:13 +0100404 }
Michal Vaskoafa7a642016-10-18 15:11:38 +0200405 } else if (schema->nodetype & (LYS_RPC | LYS_ACTION)) {
406 if (!(options & LYD_OPT_RPC) || *act_notif) {
407 LOGVAL(LYE_INELEM, LY_VLOG_LYD, (*result), schema->name);
408 LOGVAL(LYE_SPEC, LY_VLOG_LYD, (*result), "Unexpected %s node \"%s\".",
409 (schema->nodetype == LYS_RPC ? "rpc" : "action"), schema->name);
410 goto error;
411 }
412 *act_notif = *result;
413 } else if (schema->nodetype == LYS_NOTIF) {
414 if (!(options & LYD_OPT_NOTIF) || *act_notif) {
415 LOGVAL(LYE_INELEM, LY_VLOG_LYD, (*result), schema->name);
416 LOGVAL(LYE_SPEC, LY_VLOG_LYD, (*result), "Unexpected notification node \"%s\".", schema->name);
417 goto error;
418 }
419 *act_notif = *result;
Radek Krejcib9930252015-07-08 15:47:45 +0200420 }
421
Michal Vasko10e586f2016-05-18 13:25:30 +0200422 /* first part of validation checks */
423 if (!(options & LYD_OPT_TRUSTED) && lyv_data_context(*result, options, unres)) {
424 goto error;
425 }
426
Radek Krejci998a7502015-10-26 15:54:33 +0100427 for (attr = xml->attr; attr; attr = attr->next) {
Radek Krejci9a5daea2016-03-02 16:49:40 +0100428 flag = 0;
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100429 if (attr->type != LYXML_ATTR_STD) {
430 continue;
431 } else if (!attr->ns) {
Radek Krejci9a5daea2016-03-02 16:49:40 +0100432 if ((*result)->schema->nodetype != LYS_ANYXML ||
433 !ly_strequal((*result)->schema->name, "filter", 0) ||
434 !ly_strequal((*result)->schema->module->name, "ietf-netconf", 0)) {
Radek Krejci0f721232016-05-03 14:52:29 +0200435 if (options & LYD_OPT_STRICT) {
436 LOGVAL(LYE_INATTR, LY_VLOG_LYD, (*result), attr->name, xml->name);
437 LOGVAL(LYE_SPEC, LY_VLOG_LYD, (*result), "Attribute \"%s\" with no namespace (schema).",
438 attr->name);
439 goto error;
440 } else {
441 LOGWRN("Ignoring \"%s\" attribute in \"%s\" element.", attr->name, xml->name);
442 continue;
443 }
Radek Krejci9a5daea2016-03-02 16:49:40 +0100444 } else {
445 /* exception for filter's attributes */
446 flag = 1;
447 }
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100448 }
449
450 dattr = malloc(sizeof *dattr);
Michal Vasko253035f2015-12-17 16:58:13 +0100451 if (!dattr) {
452 goto error;
453 }
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100454 dattr->next = NULL;
455 dattr->name = attr->name;
Radek Krejci9a5daea2016-03-02 16:49:40 +0100456 if (flag && ly_strequal(attr->name, "select", 0)) {
457 dattr->value = transform_xml2json(ctx, attr->value, xml, 1);
458 if (!dattr->value) {
459 free(dattr);
460 goto error;
461 }
462 lydict_remove(ctx, attr->value);
463 } else {
464 dattr->value = attr->value;
465 }
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100466 attr->name = NULL;
467 attr->value = NULL;
468
Radek Krejci9a5daea2016-03-02 16:49:40 +0100469 if (!attr->ns) {
470 /* filter's attributes, it actually has no namespace, but we need some for internal representation */
471 dattr->module = (*result)->schema->module;
472 } else {
473 dattr->module = (struct lys_module *)ly_ctx_get_module_by_ns(ctx, attr->ns->value, NULL);
474 }
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100475 if (!dattr->module) {
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100476 free(dattr);
Radek Krejci0f721232016-05-03 14:52:29 +0200477 if (options & LYD_OPT_STRICT) {
478 LOGVAL(LYE_INATTR, LY_VLOG_LYD, (*result), attr->name, xml->name);
479 LOGVAL(LYE_SPEC, LY_VLOG_LYD, (*result), "Attribute \"%s\" from unknown schema (\"%s\").",
480 attr->name, attr->ns->value);
481 goto error;
482 } else {
483 LOGWRN("Attribute \"%s\" from unknown schema (\"%s\") - skipping.", attr->name, attr->ns->value);
484 continue;
485 }
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100486 }
487
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100488 if (!(*result)->attr) {
489 (*result)->attr = dattr;
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100490 } else {
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100491 for (dattr_iter = (*result)->attr; dattr_iter->next; dattr_iter = dattr_iter->next);
Radek Krejci5f9e8c92015-10-30 10:01:06 +0100492 dattr_iter->next = dattr;
Radek Krejci998a7502015-10-26 15:54:33 +0100493 }
494 }
Michal Vasko4ff7b072015-08-21 09:05:03 +0200495
Radek Krejci14c00092015-11-01 11:03:24 +0100496 /* process children */
497 if (havechildren && xml->child) {
498 diter = dlast = NULL;
499 LY_TREE_FOR_SAFE(xml->child, next, child) {
500 if (schema->nodetype & (LYS_RPC | LYS_NOTIF)) {
Michal Vaskob15cae22016-09-15 09:40:56 +0200501 r = xml_parse_data(ctx, child, *result, (*result)->child, dlast, 0, unres, &diter, act_notif);
Radek Krejci14c00092015-11-01 11:03:24 +0100502 } else {
Michal Vaskob15cae22016-09-15 09:40:56 +0200503 r = xml_parse_data(ctx, child, *result, (*result)->child, dlast, options, unres, &diter, act_notif);
Radek Krejci14c00092015-11-01 11:03:24 +0100504 }
Radek Krejci14c00092015-11-01 11:03:24 +0100505 if (r) {
506 goto error;
Radek Krejci86538212015-12-17 15:59:01 +0100507 } else if (options & LYD_OPT_DESTRUCT) {
508 lyxml_free(ctx, child);
Radek Krejci14c00092015-11-01 11:03:24 +0100509 }
Radek Krejci61767ca2016-09-19 14:21:55 +0200510 if (diter && !diter->next) {
511 /* the child was parsed/created and it was placed as the last child. The child can be inserted
512 * out of order (not as the last one) in case it is a list's key present out of the correct order */
Radek Krejci14c00092015-11-01 11:03:24 +0100513 dlast = diter;
514 }
515 }
516 }
517
Radek Krejcifb7156e2016-10-27 13:39:56 +0200518 /* if we have empty non-presence container, we keep it, but mark it as default */
Radek Krejci2537fd32016-09-07 16:22:41 +0200519 if (schema->nodetype == LYS_CONTAINER && !(*result)->child &&
Radek Krejcid3e73722016-05-23 12:24:55 +0200520 !(*result)->attr && !((struct lys_node_container *)schema)->presence) {
Radek Krejcifb7156e2016-10-27 13:39:56 +0200521 (*result)->dflt = 1;
Radek Krejci0c0086a2016-03-24 15:20:28 +0100522 }
523
Radek Krejcicf509982015-12-15 09:22:44 +0100524 /* rest of validation checks */
Radek Krejci00a0e712016-10-26 10:24:46 +0200525 ly_err_clean(1);
Radek Krejci2d5525d2016-04-04 15:43:30 +0200526 if (!(options & LYD_OPT_TRUSTED) &&
527 (lyv_data_content(*result, options, unres) ||
Radek Krejci61767ca2016-09-19 14:21:55 +0200528 lyv_multicases(*result, NULL, prev ? &first_sibling : NULL, 0, NULL))) {
Radek Krejcieab784a2015-08-27 09:56:53 +0200529 if (ly_errno) {
Radek Krejcib1c12512015-08-11 11:22:04 +0200530 goto error;
Radek Krejci1b0d01a2015-08-19 17:00:35 +0200531 } else {
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100532 goto clear;
Radek Krejcida374342015-08-19 13:33:22 +0200533 }
Radek Krejci78ce8612015-08-18 14:31:05 +0200534 }
535
Radek Krejcica7efb72016-01-18 13:06:01 +0100536 /* validation successful */
Radek Krejci63b79c82016-08-10 10:09:33 +0200537 if ((*result)->schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
538 /* postpone checking when there will be all list/leaflist instances */
539 (*result)->validity = LYD_VAL_UNIQUE;
540 } else {
541 (*result)->validity = LYD_VAL_OK;
542 }
Radek Krejcica7efb72016-01-18 13:06:01 +0100543
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100544 return ret;
Radek Krejci3e3affe2015-07-09 15:38:40 +0200545
546error:
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100547 ret--;
548
549clear:
Radek Krejcieab784a2015-08-27 09:56:53 +0200550 /* cleanup */
Radek Krejci0c0086a2016-03-24 15:20:28 +0100551 for (i = unres->count - 1; i >= 0; i--) {
552 /* remove unres items connected with the node being removed */
553 if (unres->node[i] == *result) {
554 unres_data_del(unres, i);
555 }
556 }
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100557 lyd_free(*result);
558 *result = NULL;
Radek Krejci1b0d01a2015-08-19 17:00:35 +0200559
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100560 return ret;
Radek Krejci1721c012015-07-08 12:52:33 +0200561}
562
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100563API struct lyd_node *
564lyd_parse_xml(struct ly_ctx *ctx, struct lyxml_elem **root, int options, ...)
Radek Krejcic6704c82015-10-06 11:12:45 +0200565{
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100566 va_list ap;
Radek Krejci63b79c82016-08-10 10:09:33 +0200567 int r, i;
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100568 struct unres_data *unres = NULL;
Michal Vasko945b96b2016-10-18 11:49:12 +0200569 const struct lyd_node *rpc_act = NULL, *data_tree = NULL;
570 struct lyd_node *result = NULL, *iter, *last, *reply_parent = NULL, *reply_top = NULL, *act_notif = NULL;
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100571 struct lyxml_elem *xmlstart, *xmlelem, *xmlaux;
Radek Krejci63b79c82016-08-10 10:09:33 +0200572 struct ly_set *set;
Radek Krejcic6704c82015-10-06 11:12:45 +0200573
Radek Krejci00a0e712016-10-26 10:24:46 +0200574 ly_err_clean(1);
Radek Krejci2342cf62016-01-29 16:48:23 +0100575
Radek Krejcic6704c82015-10-06 11:12:45 +0200576 if (!ctx || !root) {
577 LOGERR(LY_EINVAL, "%s: Invalid parameter.", __func__);
578 return NULL;
579 }
580
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100581 if (lyp_check_options(options)) {
582 LOGERR(LY_EINVAL, "%s: Invalid options (multiple data type flags set).", __func__);
583 return NULL;
584 }
585
Radek Krejcia6939c32016-03-24 15:19:09 +0100586 if (!(*root)) {
587 /* empty tree - no work is needed */
588 lyd_validate(&result, options, ctx);
589 return result;
590 }
591
Michal Vasko24d982f2016-04-18 15:13:58 +0200592 unres = calloc(1, sizeof *unres);
593 if (!unres) {
594 LOGMEM;
595 return NULL;
596 }
597
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100598 va_start(ap, options);
599 if (options & LYD_OPT_RPCREPLY) {
Michal Vasko945b96b2016-10-18 11:49:12 +0200600 rpc_act = va_arg(ap, const struct lyd_node *);
601 if (!rpc_act || rpc_act->parent || !(rpc_act->schema->nodetype & (LYS_RPC | LYS_LIST | LYS_CONTAINER))) {
602 LOGERR(LY_EINVAL, "%s: invalid variable parameter (const struct lyd_node *rpc_act).", __func__);
Michal Vasko24d982f2016-04-18 15:13:58 +0200603 goto error;
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100604 }
Michal Vasko945b96b2016-10-18 11:49:12 +0200605 if (rpc_act->schema->nodetype == LYS_RPC) {
606 /* RPC request */
607 reply_top = reply_parent = _lyd_new(NULL, rpc_act->schema, 0);
608 } else {
609 /* action request */
610 reply_top = lyd_dup(rpc_act, 1);
611 LY_TREE_DFS_BEGIN(reply_top, iter, reply_parent) {
612 if (reply_parent->schema->nodetype == LYS_ACTION) {
613 break;
614 }
615 LY_TREE_DFS_END(reply_top, iter, reply_parent);
616 }
617 if (!reply_parent) {
618 LOGERR(LY_EINVAL, "%s: invalid variable parameter (const struct lyd_node *rpc_act).", __func__);
619 lyd_free_withsiblings(reply_top);
620 goto error;
621 }
622 lyd_free_withsiblings(reply_parent->child);
623 }
Michal Vasko45e23652016-09-21 11:24:32 +0200624 }
625 if (options & (LYD_OPT_RPC | LYD_OPT_NOTIF | LYD_OPT_RPCREPLY)) {
Michal Vasko945b96b2016-10-18 11:49:12 +0200626 data_tree = va_arg(ap, const struct lyd_node *);
Michal Vasko6b44d712016-09-12 16:25:46 +0200627 if (data_tree) {
Michal Vasko945b96b2016-10-18 11:49:12 +0200628 LY_TREE_FOR((struct lyd_node *)data_tree, iter) {
Michal Vasko6b44d712016-09-12 16:25:46 +0200629 if (iter->parent) {
630 /* a sibling is not top-level */
631 LOGERR(LY_EINVAL, "%s: invalid variable parameter (const struct lyd_node *data_tree).", __func__);
632 goto error;
633 }
634 }
635
636 /* move it to the beginning */
637 for (; data_tree->prev->next; data_tree = data_tree->prev);
638
639 /* LYD_OPT_NOSIBLINGS cannot be set in this case */
640 if (options & LYD_OPT_NOSIBLINGS) {
641 LOGERR(LY_EINVAL, "%s: invalid parameter (variable arg const struct lyd_node *data_tree with LYD_OPT_NOSIBLINGS).", __func__);
642 goto error;
643 }
644 }
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100645 }
646
Radek Krejci86538212015-12-17 15:59:01 +0100647 if (!(options & LYD_OPT_NOSIBLINGS)) {
648 /* locate the first root to process */
649 if ((*root)->parent) {
650 xmlstart = (*root)->parent->child;
651 } else {
652 xmlstart = *root;
653 while(xmlstart->prev->next) {
654 xmlstart = xmlstart->prev;
655 }
Radek Krejci04b97de2015-10-31 23:09:15 +0100656 }
Radek Krejci86538212015-12-17 15:59:01 +0100657 } else {
658 xmlstart = *root;
659 }
Radek Krejci86538212015-12-17 15:59:01 +0100660
Michal Vaskob1b19442016-07-13 12:26:01 +0200661 if ((options & LYD_OPT_RPC)
662 && !strcmp(xmlstart->name, "action") && !strcmp(xmlstart->ns->value, "urn:ietf:params:xml:ns:yang:1")) {
663 /* it's an action, not a simple RPC */
664 xmlstart = xmlstart->child;
Michal Vaskob1b19442016-07-13 12:26:01 +0200665 }
666
667 iter = last = NULL;
Radek Krejci86538212015-12-17 15:59:01 +0100668 LY_TREE_FOR_SAFE(xmlstart, xmlaux, xmlelem) {
Michal Vaskob15cae22016-09-15 09:40:56 +0200669 r = xml_parse_data(ctx, xmlelem, reply_parent, result, last, options, unres, &iter, &act_notif);
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100670 if (r) {
Michal Vasko945b96b2016-10-18 11:49:12 +0200671 if (reply_top) {
672 result = reply_top;
Pavol Vican8a552f62016-09-05 11:20:57 +0200673 }
Michal Vasko24d982f2016-04-18 15:13:58 +0200674 goto error;
Radek Krejci86538212015-12-17 15:59:01 +0100675 } else if (options & LYD_OPT_DESTRUCT) {
676 lyxml_free(ctx, xmlelem);
677 *root = xmlaux;
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100678 }
679 if (iter) {
680 last = iter;
681 }
682 if (!result) {
683 result = iter;
684 }
Radek Krejci86538212015-12-17 15:59:01 +0100685
686 if (options & LYD_OPT_NOSIBLINGS) {
687 /* stop after the first processed root */
688 break;
689 }
Radek Krejci3b41a6c2015-10-31 23:06:12 +0100690 }
Radek Krejcic6704c82015-10-06 11:12:45 +0200691
Michal Vasko945b96b2016-10-18 11:49:12 +0200692 if (reply_top) {
693 result = reply_top;
Michal Vaskoe45aff52016-08-25 09:01:09 +0200694 }
695
Michal Vasko945b96b2016-10-18 11:49:12 +0200696 if ((options & LYD_OPT_RPCREPLY) && (rpc_act->schema->nodetype != LYS_RPC)) {
697 /* action reply */
698 act_notif = reply_parent;
Michal Vaskoafa7a642016-10-18 15:11:38 +0200699 } else if ((options & (LYD_OPT_RPC | LYD_OPT_NOTIF)) && !act_notif) {
700 ly_vecode = LYVE_INELEM;
701 LOGVAL(LYE_SPEC, LY_VLOG_LYD, result, "Missing %s node.", (options & LYD_OPT_RPC ? "action" : "notification"));
702 goto error;
Radek Krejcib45b3082016-09-09 16:08:51 +0200703 }
704
Radek Krejci63b79c82016-08-10 10:09:33 +0200705 /* check for uniquness of top-level lists/leaflists because
706 * only the inner instances were tested in lyv_data_content() */
707 set = ly_set_new();
708 LY_TREE_FOR(result, iter) {
709 if (!(iter->schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) || !(iter->validity & LYD_VAL_UNIQUE)) {
710 continue;
711 }
712
713 /* check each list/leaflist only once */
714 i = set->number;
715 if (ly_set_add(set, iter->schema, 0) != i) {
716 /* already checked */
717 continue;
718 }
719
720 if (lyv_data_unique(iter, result)) {
721 ly_set_free(set);
722 goto error;
723 }
724 }
725 ly_set_free(set);
726
Radek Krejcib45b3082016-09-09 16:08:51 +0200727 /* add default values, resolve unres and check for mandatory nodes in final tree */
Michal Vaskob15cae22016-09-15 09:40:56 +0200728 if (lyd_defaults_add_unres(&result, options, ctx, data_tree, act_notif, unres)) {
Michal Vasko6b44d712016-09-12 16:25:46 +0200729 goto error;
730 }
Michal Vaskoafa7a642016-10-18 15:11:38 +0200731 if (!(options & LYD_OPT_TRUSTED) && lyd_check_mandatory_tree((act_notif ? act_notif : result), ctx, options)) {
732 goto error;
Radek Krejci46165822016-08-26 14:06:27 +0200733 }
734
Michal Vasko24d982f2016-04-18 15:13:58 +0200735 free(unres->node);
736 free(unres->type);
737 free(unres);
Radek Krejci4a49bdf2016-01-12 17:17:01 +0100738 va_end(ap);
Radek Krejcic6704c82015-10-06 11:12:45 +0200739
740 return result;
Michal Vasko24d982f2016-04-18 15:13:58 +0200741
742error:
743 lyd_free_withsiblings(result);
744 free(unres->node);
745 free(unres->type);
746 free(unres);
747 va_end(ap);
748
749 return NULL;
Radek Krejcic6704c82015-10-06 11:12:45 +0200750}