Changeset 8:091bd494eac4 in rrlib_xml


Ignore:
Timestamp:
23.09.2010 00:50:46 (9 years ago)
Author:
Tobias Föhst <foehst@…>
Branch:
default
Phase:
public
Convert:
svn:3219ad6e-c0b7-4ac2-9554-e22e195eef7a/trunk@9
Message:
  • Fixed remaining memory leaks
  • Added methods to add/remove/set nodes/attributes/text content
  • Made tXMLNode copyable using reference counting
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • tXMLDocument.cpp

    r6 r8  
    119119  } 
    120120  this->root_node = new tXMLNode(xmlNewNode(0, reinterpret_cast<const xmlChar *>(name.c_str()))); 
    121   xmlDocSetRootElement(this->document, this->root_node->node); 
     121  xmlDocSetRootElement(this->document, this->root_node->data->node); 
    122122  return *this->root_node; 
    123123} 
  • tXMLDocument.h

    r6 r8  
    2424 * \author  Tobias Foehst 
    2525 * 
    26  * \date    2010-06-24 
     26 * \date    2010-09-18 
    2727 * 
    2828 * \brief Contains tXMLDocument 
     
    105105   * DTD specification. 
    106106   * 
     107   * \exception tXML2WrapperException is thrown if the file was not found or could not be parsed 
     108   * 
    107109   * \param file_name   The name of the file to load 
    108110   * \param validate    Whether the validation should be processed or not 
    109    * 
    110    * \exception tXML2WrapperException is thrown if the file was not found or could not be parsed 
    111111   */ 
    112112  explicit tXMLDocument(const std::string &file_name, bool validate = true); 
     
    125125  tXMLNode &GetRootNode() const; 
    126126 
     127  /*! Add a root node to a new document in DOM representation 
     128   * 
     129   * If you create a new XML document the first thing to do is to 
     130   * add a root node with a specified name. After that, the root node 
     131   * is fixed and additional calls to this method will throw an exception. 
     132   * 
     133   * \exception tXML2WrapperException is thrown if the document already had a root node 
     134   * 
     135   * \param name   The name of the root node 
     136   * 
     137   * \returns A reference to the newly created root node 
     138   */ 
    127139  tXMLNode &AddRootNode(const std::string &name); 
    128140 
     141  /*! Write the XML document to a file 
     142   * 
     143   * This method creates or truncates a file with the given name and writes 
     144   * the documents XML representation into it. 
     145   * 
     146   * \param file_name     The name of the file to use 
     147   * \param compression   Compression level [0-9] where 0 is "no compression" 
     148   */ 
    129149  void WriteToFile(const std::string &file_name, int compression = 0) const; 
    130150 
  • tXMLNode.cpp

    r7 r8  
    6161 
    6262//---------------------------------------------------------------------- 
    63 // tXMLNode constructors 
    64 //---------------------------------------------------------------------- 
    65 tXMLNode::tXMLNode(xmlNodePtr node) 
    66     : node(node), 
     63// tXMLNode::tData constructors 
     64//---------------------------------------------------------------------- 
     65tXMLNode::tData::tData(xmlNodePtr node) 
     66    : ref_counter(1), 
     67    node(node), 
    6768    name(0), 
    68     children(0) 
     69    children(0), 
     70    text_content(0) 
    6971{ 
    7072  assert(node); 
     
    7779 
    7880//---------------------------------------------------------------------- 
    79 // tXMLNode destructor 
    80 //---------------------------------------------------------------------- 
    81 tXMLNode::~tXMLNode() 
     81// tXMLNode::tData destructor 
     82//---------------------------------------------------------------------- 
     83tXMLNode::tData::~tData() 
    8284{ 
    8385  delete this->name; 
    8486  delete this->children; 
     87  delete this->text_content; 
     88//  xmlUnlinkNode(this->node); 
     89//  xmlFreeNode(this->node); 
     90} 
     91 
     92//---------------------------------------------------------------------- 
     93// tXMLNode constructors 
     94//---------------------------------------------------------------------- 
     95tXMLNode::tXMLNode(xmlNodePtr node) 
     96    : data(new tData(node)) 
     97{} 
     98 
     99tXMLNode::tXMLNode(const tXMLNode &other) 
     100    : data(other.data) 
     101{ 
     102  this->data->ref_counter++; 
     103} 
     104 
     105//---------------------------------------------------------------------- 
     106// tXMLNode destructor 
     107//---------------------------------------------------------------------- 
     108tXMLNode::~tXMLNode() 
     109{ 
     110  if (--this->data->ref_counter == 0) 
     111  { 
     112    delete this->data; 
     113  } 
     114} 
     115 
     116//---------------------------------------------------------------------- 
     117// tXMLNode GetName 
     118//---------------------------------------------------------------------- 
     119const std::string &tXMLNode::GetName() const 
     120{ 
     121  if (!this->data->name) 
     122  { 
     123    this->data->name = new std::string(reinterpret_cast<const char *>(this->data->node->name)); 
     124  } 
     125  return *this->data->name; 
    85126} 
    86127 
     
    90131const std::vector<tXMLNode> &tXMLNode::GetChildren() const 
    91132{ 
    92   if (!this->children) 
    93   { 
    94     this->children = new std::vector<tXMLNode>(); 
    95     for (xmlNodePtr child_node = this->node->children; child_node; child_node = child_node->next) 
     133  if (!this->data->children) 
     134  { 
     135    this->data->children = new std::vector<tXMLNode>(); 
     136    for (xmlNodePtr child_node = this->data->node->children; child_node; child_node = child_node->next) 
    96137    { 
    97138      if (child_node->type == XML_ELEMENT_NODE) 
    98139      { 
    99         this->children->push_back(tXMLNode(child_node)); 
     140        this->data->children->push_back(tXMLNode(child_node)); 
    100141      } 
    101142    } 
    102143  } 
    103   return *this->children; 
    104 } 
    105  
    106 //---------------------------------------------------------------------- 
    107 // tXMLNode GetName 
    108 //---------------------------------------------------------------------- 
    109 const std::string &tXMLNode::GetName() const 
    110 { 
    111   if (!this->name) 
    112   { 
    113     this->name = new std::string(reinterpret_cast<const char *>(this->node->name)); 
    114   } 
    115   return *this->name; 
     144  return *this->data->children; 
    116145} 
    117146 
     
    121150tXMLNode &tXMLNode::AddChildNode(const std::string &name) 
    122151{ 
    123   xmlNodePtr child_node = xmlNewChild(this->node, 0, reinterpret_cast<const xmlChar*>(name.c_str()), 0); 
     152  if (this->HasTextContent()) 
     153  { 
     154    throw tXML2WrapperException("Tried to add a structural child to a node that already has text content!"); 
     155  } 
     156  xmlNodePtr child_node = xmlNewChild(this->data->node, 0, reinterpret_cast<const xmlChar*>(name.c_str()), 0); 
    124157  this->GetChildren(); 
    125   this->children->push_back(tXMLNode(child_node)); 
    126   return this->children->back(); 
    127 } 
     158  this->data->children->push_back(tXMLNode(child_node)); 
     159  return this->data->children->back(); 
     160} 
     161 
     162//---------------------------------------------------------------------- 
     163// tXMLNode RemoveChildNode 
     164//---------------------------------------------------------------------- 
     165void tXMLNode::RemoveChildNode(tXMLNode &node) 
     166{ 
     167  this->GetChildren(); 
     168  std::vector<tXMLNode>::iterator child_node = std::find(this->data->children->begin(), this->data->children->end(), node); 
     169  if (child_node == this->data->children->end()) 
     170  { 
     171    throw tXML2WrapperException("Given node is not a child of this."); 
     172  } 
     173  xmlUnlinkNode(child_node->data->node); 
     174  xmlFreeNode(child_node->data->node); 
     175  this->data->children->erase(child_node); 
     176} 
     177 
     178//---------------------------------------------------------------------- 
     179// tXMLNode HasTextContent 
     180//---------------------------------------------------------------------- 
     181const bool tXMLNode::HasTextContent() const 
     182{ 
     183  if (!this->data->text_content) 
     184  { 
     185    for (xmlNodePtr child_node = this->data->node->children; child_node; child_node = child_node->next) 
     186    { 
     187      if (xmlNodeIsText(child_node)) 
     188      { 
     189        xmlChar *text_content = xmlNodeGetContent(this->data->node); 
     190        this->data->text_content = new std::string(reinterpret_cast<const char *>(text_content)); 
     191        xmlFree(text_content); 
     192      } 
     193    } 
     194  } 
     195  return this->data->text_content != 0; 
     196} 
     197 
     198//---------------------------------------------------------------------- 
     199// tXMLNode GetTextContent 
     200//---------------------------------------------------------------------- 
     201const std::string &tXMLNode::GetTextContent() const 
     202{ 
     203  if (!this->HasTextContent()) 
     204  { 
     205    throw tXML2WrapperException("This node does not have any text content!"); 
     206  } 
     207  return *this->data->text_content; 
     208} 
     209 
     210//---------------------------------------------------------------------- 
     211// tXMLNode SetTextContent 
     212//---------------------------------------------------------------------- 
     213void tXMLNode::SetTextContent(const std::string &content) 
     214{ 
     215  this->GetChildren(); 
     216  if (!this->data->children->empty()) 
     217  { 
     218    throw tXML2WrapperException("Tried to set text content in a node that already has structural children!"); 
     219  } 
     220  this->RemoveTextContent(); 
     221  xmlNodeAddContentLen(this->data->node, reinterpret_cast<const xmlChar *>(content.c_str()), content.length()); 
     222} 
     223 
     224//---------------------------------------------------------------------- 
     225// tXMLNode RemoveTextNode 
     226//---------------------------------------------------------------------- 
     227void tXMLNode::RemoveTextContent() 
     228{ 
     229  std::vector<xmlNodePtr> text_nodes; 
     230  for (xmlNodePtr child_node = this->data->node->children; child_node; child_node = child_node->next) 
     231  { 
     232    if (xmlNodeIsText(child_node)) 
     233    { 
     234      text_nodes.push_back(child_node); 
     235    } 
     236  } 
     237  for (std::vector<xmlNodePtr>::iterator it = text_nodes.begin(); it != text_nodes.end(); ++it) 
     238  { 
     239    xmlUnlinkNode(*it); 
     240    xmlFreeNode(*it); 
     241  } 
     242  delete this->data->text_content; 
     243  this->data->text_content = 0; 
     244} 
     245 
     246//---------------------------------------------------------------------- 
     247// tXMLNode SetStringAttribute 
     248//---------------------------------------------------------------------- 
     249void tXMLNode::SetStringAttribute(const std::string &name, const std::string &value, bool create) 
     250{ 
     251  if (!this->HasAttribute(name)) 
     252  { 
     253    if (create) 
     254    { 
     255      xmlNewProp(this->data->node, reinterpret_cast<const xmlChar *>(name.c_str()), reinterpret_cast<const xmlChar *>(value.c_str())); 
     256      return; 
     257    } 
     258    throw tXML2WrapperException("Attribute `" + name + "' does not exist in this node and creation was disabled!"); 
     259  } 
     260  xmlSetProp(this->data->node, reinterpret_cast<const xmlChar *>(name.c_str()), reinterpret_cast<const xmlChar *>(value.c_str())); 
     261} 
  • tXMLNode.h

    r6 r8  
    9292  friend class tXMLDocument; 
    9393 
    94   xmlNodePtr node; 
    95   mutable std::string *name; 
    96   mutable std::vector<tXMLNode> *children; 
     94  struct tData 
     95  { 
     96    unsigned int ref_counter; 
     97    xmlNodePtr node; 
     98    mutable std::string *name; 
     99    mutable std::vector<tXMLNode> *children; 
     100    mutable std::string *text_content; 
     101    tData(xmlNodePtr node); 
     102    ~tData(); 
     103  }; 
     104 
     105  tData *data; 
     106 
     107  /*! The ctor of tXMLNode 
     108   * 
     109   * This ctor is declared private and thus can only be called from other instances 
     110   * of tXMLNode or friends like tXMLDocument. 
     111   * 
     112   * \exception tXML2WrapperException is thrown if the given libxml2 element is not a node 
     113   * 
     114   * \param node   The libxml2 node that is wrapped by the new object 
     115   */ 
     116  tXMLNode(xmlNodePtr node); 
    97117 
    98118  template <typename TNumber> 
     
    126146  } 
    127147 
    128   /*! The ctor of tXMLNode 
    129    * 
    130    * This ctor is declared private and thus can only be called from other instances 
    131    * of tXMLNode or friends like tXMLDocument. 
    132    * 
    133    * \param node   The libxml2 node that is wrapped by the new object 
    134    * 
    135    * \exception tXML2WrapperException is thrown if the given libxml2 element is not a node 
    136    */ 
    137   tXMLNode(xmlNodePtr node); 
    138  
    139   inline void AddStringAttribute(const std::string &name, const std::string &value) 
    140   { 
    141     xmlNewProp(this->node, reinterpret_cast<const xmlChar *>(name.c_str()), reinterpret_cast<const xmlChar *>(value.c_str())); 
    142   } 
     148  void SetStringAttribute(const std::string &name, const std::string &value, bool create); 
    143149 
    144150//---------------------------------------------------------------------- 
     
    147153public: 
    148154 
     155  tXMLNode(const tXMLNode &other); 
     156 
    149157  /*! The dtor of tXMLNode 
    150158   */ 
    151159  ~tXMLNode(); 
     160 
     161  /*! Comparison of XML node objects for find algorithm 
     162   * 
     163   * \param other   The other node to compare to this one 
     164   * 
     165   * \returns Whether the two nodes are the same or not 
     166   */ 
     167  bool operator == (const tXMLNode &other) 
     168  { 
     169    return this->data == other.data; 
     170  } 
    152171 
    153172  /*! Get the name of that node 
     
    171190  const std::vector<tXMLNode> &GetChildren() const; 
    172191 
     192  /*! Add a child to this node 
     193   * 
     194   * In XML DOM trees a node can have several child nodes which are XML 
     195   * nodes themselves. This method add such a node with a given name to 
     196   * the structure which then can be extended by further children or 
     197   * attributes. 
     198   * 
     199   * \note Each node can either have structural child nodes or text content, 
     200   * but not both at the same time. 
     201   * 
     202   * \exception tXML2WrapperException is thrown if the node already contains text content 
     203   * 
     204   * \param name   The name of the new node 
     205   * 
     206   * \returns A reference to the newly created node 
     207   */ 
     208  tXMLNode &AddChildNode(const std::string &name); 
     209 
     210  /*! Remove a structural child node 
     211   * 
     212   * Removes a given node from the children list of this node. 
     213   * 
     214   * \exception tXML2WrapperException is thrown if the given node is not a child node 
     215   * 
     216   * \param node   The node to remove from the list 
     217   */ 
     218  void RemoveChildNode(tXMLNode &node); 
     219 
     220  /*! Get whether this node has text content or not 
     221   * 
     222   * Instead of structural child nodes each node can have plain text content. 
     223   * This method determines the existence of text content and creates an 
     224   * internal representation for fast access (lazy evaluation). Furthermore, 
     225   * calling this method befor accessing the text content can be used to 
     226   * avoid runtim errors in form of instances of tXML2WrapperException. 
     227   * 
     228   * \returns Whether this node has plain text content or not 
     229   */ 
     230  const bool HasTextContent() const; 
     231 
     232  /*! Get the plain text content of this node 
     233   * 
     234   * If the node contains plain text content this method grants access via 
     235   * a std::string reference. 
     236   * 
     237   * \exception tXML2WrapperException is thrown if the node does not contain plain text content 
     238   * 
     239   * \returns A reference to the plain text content 
     240   */ 
     241  const std::string &GetTextContent() const; 
     242 
     243  /*! Set the plain text content of this node 
     244   * 
     245   * \exception tXML2WrapperException is thrown if the node already has structural children 
     246   * 
     247   * \param content   The new plain text content of this node 
     248   */ 
     249  void SetTextContent(const std::string &content); 
     250 
     251  /*! Remove the plain text content of this node 
     252   */ 
     253  void RemoveTextContent(); 
     254 
    173255  /*! Get whether this node has the given attribute or not 
    174256   * 
     
    182264  inline const bool HasAttribute(const std::string &name) const 
    183265  { 
    184     return xmlGetProp(this->node, reinterpret_cast<const xmlChar *>(name.c_str())) != 0; 
     266    return xmlHasProp(this->data->node, reinterpret_cast<const xmlChar *>(name.c_str())) != 0; 
    185267  } 
    186268 
     
    198280  inline const std::string GetStringAttribute(const std::string &name) const 
    199281  { 
    200     const char *result = reinterpret_cast<const char *>(xmlGetProp(this->node, reinterpret_cast<const xmlChar *>(name.c_str()))); 
    201     if (!result) 
     282    xmlChar *temp = xmlGetProp(this->data->node, reinterpret_cast<const xmlChar *>(name.c_str())); 
     283    if (!temp) 
    202284    { 
    203285      throw tXML2WrapperException("Requested attribute `" + name + "' does not exist in this node!"); 
    204286    } 
     287    std::string result(reinterpret_cast<char *>(temp)); 
     288    xmlFree(temp); 
    205289    return result; 
     290  } 
     291 
     292  /*! Get an XML attribute as int 
     293   * 
     294   * If the XML node wrapped by this instance has an attribute with 
     295   * the given name, its value is returned by this method as int. 
     296   * 
     297   * \exception tXML2WrapperException is thrown if the requested attribute's value is available or not a number 
     298   * 
     299   * \param name   The name of the attribute 
     300   * \param base   The base that should be used for number interpretation 
     301   * 
     302   * \returns The attribute as int 
     303   */ 
     304  inline const int GetIntAttribute(const std::string &name, int base = 10) const 
     305  { 
     306    return this->GetLongIntAttribute(name, base); 
    206307  } 
    207308 
     
    324425   * \exception tXML2WrapperException is thrown if the requested attribute's value is available or not true/false 
    325426   * 
    326    * \param name         The name of the attribute 
     427   * \param name   The name of the attribute 
    327428   * 
    328429   * \returns Whether the attribute's value was "true" or "false" 
     
    337438  } 
    338439 
    339   tXMLNode &AddChildNode(const std::string &name); 
    340  
     440  /*! Set an XML attribute of this node 
     441   * 
     442   * This methods sets the attribute with the given name to the given value. 
     443   * If the node does not have the specified attribute yet, it will be created 
     444   * depending on the given parameter. 
     445   * 
     446   * \note The value type must support streaming to be serialized 
     447   * 
     448   * \exception tXML2WrapperException is thrown if the requested attribute does not exist and should not be created 
     449   * 
     450   * \param name     The name of the attribute 
     451   * \param value    The new value 
     452   * \param create   Whether a non-existing attribute should be created or not 
     453   */ 
    341454  template <typename TValue> 
    342   inline void AddAttribute(const std::string &name, const TValue &value) 
     455  inline void SetAttribute(const std::string &name, const TValue &value, bool create = true) 
    343456  { 
    344457    std::stringstream converted_value; 
    345458    converted_value << value; 
    346     this->AddStringAttribute(name, converted_value.str()); 
     459    this->SetStringAttribute(name, converted_value.str(), create); 
     460  } 
     461 
     462  /*! Set a bool XML attribute of this node 
     463   * 
     464   * This is a method for special handling of bool values which should be serialized 
     465   * into "true" and "false" instead of int representation. 
     466   * 
     467   * \exception tXML2WrapperException is thrown if the requested attribute does not exist and should not be created 
     468   * 
     469   * \param name     The name of the attribute 
     470   * \param value    The new value 
     471   * \param create   Whether a non-existing attribute should be created or not 
     472   */ 
     473  inline void SetAttribute(const std::string &name, bool value, bool create = true) 
     474  { 
     475    this->SetStringAttribute(name, value ? "true" : "false", create); 
     476  } 
     477 
     478  /*! Set a string XML attribute of this node 
     479   * 
     480   * This is a method for special handling of string values which do not have to be 
     481   * serialized via stringstream. 
     482   * 
     483   * \exception tXML2WrapperException is thrown if the requested attribute does not exist and should not be created 
     484   * 
     485   * \param name     The name of the attribute 
     486   * \param value    The new value 
     487   * \param create   Whether a non-existing attribute should be created or not 
     488   */ 
     489  inline void SetAttribute(const std::string &name, const std::string &value, bool create = true) 
     490  { 
     491    this->SetStringAttribute(name, value, create); 
     492  } 
     493 
     494  /*! Set a char * XML attribute of this node 
     495   * 
     496   * This is a method for special handling of string values which do not have to be 
     497   * serialized via stringstream (needed because implicit conversion does not work due 
     498   * to the template version of this method). 
     499   * 
     500   * \exception tXML2WrapperException is thrown if the requested attribute does not exist and should not be created 
     501   * 
     502   * \param name     The name of the attribute 
     503   * \param value    The new value 
     504   * \param create   Whether a non-existing attribute should be created or not 
     505   */ 
     506  inline void SetAttribute(const std::string &name, const char *value, bool create = true) 
     507  { 
     508    this->SetStringAttribute(name, value, create); 
     509  } 
     510 
     511  /*! Remove an attribute from this node 
     512   * 
     513   * \param name     The name of the attribute 
     514   */ 
     515  inline void RemoveAttribute(const std::string &name) 
     516  { 
     517    xmlAttrPtr attr = xmlHasProp(this->data->node, reinterpret_cast<const xmlChar *>(name.c_str())); 
     518    if (attr) 
     519    { 
     520      xmlRemoveProp(attr); 
     521    } 
    347522  } 
    348523 
  • test/test.xml

    r6 r8  
    11<?xml version="1.0" encoding="UTF-8"?> 
    2 <test1 prop_1="val_1" prop_2="1" prop_3="4.3" prop_4="123"/> 
     2<test prop_1="val" prop_2="true" prop_3="4.3" prop_4="123"> 
     3  <test1 prop_1="val_1" prop_2="true" prop_3="4.3">fn0rd&amp;&lt;bla</test1> 
     4</test> 
  • test/test_xml2_wrapper.cpp

    r6 r8  
    3434//---------------------------------------------------------------------- 
    3535#include <cstdlib> 
     36#include <iostream> 
    3637 
    3738#include "xml2_wrapper/tXMLDocument.h" 
     
    6364{ 
    6465  tXMLDocument document1; 
    65   document1.AddRootNode("test1"); 
    66   document1.GetRootNode().AddAttribute("prop_1", "val_1"); 
    67   document1.GetRootNode().AddAttribute("prop_2", true); 
    68   document1.GetRootNode().AddAttribute("prop_3", 4.3); 
    69   document1.GetRootNode().AddAttribute("prop_4", 123); 
     66  tXMLNode &root_node = document1.AddRootNode("test"); 
     67  root_node.SetAttribute("prop_1", "val"); 
     68  root_node.SetAttribute("prop_2", true); 
     69  root_node.SetAttribute("prop_3", 4.3); 
     70  root_node.SetAttribute("prop_4", 123); 
     71  tXMLNode &node1 = root_node.AddChildNode("test1"); 
     72  node1.SetAttribute("prop_1", "val_1"); 
     73  node1.SetAttribute("prop_2", true); 
     74  node1.SetAttribute("prop_3", 4.3); 
     75  node1.SetAttribute("prop_4", 123); 
     76  node1.SetTextContent("blubb"); 
     77  std::cout << "Content = " << node1.GetTextContent() << std::endl; 
     78  node1.SetTextContent("fn0rd&<bla"); 
     79  std::cout << "Content = " << node1.GetTextContent() << std::endl; 
     80 
     81  node1.RemoveAttribute("prop_4"); 
     82//  node1.RemoveTextContent(); 
     83 
     84//  tXMLNode &node2 = node1.AddChildNode("test2"); 
     85//  node2.SetAttribute("prop_1", "val_2"); 
     86//  node2.SetAttribute("prop_2", true); 
     87//  node2.SetAttribute("prop_3", 4.3); 
     88//  node2.SetAttribute("prop_4", 123); 
     89 
     90//  node1.RemoveChildNode(node2); 
    7091 
    7192  document1.WriteToFile("test.xml"); 
     
    7394  tXMLDocument document2("test.xml", false); 
    7495 
    75 //  tXMLDocument document3("test3", true); 
     96  std::cout << document2.GetRootNode().GetName() << std::endl; 
     97  std::cout << document2.GetRootNode().GetStringAttribute("prop_1") << std::endl; 
     98  std::cout << document2.GetRootNode().GetBoolAttribute("prop_2") << std::endl; 
     99  std::cout << document2.GetRootNode().GetDoubleAttribute("prop_3") << std::endl; 
     100  std::cout << document2.GetRootNode().GetIntAttribute("prop_4") << std::endl; 
     101 
     102  for (std::vector<tXMLNode>::const_iterator it = document2.GetRootNode().GetChildren().begin(); it != document2.GetRootNode().GetChildren().end(); ++it) 
     103  { 
     104    std::cout << it->GetName() << std::endl; 
     105    std::cout << it->GetStringAttribute("prop_1") << std::endl; 
     106    std::cout << it->GetBoolAttribute("prop_2") << std::endl; 
     107    std::cout << it->GetDoubleAttribute("prop_3") << std::endl; 
     108    if (it->HasAttribute("prop_4")) 
     109    { 
     110      std::cout << it->GetIntAttribute("prop_4") << std::endl; 
     111    } 
     112  } 
    76113 
    77114  return EXIT_SUCCESS; 
Note: See TracChangeset for help on using the changeset viewer.