0

everyone! I am using rapidxml to parse my setting file. When I do everything in a single function, it works well. But when I try to add some functions to do the work, it always give std::exception. Does anyone know the reason? A simple code example is

#include <stdexcept>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include "rapidxml.hpp"

struct MyConfig{
    bool LES_FLAG, ITP_FLAG;
    int calcCase, dataInterval, maxIter;
    double va, lesCoef, eigenLength, Re;
    double xLow, xUp, yLow, yUp, maxTime;
}config;
void readConfig(const char* fileName);
void parseFlag(rapidxml::xml_node<> *node, char *flagName, bool &flag, int namesize=0);
void parseFloat(rapidxml::xml_node<> *node, char *name, double &variable, int namesize=0);
void parseInt(rapidxml::xml_node<> *node, char *name, int &variable, int namesize=0);
void parseString(rapidxml::xml_node<> *node, char *name, std::string &str, int namesize=0);

int main(int argn, char** argv){
  try{
    readConfig("test.xml");
  }
  catch (std::exception e)
  {
    std::cout << e.what() << std::endl;
  }
}
void readConfig(const char* fileName){
  std::ifstream myfile(fileName);
  if (!myfile.is_open())
    throw std::runtime_error("Can not open the configuration file!\n");
  std::stringstream buffer;
  buffer << myfile.rdbuf();
  myfile.close();

  try{
    rapidxml::xml_document<> doc;
    doc.parse<0>(&buffer.str()[0]);
    rapidxml::xml_node<> *rNode = doc.first_node("Config_2DVPM");

    rapidxml::xml_node<> *cnode = rNode->first_node("flags",5,false);
    parseFlag(cnode, "LES_FLAG", config.LES_FLAG);
    parseFlag(cnode, "ITP_FLAG", config.ITP_FLAG);

    cnode = rNode->first_node("float",5,false);
    cnode = rNode->first_node("float",5,false);
    parseFloat(cnode, "va", config.va, 2);
    parseFloat(cnode, "lesCoef", config.lesCoef, 7);
    parseFloat(cnode, "eigenLength", config.eigenLength, 11);
    parseFloat(cnode, "Re", config.Re, 2);
    parseFloat(cnode, "xLow", config.xLow, 4);
    parseFloat(cnode, "xUp", config.xUp, 3);
    parseFloat(cnode, "yLow", config.yLow, 4);
    parseFloat(cnode, "yUp", config.yUp, 3);
    parseFloat(cnode, "maxTime", config.maxTime, 7);

    cnode = rNode->first_node("int",3,false);
    parseInt(cnode, "calcCase", config.calcCase);
    parseInt(cnode, "dataInterval", config.dataInterval);
    parseInt(cnode, "maxIter", config.maxIter);
  }
  catch (rapidxml::parse_error& e)
  {
    std::string ss = std::string("xml parse error: ") + e.what();
    throw std::runtime_error(ss);
  }
}

void parseFlag(rapidxml::xml_node<> *node, char* name, bool &flag, int namesize)
{
  char *str = node->first_attribute(name, namesize, false)->value();
  if (str == NULL)
  {
    std::string ss = std::string("Undefined attribute in flags: ") + name;
    throw std::runtime_error(ss);
  }
  if (strcmp(str, "1") == 0 || strcmp(str, "true") == 0 || strcmp(str, "True") == 0)
    flag = true;
  else flag = false;
}

void parseFloat(rapidxml::xml_node<> *node, char* name,
    double &variable, int namesize)
{
  char* str = node->first_attribute(name, namesize, false)->value();
  if (*str == '\0')
  {
    std::string ss = std::string("Undefined attribute in float: ") + name;
    throw std::runtime_error(ss);
  }
  std::stringstream ss(str);
  ss >> variable;
}
void parseInt(rapidxml::xml_node<> *node, char* name,
    int &variable, int namesize)
  {
  char *str = node->first_attribute(name, namesize, false)->value();
  if (*str == '\0')
  {
    std::string ss = std::string("Undefined attribute in int: ") + name;
    throw std::runtime_error(ss);
  }
  std::stringstream ss(str);
  ss >> variable;
}

void Calculation::parseString(rapidxml::xml_node<> *node, char* name,
    std::string &res, int namesize)
  {
  char *str = node->first_attribute(name, namesize, false)->value();
  if (*str == '\0')
  {
    std::string ss = std::string("Undefined attribute in int: ") + name;
    throw std::runtime_error(ss);
  }
  res = str;
}

The example file text.xml is

<?xml version="1.0" encoding="UTF-8"?>
<Config_2DVPM version="1.0">
    <flags LES_FLAG="true" ITP_FLAG="false"/>
    <float va="1.0" lesCoef="0.15" eigenLength="1.0" Re="500" maxTime="15" 
    xLow="-1" xUp="5" yLow="-1" yUp="1"/>
    <int calcCase="0" dataInterval="200" maxIter="100000"/>
    <string test="haha"/>
</Config_2DVPM>

The code always gives an output std::exception. After some check, the problem always happens when I parse the attribute "eingenLength".

Y.J Wang
  • 1
  • 1
  • I have solved the problem by replace 'varaible << ss' with 'variable=std::stof(str)' in the function parseFloat. However, I cannot understand why the line 'variable << ss' influence the memory owned by the rapidxml object doc. – Y.J Wang Sep 19 '17 at 12:52
  • You can pass zero in for the string lengths rather than all those constants. Rapidxml will then calculate them for you. not sure about the original problem though... – Roddy Sep 22 '17 at 12:16
  • I can't duplicate your problem. I suspect the original error is elsewhere... – Roddy Sep 22 '17 at 12:40

0 Answers0