.obj.eps:
tgif -print -eps -color $<
-XMLS = manual.xml string.xml date.xml hour.xml utc.xml Integer.xml
+XMLS = manual.xml string.xml date.xml hour.xml utc.xml Integer.xml xml.xml
IMAGES=
PICTURES=
xmlns:xi="http://www.w3.org/2001/XInclude"/>
<xi:include href="Integer.xml"
xmlns:xi="http://www.w3.org/2001/XInclude"/>
+ <xi:include href="xml.xml"
+ xmlns:xi="http://www.w3.org/2001/XInclude"/>
</book>
</doc>
--- /dev/null
+<chapter>
+<heading>xml - XML document classes</heading>
+
+<pre>
+#include <xml.h>
+
+xml document;
+xml_node node;
+xml_element element;
+</pre>
+
+<para>
+The collection of xml classes provide an easy way to process XML documents
+and to traverse the tree of XML data.
+Built upon the xml2 library on xmlsoft.org, the classes encapsulate concepts
+of XML data.
+After parsing an XML document with an xml object, the xml_node class
+can access the data of the XML document tree.
+A node in the tree can have any number of children which are also nodes.
+The child nodes are accessed by using the subscript operator with a numerical index.
+Elements of the XML data can be selected by name when a String argument is used
+with the subscript operator.
+Using this operator will return a vector of xml_element objects that hold
+all child elements having this name.
+<pre>
+
+xml data(filename);
+xml_node root(data);
+xml_node third = root[2];
+
+String tagname("chapter");
+std::vector <xml_element> all_chapters;
+
+all_chapters = root[tagname];
+
+</pre>
+</para>
+<section>
+<heading>Class xml</heading>
+<para>
+An object of class xml holds an entire XML document.
+It supports reading and writing XML documents from and to files
+as well conversion of XML objects to and from String objects.
+
+<description>
+<item tag="xml()">
+The default constructor creates an empty xml document.
+</item>
+<item tag="xml(String s)">
+Parse the xml document from s.
+</item>
+</description>
+</para>
+
+<description>
+<item tag="operator=(String &s)">
+Parse the xml document from String s.
+</item>
+</description>
+
+</section>
+
+<section>
+<heading>class xml_node</heading>
+
+<para>
+A node is the basic building block that makes up the tree of an XML document.
+There are several kinds of nodes, such as ekements, attributes and text nodes.
+If a node is an ekement node it can have any number if child nodes.
+These child nodes can be accessed by using the subscript operator with
+a numerical index.
+</para>
+
+<description>
+<item tag="xml_node()">
+The default constructor creates an empty xml node.
+</item>
+<item tag="xml_node(xml doc)">
+Construct a node from the XML document. The xml_node object will be the root node
+of the XML document.
+</item>
+<item tag="bool is_a_node(void)">
+Return true if the object actually is an XML node.
+</item>
+<item tag="xml_node operator[](int n)">
+Return the child node with index n.
+</item>
+</description>
+</section>
+
+<section>
+<heading>class xml_element : xml_node</heading>
+<para>
+The class xml_element is derived from the class xml_node and adds properties
+soecific to XML ekements.
+</para>
+
+</section>
+
+</chapter>
#include "xml.h"
+void xml::ParseFile(const char * filename)
+{
+ ctxt = xmlNewParserCtxt();
+ //document = xmlParseFile(filename);
+ document = xmlCtxtReadFile(ctxt, filename, NULL, XML_PARSE_NOWARNING|XML_PARSE_NOERROR);
+}
+
String xml::RootElementName(void)
{
String root_name;
xmlNodePtr root;
- root = xmlDocGetRootElement(document);
- root_name = String((const char *)root->name);
+ if (document != NULL)
+ {
+ root = xmlDocGetRootElement(document);
+ root_name = String((const char *)root->name);
+ }
return root_name;
}
return xml_node(root);
}
+//xml_node::xml_node(xml doc)
+//{
+// *this = doc.RootNode();
+//}
+
// Find the nth child element by name (non-recursive)
+xml_node xml_node::operator[](int i)
+{
+ xmlNodePtr np = n->children;
+
+ while (np != NULL && i != 0)
+ {
+ i--;
+ np = np->next;
+ }
+
+ return xml_node(np);
+}
+
xml_node xml_node::FindChildElement(String name, int nth)
{
xml_node element;
return element;
}
+
+
+std::vector<xml_element> xml_element::operator[](String tagname)
+{
+ std::vector<xml_element> elements_found;
+
+ xmlNodePtr np = n->children;
+ while (np != NULL)
+ {
+ if (np->type == XML_ELEMENT_NODE && tagname == (const char *)np->name)
+ {
+ xml_element e(np);
+ elements_found.push_back(e);
+ }
+ np = np->next;
+ }
+
+ return elements_found;
+}
#include <libxml/parser.h> // usually in /usr/include/libxml2, see xml2-config
+#include <vector>
#include "String.h"
+class xml_node;
+
+class xml
+{
+ xmlParserCtxtPtr ctxt;
+ xmlDocPtr document;
+
+public:
+
+ xml()
+ {
+ ctxt = NULL;
+ document = NULL;
+ }
+
+ ~xml()
+ {
+ if (document != NULL)
+ {
+ xmlFreeDoc(document);
+ document = NULL;
+ }
+ }
+
+ void ParseFile(const char * filename);
+
+ void SaveFile(const char * filename)
+ {
+ xmlSaveFile(filename, document);
+ }
+
+ String RootElementName(void);
+ xml_node RootNode(void);
+
+};
+
class xml_node
{
+protected:
xmlNodePtr n;
public:
n = np;
}
+ xml_node(xml &doc)
+ {
+ xml_node node;
+ node = doc.RootNode();
+
+ n = node.n;
+ }
+
bool is_a_node(void)
{
return n != NULL;
}
+ xml_node operator[](int n);
+
String name(void)
{
String node_name;
return node_name;
}
+ xmlElementType type(void)
+ {
+ xmlElementType nodetype;
+
+ nodetype = xmlElementType(0);
+ if (n != NULL)
+ {
+ nodetype = n->type;
+ }
+
+ return nodetype;
+ }
+
// Assumes one childnode of type TEXT
// TODO collect content from multiple TEXT nodes (recursively ?)
String content(void)
xml_node FindChildElement(String name, int nth = 0);
};
-class xml
+class xml_element : public xml_node
{
- xmlDocPtr document;
-
public:
-
- xml()
+ xml_element() : xml_node()
{
- document = NULL;
}
- ~xml()
+ xml_element(xmlNodePtr np) : xml_node(np)
{
- if (document != NULL)
- {
- xmlFreeDoc(document);
- document = NULL;
- }
}
- void ParseFile(const char * filename)
+ xml_element(xml &doc) : xml_node(doc)
{
- document = xmlParseFile(filename);
}
- void SaveFile(const char * filename)
- {
- xmlSaveFile(filename, document);
- }
+ std::vector<xml_element> operator[](String tagname);
- String RootElementName(void);
- xml_node RootNode(void);
-
};
hour_assign hour_parse hour_compare hour_arithmetic hour_check_now \
utc_assign utc_compare utc_arithmetic \
integer_assign integer_factorial integer_fibonacci integer_pow64 integer_modulo \
- xml_file xml_find \
+ xml_file xml_find xml_node xml_elem \
configuration_read configuration_find
string_assign_SOURCES = string_assign.cpp
xml_file_SOURCES = xml_file.cpp
xml_find_SOURCES = xml_find.cpp
+xml_node_SOURCES = xml_node.cpp
+xml_elem_SOURCES = xml_elem.cpp
configuration_read_SOURCES = configuration_read.cpp
configuration_find_SOURCES = configuration_find.cpp
--- /dev/null
+/*******************************************************
+ * Unit test for the xml_element class
+ *
+ * test xml element access
+ ******************************************************
+ *
+ */
+
+#include "xml.h"
+#include <assert.h>
+
+int main()
+{
+ xml doc;
+
+ const char xml_file[] = "xml_test01.xml";
+
+ std::cout << "Reading XML file " << xml_file << "\n";
+
+ doc.ParseFile("xml_test01.xml");
+
+ xml_element root_node(doc);
+
+ std::cout << "Root element is " << root_node.name() << "\n";
+ std::cout << "Root node type is " << root_node.type() << "\n";
+ assert(root_node.name() == "doc");
+
+ std::vector<xml_element> book, chapters;
+
+ book = root_node["book"];
+ assert(book.size() == 1);
+
+ chapters = book[0]["chapter"];
+
+ std::cout << "Found " << chapters.size() << " chapter elements.\n";
+
+ std::vector<xml_element> report;
+
+ report = root_node["report"];
+ assert(report.size() == 0);
+
+ // Find an element three levels deep
+
+ std::vector<xml_element> children;
+ xml_element found_node;
+
+ children = book[0]["titlepage"];
+ found_node = children[0];
+
+ assert(found_node.is_a_node() == true);
+ children = found_node["title"];
+ found_node = children[0];
+ assert(found_node.is_a_node() == true);
+ std::cout << "Name of title node = " << found_node.name() << "\n";
+ std::cout << "Content of title node = " << found_node.content() << "\n";
+
+ return 0;
+}
+
--- /dev/null
+Reading XML file xml_test01.xml
+Root element is doc
+Root node type is 1
+Found 3 chapter elements.
+Name of title node = title
+Content of title node = Andromeda Class Library
+PASS xml_elem (exit status: 0)
assert (root == "doc");
root_node = doc.RootNode();
+ assert(root_node.is_a_node() == true);
assert(root_node.name() == "doc");
+ doc.ParseFile("notexist.xml");
+ root_node = doc.RootNode();
+ assert(root_node.is_a_node() == false);
+ assert(root_node.name() == "");
+
+ doc.ParseFile("xml_test02.xml");
+ root_node = doc.RootNode();
+ assert(root_node.is_a_node() == false);
+ assert(root_node.name() == "");
+
return 0;
}
root_node = doc.RootNode();
- std::cout << "Root element is " << root_node.name() << "\n";
- assert(root_node.name() == "doc");
-
child_name = "book";
found_node = root_node.FindChildElement(child_name);
std::cout << "Child element " << child_name;
Reading XML file xml_test01.xml
-Root element is doc
Child element book found.
Child element report not found.
Name of title node = title
--- /dev/null
+/*******************************************************
+ * Unit test for the xml_node class
+ *
+ * test xml node access
+ ******************************************************
+ *
+ */
+
+#include "xml.h"
+#include <assert.h>
+
+int main()
+{
+ xml doc;
+
+ const char xml_file[] = "xml_test01.xml";
+
+ std::cout << "Reading XML file " << xml_file << "\n";
+
+ doc.ParseFile("xml_test01.xml");
+
+ xml_node root_node(doc);
+
+ std::cout << "Root element is " << root_node.name() << "\n";
+ std::cout << "Root node type is " << root_node.type() << "\n";
+ assert(root_node.name() == "doc");
+
+ int i;
+ xml_node child;
+
+ root_node = root_node[1]; // The book element
+ child = root_node[0];
+ for (i = 0; child.is_a_node(); i++)
+ {
+ child = root_node[i];
+ std::cout << "Node " << i << " type is " << child.type() << "\n";
+ std::cout << "Node " << i << " name is " << child.name() << "\n";
+ }
+
+ return 0;
+}
+
<?xml version="1.0"?>
<doc style="main.css">
- <book>
+ <book attr="value">
<titlepage>
<title>Andromeda Class Library</title>
</titlepage>
--- /dev/null
+<?xml
+Input for testing xml classes.
+this is not really xml.