blob: 345776f8c2e69a48ca606227b48c422906b5bf67 [file] [log] [blame]
Radek Krejcie7b95092019-05-15 11:03:07 +02001/**
2 * @file printer_xml.c
3 * @author Michal Vasko <mvasko@cesnet.cz>
4 * @author Radek Krejci <rkrejci@cesnet.cz>
5 * @brief XML printer for libyang data structure
6 *
7 * Copyright (c) 2015 - 2019 CESNET, z.s.p.o.
8 *
9 * This source code is licensed under BSD 3-Clause License (the "License").
10 * You may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 * https://opensource.org/licenses/BSD-3-Clause
14 */
15
Radek Krejci535ea9f2020-05-29 16:01:05 +020016#include <assert.h>
17#include <stdint.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020018#include <stdlib.h>
19#include <string.h>
20
Radek Krejci535ea9f2020-05-29 16:01:05 +020021#include "common.h"
22#include "context.h"
23#include "dict.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020024#include "log.h"
Radek Krejci7931b192020-06-25 17:05:03 +020025#include "parser_data.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020026#include "plugins_types.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020027#include "printer.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020028#include "printer_data.h"
29#include "printer_internal.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020030#include "set.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020031#include "tree.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020032#include "tree_schema.h"
33#include "xml.h"
34
35/**
36 * @brief XML printer context.
37 */
38struct xmlpr_ctx {
Radek Krejci241f6b52020-05-21 18:13:49 +020039 struct ly_out *out; /**< output specification */
Radek Krejcie7b95092019-05-15 11:03:07 +020040 unsigned int level; /**< current indentation level: 0 - no formatting, >= 1 indentation levels */
41 int options; /**< [Data printer flags](@ref dataprinterflags) */
Michal Vasko52927e22020-03-16 17:26:14 +010042 const struct ly_ctx *ctx; /**< libyang context */
43 struct ly_set prefix; /**< printed namespace prefixes */
44 struct ly_set ns; /**< printed namespaces */
Radek Krejcie7b95092019-05-15 11:03:07 +020045};
46
Michal Vasko52927e22020-03-16 17:26:14 +010047#define LYXML_PREFIX_REQUIRED 0x01 /**< The prefix is not just a suggestion but a requirement. */
Radek Krejci1798aae2020-07-14 13:26:06 +020048#define LYXML_PREFIX_DEFAULT 0x02 /**< The namespace is required to be a default (without prefix) */
Radek Krejcie7b95092019-05-15 11:03:07 +020049
50/**
Michal Vasko52927e22020-03-16 17:26:14 +010051 * @brief Print a namespace if not already printed.
52 *
53 * @param[in] ctx XML printer context.
54 * @param[in] ns Namespace to print, expected to be in dictionary.
55 * @param[in] new_prefix Suggested new prefix, NULL for a default namespace without prefix. Stored in the dictionary.
56 * @param[in] prefix_opts Prefix options changing the meaning of parameters.
57 * @return Printed prefix of the namespace to use.
Radek Krejcie7b95092019-05-15 11:03:07 +020058 */
Michal Vasko52927e22020-03-16 17:26:14 +010059static const char *
60xml_print_ns(struct xmlpr_ctx *ctx, const char *ns, const char *new_prefix, int prefix_opts)
Radek Krejcie7b95092019-05-15 11:03:07 +020061{
Michal Vasko52927e22020-03-16 17:26:14 +010062 int i;
Michal Vasko6f4cbb62020-02-28 11:15:47 +010063
Michal Vasko52927e22020-03-16 17:26:14 +010064 for (i = ctx->ns.count - 1; i > -1; --i) {
65 if (!new_prefix) {
66 /* find default namespace */
67 if (!ctx->prefix.objs[i]) {
68 if (ctx->ns.objs[i] != ns) {
69 /* different default namespace */
70 i = -1;
Radek Krejcie7b95092019-05-15 11:03:07 +020071 }
Michal Vasko52927e22020-03-16 17:26:14 +010072 break;
73 }
74 } else {
75 /* find prefixed namespace */
76 if (ctx->ns.objs[i] == ns) {
77 if (!ctx->prefix.objs[i]) {
78 /* default namespace is not interesting */
79 continue;
80 }
81
82 if (!strcmp(ctx->prefix.objs[i], new_prefix) || !(prefix_opts & LYXML_PREFIX_REQUIRED)) {
83 /* the same prefix or can be any */
84 break;
85 }
86 }
Radek Krejcie7b95092019-05-15 11:03:07 +020087 }
Radek Krejcie7b95092019-05-15 11:03:07 +020088 }
Radek Krejci28681fa2019-09-06 13:08:45 +020089
Michal Vasko52927e22020-03-16 17:26:14 +010090 if (i == -1) {
91 /* suitable namespace not found, must be printed */
Radek Krejci241f6b52020-05-21 18:13:49 +020092 ly_print(ctx->out, " xmlns%s%s=\"%s\"", new_prefix ? ":" : "", new_prefix ? new_prefix : "", ns);
Radek Krejcie7b95092019-05-15 11:03:07 +020093
Michal Vasko52927e22020-03-16 17:26:14 +010094 /* and added into namespaces */
95 if (new_prefix) {
96 new_prefix = lydict_insert(ctx->ctx, new_prefix, 0);
97 }
98 ly_set_add(&ctx->prefix, (void *)new_prefix, LY_SET_OPT_USEASLIST);
99 i = ly_set_add(&ctx->ns, (void *)ns, LY_SET_OPT_USEASLIST);
Radek Krejcie7b95092019-05-15 11:03:07 +0200100 }
Michal Vasko52927e22020-03-16 17:26:14 +0100101
102 /* return it */
103 return ctx->prefix.objs[i];
Radek Krejci28681fa2019-09-06 13:08:45 +0200104}
105
Radek Krejci1798aae2020-07-14 13:26:06 +0200106static const char*
107xml_print_ns_opaq(struct xmlpr_ctx *ctx, LYD_FORMAT format, const struct ly_prefix *prefix, int prefix_opts)
108{
109
110 switch (format) {
111 case LYD_XML:
112 return xml_print_ns(ctx, prefix->module_ns, (prefix_opts & LYXML_PREFIX_DEFAULT) ? NULL : prefix->id, prefix_opts);
113 break;
114 case LYD_JSON:
115 if (prefix->module_name) {
116 const struct lys_module *mod = ly_ctx_get_module_latest(ctx->ctx, prefix->module_name);
117 if (mod) {
118 return xml_print_ns(ctx, mod->ns, (prefix_opts & LYXML_PREFIX_DEFAULT) ? NULL : prefix->id, prefix_opts);
119 }
120 }
121 break;
Radek Krejci1798aae2020-07-14 13:26:06 +0200122 case LYD_LYB:
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200123 case LYD_UNKNOWN:
Radek Krejci1798aae2020-07-14 13:26:06 +0200124 /* cannot be created */
125 LOGINT(ctx->ctx);
126 }
127
128 return NULL;
129}
130
Radek Krejci28681fa2019-09-06 13:08:45 +0200131/**
Radek Krejcie7b95092019-05-15 11:03:07 +0200132 * TODO
133 */
Michal Vasko52927e22020-03-16 17:26:14 +0100134static void
Michal Vasko9f96a052020-03-10 09:41:45 +0100135xml_print_meta(struct xmlpr_ctx *ctx, const struct lyd_node *node)
Radek Krejcie7b95092019-05-15 11:03:07 +0200136{
Michal Vasko9f96a052020-03-10 09:41:45 +0100137 struct lyd_meta *meta;
Michal Vasko52927e22020-03-16 17:26:14 +0100138 const struct lys_module *mod;
139 struct ly_set ns_list = {0};
Radek Krejci28681fa2019-09-06 13:08:45 +0200140#if 0
Radek Krejcie7b95092019-05-15 11:03:07 +0200141 const char **prefs, **nss;
142 const char *xml_expr = NULL, *mod_name;
143 uint32_t ns_count, i;
144 int rpc_filter = 0;
Radek Krejcie7b95092019-05-15 11:03:07 +0200145 char *p;
146 size_t len;
Radek Krejci28681fa2019-09-06 13:08:45 +0200147#endif
Radek Krejci28681fa2019-09-06 13:08:45 +0200148 int dynamic;
149 unsigned int u;
Radek Krejcie7b95092019-05-15 11:03:07 +0200150
Radek Krejcie7b95092019-05-15 11:03:07 +0200151 /* with-defaults */
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100152 if (node->schema->nodetype & LYD_NODE_TERM) {
Radek Krejci7931b192020-06-25 17:05:03 +0200153 if (((node->flags & LYD_DEFAULT) && (ctx->options & (LYD_PRINT_WD_ALL_TAG | LYD_PRINT_WD_IMPL_TAG))) ||
154 ((ctx->options & LYD_PRINT_WD_ALL_TAG) && ly_is_default(node))) {
Michal Vasko52927e22020-03-16 17:26:14 +0100155 /* we have implicit OR explicit default node, print attribute only if context include with-defaults schema */
156 mod = ly_ctx_get_module_latest(node->schema->module->ctx, "ietf-netconf-with-defaults");
157 if (mod) {
Radek Krejci241f6b52020-05-21 18:13:49 +0200158 ly_print(ctx->out, " %s:default=\"true\"", xml_print_ns(ctx, mod->ns, mod->prefix, 0));
Radek Krejcie7b95092019-05-15 11:03:07 +0200159 }
160 }
161 }
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100162#if 0
Radek Krejcie7b95092019-05-15 11:03:07 +0200163 /* technically, check for the extension get-filter-element-attributes from ietf-netconf */
164 if (!strcmp(node->schema->name, "filter")
165 && (!strcmp(node->schema->module->name, "ietf-netconf") || !strcmp(node->schema->module->name, "notifications"))) {
166 rpc_filter = 1;
167 }
Radek Krejci28681fa2019-09-06 13:08:45 +0200168#endif
Michal Vasko9f96a052020-03-10 09:41:45 +0100169 for (meta = node->meta; meta; meta = meta->next) {
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200170 const char *value = meta->value.realtype->plugin->print(&meta->value, LY_PREF_XML, &ns_list, &dynamic);
Radek Krejci28681fa2019-09-06 13:08:45 +0200171
Michal Vasko52927e22020-03-16 17:26:14 +0100172 /* print namespaces connected with the value's prefixes */
Radek Krejci28681fa2019-09-06 13:08:45 +0200173 for (u = 0; u < ns_list.count; ++u) {
Michal Vasko52927e22020-03-16 17:26:14 +0100174 mod = (const struct lys_module *)ns_list.objs[u];
175 xml_print_ns(ctx, mod->ns, mod->prefix, 1);
Radek Krejci28681fa2019-09-06 13:08:45 +0200176 }
177 ly_set_erase(&ns_list, NULL);
178
179#if 0
Radek Krejcie7b95092019-05-15 11:03:07 +0200180 if (rpc_filter) {
181 /* exception for NETCONF's filter's attributes */
Michal Vasko9f96a052020-03-10 09:41:45 +0100182 if (!strcmp(meta->name, "select")) {
Radek Krejcie7b95092019-05-15 11:03:07 +0200183 /* xpath content, we have to convert the JSON format into XML first */
Michal Vasko9f96a052020-03-10 09:41:45 +0100184 xml_expr = transform_json2xml(node->schema->module, meta->value_str, 0, &prefs, &nss, &ns_count);
Radek Krejcie7b95092019-05-15 11:03:07 +0200185 if (!xml_expr) {
186 /* error */
187 return EXIT_FAILURE;
188 }
189
190 for (i = 0; i < ns_count; ++i) {
Radek Krejci241f6b52020-05-21 18:13:49 +0200191 ly_print(out, " xmlns:%s=\"%s\"", prefs[i], nss[i]);
Radek Krejcie7b95092019-05-15 11:03:07 +0200192 }
193 free(prefs);
194 free(nss);
195 }
Radek Krejci241f6b52020-05-21 18:13:49 +0200196 ly_print(out, " %s=\"", meta->name);
Radek Krejcie7b95092019-05-15 11:03:07 +0200197 } else {
Radek Krejci28681fa2019-09-06 13:08:45 +0200198#endif
Michal Vasko52927e22020-03-16 17:26:14 +0100199 /* print the metadata with its namespace */
200 mod = meta->annotation->module;
Radek Krejci241f6b52020-05-21 18:13:49 +0200201 ly_print(ctx->out, " %s:%s=\"", xml_print_ns(ctx, mod->ns, mod->prefix, 1), meta->name);
Radek Krejci28681fa2019-09-06 13:08:45 +0200202#if 0
Radek Krejcie7b95092019-05-15 11:03:07 +0200203 }
Radek Krejci28681fa2019-09-06 13:08:45 +0200204#endif
Radek Krejcie7b95092019-05-15 11:03:07 +0200205
Michal Vasko52927e22020-03-16 17:26:14 +0100206 /* print metadata value */
Radek Krejci28681fa2019-09-06 13:08:45 +0200207 if (value && value[0]) {
208 lyxml_dump_text(ctx->out, value, 1);
Radek Krejcie7b95092019-05-15 11:03:07 +0200209 }
Radek Krejci241f6b52020-05-21 18:13:49 +0200210 ly_print(ctx->out, "\"");
Radek Krejci28681fa2019-09-06 13:08:45 +0200211 if (dynamic) {
Michal Vasko52927e22020-03-16 17:26:14 +0100212 free((void *)value);
Radek Krejcie7b95092019-05-15 11:03:07 +0200213 }
214 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200215}
216
217/**
218 * @brief Print generic XML element despite of the data node type.
219 *
220 * Prints the element name, attributes and necessary namespaces.
221 *
222 * @param[in] ctx XML printer context.
223 * @param[in] node Data node to be printed.
Radek Krejcie7b95092019-05-15 11:03:07 +0200224 */
Michal Vasko52927e22020-03-16 17:26:14 +0100225static void
Radek Krejcie7b95092019-05-15 11:03:07 +0200226xml_print_node_open(struct xmlpr_ctx *ctx, const struct lyd_node *node)
227{
Michal Vasko52927e22020-03-16 17:26:14 +0100228 /* print node name */
Radek Krejci241f6b52020-05-21 18:13:49 +0200229 ly_print(ctx->out, "%*s<%s", INDENT, node->schema->name);
Michal Vasko52927e22020-03-16 17:26:14 +0100230
231 /* print default namespace */
232 xml_print_ns(ctx, node->schema->module->ns, NULL, 0);
233
234 /* print metadata */
235 xml_print_meta(ctx, node);
236}
237
238static LY_ERR
239xml_print_attr(struct xmlpr_ctx *ctx, const struct lyd_node_opaq *node)
240{
Radek Krejci5536d282020-08-04 23:27:44 +0200241 const struct lyd_attr *attr;
Michal Vasko52927e22020-03-16 17:26:14 +0100242 const char *pref;
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200243 LY_ARRAY_COUNT_TYPE u;
Michal Vasko52927e22020-03-16 17:26:14 +0100244
245 LY_LIST_FOR(node->attr, attr) {
246 pref = NULL;
Radek Krejci1798aae2020-07-14 13:26:06 +0200247 if (attr->prefix.id) {
Michal Vasko52927e22020-03-16 17:26:14 +0100248 /* print attribute namespace */
Radek Krejci1798aae2020-07-14 13:26:06 +0200249 pref = xml_print_ns_opaq(ctx, attr->format, &attr->prefix, 0);
Michal Vasko52927e22020-03-16 17:26:14 +0100250 }
251
252 /* print namespaces connected with the value's prefixes */
253 if (attr->val_prefs) {
254 LY_ARRAY_FOR(attr->val_prefs, u) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200255 xml_print_ns_opaq(ctx, attr->format, &attr->val_prefs[u], LYXML_PREFIX_REQUIRED);
Michal Vasko52927e22020-03-16 17:26:14 +0100256 }
257 }
258
259 /* print the attribute with its prefix and value */
Radek Krejci241f6b52020-05-21 18:13:49 +0200260 ly_print(ctx->out, " %s%s%s=\"%s\"", pref ? pref : "", pref ? ":" : "", attr->name, attr->value);
Radek Krejcie7b95092019-05-15 11:03:07 +0200261 }
262
Michal Vasko52927e22020-03-16 17:26:14 +0100263 return LY_SUCCESS;
264}
265
266static LY_ERR
267xml_print_opaq_open(struct xmlpr_ctx *ctx, const struct lyd_node_opaq *node)
268{
269 /* print node name */
Radek Krejci241f6b52020-05-21 18:13:49 +0200270 ly_print(ctx->out, "%*s<%s", INDENT, node->name);
Michal Vasko52927e22020-03-16 17:26:14 +0100271
272 /* print default namespace */
Radek Krejci1798aae2020-07-14 13:26:06 +0200273 xml_print_ns_opaq(ctx, node->format, &node->prefix, LYXML_PREFIX_DEFAULT);
Radek Krejcie7b95092019-05-15 11:03:07 +0200274
Michal Vasko52927e22020-03-16 17:26:14 +0100275 /* print attributes */
276 LY_CHECK_RET(xml_print_attr(ctx, node));
Radek Krejcie7b95092019-05-15 11:03:07 +0200277
278 return LY_SUCCESS;
279}
280
281static LY_ERR xml_print_node(struct xmlpr_ctx *ctx, const struct lyd_node *node);
282
283/**
284 * @brief Print XML element representing lyd_node_term.
285 *
286 * @param[in] ctx XML printer context.
287 * @param[in] node Data node to be printed.
Radek Krejcie7b95092019-05-15 11:03:07 +0200288 */
Michal Vasko52927e22020-03-16 17:26:14 +0100289static void
Radek Krejcie7b95092019-05-15 11:03:07 +0200290xml_print_term(struct xmlpr_ctx *ctx, const struct lyd_node_term *node)
291{
Radek Krejcia1911222019-07-22 17:24:50 +0200292 struct ly_set ns_list = {0};
293 unsigned int u;
294 int dynamic;
Radek Krejci28681fa2019-09-06 13:08:45 +0200295 const char *value;
296
Michal Vasko52927e22020-03-16 17:26:14 +0100297 xml_print_node_open(ctx, (struct lyd_node *)node);
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200298 value = ((struct lysc_node_leaf *)node->schema)->type->plugin->print(&node->value, LY_PREF_XML, &ns_list, &dynamic);
Radek Krejcie7b95092019-05-15 11:03:07 +0200299
Radek Krejcia1911222019-07-22 17:24:50 +0200300 /* print namespaces connected with the values's prefixes */
301 for (u = 0; u < ns_list.count; ++u) {
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100302 const struct lys_module *mod = (const struct lys_module *)ns_list.objs[u];
Radek Krejci241f6b52020-05-21 18:13:49 +0200303 ly_print(ctx->out, " xmlns:%s=\"%s\"", mod->prefix, mod->ns);
Radek Krejcie7b95092019-05-15 11:03:07 +0200304 }
Radek Krejcia1911222019-07-22 17:24:50 +0200305 ly_set_erase(&ns_list, NULL);
Radek Krejcie7b95092019-05-15 11:03:07 +0200306
Radek Krejcia1911222019-07-22 17:24:50 +0200307 if (!value || !value[0]) {
Radek Krejci5536d282020-08-04 23:27:44 +0200308 ly_print(ctx->out, "/>%s", DO_FORMAT ? "\n" : "");
Radek Krejcie7b95092019-05-15 11:03:07 +0200309 } else {
Radek Krejci241f6b52020-05-21 18:13:49 +0200310 ly_print(ctx->out, ">");
Radek Krejcia1911222019-07-22 17:24:50 +0200311 lyxml_dump_text(ctx->out, value, 0);
Radek Krejci5536d282020-08-04 23:27:44 +0200312 ly_print(ctx->out, "</%s>%s", node->schema->name, DO_FORMAT ? "\n" : "");
Radek Krejcie7b95092019-05-15 11:03:07 +0200313 }
Radek Krejcia1911222019-07-22 17:24:50 +0200314 if (dynamic) {
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100315 free((void *)value);
Radek Krejcia1911222019-07-22 17:24:50 +0200316 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200317}
318
319/**
320 * @brief Print XML element representing lyd_node_inner.
321 *
322 * @param[in] ctx XML printer context.
323 * @param[in] node Data node to be printed.
324 * @return LY_ERR value.
325 */
326static LY_ERR
327xml_print_inner(struct xmlpr_ctx *ctx, const struct lyd_node_inner *node)
328{
329 LY_ERR ret;
330 struct lyd_node *child;
331
Michal Vasko52927e22020-03-16 17:26:14 +0100332 xml_print_node_open(ctx, (struct lyd_node *)node);
Radek Krejcie7b95092019-05-15 11:03:07 +0200333
334 if (!node->child) {
Radek Krejci5536d282020-08-04 23:27:44 +0200335 ly_print(ctx->out, "/>%s", DO_FORMAT ? "\n" : "");
Radek Krejcie7b95092019-05-15 11:03:07 +0200336 return LY_SUCCESS;
337 }
338
339 /* children */
Radek Krejci5536d282020-08-04 23:27:44 +0200340 ly_print(ctx->out, ">%s", DO_FORMAT ? "\n" : "");
Radek Krejcie7b95092019-05-15 11:03:07 +0200341
342 LEVEL_INC;
343 LY_LIST_FOR(node->child, child) {
344 ret = xml_print_node(ctx, child);
345 LY_CHECK_ERR_RET(ret, LEVEL_DEC, ret);
346 }
347 LEVEL_DEC;
348
Radek Krejci5536d282020-08-04 23:27:44 +0200349 ly_print(ctx->out, "%*s</%s>%s", INDENT, node->schema->name, DO_FORMAT ? "\n" : "");
Radek Krejcie7b95092019-05-15 11:03:07 +0200350
351 return LY_SUCCESS;
352}
353
Radek Krejci26a5dfb2019-07-26 14:51:06 +0200354static LY_ERR
355xml_print_anydata(struct xmlpr_ctx *ctx, const struct lyd_node_any *node)
Radek Krejcie7b95092019-05-15 11:03:07 +0200356{
Radek Krejci26a5dfb2019-07-26 14:51:06 +0200357 struct lyd_node_any *any = (struct lyd_node_any *)node;
Radek Krejcie7b95092019-05-15 11:03:07 +0200358 struct lyd_node *iter;
Michal Vasko60ea6352020-06-29 13:39:39 +0200359 int prev_opts, prev_lo;
Michal Vasko52927e22020-03-16 17:26:14 +0100360 LY_ERR ret;
Radek Krejcie7b95092019-05-15 11:03:07 +0200361
Michal Vasko52927e22020-03-16 17:26:14 +0100362 xml_print_node_open(ctx, (struct lyd_node *)node);
Radek Krejcie7b95092019-05-15 11:03:07 +0200363
Radek Krejci26a5dfb2019-07-26 14:51:06 +0200364 if (!any->value.tree) {
Radek Krejcie7b95092019-05-15 11:03:07 +0200365 /* no content */
Radek Krejci26a5dfb2019-07-26 14:51:06 +0200366no_content:
Radek Krejci5536d282020-08-04 23:27:44 +0200367 ly_print(ctx->out, "/>%s", DO_FORMAT ? "\n" : "");
Radek Krejci26a5dfb2019-07-26 14:51:06 +0200368 return LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200369 } else {
Michal Vasko60ea6352020-06-29 13:39:39 +0200370 if (any->value_type == LYD_ANYDATA_LYB) {
371 /* turn logging off */
372 prev_lo = ly_log_options(0);
373
374 /* try to parse it into a data tree */
Radek Krejci7931b192020-06-25 17:05:03 +0200375 if (lyd_parse_data_mem((struct ly_ctx *)LYD_NODE_CTX(node), any->value.mem, LYD_LYB, LYD_PARSE_ONLY | LYD_PARSE_OPAQ | LYD_PARSE_STRICT, 0, &iter) == LY_SUCCESS) {
Michal Vasko60ea6352020-06-29 13:39:39 +0200376 /* successfully parsed */
377 free(any->value.mem);
378 any->value.tree = iter;
379 any->value_type = LYD_ANYDATA_DATATREE;
380 }
Radek Krejci7931b192020-06-25 17:05:03 +0200381
382 /* turn loggin on again */
383 ly_log_options(prev_lo);
Michal Vasko60ea6352020-06-29 13:39:39 +0200384 }
385
Radek Krejcie7b95092019-05-15 11:03:07 +0200386 switch (any->value_type) {
Radek Krejcie7b95092019-05-15 11:03:07 +0200387 case LYD_ANYDATA_DATATREE:
Radek Krejci26a5dfb2019-07-26 14:51:06 +0200388 /* close opening tag and print data */
Michal Vasko52927e22020-03-16 17:26:14 +0100389 prev_opts = ctx->options;
Radek Krejci7931b192020-06-25 17:05:03 +0200390 ctx->options &= ~LYD_PRINT_WITHSIBLINGS;
Radek Krejci26a5dfb2019-07-26 14:51:06 +0200391 LEVEL_INC;
392
Radek Krejci5536d282020-08-04 23:27:44 +0200393 ly_print(ctx->out, ">%s", DO_FORMAT ? "\n" : "");
Radek Krejci26a5dfb2019-07-26 14:51:06 +0200394 LY_LIST_FOR(any->value.tree, iter) {
Michal Vasko52927e22020-03-16 17:26:14 +0100395 ret = xml_print_node(ctx, iter);
396 LY_CHECK_ERR_RET(ret, LEVEL_DEC, ret);
Radek Krejcie7b95092019-05-15 11:03:07 +0200397 }
Radek Krejci26a5dfb2019-07-26 14:51:06 +0200398
399 LEVEL_DEC;
Michal Vasko52927e22020-03-16 17:26:14 +0100400 ctx->options = prev_opts;
Radek Krejcie7b95092019-05-15 11:03:07 +0200401 break;
402 case LYD_ANYDATA_STRING:
Radek Krejci26a5dfb2019-07-26 14:51:06 +0200403 /* escape XML-sensitive characters */
404 if (!any->value.str[0]) {
405 goto no_content;
406 }
407 /* close opening tag and print data */
Radek Krejci241f6b52020-05-21 18:13:49 +0200408 ly_print(ctx->out, ">");
Radek Krejci26a5dfb2019-07-26 14:51:06 +0200409 lyxml_dump_text(ctx->out, any->value.str, 0);
Radek Krejcie7b95092019-05-15 11:03:07 +0200410 break;
Radek Krejci26a5dfb2019-07-26 14:51:06 +0200411 case LYD_ANYDATA_XML:
412 /* print without escaping special characters */
413 if (!any->value.str[0]) {
414 goto no_content;
415 }
Radek Krejci241f6b52020-05-21 18:13:49 +0200416 ly_print(ctx->out, ">%s", any->value.str);
Radek Krejci26a5dfb2019-07-26 14:51:06 +0200417 break;
418 case LYD_ANYDATA_JSON:
Radek Krejci26a5dfb2019-07-26 14:51:06 +0200419 case LYD_ANYDATA_LYB:
Radek Krejci26a5dfb2019-07-26 14:51:06 +0200420 /* JSON and LYB format is not supported */
Michal Vasko60ea6352020-06-29 13:39:39 +0200421 LOGWRN(LYD_NODE_CTX(node), "Unable to print anydata content (type %d) as XML.", any->value_type);
Radek Krejci26a5dfb2019-07-26 14:51:06 +0200422 goto no_content;
Radek Krejcie7b95092019-05-15 11:03:07 +0200423 }
424
425 /* closing tag */
Radek Krejci26a5dfb2019-07-26 14:51:06 +0200426 if (any->value_type == LYD_ANYDATA_DATATREE) {
Radek Krejci5536d282020-08-04 23:27:44 +0200427 ly_print(ctx->out, "%*s</%s>%s", INDENT, node->schema->name, DO_FORMAT ? "\n" : "");
Radek Krejci26a5dfb2019-07-26 14:51:06 +0200428 } else {
Radek Krejci5536d282020-08-04 23:27:44 +0200429 ly_print(ctx->out, "</%s>%s", node->schema->name, DO_FORMAT ? "\n" : "");
Radek Krejci26a5dfb2019-07-26 14:51:06 +0200430 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200431 }
432
Radek Krejci26a5dfb2019-07-26 14:51:06 +0200433 return LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200434}
Radek Krejcie7b95092019-05-15 11:03:07 +0200435
Michal Vasko52927e22020-03-16 17:26:14 +0100436static LY_ERR
437xml_print_opaq(struct xmlpr_ctx *ctx, const struct lyd_node_opaq *node)
438{
439 LY_ERR ret;
440 struct lyd_node *child;
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200441 LY_ARRAY_COUNT_TYPE u;
Michal Vasko52927e22020-03-16 17:26:14 +0100442
443 LY_CHECK_RET(xml_print_opaq_open(ctx, node));
444
445 if (node->value[0]) {
446 /* print namespaces connected with the value's prefixes */
447 if (node->val_prefs) {
448 LY_ARRAY_FOR(node->val_prefs, u) {
Radek Krejci1798aae2020-07-14 13:26:06 +0200449 xml_print_ns_opaq(ctx, node->format, &node->val_prefs[u], LYXML_PREFIX_REQUIRED);
Michal Vasko52927e22020-03-16 17:26:14 +0100450 }
451 }
452
Radek Krejci241f6b52020-05-21 18:13:49 +0200453 ly_print(ctx->out, ">%s", node->value);
Michal Vasko52927e22020-03-16 17:26:14 +0100454 }
455
456 if (node->child) {
457 /* children */
458 if (!node->value[0]) {
Radek Krejci5536d282020-08-04 23:27:44 +0200459 ly_print(ctx->out, ">%s", DO_FORMAT ? "\n" : "");
Michal Vasko52927e22020-03-16 17:26:14 +0100460 }
461
462 LEVEL_INC;
463 LY_LIST_FOR(node->child, child) {
464 ret = xml_print_node(ctx, child);
465 LY_CHECK_ERR_RET(ret, LEVEL_DEC, ret);
466 }
467 LEVEL_DEC;
468
Radek Krejci5536d282020-08-04 23:27:44 +0200469 ly_print(ctx->out, "%*s</%s>%s", INDENT, node->name, DO_FORMAT ? "\n" : "");
Michal Vasko52927e22020-03-16 17:26:14 +0100470 } else if (node->value[0]) {
Radek Krejci5536d282020-08-04 23:27:44 +0200471 ly_print(ctx->out, "</%s>%s", node->name, DO_FORMAT ? "\n" : "");
Michal Vasko52927e22020-03-16 17:26:14 +0100472 } else {
473 /* no value or children */
Radek Krejci5536d282020-08-04 23:27:44 +0200474 ly_print(ctx->out, "/>%s", DO_FORMAT ? "\n" : "");
Michal Vasko52927e22020-03-16 17:26:14 +0100475 }
476
477 return LY_SUCCESS;
478}
479
Radek Krejcie7b95092019-05-15 11:03:07 +0200480/**
481 * @brief Print XML element representing lyd_node.
482 *
483 * @param[in] ctx XML printer context.
484 * @param[in] node Data node to be printed.
485 * @return LY_ERR value.
486 */
487static LY_ERR
488xml_print_node(struct xmlpr_ctx *ctx, const struct lyd_node *node)
489{
490 LY_ERR ret = LY_SUCCESS;
Michal Vasko52927e22020-03-16 17:26:14 +0100491 uint32_t ns_count;
Radek Krejcie7b95092019-05-15 11:03:07 +0200492
Michal Vasko9b368d32020-02-14 13:53:31 +0100493 if (!ly_should_print(node, ctx->options)) {
494 /* do not print at all */
Michal Vasko52927e22020-03-16 17:26:14 +0100495 return LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200496 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200497
Michal Vasko52927e22020-03-16 17:26:14 +0100498 /* remember namespace definition count on this level */
499 ns_count = ctx->ns.count;
500
501 if (!node->schema) {
502 ret = xml_print_opaq(ctx, (const struct lyd_node_opaq *)node);
503 } else {
504 switch (node->schema->nodetype) {
505 case LYS_CONTAINER:
506 case LYS_LIST:
507 case LYS_NOTIF:
Michal Vasko1bf09392020-03-27 12:38:10 +0100508 case LYS_RPC:
Michal Vasko52927e22020-03-16 17:26:14 +0100509 case LYS_ACTION:
510 ret = xml_print_inner(ctx, (const struct lyd_node_inner *)node);
511 break;
512 case LYS_LEAF:
513 case LYS_LEAFLIST:
514 xml_print_term(ctx, (const struct lyd_node_term *)node);
515 break;
516 case LYS_ANYXML:
517 case LYS_ANYDATA:
518 ret = xml_print_anydata(ctx, (const struct lyd_node_any *)node);
519 break;
520 default:
521 LOGINT(node->schema->module->ctx);
522 ret = LY_EINT;
523 break;
524 }
525 }
526
527 /* remove all added namespaces */
528 while (ns_count < ctx->ns.count) {
529 FREE_STRING(ctx->ctx, ctx->prefix.objs[ctx->prefix.count - 1]);
530 ly_set_rm_index(&ctx->prefix, ctx->prefix.count - 1, NULL);
531 ly_set_rm_index(&ctx->ns, ctx->ns.count - 1, NULL);
Radek Krejcie7b95092019-05-15 11:03:07 +0200532 }
533
534 return ret;
535}
536
537LY_ERR
Radek Krejci241f6b52020-05-21 18:13:49 +0200538xml_print_data(struct ly_out *out, const struct lyd_node *root, int options)
Radek Krejcie7b95092019-05-15 11:03:07 +0200539{
540 const struct lyd_node *node;
Michal Vasko52927e22020-03-16 17:26:14 +0100541 struct xmlpr_ctx ctx = {0};
Radek Krejcie7b95092019-05-15 11:03:07 +0200542
543 if (!root) {
Radek Krejci241f6b52020-05-21 18:13:49 +0200544 if (out->type == LY_OUT_MEMORY || out->type == LY_OUT_CALLBACK) {
545 ly_print(out, "");
Radek Krejcie7b95092019-05-15 11:03:07 +0200546 }
547 goto finish;
548 }
549
Michal Vasko52927e22020-03-16 17:26:14 +0100550 ctx.out = out;
Radek Krejci7931b192020-06-25 17:05:03 +0200551 ctx.level = (options & LYD_PRINT_FORMAT ? 1 : 0);
Michal Vasko52927e22020-03-16 17:26:14 +0100552 ctx.options = options;
553 ctx.ctx = LYD_NODE_CTX(root);
554
Radek Krejcie7b95092019-05-15 11:03:07 +0200555 /* content */
556 LY_LIST_FOR(root, node) {
Michal Vasko52927e22020-03-16 17:26:14 +0100557 LY_CHECK_RET(xml_print_node(&ctx, node));
Radek Krejci7931b192020-06-25 17:05:03 +0200558 if (!(options & LYD_PRINT_WITHSIBLINGS)) {
Radek Krejcie7b95092019-05-15 11:03:07 +0200559 break;
560 }
561 }
562
563finish:
Michal Vasko52927e22020-03-16 17:26:14 +0100564 assert(!ctx.prefix.count && !ctx.ns.count);
565 ly_set_erase(&ctx.prefix, NULL);
566 ly_set_erase(&ctx.ns, NULL);
Radek Krejcie7b95092019-05-15 11:03:07 +0200567 ly_print_flush(out);
568 return LY_SUCCESS;
569}
570