Blame src/printer_xml.c

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