xmlconfig is used to parse a simple xml file as a configuration file.
<!-- this is an example xml configuration file -->
<?xml version="1.0" encoding="ISO-8859-1"?>
//////////////////////////////////////////////////////////////////////////////////////////////
<!-- this is an example xml configuration file -->
<?xml version="1.0" encoding="ISO-8859-1"?>
<Interday>
<Cache use="YES">
<Log>
<Name>../log/interday.log</Name>
<!-- minsize = 0, maxsize = 3.99G -->
<!-- K = 2^10 -->
<!-- M = 2^20 -->
<!-- G = 2^30 -->
<Size>3.99G</Size>
<Level>System</Level>
</Log>
</Cache>
</Interday>
//////////////////////////////////////////////////////////////////////////////////////////////
// xmlcnf.h
// Author: Seree Rakwong
// Date: 25-OCT-10
// Purpose: Read a simple XML file
#define xmlcnf_h
#include <fstream>
#include <vector>
#include <stack>
#include <map>
#include <iostream>
typedef bool xmlbool;
typedef char xmlint8;
typedef short xmlint16;
typedef int xmlint32;
typedef long xmlint64;
typedef float xmlfloat32;
typedef double xmlfloat64;
typedef unsigned char xmluint8;
typedef unsigned short xmluint16;
typedef unsigned int xmluint32;
typedef unsigned long xmluint64;
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// xmlstring
std::string trim_left(const std::string& str);
std::string trim_right(const std::string& str);
std::string trim(const std::string& str);
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// xmlcnf_interface
class xmlcnf_parser;
class xmlcnf_interface {
friend class xmlcnf_parser;
protected:
virtual void start_doc()=0;
virtual void end_doc()=0;
virtual void found_error(const std::string& filename, xmluint32 line_no, xmlint32 errcode)=0;
virtual void found_xml_element(const std::string& element)=0;
virtual void found_start_element(const std::string& element)=0;
virtual void found_end_element(const std::string& element)=0;
virtual void found_comment(const std::string& comment)=0;
virtual void found_text(const std::string& element, const std::string& text)=0;
virtual void found_attribute(const std::string& element, const std::string& attribute, const std::string& value)=0;
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// xmlcnf_attribute
class xmlcnf_attribute {
public:
xmlcnf_attribute();
xmlcnf_attribute(const std::string& attibute, const std::string& value);
public:
const std::string attribute() const;
const std::string value() const;
std::string& attribute();
std::string& value();
private:
std::string attribute_;
std::string value_;
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// xmlcnf_element
class xmlcnf_element {
public:
xmlcnf_element();
xmlcnf_element(const std::string& name, const std::string& text = "");
public:
const std::string name() const;
const std::string text() const;
std::string& name();
std::string& text();
private:
std::vector<xmlcnf_attribute> attributes_;
std::string name_;
std::string text_;
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// xmlcnf_parser
class xmlcnf_parser : public std::ifstream {
private:
std::stack<xmlcnf_element> elements_;
std::string filename_;
public:
xmlcnf_parser();
xmlcnf_parser(const char *filename, std::ios_base::openmode mode = ios_base::in);
xmlcnf_parser(const std::string& filename);
public:
void open(const char *filename, std::ios_base::openmode mode = ios_base::in);
void open(const std::string& filename);
int parse(xmlcnf_interface *xmlcnf_ptr);
#ifdef XML_DEBUG
void dump_error(const std::string& filename, xmluint32 line_no, const std::string& funcname);
#endif
protected:
int read_element(xmlcnf_interface *xmlcnf_ptr, xmluint32 *line_ptr, char *curchar_ptr);
private:
int parse_xml_element(xmlcnf_interface *xmlcnf_ptr, xmluint32 *line_ptr, const std::string& element);
int parse_xml_comment(xmlcnf_interface *xmlcnf_ptr, xmluint32 *line_ptr, const std::string& element);
int parse_xml_start_element(xmlcnf_interface *xmlcnf_ptr, xmluint32 *line_ptr, const std::string& element);
int parse_xml_end_element(xmlcnf_interface *xmlcnf_ptr, xmluint32 *line_ptr, const std::string& element);
int parse_xml_attribute(xmlcnf_interface *xmlcnf_ptr, xmluint32 *line_ptr, const std::string& element);
char skip_whitespaces(xmluint32 *line_ptr);
bool is_whitespaces(char ch);
bool is_valid_char(char ch);
char skip_if_not(xmlcnf_interface *xmlcnf_ptr, xmluint32 *line_ptr, char stop_char);
bool is_valid_name(const std::string& name);
public:
enum xmlcnf_error {
error_none = 0,
// xml continue reading
start_of_element = 1,
end_of_element = 2,
// basic file error
interface_object_is_null = -1,
file_is_not_opened = -2,
file_is_bad = -3,
file_not_complete = -4,
// parsing error
element_is_not_correct = 1000,
found_new_start_element = 1001,
element_is_reserved = 1002,
attribute_is_not_complete = 1003,
missing_quote = 1004,
end_element_not_matched = 1005,
comment_not_complete = 1006,
invalid_xml_element = 1007,
invalid_attribute_name = 1008
};
public:
std::string errtext(xmlint32 errcode) const;
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////
//
class xmlcnf : public xmlcnf_interface,
public xmlcnf_parser {
protected:
void start_doc();
void end_doc();
void found_error(const std::string& filename, xmluint32 line_no, xmlint32 errcode);
void found_xml_element(const std::string& element);
void found_start_element(const std::string& element);
void found_end_element(const std::string& element);
void found_comment(const std::string& comment);
void found_text(const std::string& element, const std::string& text);
void found_attribute(const std::string& element, const std::string& attribute, const std::string& value);
public:
int parse();
#ifdef XML_DEBUG
void dump_keys();
#endif
std::string get_string(const std::string& key, const std::string& def_value = "");
xmlint64 get_int(const std::string& key, xmlint64 def_value = 0);
xmluint64 get_uint(const std::string& key, xmlint64 def_value = 0);
xmlfloat64 get_float(const std::string& key, xmlfloat64 def_value = 0.0);
xmlbool get_bool(const std::string& key, const std::string& true_value = "YES");
private:
std::map<std::string, std::string> map_keys_;
std::vector<std::string> vector_keys_;
};
#endif //xmlcnf_h
//////////////////////////////////////////////////////////////////////////////////////////////
// xmlcnf.cpp
// Author: Seree Rakwong
// Date: 25-OCT-10
// Purpose: Read a simple XML file
#ifdef XML_DEBUG
#include <iostream>
using std::cerr;
using std::cout;
using std::endl;
#endif
using std::string;
using std::vector;
using std::stack;
using std::ifstream;
using std::map;
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// xmlcnf_attribute
xmlcnf_attribute::xmlcnf_attribute()
: attribute_(),
value_() {
}
xmlcnf_attribute::xmlcnf_attribute(const string& attribute, const string& value)
: attribute_(attribute),
value_(value) {
}
const string xmlcnf_attribute::attribute() const {
return attribute_;
}
const string xmlcnf_attribute::value() const {
return value_;
}
string& xmlcnf_attribute::attribute() {
return attribute_;
}
string& xmlcnf_attribute::value() {
return value_;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// xmlcnf_element
xmlcnf_element::xmlcnf_element()
: name_(),
text_() {
}
xmlcnf_element::xmlcnf_element(const string& name, const string& text)
: name_(name),
text_(text) {
}
const string xmlcnf_element::name() const {
return name_;
}
const string xmlcnf_element::text() const {
return text_;
}
string& xmlcnf_element::name() {
return name_;
}
string& xmlcnf_element::text() {
return text_;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// xmlcnf_parser
xmlcnf_parser::xmlcnf_parser()
: filename_("") {
}
xmlcnf_parser::xmlcnf_parser(const char *filename, ios_base::openmode mode)
: ifstream(filename, mode),
filename_(filename) {
}
xmlcnf_parser::xmlcnf_parser(const string& filename)
: ifstream(filename.c_str()),
filename_(filename) {
}
void xmlcnf_parser::open(const char *filename, ios_base::openmode mode) {
ifstream::open(filename, mode);
filename_ = filename;
}
void xmlcnf_parser::open(const string& filename) {
ifstream::open(filename.c_str());
filename_ = filename;
}
#ifdef XML_DEBUG
void xmlcnf_parser::dump_error(const string& filename, xmluint32 line_no, const string& funcname) {
cerr << "\nFilename: " << filename
<< "\tLine: " << line_no
<< "\tFunction: " << funcname
<< endl;
}
#endif
char xmlcnf_parser::skip_whitespaces(xmluint32 *line_ptr) {
char ch = 0;
while(good()) {
ch = get();
if(is_whitespaces(ch)) {
if(ch == '\n') (*line_ptr)++;
}
else return ch;
}
return ch;
}
char xmlcnf_parser::skip_if_not(xmlcnf_interface *xmlcnf_ptr, xmluint32 *line_ptr, char stop_char) {
char ch = 0;
string text;
while(good()) {
ch = get();
if(ch == stop_char) {
if(!elements_.empty()) {
if(elements_.top().text().empty()) {
string trim_text = trim(text);
if(trim_text.length() > 0) {
elements_.top().text() = trim_text;
xmlcnf_ptr->found_text(elements_.top().name(), trim_text);
//elements_.top().text() = text;
//xmlcnf_ptr->found_text(elements_.top().name(), text);
}
}
}
return stop_char;
}
else if(ch == '\n') (*line_ptr)++;
text += ch;
}
return ch;
}
bool xmlcnf_parser::is_whitespaces(char ch) {
if(ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n')
return true;
return false;
}
int xmlcnf_parser::parse(xmlcnf_interface *xmlcnf_ptr) {
if(!xmlcnf_ptr) return interface_object_is_null;
if(!is_open()) return file_is_not_opened;
if(!good()) return file_is_bad;
// start reading
xmlcnf_ptr->start_doc();
xmluint32 line_no = 1;
char cur_char = 0;
int rc = error_none;
if(good()) cur_char = get(); // first read
while(good()) {
// always read an element first
rc = read_element(xmlcnf_ptr, &line_no, &cur_char);
if(rc != error_none) {
if(rc != end_of_element) break;
}
cur_char = skip_if_not(xmlcnf_ptr, &line_no, '<');
}
// end reading
xmlcnf_ptr->end_doc();
return rc;
}
int xmlcnf_parser::read_element(xmlcnf_interface *xmlcnf_ptr, xmluint32 *line_ptr, char *curchar_ptr) {
if(is_whitespaces(*curchar_ptr)) {
*curchar_ptr = skip_whitespaces(line_ptr);
}
if(*curchar_ptr == '>') { //read next char
if(good()) *curchar_ptr = get();
}
// start
string element("<");
char ch = get();
while(good()) {
if(ch == '\n') { // xml stores a new line as LF
(*line_ptr)++;
}
else if(ch == '<') {
if(element.length() > 4 && element.substr(0, 4) != "<!--") {
xmlcnf_ptr->found_error(filename_, *line_ptr, found_new_start_element);
#ifdef XML_DEBUG
dump_error(__FILE__, __LINE__, "xmlcnf_parser::read_element::found_new_start_element");
#endif
return found_new_start_element;
}
}
else if(ch == '>') {
size_t len = element.length();
if(len >= 4 && element.substr(0, 4) != "<!--") {
//end-of-element
break;
}
else {
if(len >= 6 && element.substr(len-2, 2) == "--") {
// end-of-comment
break;
}
}
}
element += ch;
ch = get();
}
if(!good()) {
xmlcnf_ptr->found_error(filename_, *line_ptr, file_not_complete);
#ifdef XML_DEBUG
dump_error(__FILE__, __LINE__, "xmlcnf_parser::read_element::file_not_complete");
#endif
return file_not_complete;
}
// the last
element += ch; // should be <element_name ...> or <?xml ... ?> or <!-- ... --> or </element_name>
// begin-of-element the length has 3 characters at least, but
// if it the end-of-element has 4 characters at least
size_t len = element.length();
// check if the length is less than 3
if(len < 3) {
xmlcnf_ptr->found_error(filename_, *line_ptr, element_is_not_correct);
#ifdef XML_DEBUG
dump_error(__FILE__, __LINE__, "xmlcnf_parser::read_element::element_is_not_correct");
#endif
return element_is_not_correct;
}
// check if it is end-of-element
if(element[1] == '/' && len < 4) {
xmlcnf_ptr->found_error(filename_, *line_ptr, element_is_not_correct);
#ifdef XML_DEBUG
dump_error(__FILE__, __LINE__, "xmlcnf_parser::read_element::element_is_not_correct");
#endif
return element_is_not_correct;
}
// parsing element
int rc = error_none;
switch(element[1]) {
case '?': {
// xml declaration
rc = parse_xml_element(xmlcnf_ptr, line_ptr, element);
break;
}
case '/': {
// end-of-element
rc = parse_xml_end_element(xmlcnf_ptr, line_ptr, element);
if(rc == end_of_element) {
*curchar_ptr = ch;
return rc;
}
break;
}
case '!': {
// comment
rc = parse_xml_comment(xmlcnf_ptr, line_ptr, element);
break;
}
default: {
// begin-of-element
rc = parse_xml_start_element(xmlcnf_ptr, line_ptr, element);
break;
}
}
if(rc != error_none) return rc;
// next char
*curchar_ptr = ch;
return error_none;
}
int xmlcnf_parser::parse_xml_element(xmlcnf_interface *xmlcnf_ptr, xmluint32 *line_ptr, const string& element) {
if(element.length() < 7) {
xmlcnf_ptr->found_error(filename_, *line_ptr, invalid_xml_element);
#ifdef XML_DEBUG
dump_error(__FILE__, __LINE__, "xmlcnf_parser::parse_xml_element::invalid_xml_element");
#endif
return invalid_xml_element;
}
if(element.substr(0, 5) != "<?xml") {
xmlcnf_ptr->found_error(filename_, *line_ptr, invalid_xml_element);
#ifdef XML_DEBUG
dump_error(__FILE__, __LINE__, "xmlcnf_parser::parse_xml_element::invalid_xml_element");
#endif
return invalid_xml_element;
}
if(element.substr(element.length()-2, 2) != "?>") {
xmlcnf_ptr->found_error(filename_, *line_ptr, invalid_xml_element);
#ifdef XML_DEBUG
dump_error(__FILE__, __LINE__, "xmlcnf_parser::parse_xml_element::invalid_xml_element");
#endif
return invalid_xml_element;
}
elements_.push(xmlcnf_element("xml", ""));
xmlcnf_ptr->found_xml_element(element);
size_t pos = element.find_first_not_of(" \t\r", 5);
string xml_attribute = element.substr(pos, element.length()-pos-2);
xml_attribute = trim(xml_attribute);
int rc = parse_xml_attribute(xmlcnf_ptr, line_ptr, xml_attribute);
return rc;
}
int xmlcnf_parser::parse_xml_comment(xmlcnf_interface *xmlcnf_ptr, xmluint32 *line_ptr, const string& element) {
if(element.length() < 7) {
// this is not a comment
xmlcnf_ptr->found_error(filename_, *line_ptr, comment_not_complete);
#ifdef XML_DEBUG
dump_error(__FILE__, __LINE__, "xmlcnf_parser::parse_xml_comment::comment_not_complete");
#endif
return comment_not_complete;
}
// check 4 first characters if they must be "<!--"
if(element.substr(0, 4) != "<!--") {
// this is not a comment
xmlcnf_ptr->found_error(filename_, *line_ptr, comment_not_complete);
#ifdef XML_DEBUG
dump_error(__FILE__, __LINE__, "xmlcnf_parser::parse_xml_comment::comment_not_complete");
#endif
return comment_not_complete;
}
// check 3 last characters if they must be "-->"
if(element.substr(element.length()-3, 3) != "-->") {
// this is not a comment
xmlcnf_ptr->found_error(filename_, *line_ptr, comment_not_complete);
#ifdef XML_DEBUG
dump_error(__FILE__, __LINE__, "xmlcnf_parser::parse_xml_comment::comment_not_complete");
#endif
return comment_not_complete;
}
// this is a comment
xmlcnf_ptr->found_comment(element.substr(4, element.length()-7));
return error_none;
}
int xmlcnf_parser::parse_xml_start_element(xmlcnf_interface *xmlcnf_ptr, xmluint32 *line_ptr, const string& element) {
string start_element = element.substr(1, element.length()-2);
const char *str = start_element.c_str();
size_t len = start_element.length();
if(len < 3) { // there is no an attribute
elements_.push(xmlcnf_element(str, ""));
xmlcnf_ptr->found_start_element(start_element);
}
else {
// check if first 3 characters are 'xml', 'XML', 'Xml, or etc
if(*str == 'x' || *str == 'X') {
if(*(str+1) == 'm' || *(str+1) == 'M') {
if(*(str+2) == 'l' || *(str+2) == 'L') {
xmlcnf_ptr->found_error(filename_, *line_ptr, element_is_reserved);
#ifdef XML_DEBUG
dump_error(__FILE__, __LINE__, "xmlcnf_parser::parse_xml_start_element::element_is_reserved");
#endif
return element_is_reserved;
}
}
}
// element may have attributes
size_t pos = start_element.find_first_of('='); // find if there are some '='
if(pos != string::npos) { // found
pos = start_element.find_first_of(" \t\r");
string tag = start_element.substr(0, pos);
elements_.push(xmlcnf_element(tag, ""));
xmlcnf_ptr->found_start_element(tag);
//skip whitespaces
pos = start_element.find_first_not_of(" \t\r", pos+1);
int rc = parse_xml_attribute(xmlcnf_ptr, line_ptr, start_element.substr(pos, start_element.length()-1));
if(rc != error_none) return rc;
}
else {
// only element found
pos = start_element.find_first_of(' ');
if(pos != string::npos) {
string tag = start_element.substr(0, pos);
}
elements_.push(xmlcnf_element(str, ""));
xmlcnf_ptr->found_start_element(start_element);
}
}
return error_none;
}
int xmlcnf_parser::parse_xml_end_element(xmlcnf_interface *xmlcnf_ptr, xmluint32 *line_ptr, const string& element) {
if(elements_.empty()) {
xmlcnf_ptr->found_error(filename_, *line_ptr, end_element_not_matched);
#ifdef XML_DEBUG
dump_error(__FILE__, __LINE__, "xmlcnf_parser::parse_xml_attribute::end_element_not_matched");
#endif
return end_element_not_matched;
}
string end_tag = element.substr(2, element.length()-3);
if(end_tag != elements_.top().name()) {
#ifdef XML_DEBUG
cerr << "end_tag: [" << end_tag << "]"
<< "\ttop: [" << elements_.top().name() << "]" << endl;
#endif
xmlcnf_ptr->found_error(filename_, *line_ptr, end_element_not_matched);
#ifdef XML_DEBUG
dump_error(__FILE__, __LINE__, "xmlcnf_parser::parse_xml_attribute::end_element_not_matched");
#endif
return end_element_not_matched;
}
// found end tag and matched
xmlcnf_ptr->found_end_element(end_tag);
// remove the top
elements_.pop();
return end_of_element;
}
int xmlcnf_parser::parse_xml_attribute(xmlcnf_interface *xmlcnf_ptr, xmluint32 *line_ptr, const string& element) {
xmlcnf_element start_element = elements_.top();
string sub_element = trim(element);
size_t pos_attribute = 0;
while(sub_element.length() > 0) {
// read attribute til found whitespaces or '='
string attribute;
size_t end_attribute = sub_element.find_first_of('=');
if(end_attribute == string::npos) {
end_attribute = sub_element.find_first_of('=');
if(end_attribute == string::npos) {
//missing attribute
xmlcnf_ptr->found_error(filename_, *line_ptr, attribute_is_not_complete);
#ifdef XML_DEBUG
dump_error(__FILE__, __LINE__, "xmlcnf_parser::parse_xml_attribute::attribute_is_not_complete");
#endif
return attribute_is_not_complete;
}
}
attribute = sub_element.substr(pos_attribute, end_attribute);
attribute = trim(attribute);
if(!is_valid_name(attribute)) {
xmlcnf_ptr->found_error(filename_, *line_ptr, invalid_attribute_name);
#ifdef XML_DEBUG
dump_error(__FILE__, __LINE__, "xmlcnf_parser::parse_xml_attribute::invalid_attribute_name");
#endif
return invalid_attribute_name;
}
// read value
sub_element = sub_element.substr(end_attribute+1);
sub_element = trim(sub_element);
char quote = sub_element[0];
if(quote != '\'' && quote != '"') {
xmlcnf_ptr->found_error(filename_, *line_ptr, missing_quote);
#ifdef XML_DEBUG
dump_error(__FILE__, __LINE__, "xmlcnf_parser::parse_xml_attribute::missing_qoute");
#endif
return missing_quote;
}
// pair of qoute
size_t end_value = sub_element.find_first_of(quote, 1);
if(end_value == string::npos) {
xmlcnf_ptr->found_error(filename_, *line_ptr, missing_quote);
#ifdef XML_DEBUG
dump_error(__FILE__, __LINE__, "xmlcnf_parser::parse_xml_attribute::missing_qoute");
#endif
return missing_quote;
}
string value = sub_element.substr(0, end_value+1);
value = trim(value);
// got attribute and value
xmlcnf_ptr->found_attribute(start_element.name(), attribute, value.substr(1,value.length()-2));
// next attribute
sub_element = sub_element.substr(end_value+1);
sub_element = trim(sub_element);
size_t pos_equal = sub_element.find_first_of('=');
if(pos_equal == string::npos) {
// no more attributes found
break;
}
}
return error_none;
}
bool xmlcnf_parser::is_valid_name(const string& name) {
//no whitespaces
size_t pos_whitespaces = name.find_first_of(" \t\r\n\v\f");
if(pos_whitespaces != string::npos) {
return false;
}
return true;
}
/*
interface_object_is_null = -1,
file_is_not_opened = -2,
file_is_bad = -3,
file_not_complete = -4,
// parsing error
element_is_not_correct = 1000,
found_new_start_element = 1001,
element_is_reserved = 1002,
attribute_is_not_complete = 1003,
missing_quote = 1004,
end_element_not_matched = 1005,
comment_not_complete = 1006,
invalid_xml_element = 1007,
invalid_attribute_name = 1008
*/
string xmlcnf_parser::errtext(xmlint32 errcode) const {
switch(errcode) {
case interface_object_is_null: return "interface object is a null object";
case file_is_not_opened: return "file is not opened";
case file_is_bad: return "file is bad";
case file_not_complete: return "file is not complete";
case element_is_not_correct: return "element is not correct";
case found_new_start_element: return "found new start element";
case element_is_reserved: return "element is reserved";
case attribute_is_not_complete: return "attribute is not complete";
case missing_quote: return "missing quote";
case end_element_not_matched: return "found end element not matched with start element";
case comment_not_complete: return "comment is not complete";
case invalid_xml_element: return "invalid XML element";
case invalid_attribute_name: return "invalid attribute name";
}
return "";
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// xmlcnf
void xmlcnf::start_doc() {
map_keys_.clear();
vector_keys_.clear();
}
void xmlcnf::end_doc() {
}
int xmlcnf::parse() {
return xmlcnf_parser::parse((xmlcnf_interface*)this);
}
void xmlcnf::found_error(const std::string& filename, xmluint32 line_no, xmlint32 errcode) {
#ifdef XML_DEBUG
cerr << "xmlcnf::found_error: filename: [" << filename << "]"
<< "\tline_no: [" << line_no << "]"
<< "\terrcode: [" << errcode << "]"
<< "\terrtext: [" << errtext(errcode) << "]"
<< endl;
#endif
}
void xmlcnf::found_xml_element(const string& element) {
}
void xmlcnf::found_start_element(const string& element) {
#ifdef XML_DEBUG
cerr << "xmlcnf::found_start_element: key: [" << element << "]" << endl;
#endif
vector_keys_.push_back(element);
}
void xmlcnf::found_end_element(const string& element) {
#ifdef XML_DEBUG
cerr << "xmlcnf::found_end_element: key: [" << element << "]" << endl;
#endif
vector_keys_.pop_back();
}
void xmlcnf::found_comment(const string& comment) {
#ifdef XML_DEBUG
cerr << "xmlcnf::found_comment: comment: [" << comment << "]" << endl;
#endif
}
void xmlcnf::found_text(const string& element, const string& text) {
string key;
vector<string>::iterator it;
for(it = vector_keys_.begin(); it != vector_keys_.end(); it++) {
key += *it;
key += ".";
}
// remove '.' at the last
key = key.substr(0, key.length()-1);
map_keys_[key] = text;
}
void xmlcnf::found_attribute(const string& element, const string& attribute, const string& value) {
string key;
vector<string>::iterator it;
for(it = vector_keys_.begin(); it != vector_keys_.end(); it++) {
key += *it;
key += ".";
}
key += attribute;
map_keys_[key] = value;
}
#ifdef XML_DEBUG
void xmlcnf::dump_keys() {
map<string, string>::iterator it;
for(it = map_keys_.begin(); it != map_keys_.end(); it++) {
cout << "[" << it->first << "] = [" << it->second << "]" << endl;
}
}
#endif
string xmlcnf::get_string(const string& key, const string& def_value) {
map<string, string>::iterator it;
it = map_keys_.find(key);
if(it != map_keys_.end()) return it->second;
return def_value;
}
xmlint64 xmlcnf::get_int(const string& key, xmlint64 def_value) {
map<string, string>::iterator it;
it = map_keys_.find(key);
if(it != map_keys_.end()) {
char *end = 0;
return strtol(it->second.c_str(), &end, 10);
}
return def_value;
}
xmluint64 xmlcnf::get_uint(const string& key, xmlint64 def_value) {
map<string, string>::iterator it;
it = map_keys_.find(key);
if(it != map_keys_.end()) {
char *end = 0;
return strtoul(it->second.c_str(), &end, 10);
}
return def_value;
}
xmlfloat64 xmlcnf::get_float(const string& key, xmlfloat64 def_value) {
map<string, string>::iterator it;
it = map_keys_.find(key);
if(it != map_keys_.end()) {
char *end = 0;
return strtod(it->second.c_str(), &end);
}
return def_value;
}
xmlbool xmlcnf::get_bool(const string& key, const string& true_value) {
map<string, string>::iterator it;
it = map_keys_.find(key);
if(it != map_keys_.end() && it->second == true_value) return true;
return false;
}
////////////////////////
// xmlstring
string trim_left(const string& str) {
string temp(str);
return temp.erase(0, temp.find_first_not_of(" \t\r\n\f\v"));
}
string trim_right(const string& str) {
string temp(str);
return temp.erase(1+temp.find_last_not_of(" \t\r\n\f\v"));
}
string trim(const string& str) {
string temp(str);
temp = trim_left(temp);
return trim_right(temp);
}
//////////////////////////////////////////////////////////////////////////////////////////////
// test.cpp
// Author: Seree Rakwong
// Date: 25-OCT-10
// Purpose: Read a simple XML file
#include <iostream>
using namespace std;
class bookcnf : public xmlcnf {
public:
bool use_cache() const { return use_cache_; }
string log_name() const { return log_name_; }
string log_level() const { return log_level_; }
xmluint64 log_size() const { return log_size_; }
protected:
void end_doc() {
use_cache_ = get_bool("Interday.Cache.use", "YES");
log_name_ = get_string("Interday.Cache.Log.Name");
log_level_ = get_string("Interday.Cache.Log.Level");
string log_size = get_string("Interday.Cache.Log.Size");
size_t len = log_size.length();
if(len > 1) {
char unit = log_size[len-1];
int multiply = 1;
switch(unit) {
case 'K': multiply = 1024; break;
case 'M': multiply = 1048576; break;
case 'G': multiply = 1073741824; break;
default: multiply = 1; break;
}
char *end = 0;
if(multiply == 1) {
log_size_ = strtoul(log_size.c_str(), &end, 10);
}
else {
log_size_ = strtoul(log_size.substr(0, len-1).c_str(), &end, 10)*multiply;
}
}
else {
log_size_ = get_uint("Interday.Cache.Log.Size");
}
}
private:
bool use_cache_;
string log_name_;
xmluint64 log_size_;
string log_level_;
};
int main(int argc, char *argv[]) {
string filename;
if(argc < 2) {
filename = "books.xml";
}
else filename = argv[1];
bookcnf cnf;
cnf.open(filename);
cnf.parse();
#ifdef XML_DEBUG
cnf.dump_keys();
#endif
cout << "use cache: [" << (cnf.use_cache() ? "YES" : "NO") << "]" << endl;
cout << "log name: [" << cnf.log_name() << "]" << endl;
cout << "log size: [" << cnf.log_size() << "]" << endl;
cout << "log level: [" << cnf.log_level() << "]" << endl;
return 0;
}
/////////////////////////////////////////////////////////////
// myconfig.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<Interday>
<Cache use="YES">
<Log>
<Name>../log/interday.log</Name>
<!-- minsize = 0, maxsize = 3.99G -->
<!-- K = 2^10 -->
<!-- M = 2^20 -->
<!-- G = 2^30 -->
<Size>3.99G</Size>
<Level>System</Level>
</Log>
</Cache>
</Interday>
/////////////////////////////////////////////////////////////
// myconfig.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<Interday>
<Cache use="YES">
<Log>
<Name>../log/interday.log</Name>
<!-- minsize = 0, maxsize = 3.99G -->
<!-- K = 2^10 -->
<!-- M = 2^20 -->
<!-- G = 2^30 -->
<Size>3.99G</Size>
<Level>System</Level>
</Log>
</Cache>
</Interday>