ConfD User Community

How to convert a ConfD tag value array to XML?

It is a small task to convert a tag value array to XML. Below is a quick implementation and demo where we extend the existing ConfD intro/1-2-3-start-query-model example by first getting the subscription configuration updates using a confd_get_modifications() call and then print the tag value array result in in pretty XML format.

Example code:

Let’s first do a diff to see what we added to the 1-2-3 intro example:

$ pwd
$ diff ../1-2-3-start-query-model/dhcpd_conf.c dhcpd_conf.c 

In the 1-2-3 intro example main() function we want to first get the schema information at initialization:

>     if (confd_load_schemas((struct sockaddr*)&addr, 
>                             sizeof (struct sockaddr_in)) != CONFD_OK)
>         confd_fatal("Failed to load schemas from confd\n");

When we receive a subscription modification notification we want to first get the modifications and then we call a helper function to print the tag value array in pretty XML format:

> 	        confd_tag_value_t *values = NULL;
>                 int nvalues, i;
>                 if ((status = cdb_get_modifications(subsock, 
>          					    sub_points[0], 
> 					            &values, 
> 						    &nvalues, 
> 						    "/dhcp")) == CONFD_OK) {
> 		    printf("Modifications in pretty printed XML:\n");
> 		    print_modifications_xml_pretty(values, nvalues, NULL, 0);
> 		    for (i = 0; i < nvalues; i++)
> 		        confd_free_value(CONFD_GET_TAG_VALUE(&values[i]));
>                     free(values); 
> 		} else {
> 		    fprintf(stderr, "failed to get modifications %d\n", status);
>                 }

Our helper function that print a tag value array in pretty XML format:

> static void print_modifications_xml_pretty(confd_tag_value_t *val, int nvals,
>                                 struct confd_cs_node *start_node,
>                                 int start_indent)
> {
>     int i, indent = start_indent;
>     struct confd_cs_node root, *pnode = start_node, *node;
>     char tmpbuf[BUFSIZ];
>     char *tmp;
>     for (i=0; i<nvals; i++) {
>         if (indent == start_indent && start_node == NULL) {
>             node = confd_find_cs_root(CONFD_GET_TAG_NS(&val[i]));
>             root.children = node;
>             pnode = &root;
>         }
>         switch (CONFD_GET_TAG_VALUE(&val[i])->type) {
>         case C_XMLBEGIN:
> 	    tmp = ""; //begin;
>             if (pnode != NULL)
>                 pnode = confd_find_cs_node_child(pnode, val[i].tag);
>             break;
>         case C_XMLBEGINDEL:
> 	    tmp = ""; //begin-deleted
>             if (pnode != NULL)
>                 pnode = confd_find_cs_node_child(pnode, val[i].tag);
>             break;
>         case C_XMLEND:
> 	    tmp = ""; //end;
>             if (pnode != NULL)
>                 pnode = pnode->parent;
>             break;
>         case C_XMLTAG:
> 	  tmp = ""; //created;
>             break;
>         case C_NOEXISTS:
> 	    tmp = ""; //deleted;
>             break;
>         default:
>             if (pnode == NULL ||
>                 (node = confd_find_cs_node_child(pnode, val[i].tag)) == NULL ||
>                 confd_val2str(node->info.type, CONFD_GET_TAG_VALUE(&val[i]),
>                               tmpbuf, sizeof(tmpbuf)) == CONFD_ERR) {
>                 confd_pp_value(tmpbuf, sizeof(tmpbuf),
>                                CONFD_GET_TAG_VALUE(&val[i]));
>             }
>             tmp = tmpbuf; //merge
>         }
>         switch (CONFD_GET_TAG_VALUE(&val[i])->type) {
>         case C_XMLBEGIN:
>         case C_XMLBEGINDEL:
> 	    printf("%*s<%s> %s\n", indent, "",
>                confd_hash2str(CONFD_GET_TAG_TAG(&val[i])), tmp);
> 	    indent += 2;
>             break;
> 	case C_XMLEND:
> 	    indent -= 2;
>             printf("%*s</%s> %s\n", indent, "",
>                confd_hash2str(CONFD_GET_TAG_TAG(&val[i])), tmp);
> 	    break;
>         default:
> 	    printf("%*s<%s>%s</%s>\n", indent, "",
> 		   confd_hash2str(CONFD_GET_TAG_TAG(&val[i])), tmp, confd_hash2str(CONFD_GET_TAG_TAG(&val[i])));
>             break;
>         }
>     }
> }

Quick demo:

In terminal window1 we set some new configuration using the netconf-console by issuing a NETCONF <edit-config> request:

$ netconf-console -i

* Enter a NETCONF operation, end with an empty line
      <dhcp xmlns=""
        <defaultLeaseTime nc:operation="merge">
          <subNet nc:operation="create">

<?xml version="1.0" encoding="UTF-8"?>
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="2">

In terminal window2 the ConfD tag value array result from the cdb_get_modifications() is printed in XML pretty:

Modifications in pretty printed XML:

If you for example want to add NETCONF xml tags like for example nc:operation, xmlns or xmlns:nc , just add them to the print function.

I am also looking something very similar. So can you please continue your previous answer and tell us how can we add nc:operation=“merge” vs “create” vs “replace” vs “modify”?
Is there a way to know which operation has happened on element/object using cdb_get_modification.

All I see is xmlbegin/xmlbegindel and end but no modify/merge/replace.
Please clarify what to do if the output we want is similar to the applied input so that we can apply this output to some remote cdb as edit-config.

Hi Gopal,

Note that it is the new configuration vs the previous old configuration, i.e. the configuration changes that his presented in the tag value array returned by the cdb_get_modifications() API call. Not the NETCONF operations that was used to set the resulting new configuration.

Hence, in your case when you create a XML representation from the tag value array returned by cdb_get_modifications(), it would be sufficient if you use the “merge” operation for the changed/new configuration indicated by C_XMLBEGIN / C_XMLEND and the “remove” operation (or “delete” operation if you want an error message if you are deleting something that does not exist) on elements as indicated C_NOEXISTS and C_XMLBEGINDEL / C_XMLEND.

Hi Cohult,

I am using cdb_diff_iterate API for getting the difference of old and new data .
How i can convert the same to xml format ? Because for cdb_diff_iterate we will get value in confd_value_t struct not in confd_tag_value_t

How we can modify above print_modifications_xml_pretty to handle confd_value_t struct


Perhaps something like:

struct confd_cs_node *cs_node = confd_cs_node_cd(NULL, kp);
u_int32_t tag = cs_node->tag 

…and there’s your tag to go with the value.

thanks Cohult, we will try this and let you know update.