110 lines
2.8 KiB
C++
110 lines
2.8 KiB
C++
#include <ZUtil/ZXMLReader.hpp>
|
|
|
|
//We don't want rapidxml throwing exceptions at us, let the parse handler do it
|
|
#ifndef RAPIDXML_NO_EXCEPTIONS
|
|
#define RAPIDXML_NO_EXCEPTIONS
|
|
#endif
|
|
|
|
#include <rapidxml/rapidxml.hpp>
|
|
|
|
namespace rapidxml
|
|
{
|
|
void parse_error_handler(const char *what, void *where, void *arg)
|
|
{
|
|
URFP(where); //For now
|
|
|
|
ZString& errorMsg = *((ZString*)arg);
|
|
|
|
errorMsg = "ZXMLReader (rapidxml): ";
|
|
ZStringAlgo::Append(errorMsg, what);
|
|
}
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
bool ZXMLReader::Read(const char* data, size_t length)
|
|
{
|
|
Tree.Clear();
|
|
|
|
ZString name; // current node name
|
|
ZString value; // current node value
|
|
|
|
// make a copy of xml data so we can use rapidxml in destructive mode
|
|
ZString xmlData(data, length);
|
|
rapidxml::xml_document<> doc(&ErrorMessage); // character type is 'char'
|
|
|
|
// 0 is default flags (error message will be set by handler)
|
|
if (!doc.parse<rapidxml::parse_no_data_nodes>(xmlData.Data())) {
|
|
return false;
|
|
}
|
|
|
|
// iterate the nodes and set data in the tree
|
|
rapidxml::xml_node<> *node = doc.first_node();
|
|
ZKVTree::Iterator itr = Tree.Begin();
|
|
|
|
while (node != NULL) {
|
|
name = node->name();
|
|
value = node->value();
|
|
|
|
// xml often contains a lot of control characters within the 'body'
|
|
ZStringAlgo::Trim(value);
|
|
|
|
// add this node under the root node
|
|
ZKVTree::Iterator node_itr = Tree.Add(itr, name, value);
|
|
|
|
// iterate the attributes and set data in the kvtree
|
|
for (rapidxml::xml_attribute<> *attr = node->first_attribute(); attr != NULL; attr = attr->next_attribute()) {
|
|
ZString attr_name = attr->name();
|
|
ZString attr_value = attr->value();
|
|
|
|
// add this node under the newly created node
|
|
Tree.Add(node_itr, attr_name, attr_value);
|
|
}
|
|
|
|
// iterate to next node (check child first, then sibling, then go up to parent)
|
|
if (node->first_node() != NULL) {
|
|
node = node->first_node();
|
|
itr = node_itr;
|
|
} else if (node->next_sibling() != NULL) {
|
|
node = node->next_sibling();
|
|
} else {
|
|
|
|
// go to next element (up and out)
|
|
while (node->parent() != NULL) {
|
|
node = node->parent();
|
|
|
|
if (node->type() != rapidxml::node_document) {
|
|
itr = itr.Parent();
|
|
} else break;
|
|
|
|
if (node->next_sibling() != NULL) {
|
|
node = node->next_sibling();
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
// if we end up NULL or back at the 'document' node by going to parent, then we are done.
|
|
if (node == NULL || node->parent() == NULL || node->type() == rapidxml::node_document) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
const ZString& ZXMLReader::GetErrorString()
|
|
{
|
|
return ErrorMessage;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
void ZXMLReader::GetKVTree(ZKVTree& _kvtree)
|
|
{
|
|
_kvtree = Tree;
|
|
}
|