ViennaGrid - The Vienna Grid Library
2.1.0
|
00001 #ifndef VIENNAGRID_IO_XML_TAG_HPP 00002 #define VIENNAGRID_IO_XML_TAG_HPP 00003 00004 /* ======================================================================= 00005 Copyright (c) 2011-2014, Institute for Microelectronics, 00006 Institute for Analysis and Scientific Computing, 00007 TU Wien. 00008 00009 ----------------- 00010 ViennaGrid - The Vienna Grid Library 00011 ----------------- 00012 00013 License: MIT (X11), see file LICENSE in the base directory 00014 ======================================================================= */ 00015 00016 00021 #include <fstream> 00022 #include <iostream> 00023 #include <sstream> 00024 #include <list> 00025 #include <string> 00026 #include <algorithm> 00027 00028 00029 #include "viennagrid/io/helper.hpp" 00030 00035 namespace viennagrid 00036 { 00037 namespace io 00038 { 00039 00044 template <int dummy = 0> 00045 struct char_to_lower 00046 { 00047 char operator()(char c) const 00048 { 00049 if(c <= 'Z' && c >= 'A') 00050 return c - static_cast<char>('Z'-'z'); 00051 return c; 00052 } 00053 }; 00054 00059 template <typename StringType> //Note: Using artifically a template argument t 00060 StringType string_to_lower(StringType const & s) 00061 { 00062 std::string ret = s; 00063 std::transform(ret.begin(), ret.end(), ret.begin(), char_to_lower<0>()); 00064 00065 return ret; 00066 } 00067 00072 template <typename dummy = bool> 00073 class xml_tag 00074 { 00075 typedef std::pair<std::string, std::string> AttributeType; 00076 typedef std::list<AttributeType> AttributeContainer; 00077 00078 public: 00079 00081 template <typename InputStream> 00082 void parse(InputStream & reader) 00083 { 00084 reader.unsetf(std::ios_base::skipws); 00085 clear(); 00086 00087 char c = ' '; 00088 00089 //go to start of tag: 00090 while (c != '<' && reader.good()) 00091 reader >> c; 00092 00093 //read tag name: 00094 while ( (c != ' ' && c != '>') && reader.good() ) 00095 { 00096 reader >> c; 00097 name_.append(1, make_lower(c)); 00098 } 00099 00100 //strip whitespace or closing tag at the end 00101 name_.resize(name_.size()-1); 00102 00103 #ifdef VIENNAGRID_DEBUG_IO 00104 std::cout << name_ << std::endl; 00105 #endif 00106 00107 if (c == '>') //we are all done 00108 return; 00109 00110 //get attributes: 00111 bool end_of_attribute = false; 00112 bool inside_string = false; 00113 std::string token; 00114 while (c != '>' && reader.good()) 00115 { 00116 reader >> c; 00117 00118 if (inside_string && c == '"') //terminate string 00119 { 00120 end_of_attribute = true; 00121 } 00122 else if (!inside_string && c == '"') //start of string 00123 { 00124 inside_string = true; 00125 } 00126 00127 if (inside_string) 00128 token.append(1, c); //do not transform values to lower-case (e.g. filenames may get invalid) 00129 else if (c != ' ') 00130 token.append(1, make_lower(c)); 00131 00132 00133 if (end_of_attribute) 00134 { 00135 std::size_t pos = token.find_first_of('='); 00136 if (pos == std::string::npos) 00137 { 00138 throw bad_file_format_exception("* ViennaGrid: xml_tag::parse(): Parse error: XML attribute does not have '=' sign."); 00139 } 00140 else if (pos == 0) 00141 { 00142 throw bad_file_format_exception("* ViennaGrid: xml_tag::parse(): Parse error: XML attribute name missing."); 00143 } 00144 00145 00146 std::string name = token.substr(0, pos); 00147 std::string value = token.substr(pos+2, token.size()); 00148 00149 pos = value.rfind('"'); 00150 if (pos == std::string::npos || pos == 0) 00151 throw bad_file_format_exception("* ViennaGrid: xml_tag::parse(): Internal XML parse error: XML attribute string not terminated."); 00152 00153 #ifdef VIENNAGRID_DEBUG_IO 00154 std::cout << name << ":" << value.substr(0, pos) << std::endl; 00155 #endif 00156 attributes_.push_back(std::make_pair(name, value.substr(0, pos))); 00157 00158 token.clear(); 00159 00160 end_of_attribute = false; 00161 inside_string = false; 00162 } 00163 } 00164 00165 reader.setf(std::ios_base::skipws); 00166 } 00167 00169 void check_name(std::string const & expected_name, 00170 std::string const & filename = std::string()) 00171 { 00172 if (name_ != string_to_lower(expected_name)) 00173 { 00174 std::stringstream ss; 00175 ss << "* ViennaGrid: xml_tag::check_name(): XML Parse error in file " << filename << ": " << expected_name << " expected, but got " << name_ << std::endl; 00176 throw bad_file_format_exception(ss.str()); 00177 } 00178 } 00179 00181 template <typename InputStream> 00182 void parse_and_check_name(InputStream & reader, 00183 std::string const & expected_name, 00184 std::string const & filename = std::string()) 00185 { 00186 parse(reader); 00187 check_name(expected_name, filename); 00188 } 00189 00191 std::string name() const { return name_; } 00192 00194 bool has_attribute(std::string const & attrib_name) const 00195 { 00196 for (typename AttributeContainer::const_iterator it = attributes_.begin(); 00197 it != attributes_.end(); 00198 ++it) 00199 { 00200 if (it->first == attrib_name) 00201 return true; 00202 } 00203 return false; 00204 } 00205 00207 void check_attribute(std::string const & attrib_name, 00208 std::string const & filename) const 00209 { 00210 if (!has_attribute(attrib_name)) 00211 { 00212 std::stringstream ss; 00213 ss << "* ViennaGrid: xml_tag::check_attribute(): XML Parse error in file " << filename << ": Attribute " << attrib_name << " missing!" << std::endl; 00214 throw bad_file_format_exception(ss.str()); 00215 } 00216 } 00217 00219 std::string get_value(std::string const & attrib_name) const 00220 { 00221 for (typename AttributeContainer::const_iterator it = attributes_.begin(); 00222 it != attributes_.end(); 00223 ++it) 00224 { 00225 if (it->first == attrib_name) 00226 return it->second; 00227 } 00228 return ""; 00229 } 00230 00232 void clear() 00233 { 00234 name_ = std::string(); 00235 attributes_.clear(); 00236 } 00237 private: 00238 00240 char make_lower(char c) const 00241 { 00242 if(c <= 'Z' && c >= 'A') 00243 return c - ('Z'-'z'); 00244 return c; 00245 } 00246 00247 std::string name_; 00248 AttributeContainer attributes_; 00249 }; 00250 00251 00252 } //namespace io 00253 } //namespace viennagrid 00254 00255 #endif