Subversion Repositories HomeAutomation

Rev

Rev 1914 | Blame | Compare with Previous | Last modification | View Log | SVN | RSS feed

  1. /*
  2.  *
  3.  *  Copyright (C) 2010  Mattias Runge
  4.  *
  5.  *  This program is free software; you can redistribute it and/or modify
  6.  *  it under the terms of the GNU General Public License as published by
  7.  *  the Free Software Foundation; either version 2 of the License, or
  8.  *  (at your option) any later version.
  9.  *
  10.  *  This program is distributed in the hope that it will be useful,
  11.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  *  GNU General Public License for more details.
  14.  *
  15.  *  You should have received a copy of the GNU General Public License along
  16.  *  with this program; if not, write to the Free Software Foundation, Inc.,
  17.  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  18.  *
  19.  */
  20.  
  21. #include "Node.h"
  22.  
  23. //#include <iostream>
  24.  
  25. #include <fstream>
  26. #include <stdexcept>
  27.  
  28. #include <boost/lexical_cast.hpp>
  29. #include <boost/algorithm/string/trim.hpp>
  30.  
  31. namespace atom {
  32. namespace xml {
  33.  
  34. Node::Node()
  35. {
  36.  
  37. }
  38.  
  39. Node::~Node()
  40. {
  41.  
  42. }
  43.  
  44. void Node::LoadFile(std::string filename)
  45. {
  46.   std::ifstream file(filename.data());
  47.  
  48.   if (!file.is_open())
  49.   {
  50.     throw std::runtime_error("Could not find " + filename);
  51.     return;
  52.   }
  53.  
  54.   std::string buffer((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
  55.  
  56.   file.close();
  57.  
  58.   this->Parse(buffer);
  59. }
  60.  
  61. void Node::Parse(std::string data)
  62. {
  63.     char c;
  64.     int position = 0;
  65.    
  66.     while ((unsigned int)position < data.length())
  67.     {
  68.         c = data.at(position);
  69.        
  70.         switch (c)
  71.         {
  72.             case '<':
  73.             {
  74.                 position = this->ParseTag(data, position);
  75.                 break;
  76.             }
  77.         }
  78.        
  79.         position++;
  80.     }
  81. }
  82.  
  83. int Node::ParseTag(std::string data, int position)
  84. {
  85.     if (data.at(position) != '<')
  86.     {
  87.         throw std::runtime_error("Id not find < as expected. Character " + boost::lexical_cast<std::string>(position));
  88.     }
  89.    
  90.     position++;
  91.    
  92.     int end_position = data.find('>', position);
  93.    
  94.     if (data.at(position) == '?' || data.at(position) == '!' || data.at(position) == '/')
  95.     {
  96.         return end_position;
  97.     }
  98.    
  99.     std::string tag_string;
  100.    
  101.     try
  102.     {
  103.         tag_string = data.substr(position, end_position - position);
  104.     }
  105.     catch (std::out_of_range& e)
  106.     {
  107.         throw std::runtime_error(e.what());
  108.     }
  109.    
  110.     boost::algorithm::trim(tag_string);
  111.     boost::algorithm::trim_if(tag_string, boost::is_any_of("\n"));
  112.     boost::algorithm::trim(tag_string);
  113.     tag_string += " ";
  114.    
  115.     bool found_end = false;
  116.     bool found_tag = false;
  117.     std::string buffer;
  118.     int pos = 0;
  119.     char c;
  120.     int s, e;
  121.    
  122.     while ((unsigned int)pos < tag_string.length())
  123.     {
  124.         c = tag_string.at(pos);
  125.        
  126.         switch (c)
  127.         {
  128.             case ' ':
  129.             {
  130.                 if (!found_tag)
  131.                 {
  132.                     this->tag_name_ = buffer;
  133.                     buffer = "";
  134.                     //std::cout << "Found tag: " << this->tag_name_ << std::endl;
  135.                     found_tag = true;
  136.                 }
  137.                 break;
  138.             }  
  139.             case '/':
  140.             {
  141.                 found_end = true;
  142.                 break;
  143.             }
  144.             case '=':
  145.             {
  146.                 s = tag_string.find('"', pos) + 1;
  147.                 e = tag_string.find('"', s);
  148.                
  149.                 try
  150.                 {
  151.                     this->attributes_[buffer] = tag_string.substr(s, e - s);
  152.                 }
  153.                 catch (std::out_of_range& ex)
  154.                 {
  155.                     throw std::runtime_error(ex.what());
  156.                 }
  157.  
  158.                 pos = e;
  159.                 buffer = "";
  160.                 break;
  161.             }
  162.             default:
  163.             {
  164.                 buffer += c;
  165.                 break;
  166.             }
  167.         }
  168.        
  169.         pos++;
  170.     }
  171.    
  172.     position = end_position;
  173.    
  174.     if (!found_end)
  175.     {
  176.         while ((unsigned int)position < data.length())
  177.         {
  178.             c = data.at(position);
  179.            
  180.             switch (c)
  181.             {
  182.                 case '<':
  183.                 {
  184.                     if (data.at(position+1) == '/')
  185.                     {
  186.                         position += 2;
  187.                         end_position = data.find('>', position);
  188.                        
  189.                         try
  190.                         {
  191.                             if (this->tag_name_.compare(data.substr(position, end_position - position)) == 0)
  192.                             {
  193.                                 //std::cout << "Found end tag: " << this->tag_name_ << std::endl;
  194.                                 return end_position;
  195.                             }
  196.                             else
  197.                             {
  198.                                 throw std::runtime_error("Invalid end tag found. " + data.substr(position, end_position - position) + "::" + this->tag_name_);
  199.                             }
  200.                         }
  201.                         catch (std::out_of_range& e)
  202.                         {
  203.                             throw std::runtime_error(e.what());
  204.                         }
  205.                        
  206.                        
  207.                     }
  208.                    
  209.                     Node sub_node;
  210.                     position = sub_node.ParseTag(data, position);
  211.                     this->children_.push_back(sub_node);
  212.                     break;
  213.                 }
  214.             }
  215.            
  216.             position++;
  217.         }
  218.     }
  219.    
  220.     return position;
  221. }
  222.  
  223. Node Node::FindChild(std::string tag_name)
  224. {
  225.     for (unsigned int n = 0; n < this->children_.size(); n++)
  226.     {
  227.         if (this->children_[n].GetTagName().compare(tag_name) == 0)
  228.         {
  229.             return this->children_[n];
  230.         }
  231.     }
  232.    
  233.     throw std::runtime_error("No child with that tag name found, " + tag_name);
  234. }
  235.  
  236. Node Node::SelectChild(std::string attribute_name, std::string attribute_value)
  237. {
  238.     for (unsigned int n = 0; n < this->children_.size(); n++)
  239.     {
  240.         if (this->children_[n].GetAttributeValue(attribute_name) == attribute_value)
  241.         {
  242.             return this->children_[n];
  243.         }
  244.     }
  245.    
  246.     throw std::runtime_error("No child with that attribute combination found, " + attribute_name + " = " + attribute_value);
  247. }
  248.  
  249. Node Node::SelectChild(std::string attribute_name1, std::string attribute_value1, std::string attribute_name2, std::string attribute_value2)
  250. {
  251.     for (unsigned int n = 0; n < this->children_.size(); n++)
  252.     {
  253.         if (this->children_[n].GetAttributeValue(attribute_name1) == attribute_value1 && this->children_[n].GetAttributeValue(attribute_name2) == attribute_value2)
  254.         {
  255.             return this->children_[n];
  256.         }
  257.     }
  258.    
  259.     throw std::runtime_error("No child with that attribute combination found, " + attribute_name1 + " = " + attribute_value1 + " && " + attribute_name2 + " = " + attribute_value2);
  260. }
  261.  
  262. std::string Node::GetAttributeValue(std::string attribute_name)
  263. {
  264.     AttributeList::const_iterator iterator = this->attributes_.find(attribute_name);
  265.    
  266.     if (iterator == this->attributes_.end())
  267.     {
  268.         throw std::runtime_error("No attribute with that name found, " + attribute_name);
  269.     }
  270.    
  271.     return iterator->second;
  272. }
  273.  
  274. Node::AttributeList Node::GetAttributes()
  275. {
  276.     return this->attributes_;
  277. }
  278.  
  279. std::vector<Node> Node::GetChildren()
  280. {
  281.     return this->children_;
  282. }
  283.  
  284. std::string Node::GetTagName()
  285. {
  286.     return this->tag_name_;
  287. }
  288.  
  289. }; // namespace xml
  290. }; // namespace atom
  291.