Back to posts.

RapidXML

RapidXML is my preferred XML parser. It's fast, has a great api and it's stable. Oh yeah, and it's template based, so no need to compile a library which is sometimes easy.

Including the header

#include <rapidxml.hpp>
using namespace rapidxml

Loading the contents of you XML file

std::ifstream ifs("file.xml", std::ios::in);
if(!ifs.is_open()) {
    return false;
}
 
std::string xml_str;
xml_str.assign(std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>());

Create XML instance with the loaded contents

xml_document<> doc;
try {
  doc.parse<0>((char*)xml_str.c_str());
}
catch (...) {
  return false;
}

Fetching data

xml_node<>* cfg = doc.first_node("settings");
std::string str = cfg->value();

Fetching attributes

xml_node<>* cfg = doc.first_node("video");
xml_attribute<>* att = cfg->first_attribute("width");
std::string w = att->value();

Iterating over children

<chars count="276">
  <char id="32" x="93"  y="93"  />
  <char id="33" x="125" y="23"  />
  <char id="34" x="30"  y="95"  />
  <char id="35" x="85"  y="70"  />
  <char id="36" x="13"  y="35"  />
</chars>
xml_node<>* chars = xfont->first_node("chars"); 
xml_node<>* char = xchars->first_node();
while(xchar) {
   // do something with the current char            
  char = char->next_sibling();
}

Using a templated function to read different types of values

template <class T> int read_xml(xml_node<>* node, std::string name, T defaultval, T& result) {
 
  result = defaultval;
 
  if (0 == name.size()) {
    RX_ERROR("name.size() == 0.");
    return -1;
  }
 
  if (NULL == node) {
    RX_ERROR("Container node for %s is NULL.", name.c_str());
    return -2;
  }
 
  xml_node<>* el = node->first_node(name.c_str());
  if (NULL == el) {
    RX_ERROR("%s not found in %s", name.c_str(), node->name());
    return -3;
  }
 
  std::stringstream ss;
  ss << el->value();
  ss >> result;
 
  return 0;
}