|
Packit |
8fb591 |
/**
|
|
Packit |
8fb591 |
* @file printer_xml.c
|
|
Packit |
8fb591 |
* @author Michal Vasko <mvasko@cesnet.cz>
|
|
Packit |
8fb591 |
* @brief XML printer for libyang data structure
|
|
Packit |
8fb591 |
*
|
|
Packit |
8fb591 |
* Copyright (c) 2015 CESNET, z.s.p.o.
|
|
Packit |
8fb591 |
*
|
|
Packit |
8fb591 |
* This source code is licensed under BSD 3-Clause License (the "License").
|
|
Packit |
8fb591 |
* You may not use this file except in compliance with the License.
|
|
Packit |
8fb591 |
* You may obtain a copy of the License at
|
|
Packit |
8fb591 |
*
|
|
Packit |
8fb591 |
* https://opensource.org/licenses/BSD-3-Clause
|
|
Packit |
8fb591 |
*/
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
#define _GNU_SOURCE
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
#include <stdlib.h>
|
|
Packit |
8fb591 |
#include <stdio.h>
|
|
Packit |
8fb591 |
#include <string.h>
|
|
Packit |
8fb591 |
#include <assert.h>
|
|
Packit |
8fb591 |
#include <inttypes.h>
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
#include "common.h"
|
|
Packit |
8fb591 |
#include "parser.h"
|
|
Packit |
8fb591 |
#include "printer.h"
|
|
Packit |
8fb591 |
#include "xml_internal.h"
|
|
Packit |
8fb591 |
#include "tree_data.h"
|
|
Packit |
8fb591 |
#include "tree_schema.h"
|
|
Packit |
8fb591 |
#include "resolve.h"
|
|
Packit |
8fb591 |
#include "tree_internal.h"
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
#define INDENT ""
|
|
Packit |
8fb591 |
#define LEVEL (level ? level*2-2 : 0)
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
struct mlist {
|
|
Packit |
8fb591 |
struct mlist *next;
|
|
Packit |
8fb591 |
struct lys_module *module;
|
|
Packit |
8fb591 |
} *mlist = NULL, *mlist_new;
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
static int
|
|
Packit |
8fb591 |
modlist_add(struct mlist **mlist, const struct lys_module *mod)
|
|
Packit |
8fb591 |
{
|
|
Packit |
8fb591 |
struct mlist *iter;
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
for (iter = *mlist; iter; iter = iter->next) {
|
|
Packit |
8fb591 |
if (mod == iter->module) {
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
if (!iter) {
|
|
Packit |
8fb591 |
iter = malloc(sizeof *iter);
|
|
Packit |
8fb591 |
LY_CHECK_ERR_RETURN(!iter, LOGMEM(mod->ctx), EXIT_FAILURE);
|
|
Packit |
8fb591 |
iter->next = *mlist;
|
|
Packit |
8fb591 |
iter->module = (struct lys_module *)mod;
|
|
Packit |
8fb591 |
*mlist = iter;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
return EXIT_SUCCESS;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
static void
|
|
Packit |
8fb591 |
xml_print_ns(struct lyout *out, const struct lyd_node *node, int options)
|
|
Packit |
8fb591 |
{
|
|
Packit |
8fb591 |
struct lyd_node *next, *cur, *node2;
|
|
Packit |
8fb591 |
struct lyd_attr *attr;
|
|
Packit |
8fb591 |
const struct lys_module *wdmod = NULL;
|
|
Packit |
8fb591 |
struct mlist *mlist = NULL, *miter;
|
|
Packit |
8fb591 |
int r;
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
assert(out);
|
|
Packit |
8fb591 |
assert(node);
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
/* add node attribute modules */
|
|
Packit |
8fb591 |
for (attr = node->attr; attr; attr = attr->next) {
|
|
Packit |
8fb591 |
if (!strcmp(node->schema->name, "filter") &&
|
|
Packit |
8fb591 |
(!strcmp(node->schema->module->name, "ietf-netconf") ||
|
|
Packit |
8fb591 |
!strcmp(node->schema->module->name, "notifications"))) {
|
|
Packit |
8fb591 |
/* exception for NETCONF's filter attributes */
|
|
Packit |
8fb591 |
continue;
|
|
Packit |
8fb591 |
} else {
|
|
Packit |
8fb591 |
r = modlist_add(&mlist, lys_main_module(attr->annotation->module));
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
if (r) {
|
|
Packit |
8fb591 |
goto print;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
/* add node children nodes and attribute modules */
|
|
Packit |
8fb591 |
switch (node->schema->nodetype) {
|
|
Packit |
8fb591 |
case LYS_LEAFLIST:
|
|
Packit |
8fb591 |
case LYS_LEAF:
|
|
Packit |
8fb591 |
if (node->dflt && (options & (LYP_WD_ALL_TAG | LYP_WD_IMPL_TAG))) {
|
|
Packit |
8fb591 |
/* get with-defaults module and print its namespace */
|
|
Packit |
8fb591 |
wdmod = ly_ctx_get_module(node->schema->module->ctx, "ietf-netconf-with-defaults", NULL, 1);
|
|
Packit |
8fb591 |
if (wdmod && modlist_add(&mlist, wdmod)) {
|
|
Packit |
8fb591 |
goto print;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
case LYS_CONTAINER:
|
|
Packit |
8fb591 |
case LYS_LIST:
|
|
Packit |
8fb591 |
case LYS_RPC:
|
|
Packit |
8fb591 |
case LYS_ACTION:
|
|
Packit |
8fb591 |
case LYS_NOTIF:
|
|
Packit |
8fb591 |
if (options & (LYP_WD_ALL_TAG | LYP_WD_IMPL_TAG)) {
|
|
Packit |
8fb591 |
/* get with-defaults module and print its namespace */
|
|
Packit |
8fb591 |
wdmod = ly_ctx_get_module(node->schema->module->ctx, "ietf-netconf-with-defaults", NULL, 1);
|
|
Packit |
8fb591 |
if (wdmod && modlist_add(&mlist, wdmod)) {
|
|
Packit |
8fb591 |
goto print;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
LY_TREE_FOR(node->child, node2) {
|
|
Packit |
8fb591 |
LY_TREE_DFS_BEGIN(node2, next, cur) {
|
|
Packit |
8fb591 |
for (attr = cur->attr; attr; attr = attr->next) {
|
|
Packit |
8fb591 |
if (!strcmp(cur->schema->name, "filter") &&
|
|
Packit |
8fb591 |
(!strcmp(cur->schema->module->name, "ietf-netconf") ||
|
|
Packit |
8fb591 |
!strcmp(cur->schema->module->name, "notifications"))) {
|
|
Packit |
8fb591 |
/* exception for NETCONF's filter attributes */
|
|
Packit |
8fb591 |
continue;
|
|
Packit |
8fb591 |
} else {
|
|
Packit |
8fb591 |
r = modlist_add(&mlist, lys_main_module(attr->annotation->module));
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
if (r) {
|
|
Packit |
8fb591 |
goto print;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
LY_TREE_DFS_END(node2, next, cur)}
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
default:
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
print:
|
|
Packit |
8fb591 |
/* print used namespaces */
|
|
Packit |
8fb591 |
while (mlist) {
|
|
Packit |
8fb591 |
miter = mlist;
|
|
Packit |
8fb591 |
mlist = mlist->next;
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
ly_print(out, " xmlns:%s=\"%s\"", miter->module->prefix, miter->module->ns);
|
|
Packit |
8fb591 |
free(miter);
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
static int
|
|
Packit |
8fb591 |
xml_print_attrs(struct lyout *out, const struct lyd_node *node, int options)
|
|
Packit |
8fb591 |
{
|
|
Packit |
8fb591 |
struct lyd_attr *attr;
|
|
Packit |
8fb591 |
const char **prefs, **nss;
|
|
Packit |
8fb591 |
const char *xml_expr = NULL, *mod_name;
|
|
Packit |
8fb591 |
uint32_t ns_count, i;
|
|
Packit |
8fb591 |
int rpc_filter = 0;
|
|
Packit |
8fb591 |
const struct lys_module *wdmod = NULL;
|
|
Packit |
8fb591 |
char *p;
|
|
Packit |
8fb591 |
size_t len;
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
/* with-defaults */
|
|
Packit |
8fb591 |
if (node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
|
|
Packit |
8fb591 |
if ((node->dflt && (options & (LYP_WD_ALL_TAG | LYP_WD_IMPL_TAG))) ||
|
|
Packit |
8fb591 |
(!node->dflt && (options & LYP_WD_ALL_TAG) && lyd_wd_default((struct lyd_node_leaf_list *)node))) {
|
|
Packit |
8fb591 |
/* we have implicit OR explicit default node */
|
|
Packit |
8fb591 |
/* get with-defaults module */
|
|
Packit |
8fb591 |
wdmod = ly_ctx_get_module(node->schema->module->ctx, "ietf-netconf-with-defaults", NULL, 1);
|
|
Packit |
8fb591 |
if (wdmod) {
|
|
Packit |
8fb591 |
/* print attribute only if context include with-defaults schema */
|
|
Packit |
8fb591 |
ly_print(out, " %s:default=\"true\"", wdmod->prefix);
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
/* technically, check for the extension get-filter-element-attributes from ietf-netconf */
|
|
Packit |
8fb591 |
if (!strcmp(node->schema->name, "filter")
|
|
Packit |
8fb591 |
&& (!strcmp(node->schema->module->name, "ietf-netconf") || !strcmp(node->schema->module->name, "notifications"))) {
|
|
Packit |
8fb591 |
rpc_filter = 1;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
for (attr = node->attr; attr; attr = attr->next) {
|
|
Packit |
8fb591 |
if (rpc_filter) {
|
|
Packit |
8fb591 |
/* exception for NETCONF's filter's attributes */
|
|
Packit |
8fb591 |
if (!strcmp(attr->name, "select")) {
|
|
Packit |
8fb591 |
/* xpath content, we have to convert the JSON format into XML first */
|
|
Packit |
8fb591 |
xml_expr = transform_json2xml(node->schema->module, attr->value_str, 0, &prefs, &nss, &ns_count);
|
|
Packit |
8fb591 |
if (!xml_expr) {
|
|
Packit |
8fb591 |
/* error */
|
|
Packit |
8fb591 |
ly_print(out, "\"(!error!)\"");
|
|
Packit |
8fb591 |
return EXIT_FAILURE;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
for (i = 0; i < ns_count; ++i) {
|
|
Packit |
8fb591 |
ly_print(out, " xmlns:%s=\"%s\"", prefs[i], nss[i]);
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
free(prefs);
|
|
Packit |
8fb591 |
free(nss);
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
ly_print(out, " %s=\"", attr->name);
|
|
Packit |
8fb591 |
} else {
|
|
Packit |
8fb591 |
ly_print(out, " %s:%s=\"", attr->annotation->module->prefix, attr->name);
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
switch (attr->value_type) {
|
|
Packit |
8fb591 |
case LY_TYPE_BINARY:
|
|
Packit |
8fb591 |
case LY_TYPE_STRING:
|
|
Packit |
8fb591 |
case LY_TYPE_BITS:
|
|
Packit |
8fb591 |
case LY_TYPE_ENUM:
|
|
Packit |
8fb591 |
case LY_TYPE_BOOL:
|
|
Packit |
8fb591 |
case LY_TYPE_DEC64:
|
|
Packit |
8fb591 |
case LY_TYPE_INT8:
|
|
Packit |
8fb591 |
case LY_TYPE_INT16:
|
|
Packit |
8fb591 |
case LY_TYPE_INT32:
|
|
Packit |
8fb591 |
case LY_TYPE_INT64:
|
|
Packit |
8fb591 |
case LY_TYPE_UINT8:
|
|
Packit |
8fb591 |
case LY_TYPE_UINT16:
|
|
Packit |
8fb591 |
case LY_TYPE_UINT32:
|
|
Packit |
8fb591 |
case LY_TYPE_UINT64:
|
|
Packit |
8fb591 |
if (attr->value_str) {
|
|
Packit |
8fb591 |
/* xml_expr can contain transformed xpath */
|
|
Packit |
8fb591 |
lyxml_dump_text(out, xml_expr ? xml_expr : attr->value_str, LYXML_DATA_ATTR);
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
case LY_TYPE_IDENT:
|
|
Packit |
8fb591 |
if (!attr->value_str) {
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
p = strchr(attr->value_str, ':');
|
|
Packit |
8fb591 |
assert(p);
|
|
Packit |
8fb591 |
len = p - attr->value_str;
|
|
Packit |
8fb591 |
mod_name = attr->annotation->module->name;
|
|
Packit |
8fb591 |
if (!strncmp(attr->value_str, mod_name, len) && !mod_name[len]) {
|
|
Packit |
8fb591 |
lyxml_dump_text(out, ++p, LYXML_DATA_ATTR);
|
|
Packit |
8fb591 |
} else {
|
|
Packit |
8fb591 |
/* avoid code duplication - use instance-identifier printer which gets necessary namespaces to print */
|
|
Packit |
8fb591 |
goto printinst;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
case LY_TYPE_INST:
|
|
Packit |
8fb591 |
printinst:
|
|
Packit |
8fb591 |
xml_expr = transform_json2xml(node->schema->module, ((struct lyd_node_leaf_list *)node)->value_str, 1,
|
|
Packit |
8fb591 |
&prefs, &nss, &ns_count);
|
|
Packit |
8fb591 |
if (!xml_expr) {
|
|
Packit |
8fb591 |
/* error */
|
|
Packit |
8fb591 |
ly_print(out, "(!error!)");
|
|
Packit |
8fb591 |
return EXIT_FAILURE;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
for (i = 0; i < ns_count; ++i) {
|
|
Packit |
8fb591 |
ly_print(out, " xmlns:%s=\"%s\"", prefs[i], nss[i]);
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
free(prefs);
|
|
Packit |
8fb591 |
free(nss);
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
lyxml_dump_text(out, xml_expr, LYXML_DATA_ATTR);
|
|
Packit |
8fb591 |
lydict_remove(node->schema->module->ctx, xml_expr);
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
/* LY_TYPE_LEAFREF not allowed */
|
|
Packit |
8fb591 |
case LY_TYPE_EMPTY:
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
default:
|
|
Packit |
8fb591 |
/* error */
|
|
Packit |
8fb591 |
ly_print(out, "(!error!)");
|
|
Packit |
8fb591 |
return EXIT_FAILURE;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
ly_print(out, "\"");
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
if (xml_expr) {
|
|
Packit |
8fb591 |
lydict_remove(node->schema->module->ctx, xml_expr);
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
return EXIT_SUCCESS;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
static int
|
|
Packit |
8fb591 |
xml_print_leaf(struct lyout *out, int level, const struct lyd_node *node, int toplevel, int options)
|
|
Packit |
8fb591 |
{
|
|
Packit |
8fb591 |
const struct lyd_node_leaf_list *leaf = (struct lyd_node_leaf_list *)node, *iter;
|
|
Packit |
8fb591 |
const struct lys_type *type;
|
|
Packit |
8fb591 |
struct lys_tpdf *tpdf;
|
|
Packit |
8fb591 |
const char *ns, *mod_name;
|
|
Packit |
8fb591 |
const char **prefs, **nss;
|
|
Packit |
8fb591 |
const char *xml_expr;
|
|
Packit |
8fb591 |
uint32_t ns_count, i;
|
|
Packit |
8fb591 |
LY_DATA_TYPE datatype;
|
|
Packit |
8fb591 |
char *p;
|
|
Packit |
8fb591 |
size_t len;
|
|
Packit |
8fb591 |
enum int_log_opts prev_ilo;
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
if (toplevel || !node->parent || nscmp(node, node->parent)) {
|
|
Packit |
8fb591 |
/* print "namespace" */
|
|
Packit |
8fb591 |
ns = lyd_node_module(node)->ns;
|
|
Packit |
8fb591 |
ly_print(out, "%*s<%s xmlns=\"%s\"", LEVEL, INDENT, node->schema->name, ns);
|
|
Packit |
8fb591 |
} else {
|
|
Packit |
8fb591 |
ly_print(out, "%*s<%s", LEVEL, INDENT, node->schema->name);
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
if (toplevel) {
|
|
Packit |
8fb591 |
xml_print_ns(out, node, options);
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
if (xml_print_attrs(out, node, options)) {
|
|
Packit |
8fb591 |
return EXIT_FAILURE;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
datatype = leaf->value_type;
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
printvalue:
|
|
Packit |
8fb591 |
switch (datatype) {
|
|
Packit |
8fb591 |
case LY_TYPE_STRING:
|
|
Packit |
8fb591 |
ly_ilo_change(NULL, ILO_IGNORE, &prev_ilo, NULL);
|
|
Packit |
8fb591 |
type = lyd_leaf_type((struct lyd_node_leaf_list *)leaf);
|
|
Packit |
8fb591 |
ly_ilo_restore(NULL, prev_ilo, NULL, 0);
|
|
Packit |
8fb591 |
if (type) {
|
|
Packit |
8fb591 |
for (tpdf = type->der;
|
|
Packit |
8fb591 |
tpdf->module && (strcmp(tpdf->name, "xpath1.0") || strcmp(tpdf->module->name, "ietf-yang-types"));
|
|
Packit |
8fb591 |
tpdf = tpdf->type.der);
|
|
Packit |
8fb591 |
/* special handling of ietf-yang-types xpath1.0 */
|
|
Packit |
8fb591 |
if (tpdf->module) {
|
|
Packit |
8fb591 |
/* avoid code duplication - use instance-identifier printer which gets necessary namespaces to print */
|
|
Packit |
8fb591 |
datatype = LY_TYPE_INST;
|
|
Packit |
8fb591 |
goto printvalue;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
/* fallthrough */
|
|
Packit |
8fb591 |
case LY_TYPE_BINARY:
|
|
Packit |
8fb591 |
case LY_TYPE_BITS:
|
|
Packit |
8fb591 |
case LY_TYPE_ENUM:
|
|
Packit |
8fb591 |
case LY_TYPE_BOOL:
|
|
Packit |
8fb591 |
case LY_TYPE_UNION:
|
|
Packit |
8fb591 |
case LY_TYPE_DEC64:
|
|
Packit |
8fb591 |
case LY_TYPE_INT8:
|
|
Packit |
8fb591 |
case LY_TYPE_INT16:
|
|
Packit |
8fb591 |
case LY_TYPE_INT32:
|
|
Packit |
8fb591 |
case LY_TYPE_INT64:
|
|
Packit |
8fb591 |
case LY_TYPE_UINT8:
|
|
Packit |
8fb591 |
case LY_TYPE_UINT16:
|
|
Packit |
8fb591 |
case LY_TYPE_UINT32:
|
|
Packit |
8fb591 |
case LY_TYPE_UINT64:
|
|
Packit |
8fb591 |
if (!leaf->value_str || !leaf->value_str[0]) {
|
|
Packit |
8fb591 |
ly_print(out, "/>");
|
|
Packit |
8fb591 |
} else {
|
|
Packit |
8fb591 |
ly_print(out, ">");
|
|
Packit |
8fb591 |
lyxml_dump_text(out, leaf->value_str, LYXML_DATA_ELEM);
|
|
Packit |
8fb591 |
ly_print(out, "</%s>", node->schema->name);
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
case LY_TYPE_IDENT:
|
|
Packit |
8fb591 |
if (!leaf->value_str || !leaf->value_str[0]) {
|
|
Packit |
8fb591 |
ly_print(out, "/>");
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
p = strchr(leaf->value_str, ':');
|
|
Packit |
8fb591 |
assert(p);
|
|
Packit |
8fb591 |
len = p - leaf->value_str;
|
|
Packit |
8fb591 |
mod_name = leaf->schema->module->name;
|
|
Packit |
8fb591 |
if (!strncmp(leaf->value_str, mod_name, len) && !mod_name[len]) {
|
|
Packit |
8fb591 |
ly_print(out, ">");
|
|
Packit |
8fb591 |
lyxml_dump_text(out, ++p, LYXML_DATA_ELEM);
|
|
Packit |
8fb591 |
ly_print(out, "</%s>", node->schema->name);
|
|
Packit |
8fb591 |
} else {
|
|
Packit |
8fb591 |
/* avoid code duplication - use instance-identifier printer which gets necessary namespaces to print */
|
|
Packit |
8fb591 |
datatype = LY_TYPE_INST;
|
|
Packit |
8fb591 |
goto printvalue;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
case LY_TYPE_INST:
|
|
Packit |
8fb591 |
xml_expr = transform_json2xml(node->schema->module, ((struct lyd_node_leaf_list *)node)->value_str, 1,
|
|
Packit |
8fb591 |
&prefs, &nss, &ns_count);
|
|
Packit |
8fb591 |
if (!xml_expr) {
|
|
Packit |
8fb591 |
/* error */
|
|
Packit |
8fb591 |
ly_print(out, "\"(!error!)\"");
|
|
Packit |
8fb591 |
return EXIT_FAILURE;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
for (i = 0; i < ns_count; ++i) {
|
|
Packit |
8fb591 |
ly_print(out, " xmlns:%s=\"%s\"", prefs[i], nss[i]);
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
free(prefs);
|
|
Packit |
8fb591 |
free(nss);
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
if (xml_expr[0]) {
|
|
Packit |
8fb591 |
ly_print(out, ">");
|
|
Packit |
8fb591 |
lyxml_dump_text(out, xml_expr, LYXML_DATA_ELEM);
|
|
Packit |
8fb591 |
ly_print(out, "</%s>", node->schema->name);
|
|
Packit |
8fb591 |
} else {
|
|
Packit |
8fb591 |
ly_print(out, "/>");
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
lydict_remove(node->schema->module->ctx, xml_expr);
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
case LY_TYPE_LEAFREF:
|
|
Packit |
8fb591 |
iter = (struct lyd_node_leaf_list *)leaf->value.leafref;
|
|
Packit |
8fb591 |
while (iter && (iter->value_type == LY_TYPE_LEAFREF)) {
|
|
Packit |
8fb591 |
iter = (struct lyd_node_leaf_list *)iter->value.leafref;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
if (!iter) {
|
|
Packit |
8fb591 |
/* unresolved and invalid, but we can learn the correct type anyway */
|
|
Packit |
8fb591 |
type = lyd_leaf_type((struct lyd_node_leaf_list *)leaf);
|
|
Packit |
8fb591 |
if (!type) {
|
|
Packit |
8fb591 |
/* error */
|
|
Packit |
8fb591 |
ly_print(out, "\"(!error!)\"");
|
|
Packit |
8fb591 |
return EXIT_FAILURE;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
datatype = type->base;
|
|
Packit |
8fb591 |
} else {
|
|
Packit |
8fb591 |
datatype = iter->value_type;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
goto printvalue;
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
case LY_TYPE_EMPTY:
|
|
Packit |
8fb591 |
ly_print(out, "/>");
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
default:
|
|
Packit |
8fb591 |
/* error */
|
|
Packit |
8fb591 |
ly_print(out, "\"(!error!)\"");
|
|
Packit |
8fb591 |
return EXIT_FAILURE;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
if (level) {
|
|
Packit |
8fb591 |
ly_print(out, "\n");
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
return EXIT_SUCCESS;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
static int
|
|
Packit |
8fb591 |
xml_print_container(struct lyout *out, int level, const struct lyd_node *node, int toplevel, int options)
|
|
Packit |
8fb591 |
{
|
|
Packit |
8fb591 |
struct lyd_node *child;
|
|
Packit |
8fb591 |
const char *ns;
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
if (toplevel || !node->parent || nscmp(node, node->parent)) {
|
|
Packit |
8fb591 |
/* print "namespace" */
|
|
Packit |
8fb591 |
ns = lyd_node_module(node)->ns;
|
|
Packit |
8fb591 |
ly_print(out, "%*s<%s xmlns=\"%s\"", LEVEL, INDENT, node->schema->name, ns);
|
|
Packit |
8fb591 |
} else {
|
|
Packit |
8fb591 |
ly_print(out, "%*s<%s", LEVEL, INDENT, node->schema->name);
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
if (toplevel) {
|
|
Packit |
8fb591 |
xml_print_ns(out, node, options);
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
if (xml_print_attrs(out, node, options)) {
|
|
Packit |
8fb591 |
return EXIT_FAILURE;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
if (!node->child) {
|
|
Packit |
8fb591 |
ly_print(out, "/>%s", level ? "\n" : "");
|
|
Packit |
8fb591 |
return EXIT_SUCCESS;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
ly_print(out, ">%s", level ? "\n" : "");
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
LY_TREE_FOR(node->child, child) {
|
|
Packit |
8fb591 |
if (xml_print_node(out, level ? level + 1 : 0, child, 0, options)) {
|
|
Packit |
8fb591 |
return EXIT_FAILURE;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
ly_print(out, "%*s</%s>%s", LEVEL, INDENT, node->schema->name, level ? "\n" : "");
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
return EXIT_SUCCESS;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
static int
|
|
Packit |
8fb591 |
xml_print_list(struct lyout *out, int level, const struct lyd_node *node, int is_list, int toplevel, int options)
|
|
Packit |
8fb591 |
{
|
|
Packit |
8fb591 |
struct lyd_node *child;
|
|
Packit |
8fb591 |
const char *ns;
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
if (is_list) {
|
|
Packit |
8fb591 |
/* list print */
|
|
Packit |
8fb591 |
if (toplevel || !node->parent || nscmp(node, node->parent)) {
|
|
Packit |
8fb591 |
/* print "namespace" */
|
|
Packit |
8fb591 |
ns = lyd_node_module(node)->ns;
|
|
Packit |
8fb591 |
ly_print(out, "%*s<%s xmlns=\"%s\"", LEVEL, INDENT, node->schema->name, ns);
|
|
Packit |
8fb591 |
} else {
|
|
Packit |
8fb591 |
ly_print(out, "%*s<%s", LEVEL, INDENT, node->schema->name);
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
if (toplevel) {
|
|
Packit |
8fb591 |
xml_print_ns(out, node, options);
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
if (xml_print_attrs(out, node, options)) {
|
|
Packit |
8fb591 |
return EXIT_FAILURE;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
if (!node->child) {
|
|
Packit |
8fb591 |
ly_print(out, "/>%s", level ? "\n" : "");
|
|
Packit |
8fb591 |
return EXIT_SUCCESS;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
ly_print(out, ">%s", level ? "\n" : "");
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
LY_TREE_FOR(node->child, child) {
|
|
Packit |
8fb591 |
if (xml_print_node(out, level ? level + 1 : 0, child, 0, options)) {
|
|
Packit |
8fb591 |
return EXIT_FAILURE;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
ly_print(out, "%*s</%s>%s", LEVEL, INDENT, node->schema->name, level ? "\n" : "");
|
|
Packit |
8fb591 |
} else {
|
|
Packit |
8fb591 |
/* leaf-list print */
|
|
Packit |
8fb591 |
xml_print_leaf(out, level, node, toplevel, options);
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
return EXIT_SUCCESS;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
static int
|
|
Packit |
8fb591 |
xml_print_anydata(struct lyout *out, int level, const struct lyd_node *node, int toplevel, int options)
|
|
Packit |
8fb591 |
{
|
|
Packit |
8fb591 |
char *buf;
|
|
Packit |
8fb591 |
struct lyd_node_anydata *any = (struct lyd_node_anydata *)node;
|
|
Packit |
8fb591 |
struct lyd_node *iter;
|
|
Packit |
8fb591 |
const char *ns;
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
if (toplevel || !node->parent || nscmp(node, node->parent)) {
|
|
Packit |
8fb591 |
/* print "namespace" */
|
|
Packit |
8fb591 |
ns = lyd_node_module(node)->ns;
|
|
Packit |
8fb591 |
ly_print(out, "%*s<%s xmlns=\"%s\"", LEVEL, INDENT, node->schema->name, ns);
|
|
Packit |
8fb591 |
} else {
|
|
Packit |
8fb591 |
ly_print(out, "%*s<%s", LEVEL, INDENT, node->schema->name);
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
if (toplevel) {
|
|
Packit |
8fb591 |
xml_print_ns(out, node, options);
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
if (xml_print_attrs(out, node, options)) {
|
|
Packit |
8fb591 |
return EXIT_FAILURE;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
if (!(void*)any->value.tree || (any->value_type == LYD_ANYDATA_CONSTSTRING && !any->value.str[0])) {
|
|
Packit |
8fb591 |
/* no content */
|
|
Packit |
8fb591 |
ly_print(out, "/>%s", level ? "\n" : "");
|
|
Packit |
8fb591 |
} else {
|
|
Packit |
8fb591 |
if (any->value_type == LYD_ANYDATA_DATATREE) {
|
|
Packit |
8fb591 |
/* print namespaces in the anydata data tree */
|
|
Packit |
8fb591 |
LY_TREE_FOR(any->value.tree, iter) {
|
|
Packit |
8fb591 |
xml_print_ns(out, iter, options);
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
/* close opening tag ... */
|
|
Packit |
8fb591 |
ly_print(out, ">");
|
|
Packit |
8fb591 |
/* ... and print anydata content */
|
|
Packit |
8fb591 |
switch (any->value_type) {
|
|
Packit |
8fb591 |
case LYD_ANYDATA_CONSTSTRING:
|
|
Packit |
8fb591 |
lyxml_dump_text(out, any->value.str, LYXML_DATA_ELEM);
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
case LYD_ANYDATA_DATATREE:
|
|
Packit |
8fb591 |
if (any->value.tree) {
|
|
Packit |
8fb591 |
if (level) {
|
|
Packit |
8fb591 |
ly_print(out, "\n");
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
LY_TREE_FOR(any->value.tree, iter) {
|
|
Packit |
8fb591 |
if (xml_print_node(out, level ? level + 1 : 0, iter, 0, (options & ~(LYP_WITHSIBLINGS | LYP_NETCONF)))) {
|
|
Packit |
8fb591 |
return EXIT_FAILURE;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
case LYD_ANYDATA_XML:
|
|
Packit |
8fb591 |
lyxml_print_mem(&buf, any->value.xml, (level ? LYXML_PRINT_FORMAT | LYXML_PRINT_NO_LAST_NEWLINE : 0)
|
|
Packit |
8fb591 |
| LYXML_PRINT_SIBLINGS);
|
|
Packit |
8fb591 |
ly_print(out, "%s%s", level ? "\n" : "", buf);
|
|
Packit |
8fb591 |
free(buf);
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
case LYD_ANYDATA_SXML:
|
|
Packit |
8fb591 |
/* print without escaping special characters */
|
|
Packit |
8fb591 |
ly_print(out, "%s", any->value.str);
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
case LYD_ANYDATA_JSON:
|
|
Packit |
8fb591 |
case LYD_ANYDATA_LYB:
|
|
Packit |
8fb591 |
/* JSON and LYB format is not supported */
|
|
Packit |
8fb591 |
LOGWRN(node->schema->module->ctx, "Unable to print anydata content (type %d) as XML.", any->value_type);
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
case LYD_ANYDATA_STRING:
|
|
Packit |
8fb591 |
case LYD_ANYDATA_SXMLD:
|
|
Packit |
8fb591 |
case LYD_ANYDATA_JSOND:
|
|
Packit |
8fb591 |
case LYD_ANYDATA_LYBD:
|
|
Packit |
8fb591 |
/* dynamic strings are used only as input parameters */
|
|
Packit |
8fb591 |
assert(0);
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
/* closing tag */
|
|
Packit |
8fb591 |
ly_print(out, "</%s>%s", node->schema->name, level ? "\n" : "");
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
return EXIT_SUCCESS;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
int
|
|
Packit |
8fb591 |
xml_print_node(struct lyout *out, int level, const struct lyd_node *node, int toplevel, int options)
|
|
Packit |
8fb591 |
{
|
|
Packit |
8fb591 |
int ret = EXIT_SUCCESS;
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
if (!lyd_wd_toprint(node, options)) {
|
|
Packit |
8fb591 |
/* wd says do not print */
|
|
Packit |
8fb591 |
return EXIT_SUCCESS;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
switch (node->schema->nodetype) {
|
|
Packit |
8fb591 |
case LYS_NOTIF:
|
|
Packit |
8fb591 |
case LYS_RPC:
|
|
Packit |
8fb591 |
case LYS_ACTION:
|
|
Packit |
8fb591 |
case LYS_CONTAINER:
|
|
Packit |
8fb591 |
ret = xml_print_container(out, level, node, toplevel, options);
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
case LYS_LEAF:
|
|
Packit |
8fb591 |
ret = xml_print_leaf(out, level, node, toplevel, options);
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
case LYS_LEAFLIST:
|
|
Packit |
8fb591 |
ret = xml_print_list(out, level, node, 0, toplevel, options);
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
case LYS_LIST:
|
|
Packit |
8fb591 |
ret = xml_print_list(out, level, node, 1, toplevel, options);
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
case LYS_ANYXML:
|
|
Packit |
8fb591 |
case LYS_ANYDATA:
|
|
Packit |
8fb591 |
ret = xml_print_anydata(out, level, node, toplevel, options);
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
default:
|
|
Packit |
8fb591 |
LOGINT(node->schema->module->ctx);
|
|
Packit |
8fb591 |
ret = EXIT_FAILURE;
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
return ret;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
int
|
|
Packit |
8fb591 |
xml_print_data(struct lyout *out, const struct lyd_node *root, int options)
|
|
Packit |
8fb591 |
{
|
|
Packit |
8fb591 |
const struct lyd_node *node, *next;
|
|
Packit |
8fb591 |
struct lys_node *parent = NULL;
|
|
Packit |
8fb591 |
int level, action_input = 0;
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
if (!root) {
|
|
Packit |
8fb591 |
if (out->type == LYOUT_MEMORY || out->type == LYOUT_CALLBACK) {
|
|
Packit |
8fb591 |
ly_print(out, "");
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
return EXIT_SUCCESS;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
level = (options & LYP_FORMAT ? 1 : 0);
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
if (options & LYP_NETCONF) {
|
|
Packit |
8fb591 |
if (root->schema->nodetype != LYS_RPC) {
|
|
Packit |
8fb591 |
/* learn whether we are printing an action */
|
|
Packit |
8fb591 |
LY_TREE_DFS_BEGIN(root, next, node) {
|
|
Packit |
8fb591 |
if (node->schema->nodetype == LYS_ACTION) {
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
LY_TREE_DFS_END(root, next, node);
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
} else {
|
|
Packit |
8fb591 |
node = root;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
if (node) {
|
|
Packit |
8fb591 |
if ((node->schema->nodetype & (LYS_LIST | LYS_CONTAINER | LYS_RPC | LYS_NOTIF | LYS_ACTION)) && node->child) {
|
|
Packit |
8fb591 |
for (parent = lys_parent(node->child->schema); parent && (parent->nodetype == LYS_USES); parent = lys_parent(parent));
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
if (parent && (parent->nodetype == LYS_OUTPUT)) {
|
|
Packit |
8fb591 |
/* rpc/action output - skip the container */
|
|
Packit |
8fb591 |
root = node->child;
|
|
Packit |
8fb591 |
} else if (node->schema->nodetype == LYS_ACTION) {
|
|
Packit |
8fb591 |
/* action input - print top-level action element */
|
|
Packit |
8fb591 |
action_input = 1;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
if (action_input) {
|
|
Packit |
8fb591 |
ly_print(out, "%*s<action xmlns=\"urn:ietf:params:xml:ns:yang:1\">%s", LEVEL, INDENT, level ? "\n" : "");
|
|
Packit |
8fb591 |
if (level) {
|
|
Packit |
8fb591 |
++level;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
/* content */
|
|
Packit |
8fb591 |
LY_TREE_FOR(root, node) {
|
|
Packit |
8fb591 |
if (xml_print_node(out, level, node, 1, options)) {
|
|
Packit |
8fb591 |
return EXIT_FAILURE;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
if (!(options & LYP_WITHSIBLINGS)) {
|
|
Packit |
8fb591 |
break;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
if (action_input) {
|
|
Packit |
8fb591 |
if (level) {
|
|
Packit |
8fb591 |
--level;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
ly_print(out, "%*s</action>%s", LEVEL, INDENT, level ? "\n" : "");
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
ly_print_flush(out);
|
|
Packit |
8fb591 |
|
|
Packit |
8fb591 |
return EXIT_SUCCESS;
|
|
Packit |
8fb591 |
}
|
|
Packit |
8fb591 |
|