The YANG anydata or anyxml node types allow a generic container of arbitrary child nodes to be returned.

This is simply a terminal data node in YANG, meaning the schema nodes in the YANG model do not specify the contents.

From the YANG modeling point of view, these nodes are like leafs.

module testany {
  yang-version 1.1;
  namespace "";
  prefix "ta";
  revision 2019-04-04;

  container top {
    config false;
    anydata template;

In this example the GET2 callback for the "top" container expects a return value to be created for the "template" node.

The example code will create a :template" container and add 2 leafs to the container as child nodes. In practice, any type of real child node (container, list, leaf, leaf-list) can be added to the anydata structure.

The SIL code is generated using the following command:

> make_sil_dir_pro --split testany --sil-get2

The only code that needs to be filled in is the u_testany_top_get function in u_testany.c

The initial auto-generated code is shown below:

* FUNCTION u_testany_top_get
* Get database object callback for container top
* Path: /top
* Fill in 'get2cb' response fields
*     see ncx/getcb.h for details (getcb_fn2_t)
*     error status
status_t u_testany_top_get (
    getcb_get2_t *get2cb)
    /* check the callback mode type */
    getcb_mode_t cbmode = GETCB_GET2_CBMODE(get2cb);
    switch (cbmode) {
        return ERR_NCX_NO_INSTANCE;

    /* an NP container always exists so no test for node_exists
     * by the SIL or SIL-SA callback is needed */
    obj_template_t *obj = GETCB_GET2_OBJ(get2cb);
    status_t res = NO_ERR;

    /* optional: check if any content-match nodes are present */
    boolean match_test_done = FALSE;
    val_value_t *match_val = GETCB_GET2_FIRST_MATCH(get2cb);
    for (; match_val; match_val =
        GETCB_GET2_NEXT_MATCH(get2cb, match_val)) {


    GETCB_GET2_MATCH_TEST_DONE(get2cb) = match_test_done;

    /* go through all the requested terminal child objects */
    obj_template_t *childobj =
        getcb_first_requested_child(get2cb, obj);
    for (; childobj; childobj =
        getcb_next_requested_child(get2cb, childobj)) {

        const xmlChar *name = obj_get_name(childobj);

        /* Retrieve the value of this terminal node and 
         * add with getcb_add_return_val */

        if (!xml_strcmp(name, y_testany_N_template)) {
            /* anydata template */


    return res;

} /* u_testany_top_get */

An include directive needs to be added for the val_child module:

#include "val_child.h"

The "match_val" code is intended to support content match filters used in NETCONF subtree filtering. That does not apply to an "anydata" node, so that code can be ignored or removed.

The code that needs to be filled in is shown below:

        if (!xml_strcmp(name, y_testany_N_template)) {
            /* anydata template */


The following steps are required in this example.

  1. get the namespace identifier to use when creating the return values
  2. create the "template" structure
  3. add the "status" leaf (type string) to the template structure
  4. add the "error-count" leaf (type uint32) to the template structure
  5. add the "template" structure to the getcb return value queue

        if (!xml_strcmp(name, y_testany_N_template)) {
            /* anydata template */

            // step 1: get the NSID for the leafs
            xmlns_id_t nsid = obj_get_nsid(obj);

            // step 2: create the template structure
            val_value_t *template_val = val_new_value();
            if (template_val == NULL) {
                return ERR_INTERNAL_MEM;
            val_init_from_template(template_val, childobj);

            // step 3: make a status child leaf and add the child last
            val_value_t *status_val =
                                (const xmlChar *)"status",
                                (const xmlChar *)"This is my status");
            if (status_val == NULL) {
                return ERR_INTERNAL_MEM;
            res = val_child_add_last(status_val, template_val);
            if (res != NO_ERR) {
                return res;
            } // else status_val memory passed to parent val

            // step 4: make an error-count child leaf and add the child last
            // there are no APIs that can be used to create anydata child nodes
            // except val_make_string, so convert number to string
            char numbuff[NCX_MAX_NUMLEN];
            uint32 some_count = 42;  // get from system
            snprintf(numbuff, NCX_MAX_NUMLEN, "%u", some_count);
            val_value_t *error_count_val =
                                (const xmlChar *)"error-count",
                                (const xmlChar *)numbuff);
            if (error_count_val == NULL) {
                return ERR_INTERNAL_MEM;
            res = val_child_add_last(error_count_val, template_val);
            if (res != NO_ERR) {
                return res;

            // step 5: add the return value
            getcb_add_return_val(get2cb, template_val);

If the yangcli request "sget /top" is given the server will return the following XML

<?xml version="1.0" encoding="UTF-8"?>
<rpc-reply message-id="1"
 ncx:last-modified="2019-04-04T18:29:41Z" ncx:etag="200"
  <top xmlns="">
    <status>This is my status</status>