Browse Source

xml: Add unworking xml parsing engines

Serj Kalichev 3 years ago
parent
commit
b063b05d57
3 changed files with 1278 additions and 0 deletions
  1. 539 0
      klish/kdb/expat/shell_expat.c
  2. 381 0
      klish/kdb/libxml2/shell_libxml2.c
  3. 358 0
      klish/kdb/roxml/shell_roxml.c

+ 539 - 0
klish/kdb/expat/shell_expat.c

@@ -0,0 +1,539 @@
+/*
+ * ------------------------------------------------------
+ * shell_expat.c
+ *
+ * This file implements the means to read an XML encoded file
+ * and populate the CLI tree based on the contents. It implements
+ * the clish_xml API using the expat XML parser
+ *
+ * expat is not your typicall XML parser. It does not work
+ * by creating a full in-memory XML tree, but by calling specific
+ * callbacks (element handlers) regularly while parsing. It's up
+ * to the user to create the corresponding XML tree if needed
+ * (obviously, this is what we're doing, as we really need the XML
+ * tree in klish).
+ *
+ * The code below do that. It transforms the output of expat
+ * to a DOM representation of the underlying XML file. This is
+ * a bit overkill, and maybe a later implementation will help to
+ * cut the work to something simpler, but the current klish
+ * implementation requires this.
+ * ------------------------------------------------------
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if defined(HAVE_LIB_EXPAT)
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+
+/* FreeBSD have verbatim version of expat named bsdxml */
+#ifdef HAVE_LIB_BSDXML
+#include <bsdxml.h>
+#else
+#include <expat.h>
+#endif
+
+#include "xmlapi.h"
+
+/** DOM_like XML node
+ *
+ * @struct clish_xmlnode_s
+ */
+struct clish_xmlnode_s {
+	char *name;
+	clish_xmlnode_t *parent; /**< parent node */
+	clish_xmlnode_t *children; /**< list of children */
+	clish_xmlnode_t *next; /**< next sibling */
+	clish_xmlnode_t *attributes; /**< attributes are nodes too */
+	char *content; /**< !NULL for text and attributes nodes */
+	clish_xmlnodetype_e type; /**< node type */
+	int depth; /**< node depth */
+	clish_xmldoc_t *doc;
+};
+
+/** DOM-like XML document
+ *
+ * @struct clish_xmldoc_s
+ */
+struct clish_xmldoc_s {
+	clish_xmlnode_t *root; /**< list of root elements */
+	clish_xmlnode_t *current; /**< current element */
+	char *filename; /**< current filename */
+};
+
+/*
+ * Expat need these functions to be able to build a DOM-like tree that
+ * will be usable by klish.
+ */
+/** Put a element at the and of an element list
+ *
+ * @param first first element of the list
+ * @param node element to add
+ * @return new first element of the list
+ */
+static clish_xmlnode_t *clish_expat_list_push_back(clish_xmlnode_t *first, clish_xmlnode_t *node)
+{
+	clish_xmlnode_t *cur = first;
+	clish_xmlnode_t *prev = NULL;
+
+	while (cur) {
+		prev = cur;
+		cur = cur->next;
+	}
+	if (prev) {
+		prev->next = node;
+		return first;
+	}
+	return node;
+}
+
+/** Generic add_attr() function
+ *
+ * @param first first attribute in the attribute list
+ * @param n attribute name
+ * @param v attribute value
+ * @return the new first attribute in the attribute list
+ */
+static clish_xmlnode_t *clish_expat_add_attr(clish_xmlnode_t *first, const char *n, const char *v)
+{
+	clish_xmlnode_t *node;
+
+	node = malloc(sizeof(clish_xmlnode_t));
+	if (!node)
+		return first;
+
+	node->name = strdup(n);
+	node->content = strdup(v);
+	node->children = NULL;
+	node->attributes = NULL;
+	node->next = NULL;
+	node->type = CLISH_XMLNODE_ATTR;
+	node->depth = 0;
+
+	return clish_expat_list_push_back(first, node);
+}
+
+/** Run through an expat attribute list, and create a DOM-like attribute list
+ *
+ * @param node parent node
+ * @param attr NULL-terminated attribute liste
+ *
+ * Each attribute uses two slots in the expat attribute list. The first one is
+ * used to store the name, the second one is used to store the value.
+ */
+static void clish_expat_add_attrlist(clish_xmlnode_t *node, const char **attr)
+{
+	int i;
+
+	for (i = 0; attr[i]; i += 2) {
+		node->attributes = clish_expat_add_attr(node->attributes,
+			attr[i], attr[i+1]);
+	}
+}
+
+/** Generic make_node() function
+ *
+ * @param parent XML parent node
+ * @param type XML node type
+ * @param n node name (can be NULL, strdup'ed)
+ * @param v node content (can be NULL, strdup'ed)
+ * @param attr attribute list
+ * @return a new node or NULL on error
+ */
+static clish_xmlnode_t *clish_expat_make_node(clish_xmlnode_t *parent,
+					      clish_xmlnodetype_e type,
+					      const char *n,
+					      const char *v,
+					      const char **attr)
+{
+	clish_xmlnode_t *node;
+
+	node = malloc(sizeof(clish_xmlnode_t));
+	if (!node)
+		return NULL;
+	node->name = n ? strdup(n) : NULL;
+	node->content = v ? strdup(v) : NULL;
+	node->children = NULL;
+	node->attributes = NULL;
+	node->next = NULL;
+	node->parent = parent;
+	node->doc = parent ? parent->doc : NULL;
+	node->depth = parent ? parent->depth + 1 : 0;
+	node->type = type;
+
+	if (attr)
+		clish_expat_add_attrlist(node, attr);
+
+	if (parent)
+		parent->children = clish_expat_list_push_back(parent->children, node);
+
+	return node;
+}
+
+/** Add a new XML root
+ *
+ * @param doc XML document
+ * @param el root node name
+ * @param attr expat attribute list
+ * @return a new root element
+ */
+static clish_xmlnode_t *clish_expat_add_root(clish_xmldoc_t *doc, const char *el, const char **attr)
+{
+	clish_xmlnode_t *node;
+
+	node = clish_expat_make_node(NULL, CLISH_XMLNODE_ELM, el, NULL, attr);
+	if (!node)
+		return doc->root;
+
+	doc->root = clish_expat_list_push_back(doc->root, node);
+
+	return node;
+}
+
+/** Add a new XML element as a child
+ *
+ * @param cur parent XML element
+ * @param el element name
+ * @param attr expat attribute list
+ * @return a new XMl element
+ */
+static clish_xmlnode_t *clish_expat_add_child(clish_xmlnode_t *cur, const char *el, const char **attr)
+{
+	clish_xmlnode_t *node;
+
+	node = clish_expat_make_node(cur, CLISH_XMLNODE_ELM, el, NULL, attr);
+	if (!node)
+		return cur;
+
+	return node;
+}
+
+/** Expat handler: element content
+ *
+ * @param data user data
+ * @param s content (not nul-termainated)
+ * @param len content length
+ */
+static void clish_expat_chardata_handler(void *data, const char *s, int len)
+{
+	clish_xmldoc_t *doc = data;
+
+	if (doc->current) {
+		char *content = malloc(len + 1);
+		strncpy(content, s, len);
+		content[len] = '\0';
+
+		clish_expat_make_node(doc->current, CLISH_XMLNODE_TEXT, NULL, content, NULL);
+		/*
+		 * the previous call is a bit too generic, and strdup() content
+		 * so we need to free out own version of content.
+		 */
+		free(content);
+	}
+}
+
+/** Expat handler: start XML element
+ *
+ * @param data user data
+ * @param el element name (nul-terminated)
+ * @param attr expat attribute list
+ */
+static void clish_expat_element_start(void *data, const char *el, const char **attr)
+{
+	clish_xmldoc_t *doc = data;
+
+	if (!doc->current) {
+		doc->current = clish_expat_add_root(doc, el, attr);
+	} else {
+		doc->current = clish_expat_add_child(doc->current, el, attr);
+	}
+}
+
+/** Expat handler: end XML element
+ *
+ * @param data user data
+ * @param el element name
+ */
+static void clish_expat_element_end(void *data, const char *el)
+{
+	clish_xmldoc_t *doc = data;
+
+	if (doc->current) {
+		doc->current = doc->current->parent;
+	}
+
+	el = el; /* Happy compiler */
+}
+
+/** Free a node, its children and its attributes
+ *
+ * @param node node to free
+ */
+static void clish_expat_free_node(clish_xmlnode_t *cur)
+{
+	clish_xmlnode_t *node;
+	clish_xmlnode_t *first;
+
+	if (cur->attributes) {
+		first = cur->attributes;
+		while (first) {
+			node = first;
+			first = first->next;
+			clish_expat_free_node(node);
+		}
+	}
+	if (cur->children) {
+		first = cur->children;
+		while (first) {
+			node = first;
+			first = first->next;
+			clish_expat_free_node(node);
+		}
+	}
+	if (cur->name)
+		free(cur->name);
+	if (cur->content)
+		free(cur->content);
+	free(cur);
+}
+
+/*
+ * Public interface
+ */
+
+int clish_xmldoc_start(void)
+{
+	return 0;
+}
+
+int clish_xmldoc_stop(void)
+{
+	return 0;
+}
+
+clish_xmldoc_t *clish_xmldoc_read(const char *filename)
+{
+	clish_xmldoc_t *doc;
+	struct stat sb;
+	int fd;
+	char *buffer;
+	XML_Parser parser;
+	int rb;
+
+	doc = malloc(sizeof(clish_xmldoc_t));
+	if (!doc)
+		return NULL;
+	memset(doc, 0, sizeof(clish_xmldoc_t));
+	doc->filename = strdup(filename);
+	parser = XML_ParserCreate(NULL);
+	if (!parser)
+		goto error_parser_create;
+	XML_SetUserData(parser, doc);
+	XML_SetCharacterDataHandler(parser, clish_expat_chardata_handler);
+	XML_SetElementHandler(parser,
+		clish_expat_element_start,
+		clish_expat_element_end);
+
+	fd = open(filename, O_RDONLY);
+	if (fd < 0)
+		goto error_open;
+	fstat(fd, &sb);
+	buffer = malloc(sb.st_size+1);
+	rb = read(fd, buffer, sb.st_size);
+	if (rb < 0) {
+		close(fd);
+		goto error_parse;
+	}
+	buffer[sb.st_size] = 0;
+	close(fd);
+
+	if (!XML_Parse(parser, buffer, sb.st_size, 1))
+		goto error_parse;
+
+	XML_ParserFree(parser);
+	free(buffer);
+
+	return doc;
+
+error_parse:
+	free(buffer);
+
+error_open:
+	XML_ParserFree(parser);
+
+error_parser_create:
+	clish_xmldoc_release(doc);
+
+	return NULL;
+}
+
+void clish_xmldoc_release(clish_xmldoc_t *doc)
+{
+	if (doc) {
+		clish_xmlnode_t *node;
+		while (doc->root) {
+			node = doc->root;
+			doc->root = node->next;
+			clish_expat_free_node(node);
+		}
+		if (doc->filename)
+			free(doc->filename);
+		free(doc);
+	}
+}
+
+int clish_xmldoc_is_valid(clish_xmldoc_t *doc)
+{
+	return doc && doc->root;
+}
+
+int clish_xmldoc_error_caps(clish_xmldoc_t *doc)
+{
+	doc = doc; /* Happy compiler */
+
+	return CLISH_XMLERR_NOCAPS;
+}
+
+int clish_xmldoc_get_err_line(clish_xmldoc_t *doc)
+{
+	doc = doc; /* Happy compiler */
+
+	return -1;
+}
+
+int clish_xmldoc_get_err_col(clish_xmldoc_t *doc)
+{
+	doc = doc; /* Happy compiler */
+
+	return -1;
+}
+
+const char *clish_xmldoc_get_err_msg(clish_xmldoc_t *doc)
+{
+	doc = doc; /* Happy compiler */
+
+	return "";
+}
+
+int clish_xmlnode_get_type(clish_xmlnode_t *node)
+{
+	if (node)
+		return node->type;
+	return CLISH_XMLNODE_UNKNOWN;
+}
+
+clish_xmlnode_t *clish_xmldoc_get_root(clish_xmldoc_t *doc)
+{
+	if (doc)
+		return doc->root;
+	return NULL;
+}
+
+clish_xmlnode_t *clish_xmlnode_parent(clish_xmlnode_t *node)
+{
+	if (node)
+		return node->parent;
+	return NULL;
+}
+
+clish_xmlnode_t *clish_xmlnode_next_child(clish_xmlnode_t *parent,
+					  clish_xmlnode_t *curchild)
+{
+	if (curchild)
+		return curchild->next;
+	if (parent)
+		return parent->children;
+	return NULL;
+}
+
+char *clish_xmlnode_fetch_attr(clish_xmlnode_t *node,
+			       const char *attrname)
+{
+	if (node) {
+		clish_xmlnode_t *n = node->attributes;
+		while (n) {
+			if (strcmp(n->name, attrname) == 0)
+				return n->content;
+			n = n->next;
+		}
+	}
+	return NULL;
+}
+
+int clish_xmlnode_get_content(clish_xmlnode_t *node, char *content,
+			      unsigned int *contentlen)
+{
+	unsigned int minlen = 1;
+
+	if (node && content && contentlen) {
+		clish_xmlnode_t *children = node->children;
+		while (children) {
+			if (children->type == CLISH_XMLNODE_TEXT && children->content)
+				minlen += strlen(children->content);
+			children = children->next;
+		}
+		if (minlen >= *contentlen) {
+			*contentlen = minlen + 1;
+			return -E2BIG;
+		}
+		children = node->children;
+		*content = 0;
+		while (children) {
+			if (children->type == CLISH_XMLNODE_TEXT && children->content)
+				strcat(content, children->content);
+			children = children->next;
+		}
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+int clish_xmlnode_get_name(clish_xmlnode_t *node, char *name,
+	unsigned int *namelen)
+{
+	if (node && name && namelen) {
+		if (strlen(node->name) >= *namelen) {
+			*namelen = strlen(node->name) + 1;
+			return -E2BIG;
+		}
+		snprintf(name, *namelen, "%s", node->name);
+		name[*namelen - 1] = '\0';
+		return 0;
+	}
+	return -EINVAL;
+}
+
+void clish_xmlnode_print(clish_xmlnode_t *node, FILE *out)
+{
+	if (node) {
+		int i;
+		clish_xmlnode_t *a;
+		for (i=0; i<node->depth; ++i) {
+			fprintf(out, "  ");
+		}
+		fprintf(out, "<%s", node->name);
+		a = node->attributes;
+		while (a) {
+			fprintf(out, " %s='%s'", a->name, a->content);
+			a = a->next;
+		}
+		fprintf(out, ">...");
+	}
+}
+
+void clish_xml_release(void *p)
+{
+	p = p; /* Happy compiler */
+	/* nothing to release */
+}
+
+#endif /* HAVE_LIB_EXPAT */
+

+ 381 - 0
klish/kdb/libxml2/shell_libxml2.c

@@ -0,0 +1,381 @@
+/*
+ * ------------------------------------------------------
+ * shell_roxml.c
+ *
+ * This file implements the means to read an XML encoded file 
+ * and populate the CLI tree based on the contents. It implements
+ * the clish_xml API using roxml
+ * ------------------------------------------------------
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if defined(HAVE_LIB_LIBXML2)
+#include <errno.h>
+#include <string.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include "xmlapi.h"
+
+#ifdef HAVE_LIB_LIBXSLT
+#include <libxslt/xslt.h>
+#include <libxslt/xsltInternals.h>
+#include <libxslt/transform.h>
+#include <libxslt/xsltutils.h>
+extern int xmlLoadExtDtdDefaultValue;
+
+/* dummy stuff ; really a xsltStylesheet */
+struct clish_xslt_s {
+	int dummy;
+};
+#endif
+
+/* dummy stuff ; really a xmlDoc */
+struct clish_xmldoc_s {
+	int dummy;
+};
+
+/* dummy stuff ; really a xmlNode */
+struct clish_xmlnode_s {
+	int dummy;
+};
+
+static inline xmlDoc *xmldoc_to_doc(clish_xmldoc_t *doc)
+{
+	return (xmlDoc*)doc;
+}
+
+static inline xmlNode *xmlnode_to_node(clish_xmlnode_t *node)
+{
+	return (xmlNode*)node;
+}
+
+static inline clish_xmldoc_t *doc_to_xmldoc(xmlDoc *node)
+{
+	return (clish_xmldoc_t*)node;
+}
+
+static inline clish_xmlnode_t *node_to_xmlnode(xmlNode *node)
+{
+	return (clish_xmlnode_t*)node;
+}
+
+/*
+ * public interface
+ */
+
+int clish_xmldoc_start(void)
+{
+#ifdef HAVE_LIB_LIBXSLT
+	/* The XSLT example contain these settings but I doubt 
+	 * it's really necessary.
+	 */
+/*	xmlSubstituteEntitiesDefault(1);
+	xmlLoadExtDtdDefaultValue = 1;
+*/
+#endif
+	return 0;
+}
+
+int clish_xmldoc_stop(void)
+{
+#ifdef HAVE_LIB_LIBXSLT
+	xsltCleanupGlobals();
+#endif
+	xmlCleanupParser();
+	return 0;
+}
+
+clish_xmldoc_t *clish_xmldoc_read(const char *filename)
+{
+	xmlDoc *doc;
+	doc = xmlReadFile(filename, NULL, 0);
+	return doc_to_xmldoc(doc);
+}
+
+void clish_xmldoc_release(clish_xmldoc_t *doc)
+{
+	if (doc)
+		xmlFreeDoc(xmldoc_to_doc(doc));
+}
+
+int clish_xmldoc_is_valid(clish_xmldoc_t *doc)
+{
+	return doc != NULL;
+}
+
+int clish_xmldoc_error_caps(clish_xmldoc_t *doc)
+{
+	doc = doc; // happy compiler
+	return CLISH_XMLERR_NOCAPS;
+}
+
+int clish_xmldoc_get_err_line(clish_xmldoc_t *doc)
+{
+	doc = doc; // happy compiler
+	return -1;
+}
+
+int clish_xmldoc_get_err_col(clish_xmldoc_t *doc)
+{
+	doc = doc; // happy compiler
+	return -1;
+}
+
+const char *clish_xmldoc_get_err_msg(clish_xmldoc_t *doc)
+{
+	doc = doc; // happy compiler
+	return "";
+}
+
+int clish_xmlnode_get_type(clish_xmlnode_t *node)
+{
+	if (node) {
+		xmlNode *n = xmlnode_to_node(node);
+		switch (n->type) {
+		case XML_ELEMENT_NODE: 
+			return CLISH_XMLNODE_ELM;
+		case XML_TEXT_NODE: 
+			return CLISH_XMLNODE_TEXT;
+		case XML_COMMENT_NODE: 
+			return CLISH_XMLNODE_COMMENT;
+		case XML_PI_NODE: 
+			return CLISH_XMLNODE_PI;
+		case XML_ATTRIBUTE_NODE: 
+			return CLISH_XMLNODE_ATTR;
+		default:
+			break;
+		}
+	}
+
+	return CLISH_XMLNODE_UNKNOWN;
+}
+
+clish_xmlnode_t *clish_xmldoc_get_root(clish_xmldoc_t *doc)
+{
+	if (doc) {
+		xmlNode *root = xmlDocGetRootElement(xmldoc_to_doc(doc));
+		return node_to_xmlnode(root);
+	}
+	return NULL;
+}
+
+clish_xmlnode_t *clish_xmlnode_parent(clish_xmlnode_t *node)
+{
+	if (node) {
+		xmlNode *n = xmlnode_to_node(node);
+		xmlNode *root = xmlDocGetRootElement(n->doc);
+		if (n != root)
+			return node_to_xmlnode(n->parent);
+	}
+	return NULL;
+}
+
+clish_xmlnode_t *clish_xmlnode_next_child(clish_xmlnode_t *parent, 
+					  clish_xmlnode_t *curchild)
+{
+	xmlNode *child;
+
+	if (!parent)
+		return NULL;
+
+	if (curchild) {
+		child = xmlnode_to_node(curchild)->next;
+	} else {
+		child = xmlnode_to_node(parent)->children;
+	}
+
+	return node_to_xmlnode(child);
+}
+
+char *clish_xmlnode_fetch_attr(clish_xmlnode_t *node,
+					  const char *attrname)
+{
+	xmlNode *n;
+
+	if (!node || !attrname)
+		return NULL;
+
+	n = xmlnode_to_node(node);
+
+	if (n->type == XML_ELEMENT_NODE) {
+		xmlAttr *a = n->properties;
+		while (a) {
+			if (strcmp((char*)a->name, attrname) == 0) {
+				if (a->children && a->children->content)
+					return (char *)a->children->content;
+				else
+					return NULL;
+			}
+			a = a->next;
+		}
+	}
+		
+	return NULL;
+}
+
+int clish_xmlnode_get_content(clish_xmlnode_t *node, char *content, 
+			      unsigned int *contentlen)
+{
+	xmlNode *n;
+	xmlNode *c;
+	unsigned int rlen = 0;
+
+	if (content && contentlen && *contentlen)
+		*content = 0;
+
+	if (!node || !content || !contentlen)
+		return -EINVAL;
+
+	if (*contentlen <= 1)
+		return -EINVAL;
+
+	*content = 0;
+	n = xmlnode_to_node(node);
+
+	/* first, get the content length */
+	c = n->children;
+	while (c) {
+		if ((c->type == XML_TEXT_NODE || c->type == XML_CDATA_SECTION_NODE)
+			&& !xmlIsBlankNode(c)) {
+			rlen += strlen((char*)c->content);
+		}
+		c = c->next;
+	}
+	++rlen;
+
+	if (rlen <= *contentlen) {
+		c = n->children;
+		while (c) {
+			if ((c->type == XML_TEXT_NODE || c->type == XML_CDATA_SECTION_NODE)
+				 && !xmlIsBlankNode(c)) {
+				strcat(content, (char*)c->content);
+			}
+			c = c->next;
+		}
+		return 0;
+	} else {
+		*contentlen = rlen;
+		return -E2BIG;
+	}
+}
+
+int clish_xmlnode_get_name(clish_xmlnode_t *node, char *name, 
+			    unsigned int *namelen)
+{
+	unsigned int rlen;
+	xmlNode *n;
+
+	if (name && namelen && *namelen)
+		*name = 0;
+
+	if (!node || !name || !namelen)
+		return -EINVAL;
+
+	if (*namelen <= 1)
+		return -EINVAL;
+
+	*name = 0;
+	n = xmlnode_to_node(node);
+	rlen = strlen((char*)n->name) + 1;
+	
+	if (rlen <= *namelen) {
+		snprintf(name, *namelen, "%s", (char*)n->name);
+		name[*namelen - 1] = '\0';
+		return 0;
+	} else {
+		*namelen = rlen;
+		return -E2BIG;
+	}
+}
+
+void clish_xmlnode_print(clish_xmlnode_t *node, FILE *out)
+{
+	xmlNode *n;
+	xmlAttr *a;
+
+	n = xmlnode_to_node(node);
+	if (n && n->name) {
+		fprintf(out, "<%s", (char*)n->name);
+		a = n->properties;
+		while (a) {
+			char *av = "";
+			if (a->children && a->children->content)
+				av = (char*)a->children->content;
+			fprintf(out, " %s='%s'", (char*)a->name, av);
+			a = a->next;
+		}
+		fprintf(out, ">");
+	}
+}
+
+void clish_xml_release(void *p)
+{
+	p = p; // happy compiler
+	/* do we allocate memory? not yet. */
+}
+
+#ifdef HAVE_LIB_LIBXSLT
+
+static inline xsltStylesheet *xslt_to_xsltStylesheet(clish_xslt_t *xslt)
+{
+	return (xsltStylesheet*)xslt;
+}
+
+static inline clish_xslt_t *xsltStylesheet_to_xslt(xsltStylesheet *xslt)
+{
+	return (clish_xslt_t*)xslt;
+}
+
+int clish_xslt_is_valid(clish_xslt_t *stylesheet)
+{
+	return stylesheet != NULL;
+}
+
+clish_xmldoc_t *clish_xslt_apply(clish_xmldoc_t *xmldoc, clish_xslt_t *stylesheet)
+{
+	xmlDoc *doc = xmldoc_to_doc(xmldoc);
+	xsltStylesheetPtr cur = xslt_to_xsltStylesheet(stylesheet);
+	xmlDoc *res;
+
+	if (!doc || !cur)
+		return doc_to_xmldoc(NULL);
+	res = xsltApplyStylesheet(cur, doc, NULL);
+
+	return doc_to_xmldoc(res);
+}
+
+clish_xslt_t *clish_xslt_read(const char *filename)
+{
+	xsltStylesheet* cur = NULL;
+
+	cur = xsltParseStylesheetFile((const xmlChar *)filename);
+
+	return xsltStylesheet_to_xslt(cur);
+}
+
+clish_xslt_t *clish_xslt_read_embedded(clish_xmldoc_t *xmldoc)
+{
+	xsltStylesheet* cur = NULL;
+	xmlDoc *doc = xmldoc_to_doc(xmldoc);
+
+	cur = xsltLoadStylesheetPI(doc);
+
+	return xsltStylesheet_to_xslt(cur);
+}
+
+void clish_xslt_release(clish_xslt_t *stylesheet)
+{
+	xsltStylesheet* cur = xslt_to_xsltStylesheet(stylesheet);
+
+	if (!cur)
+		return;
+	xsltFreeStylesheet(cur);
+}
+
+#endif /* HAVE_LIB_LIBXSLT */
+
+#endif /* HAVE_LIB_LIBXML2 */
+

+ 358 - 0
klish/kdb/roxml/shell_roxml.c

@@ -0,0 +1,358 @@
+/*
+ * ------------------------------------------------------
+ * shell_roxml.c
+ *
+ * This file implements the means to read an XML encoded file 
+ * and populate the CLI tree based on the contents. It implements
+ * the clish_xml API using roxml
+ * ------------------------------------------------------
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if defined(HAVE_LIB_ROXML)
+#include <errno.h>
+#include <roxml.h>
+#include "xmlapi.h"
+
+/* dummy stuff ; really a node_t */
+struct clish_xmldoc_s {
+	int dummy;
+};
+
+/* dummy stuff ; really a node_t */
+struct clish_xmlnode_s {
+	int dummy;
+};
+
+static inline node_t *xmldoc_to_node(clish_xmldoc_t *doc)
+{
+	return (node_t*)doc;
+}
+
+static inline node_t *xmlnode_to_node(clish_xmlnode_t *node)
+{
+	return (node_t*)node;
+}
+
+static inline clish_xmldoc_t *node_to_xmldoc(node_t *node)
+{
+	return (clish_xmldoc_t*)node;
+}
+
+static inline clish_xmlnode_t *node_to_xmlnode(node_t *node)
+{
+	return (clish_xmlnode_t*)node;
+}
+
+/*
+ * public interface
+ */
+
+int clish_xmldoc_start(void)
+{
+	return 0;
+}
+
+int clish_xmldoc_stop(void)
+{
+	return 0;
+}
+
+clish_xmldoc_t *clish_xmldoc_read(const char *filename)
+{
+	node_t *doc = roxml_load_doc((char*)filename);
+	return node_to_xmldoc(doc);
+}
+
+void clish_xmldoc_release(clish_xmldoc_t *doc)
+{
+	if (doc) {
+		node_t *node = xmldoc_to_node(doc);
+		roxml_release(RELEASE_ALL);
+		roxml_close(node);
+	}
+}
+
+int clish_xmldoc_is_valid(clish_xmldoc_t *doc)
+{
+	return doc != NULL;
+}
+
+int clish_xmldoc_error_caps(clish_xmldoc_t *doc)
+{
+	return CLISH_XMLERR_NOCAPS;
+}
+
+int clish_xmldoc_get_err_line(clish_xmldoc_t *doc)
+{
+	return -1;
+}
+
+int clish_xmldoc_get_err_col(clish_xmldoc_t *doc)
+{
+	return -1;
+}
+
+const char *clish_xmldoc_get_err_msg(clish_xmldoc_t *doc)
+{
+	return "";
+}
+
+int clish_xmlnode_get_type(clish_xmlnode_t *node)
+{
+	if (node) {
+		int type = roxml_get_type(xmlnode_to_node(node));
+		switch (type) {
+		case ROXML_ELM_NODE: 
+			return CLISH_XMLNODE_ELM;
+		case ROXML_TXT_NODE: 
+			return CLISH_XMLNODE_TEXT;
+		case ROXML_CMT_NODE: 
+			return CLISH_XMLNODE_COMMENT;
+		case ROXML_PI_NODE: 
+			return CLISH_XMLNODE_PI;
+		case ROXML_ATTR_NODE: 
+			return CLISH_XMLNODE_ATTR;
+		default:
+			break;
+		}
+	}
+
+	return CLISH_XMLNODE_UNKNOWN;
+}
+
+clish_xmlnode_t *clish_xmldoc_get_root(clish_xmldoc_t *doc)
+{
+	node_t *root;
+	char *name = NULL;
+
+	if (!doc)
+		return NULL;
+	root = roxml_get_root(xmldoc_to_node(doc));
+	if (!root)
+		return NULL;
+	/* The root node is always documentRoot since libroxml-2.2.2. */
+	/* It's good but not compatible with another XML parsers. */
+	name = roxml_get_name(root, NULL, 0);
+	if (0 == strcmp(name, "documentRoot"))
+		root = roxml_get_chld(root, NULL, 0);
+	roxml_release(name);
+
+	return node_to_xmlnode(root);
+}
+
+clish_xmlnode_t *clish_xmlnode_parent(clish_xmlnode_t *node)
+{
+	if (node) {
+		node_t *roxn = xmlnode_to_node(node);
+		node_t *root = roxml_get_root(roxn);
+		if (roxn != root)
+			return node_to_xmlnode(roxml_get_parent(roxn));
+	}
+	return NULL;
+}
+
+clish_xmlnode_t *clish_xmlnode_next_child(clish_xmlnode_t *parent, 
+					  clish_xmlnode_t *curchild)
+{
+	node_t *roxc;
+
+	if (!parent)
+		return NULL;
+
+	roxc = xmlnode_to_node(curchild);
+
+	if (roxc) {
+		return node_to_xmlnode(roxml_get_next_sibling(roxc));
+	} else {
+		node_t *roxp = xmlnode_to_node(parent);
+		node_t *child = NULL;
+		int count;
+
+		count = roxml_get_chld_nb(roxp);
+		if (count)
+			child = roxml_get_chld(roxp, NULL, 0);
+
+		return node_to_xmlnode(child);
+	}
+
+	return NULL;
+}
+
+static int i_is_needle(char *src, const char *needle)
+{
+	int nlen = strlen(needle);
+	int slen = strlen(src);
+
+	if (slen >= nlen) {
+		if (strncmp(src, needle, nlen) == 0)
+			return 1;
+	}
+	return 0;
+}
+
+/* warning: dst == src is valid */
+static void i_decode_and_copy(char *dst, char *src)
+{
+	while (*src) {
+		if (*src == '&') {
+			if (i_is_needle(src, "&lt;")) {
+				*dst++ = '<';
+				src += 4;
+			} else if (i_is_needle(src, "&gt;")) {
+				*dst++ = '>';
+				src += 4;
+			} else if (i_is_needle(src, "&amp;")) {
+				*dst++ = '&';
+				src += 5;
+			} else {
+				*dst++ = *src++;
+			}
+		} else {
+			*dst++ = *src++;
+		}
+	}
+	*dst++ = 0;
+}
+
+char *clish_xmlnode_fetch_attr(clish_xmlnode_t *node,
+			       const char *attrname)
+{
+	node_t *roxn;
+	node_t *attr;
+	char *content;
+
+	if (!node || !attrname)
+		return NULL;
+
+	roxn = xmlnode_to_node(node);
+	attr = roxml_get_attr(roxn, (char*)attrname, 0);
+
+	content = roxml_get_content(attr, NULL, 0, NULL);
+	if (content) {
+		i_decode_and_copy(content, content);
+	}
+	return content;
+}
+
+static int i_get_content(node_t *n, char *v, unsigned int *vl)
+{
+	char *c;
+	int len;
+
+	c = roxml_get_content(n, NULL, 0, NULL);
+	if (c) {
+		len = strlen(c) + 1;
+		if (len <= *vl) {
+			i_decode_and_copy(v, c);
+			roxml_release(c);
+			return 0;
+		} else {
+			*vl = len;
+			roxml_release(c);
+			return -E2BIG;
+		}
+	}
+	*vl = (unsigned int)-1;
+	return -ENOMEM;
+}
+
+int clish_xmlnode_get_content(clish_xmlnode_t *node, char *content, 
+			      unsigned int *contentlen)
+{
+	if (content && contentlen && *contentlen)
+		*content = 0;
+
+	if (!node || !content || !contentlen)
+		return -EINVAL;
+
+	if (*contentlen <= 1)
+		return -EINVAL;
+
+	*content = 0;
+
+	return i_get_content(xmlnode_to_node(node), content, contentlen);
+}
+
+static int i_get_name(node_t *n, char *v, unsigned int *vl)
+{
+	char *c;
+	int len;
+
+	c = roxml_get_name(n, NULL, 0);
+	if (c) {
+		len = strlen(c) + 1;
+		if (len <= *vl) {
+			snprintf(v, *vl, "%s", c);
+			v[*vl - 1] = '\0';
+			roxml_release(c);
+			return 0;
+		} else {
+			*vl = len;
+			roxml_release(c);
+			return -E2BIG;
+		}
+	}
+	*vl = (unsigned int)-1;
+	return -ENOMEM;
+}
+
+int clish_xmlnode_get_name(clish_xmlnode_t *node, char *name, 
+			    unsigned int *namelen)
+{
+	if (name && namelen && *namelen)
+		*name = 0;
+
+	if (!node || !name || !namelen)
+		return -EINVAL;
+
+	if (*namelen <= 1)
+		return -EINVAL;
+
+	*name = 0;
+
+	return i_get_name(xmlnode_to_node(node), name, namelen);
+}
+
+void clish_xmlnode_print(clish_xmlnode_t *node, FILE *out)
+{
+	node_t *roxn;
+	char *name;
+
+	roxn = xmlnode_to_node(node);
+	name = roxml_get_name(roxn, NULL, 0);
+	if (name) {
+		fprintf(out, "<%s", name);
+		roxml_release(name);
+		if (roxml_get_attr_nb(roxn)) {
+			int attr_count = roxml_get_attr_nb(roxn);
+			int attr_pos;
+			for (attr_pos = 0; attr_pos < attr_count; ++attr_pos) {
+				node_t *attr = roxml_get_attr(roxn, NULL, attr_pos);
+				char *n = roxml_get_name(attr, NULL, 0);
+				char *v = roxml_get_content(attr, NULL, 0, NULL);
+				if (n && v) {
+					fprintf(out, " %s='%s'", n, v);
+				}
+				if (v) 
+					roxml_release(v);
+				if (n) 
+					roxml_release(n);
+			}
+		}
+		fprintf(out, ">");
+	}
+}
+
+void clish_xml_release(void *p)
+{
+	if (p) {
+		roxml_release(p);
+	}
+}
+
+#endif /* HAVE_LIB_ROXML */
+