Radek Krejci | 1721c01 | 2015-07-08 12:52:33 +0200 | [diff] [blame] | 1 | /** |
| 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 Krejci | 54f6fb3 | 2016-02-24 12:56:39 +0100 | [diff] [blame] | 8 | * 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 Vasko | 8de098c | 2016-02-26 10:00:25 +0100 | [diff] [blame] | 11 | * |
Radek Krejci | 54f6fb3 | 2016-02-24 12:56:39 +0100 | [diff] [blame] | 12 | * https://opensource.org/licenses/BSD-3-Clause |
Radek Krejci | 1721c01 | 2015-07-08 12:52:33 +0200 | [diff] [blame] | 13 | */ |
| 14 | |
| 15 | #include <assert.h> |
Radek Krejci | 3e3affe | 2015-07-09 15:38:40 +0200 | [diff] [blame] | 16 | #include <ctype.h> |
Radek Krejci | 1721c01 | 2015-07-08 12:52:33 +0200 | [diff] [blame] | 17 | #include <errno.h> |
Radek Krejci | 4a49bdf | 2016-01-12 17:17:01 +0100 | [diff] [blame] | 18 | #include <stdarg.h> |
Radek Krejci | 1721c01 | 2015-07-08 12:52:33 +0200 | [diff] [blame] | 19 | #include <stdlib.h> |
| 20 | #include <string.h> |
Michal Vasko | 8bcdf29 | 2015-08-19 14:04:43 +0200 | [diff] [blame] | 21 | #include <limits.h> |
Radek Krejci | 1721c01 | 2015-07-08 12:52:33 +0200 | [diff] [blame] | 22 | |
Radek Krejci | 998a0b8 | 2015-08-17 13:14:36 +0200 | [diff] [blame] | 23 | #include "libyang.h" |
| 24 | #include "common.h" |
| 25 | #include "context.h" |
Michal Vasko | b798232 | 2015-10-16 13:56:12 +0200 | [diff] [blame] | 26 | #include "parser.h" |
Radek Krejci | 998a0b8 | 2015-08-17 13:14:36 +0200 | [diff] [blame] | 27 | #include "tree_internal.h" |
| 28 | #include "validation.h" |
Michal Vasko | fc5744d | 2015-10-22 12:09:34 +0200 | [diff] [blame] | 29 | #include "xml_internal.h" |
Radek Krejci | 1721c01 | 2015-07-08 12:52:33 +0200 | [diff] [blame] | 30 | |
Michal Vasko | 0d343d1 | 2015-08-24 14:57:36 +0200 | [diff] [blame] | 31 | /* does not log */ |
Radek Krejci | 7651257 | 2015-08-04 09:47:08 +0200 | [diff] [blame] | 32 | static struct lys_node * |
Radek Krejci | 4a49bdf | 2016-01-12 17:17:01 +0100 | [diff] [blame] | 33 | xml_data_search_schemanode(struct lyxml_elem *xml, struct lys_node *start, int options) |
Radek Krejci | 1721c01 | 2015-07-08 12:52:33 +0200 | [diff] [blame] | 34 | { |
Radek Krejci | 7651257 | 2015-08-04 09:47:08 +0200 | [diff] [blame] | 35 | struct lys_node *result, *aux; |
Radek Krejci | 1721c01 | 2015-07-08 12:52:33 +0200 | [diff] [blame] | 36 | |
| 37 | LY_TREE_FOR(start, result) { |
Radek Krejci | 4a49bdf | 2016-01-12 17:17:01 +0100 | [diff] [blame] | 38 | /* skip groupings ... */ |
Radek Krejci | 7651257 | 2015-08-04 09:47:08 +0200 | [diff] [blame] | 39 | if (result->nodetype == LYS_GROUPING) { |
Radek Krejci | 1721c01 | 2015-07-08 12:52:33 +0200 | [diff] [blame] | 40 | continue; |
Radek Krejci | 4a49bdf | 2016-01-12 17:17:01 +0100 | [diff] [blame] | 41 | /* ... 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 Krejci | 1721c01 | 2015-07-08 12:52:33 +0200 | [diff] [blame] | 47 | } |
| 48 | |
Radek Krejci | fb54be4 | 2015-10-02 15:21:16 +0200 | [diff] [blame] | 49 | /* 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 Krejci | 4a49bdf | 2016-01-12 17:17:01 +0100 | [diff] [blame] | 51 | aux = xml_data_search_schemanode(xml, result->child, options); |
Radek Krejci | 1721c01 | 2015-07-08 12:52:33 +0200 | [diff] [blame] | 52 | 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 Krejci | 749190d | 2016-02-18 16:26:25 +0100 | [diff] [blame] | 61 | if (ly_strequal(result->name, xml->name, 1)) { |
Radek Krejci | 1721c01 | 2015-07-08 12:52:33 +0200 | [diff] [blame] | 62 | /* names matches, what about namespaces? */ |
Radek Krejci | 749190d | 2016-02-18 16:26:25 +0100 | [diff] [blame] | 63 | if (ly_strequal(result->module->ns, xml->ns->value, 1)) { |
Radek Krejci | 1721c01 | 2015-07-08 12:52:33 +0200 | [diff] [blame] | 64 | /* 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 Vasko | 0d343d1 | 2015-08-24 14:57:36 +0200 | [diff] [blame] | 76 | /* logs directly */ |
Radek Krejci | e474847 | 2015-07-08 18:00:22 +0200 | [diff] [blame] | 77 | static int |
Michal Vasko | 8ea2b7f | 2015-09-29 14:30:53 +0200 | [diff] [blame] | 78 | xml_get_value(struct lyd_node *node, struct lyxml_elem *xml, int options, struct unres_data *unres) |
Michal Vasko | 07471a5 | 2015-07-16 11:18:48 +0200 | [diff] [blame] | 79 | { |
Michal Vasko | 4c18331 | 2015-09-25 10:41:47 +0200 | [diff] [blame] | 80 | struct lyd_node_leaf_list *leaf = (struct lyd_node_leaf_list *)node; |
Radek Krejci | 37b756f | 2016-01-18 10:15:03 +0100 | [diff] [blame] | 81 | int resolve; |
Michal Vasko | 23b61ec | 2015-08-19 11:19:50 +0200 | [diff] [blame] | 82 | |
Michal Vasko | 8ea2b7f | 2015-09-29 14:30:53 +0200 | [diff] [blame] | 83 | assert(node && (node->schema->nodetype & (LYS_LEAFLIST | LYS_LEAF)) && xml && unres); |
Radek Krejci | 5a98815 | 2015-07-15 11:16:26 +0200 | [diff] [blame] | 84 | |
| 85 | leaf->value_str = xml->content; |
| 86 | xml->content = NULL; |
Radek Krejci | e474847 | 2015-07-08 18:00:22 +0200 | [diff] [blame] | 87 | |
Michal Vasko | 8ea2b7f | 2015-09-29 14:30:53 +0200 | [diff] [blame] | 88 | /* will be changed in case of union */ |
Radek Krejci | 37b756f | 2016-01-18 10:15:03 +0100 | [diff] [blame] | 89 | leaf->value_type = ((struct lys_node_leaf *)node->schema)->type.base; |
Radek Krejci | e3c3314 | 2015-08-10 15:04:36 +0200 | [diff] [blame] | 90 | |
Radek Krejci | e2cf7c1 | 2015-08-12 10:24:05 +0200 | [diff] [blame] | 91 | if ((options & LYD_OPT_FILTER) && !leaf->value_str) { |
| 92 | /* no value in filter (selection) node -> nothing more is needed */ |
| 93 | return EXIT_SUCCESS; |
| 94 | } |
| 95 | |
Radek Krejci | 20cdf63 | 2015-11-09 14:44:58 +0100 | [diff] [blame] | 96 | if (options & (LYD_OPT_FILTER | LYD_OPT_EDIT | LYD_OPT_GET | LYD_OPT_GETCONFIG)) { |
Michal Vasko | 8ea2b7f | 2015-09-29 14:30:53 +0200 | [diff] [blame] | 97 | resolve = 0; |
| 98 | } else { |
| 99 | resolve = 1; |
| 100 | } |
Radek Krejci | 3e3affe | 2015-07-09 15:38:40 +0200 | [diff] [blame] | 101 | |
Radek Krejci | 37b756f | 2016-01-18 10:15:03 +0100 | [diff] [blame] | 102 | if ((leaf->value_type == LY_TYPE_IDENT) || (leaf->value_type == LY_TYPE_INST)) { |
Michal Vasko | fb0873c | 2015-08-21 09:00:07 +0200 | [diff] [blame] | 103 | /* convert the path from the XML form using XML namespaces into the JSON format |
| 104 | * using module names as namespaces |
| 105 | */ |
| 106 | xml->content = leaf->value_str; |
Michal Vasko | fba1526 | 2015-10-21 12:10:28 +0200 | [diff] [blame] | 107 | leaf->value_str = transform_xml2json(leaf->schema->module->ctx, xml->content, xml, 1); |
Michal Vasko | 8ea2b7f | 2015-09-29 14:30:53 +0200 | [diff] [blame] | 108 | lydict_remove(leaf->schema->module->ctx, xml->content); |
Michal Vasko | fb0873c | 2015-08-21 09:00:07 +0200 | [diff] [blame] | 109 | xml->content = NULL; |
| 110 | if (!leaf->value_str) { |
| 111 | return EXIT_FAILURE; |
Radek Krejci | ac8aac6 | 2015-07-10 15:36:35 +0200 | [diff] [blame] | 112 | } |
Michal Vasko | 8ea2b7f | 2015-09-29 14:30:53 +0200 | [diff] [blame] | 113 | } |
Radek Krejci | ac8aac6 | 2015-07-10 15:36:35 +0200 | [diff] [blame] | 114 | |
Radek Krejci | 37b756f | 2016-01-18 10:15:03 +0100 | [diff] [blame] | 115 | if (lyp_parse_value(leaf, xml, resolve, unres, LOGLINE(xml))) { |
Michal Vasko | 493bea7 | 2015-07-16 16:08:12 +0200 | [diff] [blame] | 116 | return EXIT_FAILURE; |
Radek Krejci | e474847 | 2015-07-08 18:00:22 +0200 | [diff] [blame] | 117 | } |
| 118 | |
| 119 | return EXIT_SUCCESS; |
| 120 | } |
| 121 | |
Michal Vasko | 0d343d1 | 2015-08-24 14:57:36 +0200 | [diff] [blame] | 122 | /* logs directly */ |
Radek Krejci | 3b41a6c | 2015-10-31 23:06:12 +0100 | [diff] [blame] | 123 | static int |
Michal Vasko | 36ef693 | 2015-12-01 14:30:17 +0100 | [diff] [blame] | 124 | xml_parse_data(struct ly_ctx *ctx, struct lyxml_elem *xml, const struct lys_node *schema_parent, struct lyd_node *parent, |
| 125 | struct lyd_node *prev, int options, struct unres_data *unres, struct lyd_node **result) |
Radek Krejci | 1721c01 | 2015-07-08 12:52:33 +0200 | [diff] [blame] | 126 | { |
Radek Krejci | 3b41a6c | 2015-10-31 23:06:12 +0100 | [diff] [blame] | 127 | struct lyd_node *diter, *dlast; |
Radek Krejci | eab784a | 2015-08-27 09:56:53 +0200 | [diff] [blame] | 128 | struct lys_node *schema = NULL; |
Radek Krejci | 5f9e8c9 | 2015-10-30 10:01:06 +0100 | [diff] [blame] | 129 | struct lyd_attr *dattr, *dattr_iter; |
Radek Krejci | a5241e5 | 2015-08-19 15:09:31 +0200 | [diff] [blame] | 130 | struct lyxml_attr *attr; |
Michal Vasko | 17cc706 | 2015-12-10 14:31:48 +0100 | [diff] [blame] | 131 | struct lyxml_elem *tmp_xml, *child, *next; |
Radek Krejci | 9a5daea | 2016-03-02 16:49:40 +0100 | [diff] [blame^] | 132 | int i, havechildren, r, flag; |
Radek Krejci | 3b41a6c | 2015-10-31 23:06:12 +0100 | [diff] [blame] | 133 | int ret = 0; |
Radek Krejci | 1721c01 | 2015-07-08 12:52:33 +0200 | [diff] [blame] | 134 | |
Radek Krejci | 3b41a6c | 2015-10-31 23:06:12 +0100 | [diff] [blame] | 135 | assert(xml); |
| 136 | assert(result); |
| 137 | *result = NULL; |
| 138 | |
Radek Krejci | 1721c01 | 2015-07-08 12:52:33 +0200 | [diff] [blame] | 139 | if (!xml->ns || !xml->ns->value) { |
Radek Krejci | 2342cf6 | 2016-01-29 16:48:23 +0100 | [diff] [blame] | 140 | if (options & LYD_OPT_STRICT) { |
Radek Krejci | adb5761 | 2016-02-16 13:34:34 +0100 | [diff] [blame] | 141 | LOGVAL(LYE_XML_MISS, LOGLINE(xml), LY_VLOG_XML, xml, "element's", "namespace"); |
Radek Krejci | 2342cf6 | 2016-01-29 16:48:23 +0100 | [diff] [blame] | 142 | return -1; |
| 143 | } else { |
| 144 | return 0; |
| 145 | } |
Radek Krejci | 1721c01 | 2015-07-08 12:52:33 +0200 | [diff] [blame] | 146 | } |
| 147 | |
| 148 | /* find schema node */ |
Michal Vasko | 36ef693 | 2015-12-01 14:30:17 +0100 | [diff] [blame] | 149 | if (schema_parent) { |
Radek Krejci | 4a49bdf | 2016-01-12 17:17:01 +0100 | [diff] [blame] | 150 | schema = xml_data_search_schemanode(xml, schema_parent->child, options); |
Michal Vasko | 36ef693 | 2015-12-01 14:30:17 +0100 | [diff] [blame] | 151 | } else if (!parent) { |
Radek Krejci | 1721c01 | 2015-07-08 12:52:33 +0200 | [diff] [blame] | 152 | /* starting in root */ |
| 153 | for (i = 0; i < ctx->models.used; i++) { |
| 154 | /* match data model based on namespace */ |
Radek Krejci | 749190d | 2016-02-18 16:26:25 +0100 | [diff] [blame] | 155 | if (ly_strequal(ctx->models.list[i]->ns, xml->ns->value, 1)) { |
Radek Krejci | 1721c01 | 2015-07-08 12:52:33 +0200 | [diff] [blame] | 156 | /* get the proper schema node */ |
| 157 | LY_TREE_FOR(ctx->models.list[i]->data, schema) { |
Radek Krejci | 4a49bdf | 2016-01-12 17:17:01 +0100 | [diff] [blame] | 158 | /* skip nodes in module's data which are not expected here according to options' data type */ |
| 159 | if (options & LYD_OPT_RPC) { |
| 160 | if (schema->nodetype != LYS_RPC) { |
| 161 | continue; |
| 162 | } |
| 163 | } else if (options & LYD_OPT_NOTIF) { |
| 164 | if (schema->nodetype != LYS_NOTIF) { |
| 165 | continue; |
| 166 | } |
| 167 | } else if (!(options & LYD_OPT_RPCREPLY)) { |
| 168 | /* rest of the data types except RPCREPLY which cannot be here */ |
| 169 | if (schema->nodetype & (LYS_RPC | LYS_NOTIF)) { |
| 170 | continue; |
| 171 | } |
| 172 | } |
Radek Krejci | 749190d | 2016-02-18 16:26:25 +0100 | [diff] [blame] | 173 | if (ly_strequal(schema->name, xml->name, 1)) { |
Radek Krejci | 1721c01 | 2015-07-08 12:52:33 +0200 | [diff] [blame] | 174 | break; |
| 175 | } |
| 176 | } |
| 177 | break; |
| 178 | } |
| 179 | } |
| 180 | } else { |
| 181 | /* parsing some internal node, we start with parent's schema pointer */ |
Radek Krejci | 4a49bdf | 2016-01-12 17:17:01 +0100 | [diff] [blame] | 182 | schema = xml_data_search_schemanode(xml, parent->schema->child, options); |
Radek Krejci | 1721c01 | 2015-07-08 12:52:33 +0200 | [diff] [blame] | 183 | } |
| 184 | if (!schema) { |
Radek Krejci | 25b9fd3 | 2015-08-10 15:06:07 +0200 | [diff] [blame] | 185 | if ((options & LYD_OPT_STRICT) || ly_ctx_get_module_by_ns(ctx, xml->ns->value, NULL)) { |
Radek Krejci | adb5761 | 2016-02-16 13:34:34 +0100 | [diff] [blame] | 186 | LOGVAL(LYE_INELEM, LOGLINE(xml), LY_VLOG_LYD, parent, xml->name); |
Radek Krejci | 3b41a6c | 2015-10-31 23:06:12 +0100 | [diff] [blame] | 187 | return -1; |
Radek Krejci | 25b9fd3 | 2015-08-10 15:06:07 +0200 | [diff] [blame] | 188 | } else { |
Radek Krejci | 3b41a6c | 2015-10-31 23:06:12 +0100 | [diff] [blame] | 189 | return 0; |
Radek Krejci | 25b9fd3 | 2015-08-10 15:06:07 +0200 | [diff] [blame] | 190 | } |
Radek Krejci | 1721c01 | 2015-07-08 12:52:33 +0200 | [diff] [blame] | 191 | } |
| 192 | |
Radek Krejci | adb5761 | 2016-02-16 13:34:34 +0100 | [diff] [blame] | 193 | /* create the element structure */ |
Radek Krejci | b993025 | 2015-07-08 15:47:45 +0200 | [diff] [blame] | 194 | switch (schema->nodetype) { |
Radek Krejci | 7651257 | 2015-08-04 09:47:08 +0200 | [diff] [blame] | 195 | case LYS_CONTAINER: |
Radek Krejci | 27aaa73 | 2015-09-04 15:24:04 +0200 | [diff] [blame] | 196 | case LYS_LIST: |
Michal Vasko | 2f30e57 | 2015-10-01 16:00:38 +0200 | [diff] [blame] | 197 | case LYS_NOTIF: |
| 198 | case LYS_RPC: |
Radek Krejci | 3b41a6c | 2015-10-31 23:06:12 +0100 | [diff] [blame] | 199 | *result = calloc(1, sizeof **result); |
Michal Vasko | ab8e440 | 2015-07-17 12:54:28 +0200 | [diff] [blame] | 200 | havechildren = 1; |
Radek Krejci | b993025 | 2015-07-08 15:47:45 +0200 | [diff] [blame] | 201 | break; |
Radek Krejci | 7651257 | 2015-08-04 09:47:08 +0200 | [diff] [blame] | 202 | case LYS_LEAF: |
Radek Krejci | 7651257 | 2015-08-04 09:47:08 +0200 | [diff] [blame] | 203 | case LYS_LEAFLIST: |
Radek Krejci | 3b41a6c | 2015-10-31 23:06:12 +0100 | [diff] [blame] | 204 | *result = calloc(1, sizeof(struct lyd_node_leaf_list)); |
Radek Krejci | e474847 | 2015-07-08 18:00:22 +0200 | [diff] [blame] | 205 | havechildren = 0; |
| 206 | break; |
Radek Krejci | 7651257 | 2015-08-04 09:47:08 +0200 | [diff] [blame] | 207 | case LYS_ANYXML: |
Radek Krejci | 3b41a6c | 2015-10-31 23:06:12 +0100 | [diff] [blame] | 208 | *result = calloc(1, sizeof(struct lyd_node_anyxml)); |
Michal Vasko | ab8e440 | 2015-07-17 12:54:28 +0200 | [diff] [blame] | 209 | havechildren = 0; |
| 210 | break; |
Radek Krejci | b993025 | 2015-07-08 15:47:45 +0200 | [diff] [blame] | 211 | default: |
Michal Vasko | 0c888fd | 2015-08-11 15:54:08 +0200 | [diff] [blame] | 212 | LOGINT; |
Radek Krejci | 3b41a6c | 2015-10-31 23:06:12 +0100 | [diff] [blame] | 213 | return -1; |
Radek Krejci | b993025 | 2015-07-08 15:47:45 +0200 | [diff] [blame] | 214 | } |
Michal Vasko | 253035f | 2015-12-17 16:58:13 +0100 | [diff] [blame] | 215 | if (!(*result)) { |
| 216 | LOGMEM; |
| 217 | return -1; |
| 218 | } |
| 219 | |
Radek Krejci | 3b41a6c | 2015-10-31 23:06:12 +0100 | [diff] [blame] | 220 | (*result)->parent = parent; |
Radek Krejci | c41bf8a | 2015-08-21 10:28:48 +0200 | [diff] [blame] | 221 | if (parent && !parent->child) { |
Radek Krejci | 3b41a6c | 2015-10-31 23:06:12 +0100 | [diff] [blame] | 222 | parent->child = *result; |
Radek Krejci | c41bf8a | 2015-08-21 10:28:48 +0200 | [diff] [blame] | 223 | } |
| 224 | if (prev) { |
Radek Krejci | 3b41a6c | 2015-10-31 23:06:12 +0100 | [diff] [blame] | 225 | (*result)->prev = prev; |
| 226 | prev->next = *result; |
Radek Krejci | c41bf8a | 2015-08-21 10:28:48 +0200 | [diff] [blame] | 227 | |
| 228 | /* fix the "last" pointer */ |
Radek Krejci | 93fab98 | 2016-02-03 15:58:19 +0100 | [diff] [blame] | 229 | if (parent) { |
| 230 | diter = parent->child; |
| 231 | } else { |
| 232 | for (diter = prev; diter->prev != prev; diter = diter->prev); |
| 233 | } |
Radek Krejci | 3b41a6c | 2015-10-31 23:06:12 +0100 | [diff] [blame] | 234 | diter->prev = *result; |
Radek Krejci | c41bf8a | 2015-08-21 10:28:48 +0200 | [diff] [blame] | 235 | } else { |
Radek Krejci | 3b41a6c | 2015-10-31 23:06:12 +0100 | [diff] [blame] | 236 | (*result)->prev = *result; |
Radek Krejci | c41bf8a | 2015-08-21 10:28:48 +0200 | [diff] [blame] | 237 | } |
Radek Krejci | 3b41a6c | 2015-10-31 23:06:12 +0100 | [diff] [blame] | 238 | (*result)->schema = schema; |
Radek Krejci | ca7efb7 | 2016-01-18 13:06:01 +0100 | [diff] [blame] | 239 | (*result)->validity = LYD_VAL_NOT; |
Radek Krejci | 1721c01 | 2015-07-08 12:52:33 +0200 | [diff] [blame] | 240 | |
Radek Krejci | adb5761 | 2016-02-16 13:34:34 +0100 | [diff] [blame] | 241 | /* check insert attribute and its values */ |
| 242 | if (options & LYD_OPT_EDIT) { |
| 243 | i = 0; |
| 244 | for (attr = xml->attr; attr; attr = attr->next) { |
| 245 | if (attr->type != LYXML_ATTR_STD || !attr->ns || |
| 246 | strcmp(attr->name, "insert") || strcmp(attr->ns->value, LY_NSYANG)) { |
| 247 | continue; |
| 248 | } |
| 249 | |
| 250 | /* insert attribute present */ |
| 251 | if (!(schema->flags & LYS_USERORDERED)) { |
| 252 | /* ... but it is not expected */ |
| 253 | LOGVAL(LYE_INATTR, LOGLINE(xml), LY_VLOG_LYD, (*result), "insert", schema->name); |
| 254 | return -1; |
| 255 | } |
| 256 | |
| 257 | if (i) { |
| 258 | LOGVAL(LYE_TOOMANY, LOGLINE(xml), LY_VLOG_LYD, (*result), "insert attributes", xml->name); |
| 259 | return -1; |
| 260 | } |
| 261 | if (!strcmp(attr->value, "first") || !strcmp(attr->value, "last")) { |
| 262 | i = 1; |
| 263 | } else if (!strcmp(attr->value, "before") || !strcmp(attr->value, "after")) { |
| 264 | i = 2; |
| 265 | } else { |
| 266 | LOGVAL(LYE_INARG, LOGLINE(xml), LY_VLOG_LYD, (*result), attr->value, attr->name); |
| 267 | return -1; |
| 268 | } |
| 269 | } |
| 270 | |
| 271 | for (attr = xml->attr; attr; attr = attr->next) { |
| 272 | if (attr->type != LYXML_ATTR_STD || !attr->ns || |
| 273 | strcmp(attr->name, "value") || strcmp(attr->ns->value, LY_NSYANG)) { |
| 274 | continue; |
| 275 | } |
| 276 | |
| 277 | /* the value attribute is present */ |
| 278 | if (i < 2) { |
| 279 | /* but it shouldn't */ |
| 280 | LOGVAL(LYE_INATTR, LOGLINE(xml), LY_VLOG_LYD, (*result), "value", schema->name); |
| 281 | return -1; |
| 282 | } |
| 283 | i++; |
| 284 | } |
| 285 | if (i == 2) { |
| 286 | /* missing value attribute for "before" or "after" */ |
| 287 | LOGVAL(LYE_MISSATTR, LOGLINE(xml), LY_VLOG_LYD, (*result), "value", xml->name); |
| 288 | return -1; |
| 289 | } else if (i > 3) { |
| 290 | /* more than one instance of the value attribute */ |
| 291 | LOGVAL(LYE_TOOMANY, LOGLINE(xml), LY_VLOG_LYD, (*result), "value attributes", xml->name); |
| 292 | return -1; |
| 293 | } |
| 294 | } |
| 295 | |
| 296 | /* first part of validation checks */ |
Radek Krejci | 93fab98 | 2016-02-03 15:58:19 +0100 | [diff] [blame] | 297 | if (!(options & LYD_OPT_TRUSTED) && lyv_data_context(*result, options, LOGLINE(xml), unres)) { |
Michal Vasko | cf02470 | 2015-10-08 15:01:42 +0200 | [diff] [blame] | 298 | goto error; |
| 299 | } |
| 300 | |
Radek Krejci | b993025 | 2015-07-08 15:47:45 +0200 | [diff] [blame] | 301 | /* type specific processing */ |
Radek Krejci | 27aaa73 | 2015-09-04 15:24:04 +0200 | [diff] [blame] | 302 | if (schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) { |
Radek Krejci | e474847 | 2015-07-08 18:00:22 +0200 | [diff] [blame] | 303 | /* type detection and assigning the value */ |
Radek Krejci | 3b41a6c | 2015-10-31 23:06:12 +0100 | [diff] [blame] | 304 | if (xml_get_value(*result, xml, options, unres)) { |
Radek Krejci | 3e3affe | 2015-07-09 15:38:40 +0200 | [diff] [blame] | 305 | goto error; |
| 306 | } |
Radek Krejci | 1b0d01a | 2015-08-19 17:00:35 +0200 | [diff] [blame] | 307 | } else if (schema->nodetype == LYS_ANYXML && !(options & LYD_OPT_FILTER)) { |
Michal Vasko | 17cc706 | 2015-12-10 14:31:48 +0100 | [diff] [blame] | 308 | /* HACK unlink xml children and link them to a separate copy of xml */ |
| 309 | tmp_xml = calloc(1, sizeof *tmp_xml); |
Michal Vasko | 253035f | 2015-12-17 16:58:13 +0100 | [diff] [blame] | 310 | if (!tmp_xml) { |
| 311 | LOGMEM; |
| 312 | goto error; |
| 313 | } |
Michal Vasko | 17cc706 | 2015-12-10 14:31:48 +0100 | [diff] [blame] | 314 | memcpy(tmp_xml, xml, sizeof *tmp_xml); |
| 315 | /* keep attributes in the original */ |
| 316 | tmp_xml->attr = NULL; |
| 317 | /* increase reference counters on strings */ |
| 318 | tmp_xml->name = lydict_insert(ctx, tmp_xml->name, 0); |
| 319 | tmp_xml->content = lydict_insert(ctx, tmp_xml->content, 0); |
| 320 | xml->child = NULL; |
| 321 | /* xml is correct now */ |
Michal Vasko | 60beecb | 2015-09-03 14:24:09 +0200 | [diff] [blame] | 322 | |
Michal Vasko | 17cc706 | 2015-12-10 14:31:48 +0100 | [diff] [blame] | 323 | LY_TREE_FOR(tmp_xml->child, child) { |
| 324 | child->parent = tmp_xml; |
| 325 | } |
| 326 | /* children are correct now */ |
| 327 | |
Michal Vasko | 63fac9e | 2016-02-24 10:42:02 +0100 | [diff] [blame] | 328 | /* unlink manually */ |
Michal Vasko | 17cc706 | 2015-12-10 14:31:48 +0100 | [diff] [blame] | 329 | tmp_xml->parent = NULL; |
Michal Vasko | 63fac9e | 2016-02-24 10:42:02 +0100 | [diff] [blame] | 330 | tmp_xml->next = NULL; |
| 331 | tmp_xml->prev = tmp_xml; |
| 332 | |
| 333 | /* just to correct namespaces */ |
Michal Vasko | 17cc706 | 2015-12-10 14:31:48 +0100 | [diff] [blame] | 334 | lyxml_unlink_elem(ctx, tmp_xml, 1); |
| 335 | /* tmp_xml is correct now */ |
| 336 | |
| 337 | ((struct lyd_node_anyxml *)*result)->value = tmp_xml; |
Michal Vasko | 60beecb | 2015-09-03 14:24:09 +0200 | [diff] [blame] | 338 | /* we can safely continue with xml, it's like it was, only without children */ |
Radek Krejci | b993025 | 2015-07-08 15:47:45 +0200 | [diff] [blame] | 339 | } |
| 340 | |
Radek Krejci | 998a750 | 2015-10-26 15:54:33 +0100 | [diff] [blame] | 341 | for (attr = xml->attr; attr; attr = attr->next) { |
Radek Krejci | 9a5daea | 2016-03-02 16:49:40 +0100 | [diff] [blame^] | 342 | flag = 0; |
Radek Krejci | 5f9e8c9 | 2015-10-30 10:01:06 +0100 | [diff] [blame] | 343 | if (attr->type != LYXML_ATTR_STD) { |
| 344 | continue; |
| 345 | } else if (!attr->ns) { |
Radek Krejci | 9a5daea | 2016-03-02 16:49:40 +0100 | [diff] [blame^] | 346 | if ((*result)->schema->nodetype != LYS_ANYXML || |
| 347 | !ly_strequal((*result)->schema->name, "filter", 0) || |
| 348 | !ly_strequal((*result)->schema->module->name, "ietf-netconf", 0)) { |
| 349 | LOGWRN("Ignoring \"%s\" attribute in \"%s\" element.", attr->name, xml->name); |
| 350 | continue; |
| 351 | } else { |
| 352 | /* exception for filter's attributes */ |
| 353 | flag = 1; |
| 354 | } |
Radek Krejci | 5f9e8c9 | 2015-10-30 10:01:06 +0100 | [diff] [blame] | 355 | } |
| 356 | |
| 357 | dattr = malloc(sizeof *dattr); |
Michal Vasko | 253035f | 2015-12-17 16:58:13 +0100 | [diff] [blame] | 358 | if (!dattr) { |
| 359 | goto error; |
| 360 | } |
Radek Krejci | 5f9e8c9 | 2015-10-30 10:01:06 +0100 | [diff] [blame] | 361 | dattr->next = NULL; |
| 362 | dattr->name = attr->name; |
Radek Krejci | 9a5daea | 2016-03-02 16:49:40 +0100 | [diff] [blame^] | 363 | if (flag && ly_strequal(attr->name, "select", 0)) { |
| 364 | dattr->value = transform_xml2json(ctx, attr->value, xml, 1); |
| 365 | if (!dattr->value) { |
| 366 | free(dattr); |
| 367 | goto error; |
| 368 | } |
| 369 | lydict_remove(ctx, attr->value); |
| 370 | } else { |
| 371 | dattr->value = attr->value; |
| 372 | } |
Radek Krejci | 5f9e8c9 | 2015-10-30 10:01:06 +0100 | [diff] [blame] | 373 | attr->name = NULL; |
| 374 | attr->value = NULL; |
| 375 | |
Radek Krejci | 9a5daea | 2016-03-02 16:49:40 +0100 | [diff] [blame^] | 376 | if (!attr->ns) { |
| 377 | /* filter's attributes, it actually has no namespace, but we need some for internal representation */ |
| 378 | dattr->module = (*result)->schema->module; |
| 379 | } else { |
| 380 | dattr->module = (struct lys_module *)ly_ctx_get_module_by_ns(ctx, attr->ns->value, NULL); |
| 381 | } |
Radek Krejci | 5f9e8c9 | 2015-10-30 10:01:06 +0100 | [diff] [blame] | 382 | if (!dattr->module) { |
| 383 | LOGWRN("Attribute \"%s\" from unknown schema (\"%s\") - skipping.", attr->name, attr->ns->value); |
| 384 | free(dattr); |
| 385 | continue; |
| 386 | } |
| 387 | |
Radek Krejci | 3b41a6c | 2015-10-31 23:06:12 +0100 | [diff] [blame] | 388 | if (!(*result)->attr) { |
| 389 | (*result)->attr = dattr; |
Radek Krejci | 5f9e8c9 | 2015-10-30 10:01:06 +0100 | [diff] [blame] | 390 | } else { |
Radek Krejci | 3b41a6c | 2015-10-31 23:06:12 +0100 | [diff] [blame] | 391 | for (dattr_iter = (*result)->attr; dattr_iter->next; dattr_iter = dattr_iter->next); |
Radek Krejci | 5f9e8c9 | 2015-10-30 10:01:06 +0100 | [diff] [blame] | 392 | dattr_iter->next = dattr; |
Radek Krejci | 998a750 | 2015-10-26 15:54:33 +0100 | [diff] [blame] | 393 | } |
| 394 | } |
Michal Vasko | 4ff7b07 | 2015-08-21 09:05:03 +0200 | [diff] [blame] | 395 | |
Radek Krejci | 14c0009 | 2015-11-01 11:03:24 +0100 | [diff] [blame] | 396 | /* process children */ |
| 397 | if (havechildren && xml->child) { |
| 398 | diter = dlast = NULL; |
| 399 | LY_TREE_FOR_SAFE(xml->child, next, child) { |
| 400 | if (schema->nodetype & (LYS_RPC | LYS_NOTIF)) { |
Michal Vasko | 36ef693 | 2015-12-01 14:30:17 +0100 | [diff] [blame] | 401 | r = xml_parse_data(ctx, child, NULL, *result, dlast, 0, unres, &diter); |
Radek Krejci | 14c0009 | 2015-11-01 11:03:24 +0100 | [diff] [blame] | 402 | } else { |
Michal Vasko | 36ef693 | 2015-12-01 14:30:17 +0100 | [diff] [blame] | 403 | r = xml_parse_data(ctx, child, NULL, *result, dlast, options, unres, &diter); |
Radek Krejci | 14c0009 | 2015-11-01 11:03:24 +0100 | [diff] [blame] | 404 | } |
Radek Krejci | 14c0009 | 2015-11-01 11:03:24 +0100 | [diff] [blame] | 405 | if (r) { |
| 406 | goto error; |
Radek Krejci | 8653821 | 2015-12-17 15:59:01 +0100 | [diff] [blame] | 407 | } else if (options & LYD_OPT_DESTRUCT) { |
| 408 | lyxml_free(ctx, child); |
Radek Krejci | 14c0009 | 2015-11-01 11:03:24 +0100 | [diff] [blame] | 409 | } |
| 410 | if (diter) { |
| 411 | dlast = diter; |
| 412 | } |
| 413 | } |
| 414 | } |
| 415 | |
Radek Krejci | cf50998 | 2015-12-15 09:22:44 +0100 | [diff] [blame] | 416 | /* rest of validation checks */ |
Radek Krejci | eab784a | 2015-08-27 09:56:53 +0200 | [diff] [blame] | 417 | ly_errno = 0; |
Radek Krejci | 93fab98 | 2016-02-03 15:58:19 +0100 | [diff] [blame] | 418 | if (!(options & LYD_OPT_TRUSTED) && lyv_data_content(*result, options, LOGLINE(xml), unres)) { |
Radek Krejci | eab784a | 2015-08-27 09:56:53 +0200 | [diff] [blame] | 419 | if (ly_errno) { |
Radek Krejci | b1c1251 | 2015-08-11 11:22:04 +0200 | [diff] [blame] | 420 | goto error; |
Radek Krejci | 1b0d01a | 2015-08-19 17:00:35 +0200 | [diff] [blame] | 421 | } else { |
Radek Krejci | 3b41a6c | 2015-10-31 23:06:12 +0100 | [diff] [blame] | 422 | goto clear; |
Radek Krejci | da37434 | 2015-08-19 13:33:22 +0200 | [diff] [blame] | 423 | } |
Radek Krejci | 78ce861 | 2015-08-18 14:31:05 +0200 | [diff] [blame] | 424 | } |
| 425 | |
Radek Krejci | ca7efb7 | 2016-01-18 13:06:01 +0100 | [diff] [blame] | 426 | /* validation successful */ |
| 427 | (*result)->validity = LYD_VAL_OK; |
| 428 | |
Radek Krejci | 3b41a6c | 2015-10-31 23:06:12 +0100 | [diff] [blame] | 429 | return ret; |
Radek Krejci | 3e3affe | 2015-07-09 15:38:40 +0200 | [diff] [blame] | 430 | |
| 431 | error: |
Radek Krejci | 3b41a6c | 2015-10-31 23:06:12 +0100 | [diff] [blame] | 432 | ret--; |
| 433 | |
| 434 | clear: |
Radek Krejci | eab784a | 2015-08-27 09:56:53 +0200 | [diff] [blame] | 435 | /* cleanup */ |
Radek Krejci | 3b41a6c | 2015-10-31 23:06:12 +0100 | [diff] [blame] | 436 | lyd_free(*result); |
| 437 | *result = NULL; |
Radek Krejci | 1b0d01a | 2015-08-19 17:00:35 +0200 | [diff] [blame] | 438 | |
Radek Krejci | 3b41a6c | 2015-10-31 23:06:12 +0100 | [diff] [blame] | 439 | return ret; |
Radek Krejci | 1721c01 | 2015-07-08 12:52:33 +0200 | [diff] [blame] | 440 | } |
| 441 | |
Radek Krejci | 4a49bdf | 2016-01-12 17:17:01 +0100 | [diff] [blame] | 442 | API struct lyd_node * |
| 443 | lyd_parse_xml(struct ly_ctx *ctx, struct lyxml_elem **root, int options, ...) |
Radek Krejci | c6704c8 | 2015-10-06 11:12:45 +0200 | [diff] [blame] | 444 | { |
Radek Krejci | 4a49bdf | 2016-01-12 17:17:01 +0100 | [diff] [blame] | 445 | va_list ap; |
Radek Krejci | 3b41a6c | 2015-10-31 23:06:12 +0100 | [diff] [blame] | 446 | int r; |
Radek Krejci | 4a49bdf | 2016-01-12 17:17:01 +0100 | [diff] [blame] | 447 | struct unres_data *unres = NULL; |
| 448 | const struct lys_node *rpc = NULL; |
| 449 | struct lyd_node *result = NULL, *next, *iter, *last; |
| 450 | struct lyxml_elem *xmlstart, *xmlelem, *xmlaux; |
Radek Krejci | c6704c8 | 2015-10-06 11:12:45 +0200 | [diff] [blame] | 451 | |
Radek Krejci | 2342cf6 | 2016-01-29 16:48:23 +0100 | [diff] [blame] | 452 | ly_errno = LY_SUCCESS; |
| 453 | |
Radek Krejci | c6704c8 | 2015-10-06 11:12:45 +0200 | [diff] [blame] | 454 | if (!ctx || !root) { |
| 455 | LOGERR(LY_EINVAL, "%s: Invalid parameter.", __func__); |
| 456 | return NULL; |
| 457 | } |
| 458 | |
Radek Krejci | 2342cf6 | 2016-01-29 16:48:23 +0100 | [diff] [blame] | 459 | if (!(*root)) { |
| 460 | /* empty tree - no work is needed */ |
Radek Krejci | 1daa7a4 | 2016-02-10 13:09:59 +0100 | [diff] [blame] | 461 | lyd_validate(NULL, options, ctx); |
Radek Krejci | 2342cf6 | 2016-01-29 16:48:23 +0100 | [diff] [blame] | 462 | return NULL; |
| 463 | } |
| 464 | |
Radek Krejci | 4a49bdf | 2016-01-12 17:17:01 +0100 | [diff] [blame] | 465 | if (lyp_check_options(options)) { |
| 466 | LOGERR(LY_EINVAL, "%s: Invalid options (multiple data type flags set).", __func__); |
| 467 | return NULL; |
| 468 | } |
| 469 | |
| 470 | va_start(ap, options); |
| 471 | if (options & LYD_OPT_RPCREPLY) { |
| 472 | rpc = va_arg(ap, struct lys_node*); |
| 473 | if (!rpc || (rpc->nodetype != LYS_RPC)) { |
| 474 | LOGERR(LY_EINVAL, "%s: Invalid parameter.", __func__); |
| 475 | goto cleanup; |
| 476 | } |
| 477 | } |
| 478 | |
Radek Krejci | c6704c8 | 2015-10-06 11:12:45 +0200 | [diff] [blame] | 479 | unres = calloc(1, sizeof *unres); |
Michal Vasko | 253035f | 2015-12-17 16:58:13 +0100 | [diff] [blame] | 480 | if (!unres) { |
| 481 | LOGMEM; |
Radek Krejci | 4a49bdf | 2016-01-12 17:17:01 +0100 | [diff] [blame] | 482 | goto cleanup; |
Michal Vasko | 253035f | 2015-12-17 16:58:13 +0100 | [diff] [blame] | 483 | } |
Radek Krejci | c6704c8 | 2015-10-06 11:12:45 +0200 | [diff] [blame] | 484 | |
Radek Krejci | 8653821 | 2015-12-17 15:59:01 +0100 | [diff] [blame] | 485 | if (!(options & LYD_OPT_NOSIBLINGS)) { |
| 486 | /* locate the first root to process */ |
| 487 | if ((*root)->parent) { |
| 488 | xmlstart = (*root)->parent->child; |
| 489 | } else { |
| 490 | xmlstart = *root; |
| 491 | while(xmlstart->prev->next) { |
| 492 | xmlstart = xmlstart->prev; |
| 493 | } |
Radek Krejci | 04b97de | 2015-10-31 23:09:15 +0100 | [diff] [blame] | 494 | } |
Radek Krejci | 8653821 | 2015-12-17 15:59:01 +0100 | [diff] [blame] | 495 | } else { |
| 496 | xmlstart = *root; |
| 497 | } |
| 498 | iter = result = last = NULL; |
| 499 | |
| 500 | LY_TREE_FOR_SAFE(xmlstart, xmlaux, xmlelem) { |
Radek Krejci | 4a49bdf | 2016-01-12 17:17:01 +0100 | [diff] [blame] | 501 | r = xml_parse_data(ctx, xmlelem, rpc, NULL, last, options, unres, &iter); |
Radek Krejci | 3b41a6c | 2015-10-31 23:06:12 +0100 | [diff] [blame] | 502 | if (r) { |
| 503 | LY_TREE_FOR_SAFE(result, next, iter) { |
| 504 | lyd_free(iter); |
| 505 | } |
| 506 | result = NULL; |
| 507 | goto cleanup; |
Radek Krejci | 8653821 | 2015-12-17 15:59:01 +0100 | [diff] [blame] | 508 | } else if (options & LYD_OPT_DESTRUCT) { |
| 509 | lyxml_free(ctx, xmlelem); |
| 510 | *root = xmlaux; |
Radek Krejci | 3b41a6c | 2015-10-31 23:06:12 +0100 | [diff] [blame] | 511 | } |
| 512 | if (iter) { |
| 513 | last = iter; |
| 514 | } |
| 515 | if (!result) { |
| 516 | result = iter; |
| 517 | } |
Radek Krejci | 8653821 | 2015-12-17 15:59:01 +0100 | [diff] [blame] | 518 | |
| 519 | if (options & LYD_OPT_NOSIBLINGS) { |
| 520 | /* stop after the first processed root */ |
| 521 | break; |
| 522 | } |
Radek Krejci | 3b41a6c | 2015-10-31 23:06:12 +0100 | [diff] [blame] | 523 | } |
Radek Krejci | c6704c8 | 2015-10-06 11:12:45 +0200 | [diff] [blame] | 524 | |
| 525 | /* check leafrefs and/or instids if any */ |
| 526 | if (result && resolve_unres_data(unres)) { |
| 527 | /* leafref & instid checking failed */ |
| 528 | LY_TREE_FOR_SAFE(result, next, iter) { |
| 529 | lyd_free(iter); |
| 530 | } |
| 531 | result = NULL; |
| 532 | } |
| 533 | |
Radek Krejci | 3b41a6c | 2015-10-31 23:06:12 +0100 | [diff] [blame] | 534 | cleanup: |
Radek Krejci | 4a49bdf | 2016-01-12 17:17:01 +0100 | [diff] [blame] | 535 | if (unres) { |
| 536 | free(unres->node); |
| 537 | free(unres->type); |
Radek Krejci | c6704c8 | 2015-10-06 11:12:45 +0200 | [diff] [blame] | 538 | #ifndef NDEBUG |
Radek Krejci | 4a49bdf | 2016-01-12 17:17:01 +0100 | [diff] [blame] | 539 | free(unres->line); |
Radek Krejci | c6704c8 | 2015-10-06 11:12:45 +0200 | [diff] [blame] | 540 | #endif |
Radek Krejci | 4a49bdf | 2016-01-12 17:17:01 +0100 | [diff] [blame] | 541 | free(unres); |
| 542 | } |
| 543 | va_end(ap); |
Radek Krejci | c6704c8 | 2015-10-06 11:12:45 +0200 | [diff] [blame] | 544 | |
| 545 | return result; |
| 546 | } |