ViennaGrid - The Vienna Grid Library  2.1.0
viennagrid/io/xml_tag.hpp
Go to the documentation of this file.
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