#include //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 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(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; }