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
/Users/conny/tailf/confd-5.4.2/examples.confd/intro/1-2-3-start-query-model-mod
$ 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:
162a230,232
> 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:
220a291,306
> confd_tag_value_t *values = NULL;
> int nvalues, i;
> if ((status = cdb_get_modifications(subsock,
> sub_points[0],
> CDB_GET_MODS_INCLUDE_LISTS,
> &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:
148a149,215
> 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
<edit-config>
<target>
<running/>
</target>
<config>
<dhcp xmlns="http://tail-f.com/ns/example/dhcpd"
xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
<defaultLeaseTime nc:operation="merge">
PT30M
</defaultLeaseTime>
<SubNets>
<subNet nc:operation="create">
<net>192.168.128.0</net>
<mask>255.255.255.0</mask>
<range>
<lowAddr>192.168.128.60</lowAddr>
<hiAddr>192.168.128.89</hiAddr>
</range>
</subNet>
</SubNets>
</dhcp>
</config>
</edit-config>
<?xml version="1.0" encoding="UTF-8"?>
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="2">
<ok/>
</rpc-reply>
In terminal window2 the ConfD tag value array result from the cdb_get_modifications()
is printed in XML pretty:
...
Modifications in pretty printed XML:
<defaultLeaseTime>PT30M0S.0</defaultLeaseTime>
<SubNets>
<subNet>
<net>192.168.128.0</net>
<mask>255.255.255.0</mask>
<maxLeaseTime>PT7200S.0</maxLeaseTime>
<range>
<dynamicBootP>false</dynamicBootP>
<lowAddr>192.168.128.60</lowAddr>
<hiAddr>192.168.128.89</hiAddr>
</range>
</subNet>
</SubNets>
…
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.
Python NETCONF example: ConfD-Demos/cdbl-sync-nc.py at master · ConfD-Developer/ConfD-Demos · GitHub