3. Domnode
The domnode(3m) module provides a lightweight DOM-like interface for manipulating XML documents as a tree of nodes in memory. Functions are provided to load and store XML sources to and from trees of domnode structures. It follows the "everything is a node philosophy". Four different node types are supported; element, attribute, text, and comment. The linkedlist(3m) functions are used to modify the children and attributes of a node.
Example 1. An XML configuration file
Consider the following XML fragment from an imaginary networking application. The root node in this example is zsvr. It has children #comment, net, and users. The net element has attributes laddr, timeout, and port. See the domnode_new function for a complete description of the four different node types.
<zsvr mode="server">
<!-- This is a comment -->
<net laddr="192.168.1.15" timeout="15000" port="1444"/>
<users>
This is some text
<user id="mba" auth="nis.o">nis.foo.net:9812:fretos</user>
<user id="gchan"
The values of these configuration parameters should be manipulated by iterating over elements and attributes with linkedlist_iterate and linkedlist_next and then getting or setting individual values through the value member of the domnode structure.
Please be aware that the space between elements is included in the list of children as #text nodes. This is consistent with a real DOM and is necessary if indentation and spacing in the original document is to be preserved. If your program is not interested in this space then be prepared to ignore those #text nodes.
As a convienience there is also a search function to retrieve a particular element or attribute provided it's name is unique among all elements and attributes. The following code sets the port value of a sockaddr_in structure to the port value "1444".
if ((attr = domnode_search(cfg, "port")) != NULL) {
inet.sin_port = htons(atoi(attr->value));
}
3.1. The domnode structure
The domnode structure
Synopsis
#include <mba/domnode.h>
#include <mba/linkedlist.h>
struct domnode {
const char *name;
const char *value;
struct linkedlist *children;
struct linkedlist *attrs;
};
Description
Table 1. Values of struct domnode members by node type
Type |
Members |
|
name |
value |
children |
attrs |
Element |
tag name |
NULL |
linkedlist |
linkedlist |
Attribute |
name of the attribute |
value of the attribute |
NULL |
NULL |
Text |
"#text" |
content of text node |
NULL |
NULL |
Comment |
"#comment" |
content of comment |
NULL |
NULL |
The domnode structure represents one of four possible node types; element, attribute, text, or comment. Table shows what the domnode structure members may be for each node type. This table should be considered when creating new nodes with the domnode_new function.
3.2. Memory management functions
These functions should be used to create and destroy domnode objects.
The domnode_new function
Synopsis
#include <mba/domnode.h>
struct domnode *domnode_new(const char *name, const char *value);
Description
The domnode_new function creates a new domnode structure with the specified name and value.
The type of the node created depends on the parameters specified.
If the name parameter is the string "#text" a text node is created.
If the name parameter is the string "#comment" a comment node is created.
Otherwise, consult Table for appropriate name and value parameters.
If both name and value are null pointers an "empty" node is created suitable for creating a new domnode tree from an XML source file with the domnode_load or domnode_read functions.
Returns
The domnode_new function returns a new domnode structure. If memory for the structure cannot be allocated a null pointer is returned and errno is set to ENOMEM. Domnode structures should be freed with the domnode_del function.
The domnode_del function
Synopsis
#include <mba/domnode.h>
void domnode_del(void *this);
Description
The domnode_del function recursively releases the resources associated with this domnode structure and its children and attributes.
If this node is a null pointer, no action is taken.
Any additional memory management performed by the user should consider that the name and value members of this node and all of its attributes, children, and children's attributes will also be deallocated with the free(3) function.
Returns
The domnode_del function returns no value.
3.3. Node functions
The domnode_load function
Synopsis
#include <mba/domnode.h>
int domnode_load(struct domnode *this, const char *filename);
Description
The domnode_load function loads an XML source file from the file specified by the filename parameter and populates the element node this with the corresponding domnode tree. Any existing members of this element will be deallocated. The XML source file must be a complete well-formed XML document. The possible XML source file character encodings are UTF-8, UTF-16, ISO-8859-1, or US-ASCII.
The following code illustrates how to create an initially empty root node and load an XML source document into it.
cfg = domnode_new(NULL, NULL);
if (domnode_load(cfg, argv[1]) == 0) {
fprintf(stderr, "Failed to load XML configuration file: %s", argv[1]);
return 0;
}
Returns
The domnode_load function returns non-zero if the operation was successfull. Otherwise, zero is returned and errno is set to indicate that the operation failed.
The domnode_store function
Synopsis
#include <mba/domnode.h>
int domnode_store(struct domnode *this, const char *filename);
Description
The domnode_store function serializes this domnode tree as XML source and writes the output to the file specified by the filename parameter using the locale dependent character encoding (e.g. UTF-8).
Returns
The domnode_store function returns non-zero if the operation was successfull. Otherwise, zero is returned and errno is set to indicate that the operation failed.
The domnode_read function
Synopsis
#include <mba/domnode.h>
size_t domnode_read(struct domnode *this, FILE *stream);
Description
The domnode_read function reads an XML source file from stream and populates the element node this with the corresponding domnode tree. Any existing members of this element will be deallocated. The XML source file must be a complete well-formed XML document. The possible XML source file character encodings are UTF-8, UTF-16, ISO-8859-1, or US-ASCII.
Returns
The domnode_read function returns the number of bytes read from stream or (size_t)(-1) if the operation failed in which case errno will be set appropriately.
The domnode_write function
Synopsis
#include <mba/domnode.h>
size_t domnode_write(struct domnode *this, FILE *stream);
Description
The domnode_write function serializes this domnode tree as XML source and writes the output to stream using the locale dependent character encoding (e.g. UTF-8).
Returns
The domnode_write function returns the number of bytes written to stream or (size_t)(-1) if the operation failed in which case errno will be set appropriately.
The domnode_search function
Synopsis
#include <mba/domnode.h>
struct domnode *domnode_search(struct domnode *this, const char *name);
Description
The domnode_search function performs a breadth-first-search on the entire tree for a named element or attribute node starting from this node. The first node with a name matching the name parameter is returned. If no such node is found, a null pointer is returned.
In general this function should not be used because it is common for the name of an element or attribute to be repeated several times throughout the tree in which case the user cannot always be certain which node will be found.
Returns
The domnode_search function returns the matching element or attribute or a null pointer if no such node exists in the tree.
3.4. Attribute functions
The domnode attribute functions provide a map interface for manipulating attributes of an element.
The domnode_attrs_put function
Synopsis
#include <mba/domnode.h>
int domnode_attrs_put(struct linkedlist *attrs, struct domnode *attr);
Description
The domnode_attrs_put function puts an attribute into a list of attributes of an element. The attrs parameter is the attrs member of the target element. The attr parameter is the attribute that should be placed into this list of attributes. If an attribute with the same name already exists in the list, it will be freed and then replaced with the new attribute.
The below code illustrates how to create a new attribute and add it to the attributes of the net element from Example
if ((attr = domnode_new("baddr", "192.168.1.255")) == NULL ||
domnode_attr_put(net->attrs, attr) == 0) {
domnode_del(attr);
return 0;
}
Returns
The domnode_attrs_put function returns non-zero if the operation was successfull. Otherwise, zero is returned and errno is set to indicate that the operation failed.
The domnode_attrs_get function
Synopsis
#include <mba/domnode.h>
struct domnode *domnode_attrs_get(struct linkedlist *attrs, const char *name);
Description
The domnode_attrs_get function retrieves an attribute from the attributes of an element by it's name. The attrs parameter is the attrs member of the target element. The name parameter is the name of the attribute that should be retrieved from the list of attributes.
Returns
The domnode_attrs_get function returns the attribute that is being retrieved. If no attribute with the specified name exists in the attrs list, a null pointer is returned.
The domnode_attrs_remove function
Synopsis
#include <mba/domnode.h>
struct domnode *domnode_attrs_remove(struct linkedlist *attrs, const char *name);
Description
The domnode_attrs_remove function removes an attribute from the attibutes of an element by it's name. The attrs parameter is the attrs member of the target element. The name parameter is the name of the attribute that should be removed from the list of attributes.
Returns
The domnode_attrs_remove function returns the attribute node removed. If the named attibute is not found a null pointer is returned.
Copyright 2002 Michael B. Allen <mballen@erols.com>