Changeset 16:68d59b640626 in rrlib_xml


Ignore:
Timestamp:
24.12.2010 22:53:45 (9 years ago)
Author:
Tobias Föhst <foehst@…>
Branch:
default
Phase:
public
Convert:
svn:3219ad6e-c0b7-4ac2-9554-e22e195eef7a/trunk@17
Message:

As we are not going to wrap other libs than libxml2 tXMLNode now derives from xmlNode which make things much simpler

  • Added iterator for sequential access to children or siblings
  • AddChild and AddNextSibling now move the given node (even from one document to the other) unless a copy is demanded (via flag)
  • Text together with structural nodes is allowed again
  • Cleanup of global parser structures is done by tCleanupHandler during static destruction

Drawback: tXMLNode is not copyable anymore. But this should not be needed anyway.

Files:
1 added
4 edited

Legend:

Unmodified
Added
Removed
  • tXMLDocument.cpp

    r14 r16  
    3939//---------------------------------------------------------------------- 
    4040#include "rrlib/xml2_wrapper/tXML2WrapperException.h" 
     41#include "rrlib/xml2_wrapper/tCleanupHandler.h" 
    4142 
    4243//---------------------------------------------------------------------- 
     
    7071{ 
    7172  assert(this->document); 
     73  tCleanupHandler::GetInstance(); 
    7274} 
    7375 
    7476tXMLDocument::tXMLDocument(const std::string &file_name, bool validate) 
    7577    : document(xmlReadFile(file_name.c_str(), 0, validate ? XML_PARSE_DTDVALID : 0)), 
    76     root_node(0) 
     78    root_node(reinterpret_cast<tXMLNode *>(xmlDocGetRootElement(this->document))) 
    7779{ 
    7880  assert(this->document); 
     
    8183    throw tXML2WrapperException("Could not parse XML file `" + file_name + "'!"); 
    8284  } 
     85  tCleanupHandler::GetInstance(); 
    8386} 
    8487 
     
    98101tXMLDocument::~tXMLDocument() 
    99102{ 
    100   delete this->root_node; 
    101103  xmlFreeDoc(this->document); 
    102104} 
     
    109111  if (!this->root_node) 
    110112  { 
    111     xmlNodePtr node = xmlDocGetRootElement(this->document); 
    112     if (!node) 
    113     { 
    114       throw tXML2WrapperException("No root node defined for this document!"); 
    115     } 
    116     this->root_node = new tXMLNode(xmlDocGetRootElement(this->document)); 
     113    throw tXML2WrapperException("No root node defined for this document!"); 
    117114  } 
    118115  return *this->root_node; 
     
    128125    throw tXML2WrapperException("Root node already exists with name `" + name + "'!"); 
    129126  } 
    130   this->root_node = new tXMLNode(xmlNewNode(0, reinterpret_cast<const xmlChar *>(name.c_str()))); 
    131   xmlDocSetRootElement(this->document, this->root_node->node); 
     127  this->root_node = reinterpret_cast<tXMLNode *>(xmlNewNode(0, reinterpret_cast<const xmlChar *>(name.c_str()))); 
     128  xmlDocSetRootElement(this->document, this->root_node); 
    132129  return *this->root_node; 
    133130} 
  • tXMLNode.cpp

    r14 r16  
    6262 
    6363//---------------------------------------------------------------------- 
    64 // tXMLNode constructors 
    65 //---------------------------------------------------------------------- 
    66 tXMLNode::tXMLNode(xmlNodePtr node) 
    67     : node(node), 
    68     text_content(0) 
    69 { 
    70   assert(node); 
    71   assert(node->type == XML_ELEMENT_NODE); 
    72   if (node->type != XML_ELEMENT_NODE) 
    73   { 
    74     throw tXML2WrapperException("Trying to construct a tXMLNode from an xml2 element that is not a node!"); 
    75   } 
    76 } 
    77  
    78 tXMLNode::tXMLNode(const tXMLNode &other) 
    79     : node(other.node), 
    80     text_content(0) 
    81 {} 
    82  
    83 //---------------------------------------------------------------------- 
    8464// tXMLNode destructor 
    8565//---------------------------------------------------------------------- 
    8666tXMLNode::~tXMLNode() 
    8767{ 
    88   delete this->text_content; 
    89 } 
    90  
    91 //---------------------------------------------------------------------- 
    92 // tXMLNode operator = 
    93 //---------------------------------------------------------------------- 
    94 const tXMLNode &tXMLNode::operator = (const tXMLNode & other) 
    95 { 
    96   this->node = other.node; 
    97   return *this; 
     68  static_assert(sizeof(tXMLNode) == sizeof(xmlNode), "Do not add any variables or virtual methods to tXMLNode!"); 
    9869} 
    9970 
     
    10374const std::string tXMLNode::GetName() const 
    10475{ 
    105   return reinterpret_cast<const char *>(this->node->name); 
     76  return reinterpret_cast<const char *>(this->name); 
     77} 
     78 
     79//---------------------------------------------------------------------- 
     80// tXMLNode IsInSubtreeOf 
     81//---------------------------------------------------------------------- 
     82const bool tXMLNode::IsInSubtreeOf(const tXMLNode &node) const 
     83{ 
     84  const tXMLNode *current_node = this; 
     85  do 
     86  { 
     87    if (current_node == &node) 
     88    { 
     89      return true; 
     90    } 
     91  } 
     92  while ((current_node = reinterpret_cast<tXMLNode *>(current_node->parent))); 
     93  return false; 
     94} 
     95 
     96//---------------------------------------------------------------------- 
     97// tXMLNode GetFirstChild 
     98//---------------------------------------------------------------------- 
     99tXMLNode &tXMLNode::GetFirstChild() 
     100{ 
     101  if (!this->HasChildren()) 
     102  { 
     103    throw tXML2WrapperException("Node has no children!"); 
     104  } 
     105  return *this->GetChildrenBegin(); 
    106106} 
    107107 
     
    109109// tXMLNode AddChildNode 
    110110//---------------------------------------------------------------------- 
    111 tXMLNode tXMLNode::AddChildNode(const std::string &name) 
    112 { 
    113   if (this->HasTextContent()) 
    114   { 
    115     throw tXML2WrapperException("Tried to add a structural child to a node that already has text content!"); 
    116   } 
    117   return xmlNewChild(this->node, 0, reinterpret_cast<const xmlChar*>(name.c_str()), 0); 
    118 } 
    119  
    120 tXMLNode tXMLNode::AddChildNode(const tXMLNode &node) 
    121 { 
    122   xmlNodePtr child = node.node; 
    123   if (child->doc != this->node->doc) 
    124   { 
    125     child = xmlDocCopyNode(child, this->node->doc, 1); 
    126   } 
    127   xmlAddChild(this->node, child); 
    128   return child; 
     111tXMLNode &tXMLNode::AddChildNode(const std::string &name, const std::string &content) 
     112{ 
     113  return reinterpret_cast<tXMLNode &>(*xmlNewChild(this, 0, reinterpret_cast<const xmlChar *>(name.c_str()), reinterpret_cast<const xmlChar *>(name.c_str()))); 
     114} 
     115 
     116tXMLNode &tXMLNode::AddChildNode(tXMLNode &node, bool copy) 
     117{ 
     118  tXMLNode *child = &node; 
     119  if (child->doc != this->doc) 
     120  { 
     121    xmlUnlinkNode(child); 
     122  } 
     123  if (copy) 
     124  { 
     125    child = reinterpret_cast<tXMLNode *>(xmlDocCopyNode(child, this->doc, 1)); 
     126  } 
     127  if (this->IsInSubtreeOf(*child)) 
     128  { 
     129    assert(!copy); 
     130    throw tXML2WrapperException("Cannot add node as child to its own subtree without copying!"); 
     131  } 
     132  xmlAddChild(this, child); 
     133  return *child; 
    129134} 
    130135 
     
    134139void tXMLNode::RemoveChildNode(tXMLNode &node) 
    135140{ 
    136   xmlNodePtr child_node = 0; 
    137   for (child_node = this->node->children; child_node && child_node != node.node; child_node = child_node->next); 
    138   if (!child_node) 
    139   { 
    140     throw tXML2WrapperException("Given node is not a child of this."); 
    141   } 
    142   xmlUnlinkNode(child_node); 
    143   xmlFreeNode(child_node); 
    144 } 
    145  
    146 //---------------------------------------------------------------------- 
    147 // tXMLNode AddSibling 
    148 //---------------------------------------------------------------------- 
    149 tXMLNode tXMLNode::AddSibling(const tXMLNode &node) 
    150 { 
    151   assert(*this != node); 
    152   xmlNodePtr sibling = node.node; 
    153   if (sibling->doc != this->node->doc) 
    154   { 
    155     sibling = xmlDocCopyNode(sibling, this->node->doc, 1); 
    156   } 
    157   xmlAddNextSibling(this->node, sibling); 
    158   return sibling; 
    159 } 
    160  
    161 //---------------------------------------------------------------------- 
    162 // tXMLNode HasTextContent 
    163 //---------------------------------------------------------------------- 
    164 const bool tXMLNode::HasTextContent() const 
    165 { 
    166   for (xmlNodePtr child_node = this->node->children; child_node; child_node = child_node->next) 
     141  iterator it = std::find(this->GetChildrenBegin(), this->GetChildrenEnd(), node); 
     142  if (it == this->GetChildrenEnd()) 
     143  { 
     144    throw tXML2WrapperException("Given node is not a child of this!"); 
     145  } 
     146  it->FreeNode(); 
     147} 
     148 
     149//---------------------------------------------------------------------- 
     150// tXMLNode GetNextSibling 
     151//---------------------------------------------------------------------- 
     152tXMLNode &tXMLNode::GetNextSibling() 
     153{ 
     154  if (!this->HasNextSibling()) 
     155  { 
     156    throw tXML2WrapperException("Node has no sibling!"); 
     157  } 
     158  return *this->GetNextSiblingsBegin(); 
     159} 
     160 
     161//---------------------------------------------------------------------- 
     162// tXMLNode AddNextSibling 
     163//---------------------------------------------------------------------- 
     164tXMLNode &tXMLNode::AddNextSibling(const std::string &name, const std::string &content) 
     165{ 
     166  tXMLNode *sibling = reinterpret_cast<tXMLNode *>(xmlNewNode(0, reinterpret_cast<const xmlChar *>(name.c_str()))); 
     167  if (content != "") 
     168  { 
     169    xmlNodeSetContentLen(sibling, reinterpret_cast<const xmlChar *>(content.c_str()), content.length()); 
     170  } 
     171  return reinterpret_cast<tXMLNode &>(*xmlAddNextSibling(this, sibling)); 
     172} 
     173 
     174tXMLNode &tXMLNode::AddNextSibling(tXMLNode &node, bool copy) 
     175{ 
     176  tXMLNode *sibling = &node; 
     177  if (sibling->doc != this->doc) 
     178  { 
     179    xmlUnlinkNode(sibling); 
     180  } 
     181  if (copy) 
     182  { 
     183    sibling = reinterpret_cast<tXMLNode *>(xmlDocCopyNode(sibling, this->doc, 1)); 
     184  } 
     185  if (this->IsInSubtreeOf(*sibling)) 
     186  { 
     187    assert(!copy); 
     188    throw tXML2WrapperException("Cannot add node as sibling in its own subtree without copying!"); 
     189  } 
     190  xmlAddNextSibling(this, sibling); 
     191  return *sibling; 
     192} 
     193 
     194//---------------------------------------------------------------------- 
     195// tXMLNode GetTextContent 
     196//---------------------------------------------------------------------- 
     197const std::string tXMLNode::GetTextContent() const 
     198{ 
     199  xmlChar *content = xmlNodeGetContent(const_cast<tXMLNode *>(this)); 
     200  std::string result(reinterpret_cast<const char *>(content)); 
     201  xmlFree(content); 
     202  return result; 
     203} 
     204 
     205//---------------------------------------------------------------------- 
     206// tXMLNode AddTextContent 
     207//---------------------------------------------------------------------- 
     208void tXMLNode::AddTextContent(const std::string &content) 
     209{ 
     210  xmlNodeAddContentLen(this, reinterpret_cast<const xmlChar *>(content.c_str()), content.length()); 
     211} 
     212 
     213//---------------------------------------------------------------------- 
     214// tXMLNode RemoveTextContent 
     215//---------------------------------------------------------------------- 
     216void tXMLNode::RemoveTextContent() 
     217{ 
     218  std::vector<tXMLNode *> nodes_to_delete; 
     219  for (xmlNodePtr child_node = this->children; child_node; child_node = child_node->next) 
    167220  { 
    168221    if (xmlNodeIsText(child_node)) 
    169222    { 
    170       xmlChar *text_content = xmlNodeGetContent(this->node); 
    171       if (this->text_content && std::strncmp(reinterpret_cast<const char *>(text_content), this->text_content->c_str(), this->text_content->length()) != 0) 
    172       { 
    173         delete this->text_content; 
    174         this->text_content = 0; 
    175       } 
    176       if (!this->text_content) 
    177       { 
    178         this->text_content = new std::string(reinterpret_cast<const char *>(text_content)); 
    179       } 
    180       xmlFree(text_content); 
     223      nodes_to_delete.push_back(reinterpret_cast<tXMLNode *>(child_node)); 
    181224    } 
    182225  } 
    183   return this->text_content != 0; 
    184 } 
    185  
    186 //---------------------------------------------------------------------- 
    187 // tXMLNode GetTextContent 
    188 //---------------------------------------------------------------------- 
    189 const std::string &tXMLNode::GetTextContent() const 
    190 { 
    191   if (!this->HasTextContent()) 
    192   { 
    193     throw tXML2WrapperException("This node does not have any text content!"); 
    194   } 
    195   return *this->text_content; 
    196 } 
    197  
    198 //---------------------------------------------------------------------- 
    199 // tXMLNode SetTextContent 
    200 //---------------------------------------------------------------------- 
    201 void tXMLNode::SetTextContent(const std::string &content) 
    202 { 
    203   if (this->HasChildren()) 
    204   { 
    205     throw tXML2WrapperException("Tried to set text content in a node that already has structural children!"); 
    206   } 
    207   this->RemoveTextContent(); 
    208   xmlNodeAddContentLen(this->node, reinterpret_cast<const xmlChar *>(content.c_str()), content.length()); 
    209 } 
    210  
    211 //---------------------------------------------------------------------- 
    212 // tXMLNode RemoveTextNode 
    213 //---------------------------------------------------------------------- 
    214 void tXMLNode::RemoveTextContent() 
    215 { 
    216   std::vector<xmlNodePtr> text_nodes; 
    217   for (xmlNodePtr child_node = this->node->children; child_node; child_node = child_node->next) 
    218   { 
    219     if (xmlNodeIsText(child_node)) 
    220     { 
    221       text_nodes.push_back(child_node); 
    222     } 
    223   } 
    224   for (std::vector<xmlNodePtr>::iterator it = text_nodes.begin(); it != text_nodes.end(); ++it) 
    225   { 
    226     xmlUnlinkNode(*it); 
    227     xmlFreeNode(*it); 
    228   } 
    229   delete this->text_content; 
    230   this->text_content = 0; 
     226  for (std::vector<tXMLNode *>::iterator it = nodes_to_delete.begin(); it != nodes_to_delete.end(); ++it) 
     227  { 
     228    (*it)->FreeNode(); 
     229  } 
    231230} 
    232231 
     
    240239    if (create) 
    241240    { 
    242       xmlNewProp(this->node, reinterpret_cast<const xmlChar *>(name.c_str()), reinterpret_cast<const xmlChar *>(value.c_str())); 
     241      xmlNewProp(this, reinterpret_cast<const xmlChar *>(name.c_str()), reinterpret_cast<const xmlChar *>(value.c_str())); 
    243242      return; 
    244243    } 
    245244    throw tXML2WrapperException("Attribute `" + name + "' does not exist in this node and creation was disabled!"); 
    246245  } 
    247   xmlSetProp(this->node, reinterpret_cast<const xmlChar *>(name.c_str()), reinterpret_cast<const xmlChar *>(value.c_str())); 
    248 } 
     246  xmlSetProp(this, reinterpret_cast<const xmlChar *>(name.c_str()), reinterpret_cast<const xmlChar *>(value.c_str())); 
     247} 
     248 
     249//---------------------------------------------------------------------- 
     250// tXMLNode RemoveAttribute 
     251//---------------------------------------------------------------------- 
     252void tXMLNode::RemoveAttribute(const std::string &name) 
     253{ 
     254  xmlAttrPtr attr = xmlHasProp(this, reinterpret_cast<const xmlChar *>(name.c_str())); 
     255  if (attr) 
     256  { 
     257    xmlRemoveProp(attr); 
     258  } 
     259} 
     260 
     261//---------------------------------------------------------------------- 
     262// tXMLNode GetXMLDump 
     263//---------------------------------------------------------------------- 
     264const std::string tXMLNode::GetXMLDump(bool format) const 
     265{ 
     266  xmlBufferPtr buffer = xmlBufferCreate(); 
     267  xmlNodeDump(buffer, this->doc, const_cast<tXMLNode *>(this), 0, format); 
     268  std::string result(reinterpret_cast<const char *>(buffer->content)); 
     269  xmlBufferFree(buffer); 
     270  return result; 
     271} 
  • tXMLNode.h

    r15 r16  
    5555#include <cerrno> 
    5656#include <cstdlib> 
     57#include <iterator> 
     58#include <boost/noncopyable.hpp> 
    5759 
    5860//---------------------------------------------------------------------- 
     
    8991 * 
    9092 */ 
    91 class tXMLNode 
     93class tXMLNode : protected xmlNode, boost::noncopyable 
    9294{ 
    9395  friend class tXMLDocument; 
    94   friend class tXMLNodeSiblingIterator; 
    95  
    96   xmlNodePtr node; 
    97   mutable std::string *text_content; 
    98  
    99   /*! The ctor of tXMLNode 
    100    * 
    101    * This ctor is declared private and thus can only be called from other instances 
    102    * of tXMLNode or friends like tXMLDocument. 
    103    * 
    104    * \exception tXML2WrapperException is thrown if the given libxml2 element is not a node 
    105    * 
    106    * \param node   The libxml2 node that is wrapped by the new object 
    107    */ 
    108   tXMLNode(xmlNodePtr node); 
    10996 
    11097  template <typename TNumber> 
     
    145132public: 
    146133 
    147   tXMLNode(const tXMLNode &other); 
    148  
     134  class iterator : public std::iterator<std::forward_iterator_tag, tXMLNode> 
     135  { 
     136    pointer element; 
     137 
     138  public: 
     139    inline iterator() : element(0) {} 
     140    inline iterator(pointer element) : element(element) 
     141    { 
     142      if (this->element && this->element->type != XML_ELEMENT_NODE) 
     143      { 
     144        operator++(); 
     145      } 
     146    } 
     147 
     148    inline reference operator*() const 
     149    { 
     150      return *element; 
     151    } 
     152    inline pointer operator->() const 
     153    { 
     154      return &(operator*()); 
     155    } 
     156 
     157    inline iterator &operator ++ () 
     158    { 
     159      do 
     160      { 
     161        this->element = reinterpret_cast<tXMLNode *>(this->element->next); 
     162      } 
     163      while (this->element && this->element->type != XML_ELEMENT_NODE); 
     164      return *this; 
     165    } 
     166    inline iterator operator ++ (int) 
     167    { 
     168      iterator temp(*this); 
     169      operator++(); 
     170      return temp; 
     171    } 
     172 
     173    inline const bool operator == (const iterator &other) const 
     174    { 
     175      return element == other.element; 
     176    } 
     177    inline const bool operator != (const iterator &other) const 
     178    { 
     179      return !(*this == other); 
     180    } 
     181  }; 
     182 
     183  /*! The dtor of tXMLNode 
     184   */ 
    149185  ~tXMLNode(); 
    150186 
    151   const tXMLNode &operator = (const tXMLNode &other); 
    152  
    153   /*! Comparison of XML node objects for find algorithm 
     187  /*! Comparison of XML node objects (inequality) 
    154188   * 
    155189   * \param other   The other node to compare to this one 
     
    157191   * \returns Whether the two nodes are the same or not 
    158192   */ 
     193  void FreeNode() 
     194  { 
     195    xmlUnlinkNode(this); 
     196    xmlFreeNode(this); 
     197  } 
     198 
     199  /*! Comparison of XML node objects (equality) 
     200   * 
     201   * \param other   The other node to compare to this one 
     202   * 
     203   * \returns Whether the two nodes are the same or not 
     204   */ 
    159205  inline bool operator == (const tXMLNode &other) const 
    160206  { 
    161     return this->node == other.node; 
    162   } 
    163  
    164   /*! Comparison of XML node objects for find algorithm 
     207    return this == &other; 
     208  } 
     209 
     210  /*! Comparison of XML node objects (inequality) 
    165211   * 
    166212   * \param other   The other node to compare to this one 
     
    170216  inline bool operator != (const tXMLNode &other) const 
    171217  { 
    172     return this->node != other.node; 
    173   } 
    174  
    175   /*! Get the name of that node 
     218    return !(*this == other); 
     219  } 
     220 
     221  /*! Comparison of name with given string (equality) 
     222   * 
     223   * This method can be used to find a specific node using e.g. std::find 
     224   * 
     225   * \param name   The name to be compared to the node's name 
     226   * 
     227   * \returns Whether this has the given name or not 
     228   */ 
     229  inline bool operator == (const std::string &name) const 
     230  { 
     231    return this->GetName() == name; 
     232  } 
     233 
     234  /*! Check if this node is part of the subtree of the given node 
     235   * 
     236   * This method can be used to check if a node is contained in 
     237   * the subtree of another one. If this is the case it is not 
     238   * possible to e.g. add the root of the subtree as child to the 
     239   * contained node without copying. 
     240   * 
     241   * \returns Whether \a this is contained within the subtree of \a node 
     242   */ 
     243  const bool IsInSubtreeOf(const tXMLNode &node) const; 
     244 
     245  /*! Get the name of this node 
    176246   * 
    177247   * Each XML element has an unique name within its document type. This 
     
    182252  const std::string GetName() const; 
    183253 
     254  /*! Get an iterator to the first of this node's children of type XML_ELEMENT_NODE 
     255   * 
     256   * \returns A begin-iterator 
     257   */ 
     258  inline const iterator GetChildrenBegin() const 
     259  { 
     260    return iterator(reinterpret_cast<tXMLNode *>(this->children)); 
     261  } 
     262 
     263  /*! Get an end-iterator to mark the end of children traversal 
     264   * 
     265   * \returns An end-iterator 
     266   */ 
     267  inline const iterator &GetChildrenEnd() const 
     268  { 
     269    static iterator end; 
     270    return end; 
     271  } 
     272 
     273  /*! Check if this node has children of type XML_ELEMENT_NODE 
     274   * 
     275   * This method can be used to check if a node has children before 
     276   * trying to access those, which would result in an exception if 
     277   * no child exists. 
     278   * 
     279   * \returns Whether \a this has children or not 
     280   */ 
    184281  inline const bool HasChildren() const 
    185282  { 
    186     return this->node->children != 0 && this->node->children->type == XML_ELEMENT_NODE; 
    187   } 
    188  
    189   inline std::vector<tXMLNode> GetChildren() const 
    190   { 
    191     std::vector<tXMLNode> children; 
    192     if (this->HasChildren()) 
    193     { 
    194       tXMLNode child = this->GetFirstChild(); 
    195       do 
    196       { 
    197         children.push_back(child); 
    198         child = child.GetNextSibling(); 
    199       } 
    200       while (child.HasNextSibling()); 
    201     } 
    202     return children; 
    203   } 
    204  
    205   inline tXMLNode GetFirstChild() 
    206   { 
    207     assert(this->node->children && this->node->children->type == XML_ELEMENT_NODE); 
    208     return this->node->children; 
    209   } 
    210  
    211   inline const tXMLNode GetFirstChild() const 
     283    return this->GetChildrenBegin() != this->GetChildrenEnd(); 
     284  } 
     285 
     286  /*! Get access to first child of this node 
     287   * 
     288   * This method gives access to the first child of \a this 
     289   * which is itself of type XML_ELEMENT_NODE. 
     290   * 
     291   * \exception tXML2WrapperException is thrown if this node has not children of type XML_ELEMENT_NODE 
     292   * 
     293   * \returns Whether \a this has children or not 
     294   */ 
     295  tXMLNode &GetFirstChild(); 
     296 
     297  /*! Get access to first child of this node in const context 
     298   * 
     299   * This method gives access to the first child of \a this 
     300   * which is itself of type XML_ELEMENT_NODE in const context. 
     301   * 
     302   * \exception tXML2WrapperException is thrown if this node has not children of type XML_ELEMENT_NODE 
     303   * 
     304   * \returns Whether \a this has children or not 
     305   */ 
     306  inline const tXMLNode &GetFirstChild() const 
    212307  { 
    213308    return const_cast<tXMLNode *>(this)->GetFirstChild(); 
     
    221316   * attributes. 
    222317   * 
    223    * \note Each node can either have structural child nodes or text content, 
    224    * but not both at the same time. 
    225    * 
    226    * \exception tXML2WrapperException is thrown if the node already contains text content 
    227    * 
    228318   * \param name   The name of the new node 
    229319   * 
    230320   * \returns A reference to the newly created node 
    231321   */ 
    232   tXMLNode AddChildNode(const std::string &name); 
    233  
    234   tXMLNode AddChildNode(const tXMLNode &node); 
    235  
    236   /*! Remove a structural child node 
     322  tXMLNode &AddChildNode(const std::string &name, const std::string &content = ""); 
     323 
     324  /*! Add an existing node as child to this node 
     325   * 
     326   * This methods adds an existing node to \a this children. By default, 
     327   * \a node is moved with its complete subtree to its new place. It is 
     328   * not possible to move a node into its own subtree. 
     329   * 
     330   * If \a copy is set to true the node and its complete subtree is copied 
     331   * to its new place and the old version remains at its origin. 
     332   * 
     333   * \exception tXML2WrapperException is thrown if \this is contained in the subtree of \a node and \a copy is false 
     334   * 
     335   * \param node   The node to be added 
     336   * \param copy   Set to true if a copy of \a node should be added instead of \a node itself 
     337   * 
     338   * \returns A reference to the new child 
     339   */ 
     340  tXMLNode &AddChildNode(tXMLNode &node, bool copy = false); 
     341 
     342  /*! Remove a child node 
    237343   * 
    238344   * Removes a given node from the children list of this node. 
    239345   * 
    240    * \exception tXML2WrapperException is thrown if the given node is not a child node 
     346   * \exception tXML2WrapperException is thrown if \a node is not a child of \a this 
    241347   * 
    242348   * \param node   The node to remove from the list 
     
    244350  void RemoveChildNode(tXMLNode &node); 
    245351 
     352  /*! Get an iterator to the next of this node's siblings of type XML_ELEMENT_NODE 
     353   * 
     354   * \returns A begin-iterator 
     355   */ 
     356  const iterator GetNextSiblingsBegin() const 
     357  { 
     358    return iterator(reinterpret_cast<tXMLNode *>(this->next)); 
     359  } 
     360 
     361  /*! Get an end-iterator to mark the end of sibling traversal 
     362   * 
     363   * \returns An end-iterator 
     364   */ 
     365  const iterator &GetNextSiblingsEnd() const 
     366  { 
     367    static iterator end; 
     368    return end; 
     369  } 
     370 
     371  /*! Check if siblings of type XML_ELEMENT_NODE are reachable via \c GetNextSibling from this node 
     372   * 
     373   * This method can be used to check if a node has siblings before 
     374   * trying to access those, which would result in an exception if 
     375   * no sibling is reachable. 
     376   * 
     377   * \returns Whether a sibling is reachable or not 
     378   */ 
    246379  inline const bool HasNextSibling() 
    247380  { 
    248     return this->node->next != 0 && this->node->next->type == XML_ELEMENT_NODE; 
    249   } 
    250  
    251   inline tXMLNode GetNextSibling() 
    252   { 
    253     assert(this->node->next && this->node->next->type == XML_ELEMENT_NODE); 
    254     return this->node->next; 
    255   } 
    256  
    257   inline const tXMLNode GetNextSibling() const 
     381    return this->GetNextSiblingsBegin() != this->GetNextSiblingsEnd(); 
     382  } 
     383 
     384  /*! Get access to first child of this node 
     385   * 
     386   * This method gives access to the first child of \a this 
     387   * which is itself of type XML_ELEMENT_NODE. 
     388   * 
     389   * \exception tXML2WrapperException is thrown if this node has not children of type XML_ELEMENT_NODE 
     390   * 
     391   * \returns Whether \a this has children or not 
     392   */ 
     393  tXMLNode &GetNextSibling(); 
     394 
     395  /*! Get access to first child of this node in const context 
     396   * 
     397   * This method gives access to the first child of \a this 
     398   * which is itself of type XML_ELEMENT_NODE in const context. 
     399   * 
     400   * \exception tXML2WrapperException is thrown if this node has not children of type XML_ELEMENT_NODE 
     401   * 
     402   * \returns Whether \a this has children or not 
     403   */ 
     404  inline const tXMLNode &GetNextSibling() const 
    258405  { 
    259406    return const_cast<tXMLNode *>(this)->GetNextSibling(); 
    260407  } 
    261408 
    262   tXMLNode AddSibling(const tXMLNode &node); 
    263  
    264   /*! Get whether this node has text content or not 
    265    * 
    266    * Instead of structural child nodes each node can have plain text content. 
    267    * This method determines the existence of text content and creates an 
    268    * internal representation for fast access (lazy evaluation). Furthermore, 
    269    * calling this method befor accessing the text content can be used to 
    270    * avoid runtim errors in form of instances of tXML2WrapperException. 
    271    * 
    272    * \returns Whether this node has plain text content or not 
    273    */ 
    274   const bool HasTextContent() const; 
     409  tXMLNode &AddNextSibling(const std::string &name, const std::string &content = ""); 
     410 
     411  /*! Add an existing node as next sibling to this node 
     412   * 
     413   * This methods adds an existing node to \a this siblings. By default, 
     414   * \a node is moved with its complete subtree to its new place. It is 
     415   * not possible to move a node into its own subtree. 
     416   * 
     417   * If \a copy is set to true the node and its complete subtree is copied 
     418   * to its new place and the old version remains at its origin. 
     419   * 
     420   * \exception tXML2WrapperException is thrown if \this is contained in the subtree of \a node and \a copy is false 
     421   * 
     422   * \param node   The node to be added 
     423   * \param copy   Set to true if a copy of \a node should be added instead of \a node itself 
     424   * 
     425   * \returns A reference to the new sibling 
     426   */ 
     427  tXMLNode &AddNextSibling(tXMLNode &node, bool copy = false); 
    275428 
    276429  /*! Get the plain text content of this node 
    277430   * 
    278431   * If the node contains plain text content this method grants access via 
    279    * a std::string reference. 
     432   * a std::string. 
    280433   * 
    281434   * \exception tXML2WrapperException is thrown if the node does not contain plain text content 
    282435   * 
    283    * \returns A reference to the plain text content 
    284    */ 
    285   const std::string &GetTextContent() const; 
    286  
    287   /*! Set the plain text content of this node 
    288    * 
    289    * \exception tXML2WrapperException is thrown if the node already has structural children 
    290    * 
    291    * \param content   The new plain text content of this node 
    292    */ 
    293   void SetTextContent(const std::string &content); 
     436   * \returns The plain text content 
     437   */ 
     438  const std::string GetTextContent() const; 
     439 
     440  /*! Add plain text content to this node 
     441   * 
     442   * \param content   The plain text to be added to this node 
     443   */ 
     444  void AddTextContent(const std::string &content); 
    294445 
    295446  /*! Remove the plain text content of this node 
     
    308459  inline const bool HasAttribute(const std::string &name) const 
    309460  { 
    310     return xmlHasProp(this->node, reinterpret_cast<const xmlChar *>(name.c_str())) != 0; 
     461    return xmlHasProp(const_cast<tXMLNode *>(this), reinterpret_cast<const xmlChar *>(name.c_str())) != 0; 
    311462  } 
    312463 
     
    324475  inline const std::string GetStringAttribute(const std::string &name) const 
    325476  { 
    326     xmlChar *temp = xmlGetProp(this->node, reinterpret_cast<const xmlChar *>(name.c_str())); 
     477    xmlChar *temp = xmlGetProp(const_cast<tXMLNode *>(this), reinterpret_cast<const xmlChar *>(name.c_str())); 
    327478    if (!temp) 
    328479    { 
     
    557708   * \param name     The name of the attribute 
    558709   */ 
    559   inline void RemoveAttribute(const std::string &name) 
    560   { 
    561     xmlAttrPtr attr = xmlHasProp(this->node, reinterpret_cast<const xmlChar *>(name.c_str())); 
    562     if (attr) 
    563     { 
    564       xmlRemoveProp(attr); 
    565     } 
    566   } 
     710  void RemoveAttribute(const std::string &name); 
     711 
     712  /*! Get a dump in form of xml code of the subtree starting at \a this 
     713   * 
     714   * \param format   Set to true im the dumped text should be indented 
     715   */ 
     716  const std::string GetXMLDump(bool format = false) const; 
    567717 
    568718}; 
  • test/test_xml2_wrapper.cpp

    r14 r16  
    7070  root_node.SetAttribute("prop_3", 4.3); 
    7171  root_node.SetAttribute("prop_4", 123); 
    72   tXMLNode node1 = root_node.AddChildNode("test1"); 
     72  tXMLNode &node1 = root_node.AddChildNode("test1"); 
    7373  node1.SetAttribute("prop_1", "val_1"); 
    7474  node1.SetAttribute("prop_2", true); 
     
    8080//  std::cout << "Content = " << node1.GetTextContent() << std::endl; 
    8181// 
    82 //  node1.RemoveAttribute("prop_4"); 
     82  node1.RemoveAttribute("prop_4"); 
    8383////  node1.RemoveTextContent(); 
    84 // 
    85   tXMLNode node2 = node1.AddChildNode("test2"); 
    86 //  node2.SetAttribute("prop_1", "val_2"); 
    87 //  node2.SetAttribute("prop_2", true); 
    88 //  node2.SetAttribute("prop_3", 4.3); 
    89 //  node2.SetAttribute("prop_4", 123); 
    9084 
    91 //  node1.RemoveChildNode(node2); 
     85  tXMLNode &node2 = node1.AddChildNode("test2"); 
     86  node2.SetAttribute("prop_1", "val_2"); 
     87  node2.SetAttribute("prop_2", true); 
     88  node2.SetAttribute("prop_3", 4.3); 
     89  node2.SetAttribute("prop_4", 123); 
     90 
     91//  node2.AddNextSibling(node1); 
     92 
     93  node1.RemoveChildNode(node2); 
     94 
     95  std::cout << "Accessing node with content: " << document1.GetRootNode().GetXMLDump() << std::endl; 
    9296 
    9397  std::cout << document1.GetRootNode().GetName() << std::endl; 
     
    97101  std::cout << document1.GetRootNode().GetIntAttribute("prop_4") << std::endl; 
    98102 
    99 //  for (tXMLNode::iterator it = document1.GetRootNode().GetChildrenBegin(); it != document1.GetRootNode().GetChildrenEnd(); ++it) 
    100 //  { 
    101 //    std::cout << it->GetName() << std::endl; 
    102 //    std::cout << it->GetStringAttribute("prop_1") << std::endl; 
    103 //    std::cout << it->GetBoolAttribute("prop_2") << std::endl; 
    104 //    std::cout << it->GetDoubleAttribute("prop_3") << std::endl; 
    105 //    if (it->HasAttribute("prop_4")) 
    106 //    { 
    107 //      std::cout << it->GetIntAttribute("prop_4") << std::endl; 
    108 //    } 
    109 //  } 
     103  for (tXMLNode::iterator it = document1.GetRootNode().GetChildrenBegin(); it != document1.GetRootNode().GetChildrenEnd(); ++it) 
     104  { 
     105    std::cout << "Accessing node with content: " << it->GetXMLDump() << std::endl; 
    110106 
    111 //  document1.WriteToFile("test.xml"); 
    112 // 
    113 //  tXMLDocument document2("test.xml", false); 
    114 // 
    115 //  std::cout << document2.GetRootNode().GetName() << std::endl; 
    116 //  std::cout << document2.GetRootNode().GetStringAttribute("prop_1") << std::endl; 
    117 //  std::cout << document2.GetRootNode().GetBoolAttribute("prop_2") << std::endl; 
    118 //  std::cout << document2.GetRootNode().GetDoubleAttribute("prop_3") << std::endl; 
    119 //  std::cout << document2.GetRootNode().GetIntAttribute("prop_4") << std::endl; 
    120 // 
    121 //  for (tXMLNode::const_iterator it = document2.GetRootNode().GetChildrenBegin(); it != document2.GetRootNode().GetChildrenEnd(); ++it) 
    122 //  { 
    123 //    std::cout << it->GetName() << std::endl; 
    124 //    std::cout << it->GetStringAttribute("prop_1") << std::endl; 
    125 //    std::cout << it->GetBoolAttribute("prop_2") << std::endl; 
    126 //    std::cout << it->GetDoubleAttribute("prop_3") << std::endl; 
    127 //    if (it->HasAttribute("prop_4")) 
    128 //    { 
    129 //      std::cout << it->GetIntAttribute("prop_4") << std::endl; 
    130 //    } 
    131 //  } 
     107    std::cout << it->GetName() << std::endl; 
     108    std::cout << it->GetStringAttribute("prop_1") << std::endl; 
     109    std::cout << it->GetBoolAttribute("prop_2") << std::endl; 
     110    std::cout << it->GetDoubleAttribute("prop_3") << std::endl; 
     111    if (it->HasAttribute("prop_4")) 
     112    { 
     113      std::cout << it->GetIntAttribute("prop_4") << std::endl; 
     114    } 
     115  } 
    132116 
     117  document1.WriteToFile("test.xml"); 
    133118 
    134 //  tXMLDocument document3("include.xml", false); 
    135 // 
    136 //  std::cout << document3.GetRootNode().GetName() << std::endl; 
    137 //  std::cout << document3.GetRootNode().GetStringAttribute("prop_1") << std::endl; 
    138 //  std::cout << document3.GetRootNode().GetBoolAttribute("prop_2") << std::endl; 
    139 //  std::cout << document3.GetRootNode().GetDoubleAttribute("prop_3") << std::endl; 
    140 //  std::cout << document3.GetRootNode().GetIntAttribute("prop_4") << std::endl; 
    141 // 
    142 //  for (std::vector<tXMLNode>::const_iterator it = document3.GetRootNode().GetChildren().begin(); it != document3.GetRootNode().GetChildren().end(); ++it) 
    143 //  { 
    144 //    std::cout << it->GetName() << std::endl; 
    145 //    std::cout << it->GetStringAttribute("prop_1") << std::endl; 
    146 //    std::cout << it->GetBoolAttribute("prop_2") << std::endl; 
    147 //    std::cout << it->GetDoubleAttribute("prop_3") << std::endl; 
    148 //    if (it->HasAttribute("prop_4")) 
    149 //    { 
    150 //      std::cout << it->GetIntAttribute("prop_4") << std::endl; 
    151 //    } 
    152 //  } 
     119  tXMLDocument document2("test.xml", false); 
    153120 
     121  std::cout << "doc 2" << std::endl; 
    154122 
    155 //  tXMLNode &insert_node = *document3.GetRootNode().GetChildren().begin(); 
    156 // 
    157 ////  document2.GetRootNode().AddChildNode(insert_node); 
    158 // 
    159 // 
    160 //  std::cout << "==============" << std::endl; 
    161 // 
    162 //  std::cout << document2.GetRootNode().GetName() << std::endl; 
    163 //  std::cout << document2.GetRootNode().GetStringAttribute("prop_1") << std::endl; 
    164 //  std::cout << document2.GetRootNode().GetBoolAttribute("prop_2") << std::endl; 
    165 //  std::cout << document2.GetRootNode().GetDoubleAttribute("prop_3") << std::endl; 
    166 //  std::cout << document2.GetRootNode().GetIntAttribute("prop_4") << std::endl; 
    167 // 
    168 //  for (std::vector<tXMLNode>::const_iterator it = document2.GetRootNode().GetChildren().begin(); it != document2.GetRootNode().GetChildren().end(); ++it) 
    169 //  { 
    170 //    std::cout << it->GetName() << std::endl; 
    171 //    std::cout << it->GetStringAttribute("prop_1") << std::endl; 
    172 //    std::cout << it->GetBoolAttribute("prop_2") << std::endl; 
    173 //    std::cout << it->GetDoubleAttribute("prop_3") << std::endl; 
    174 //    if (it->HasAttribute("prop_4")) 
    175 //    { 
    176 //      std::cout << it->GetIntAttribute("prop_4") << std::endl; 
    177 //    } 
    178 //  } 
     123  std::cout << "Accessing node with content: " << document2.GetRootNode().GetXMLDump() << std::endl; 
     124 
     125  std::cout << document2.GetRootNode().GetName() << std::endl; 
     126  std::cout << document2.GetRootNode().GetStringAttribute("prop_1") << std::endl; 
     127  std::cout << document2.GetRootNode().GetBoolAttribute("prop_2") << std::endl; 
     128  std::cout << document2.GetRootNode().GetDoubleAttribute("prop_3") << std::endl; 
     129  std::cout << document2.GetRootNode().GetIntAttribute("prop_4") << std::endl; 
     130 
     131  document2.GetRootNode().GetFirstChild().AddNextSibling(document1.GetRootNode().GetFirstChild()); 
     132 
     133  std::cout << "Accessing node with content: " << document2.GetRootNode().GetXMLDump(true) << std::endl; 
     134 
     135  for (tXMLNode::iterator it = document2.GetRootNode().GetChildrenBegin(); it != document2.GetRootNode().GetChildrenEnd(); ++it) 
     136  { 
     137    std::cout << "Accessing node with content: " << it->GetXMLDump() << std::endl; 
     138 
     139    std::cout << "name = " << it->GetName() << std::endl; 
     140    std::cout << it->GetStringAttribute("prop_1") << std::endl; 
     141    std::cout << it->GetBoolAttribute("prop_2") << std::endl; 
     142    std::cout << it->GetDoubleAttribute("prop_3") << std::endl; 
     143    if (it->HasAttribute("prop_4")) 
     144    { 
     145      std::cout << it->GetIntAttribute("prop_4") << std::endl; 
     146    } 
     147  } 
     148 
     149  std::cout << "doc 1: " << document1.GetRootNode().GetXMLDump() << std::endl; 
     150  std::cout << "doc 2: " << document2.GetRootNode().GetXMLDump() << std::endl; 
     151 
     152  tXMLDocument document3; 
     153 
     154  document3.AddRootNode("foo"); 
     155 
     156  xmlNewChild(reinterpret_cast<xmlNode *>(&document3.GetRootNode()), 0, reinterpret_cast<const xmlChar *>("child1"), reinterpret_cast<const xmlChar *>("text1")); 
     157  xmlNewChild(reinterpret_cast<xmlNode *>(&document3.GetRootNode().GetFirstChild()), 0, reinterpret_cast<const xmlChar *>("child2"), reinterpret_cast<const xmlChar *>("text2")); 
     158 
     159  xmlNodeAddContent(reinterpret_cast<xmlNode *>(&document3.GetRootNode().GetFirstChild()), reinterpret_cast<const xmlChar *>("text3")); 
     160 
     161  std::cout << "doc 3: " << document3.GetRootNode().GetXMLDump() << std::endl; 
     162 
     163  std::cout << "content = " << document3.GetRootNode().GetFirstChild().GetTextContent() << std::endl; 
     164 
     165  document3.GetRootNode().GetFirstChild().RemoveTextContent(); 
     166 
     167  std::cout << "content = " << document3.GetRootNode().GetFirstChild().GetTextContent() << std::endl; 
     168 
     169  for (tXMLNode::iterator it = document3.GetRootNode().GetFirstChild().GetChildrenBegin(); it != document3.GetRootNode().GetFirstChild().GetChildrenEnd(); ++it) 
     170  { 
     171    std::cout << "child: " << it->GetXMLDump() << std::endl; 
     172  } 
     173 
    179174 
    180175 
Note: See TracChangeset for help on using the changeset viewer.