xmlwrapp
node.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2001-2003 Peter J Jones (pjones@pmade.org)
3  * 2009 Vaclav Slavik <vslavik@gmail.com>
4  * All Rights Reserved
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in
14  * the documentation and/or other materials provided with the
15  * distribution.
16  * 3. Neither the name of the Author nor the names of its contributors
17  * may be used to endorse or promote products derived from this software
18  * without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
24  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
27  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
30  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 /**
35  @file
36 
37  This file contains the definition of the xml::node class.
38  */
39 
40 #ifndef _xmlwrapp_node_h_
41 #define _xmlwrapp_node_h_
42 
43 // xmlwrapp includes
44 #include "xmlwrapp/init.h"
45 #include "xmlwrapp/export.h"
46 
47 // hidden stuff
48 #include "xmlwrapp/_cbfo.h"
49 
50 // standard includes
51 #include <cstddef>
52 #include <iosfwd>
53 #include <string>
54 
55 namespace xml
56 {
57 
58 // forward declarations
59 class document;
60 class attributes;
61 class nodes_view;
62 class const_nodes_view;
63 
64 namespace impl
65 {
66 class node_iterator;
67 class iter_advance_functor;
68 struct node_impl;
69 struct doc_impl;
70 struct nipimpl;
71 struct node_cmp;
72 }
73 
74 /**
75  The xml::node class is used to hold information about one XML node.
76 
77  This includes the name of the node, the namespace of the node and
78  attributes for the node. It also has an iterator whereby you can get to the
79  children nodes.
80 
81  It should be noted that any member function that returns a const char*
82  returns a temporary value. The pointer that is returned will change with
83  ANY operation to the xml::node. If you need the data to stick around a
84  little longer you should put it inside a std::string.
85  */
86 class XMLWRAPP_API node
87 {
88 public:
89  /// size type
90  typedef std::size_t size_type;
91 
92  /// enum for the different types of XML nodes
93  enum node_type
94  {
95  type_element, ///< XML element such as "<chapter/>"
96  type_text, ///< Text node
97  type_cdata, ///< <![CDATA[text]]>
98  type_pi, ///< Processing Instruction
99  type_comment, ///< XML comment
100  type_entity, ///< Entity as in &amp;amp;
101  type_entity_ref, ///< Entity ref
102  type_xinclude, ///< <xi:include/> node
103  type_document, ///< Document node
104  type_document_type, ///< DOCTYPE node
105  type_document_frag, ///< Document Fragment
106  type_notation, ///< Notation
107  type_dtd, ///< DTD node
108  type_dtd_element, ///< DTD <!ELEMENT> node
109  type_dtd_attribute, ///< DTD <!ATTRLIST> node
110  type_dtd_entity, ///< DTD <!ENTITY>
111  type_dtd_namespace ///< ?
112  };
113 
114  /**
115  Helper struct for creating a xml::node of type_cdata.
116 
117  @code
118  xml::node mynode(xml::node::cdata("This is a CDATA section"));
119  @endcode
120  */
121  struct cdata
122  {
123  explicit cdata(const char *text) : t(text) {}
124  const char *t;
125  };
126 
127  /**
128  Helper struct for creating a xml::node of type_comment.
129 
130  @code
131  xml::node mynode(xml::node::comment("This is an XML comment"));
132  @endcode
133  */
134  struct comment
135  {
136  explicit comment (const char *text) : t(text) {}
137  const char *t;
138  };
139 
140  /**
141  Helper struct for creating a xml::node of type_pi.
142 
143  @code
144  xml::node mynode(xml::node::pi("xslt", "stylesheet=\"test.xsl\""));
145  @endcode
146  */
147  struct pi
148  {
149  explicit pi (const char *name, const char *content = NULL)
150  : n(name), c(content) {}
151  const char *n, *c;
152  };
153 
154  /**
155  Helper struct for creating a xml::node of type_text.
156 
157  @code
158  xml::node mynode(xml::node::text("This is an XML text fragment"));
159  @endcode
160  */
161  struct text
162  {
163  explicit text (const char *text) : t(text) {}
164  const char *t;
165  };
166 
167  /**
168  Construct a new blank xml::node.
169  */
170  node();
171 
172  /**
173  Construct a new xml::node and set the name of the node.
174 
175  @param name The name of the new node.
176  */
177  explicit node(const char *name);
178 
179  /**
180  Construct a new xml::node given a name and content.
181 
182  The content, if it's not an empty string, will be used to create a new
183  child text node.
184 
185  @param name The name of the new element.
186  @param content The text that will be used to create a child node.
187  */
188  node(const char *name, const char *content);
189 
190  /**
191  Construct a new xml::node that is of type_cdata. The cdata_info
192  parameter should contain the contents of the CDATA section.
193 
194  @note Sample Use Example:
195  @code
196  xml::node mynode(xml::node::cdata("This is a CDATA section"));
197  @endcode
198 
199  @param cdata_info A cdata struct that tells xml::node what the
200  content will be.
201  */
202  explicit node(cdata cdata_info);
203 
204  /**
205  Construct a new xml::node that is of type_comment. The comment_info
206  parameter should contain the contents of the XML comment.
207 
208  @note Sample Use Example:
209  @code
210  xml::node mynode(xml::node::comment("This is an XML comment"));
211  @endcode
212 
213  @param comment_info A comment struct that tells xml::node what the comment will be.
214  */
215  explicit node(comment comment_info);
216 
217  /**
218  Construct a new xml::node that is of type_pi. The pi_info parameter
219  should contain the name of the XML processing instruction (PI), and
220  optionally, the contents of the XML PI.
221 
222  @note Sample Use Example:
223  @code
224  xml::node mynode(xml::node::pi("xslt", "stylesheet=\"test.xsl\""));
225  @endcode
226 
227  @param pi_info A pi struct that tells xml::node what the name and contents of the XML PI are.
228  */
229  explicit node(pi pi_info);
230 
231  /**
232  Construct a new xml::node that is of type_text. The text_info
233  parameter should contain the text.
234 
235  @note Sample Use Example:
236  @code
237  xml::node mynode(xml::node::text("This is XML text"));
238  @endcode
239 
240  @param text_info A text struct that tells xml::node what the text will be.
241  */
242  explicit node(text text_info);
243 
244  /**
245  Construct a new xml::node by copying another xml::node.
246 
247  @param other The other node to copy.
248  */
249  node(const node& other);
250 
251  /**
252  Make this node equal to some other node via assignment.
253 
254  @param other The other node to copy.
255  @return A reference to this node.
256  */
257  node& operator=(const node& other);
258 
259  /**
260  Class destructor
261  */
262  ~node();
263 
264  /**
265  Set the name of this xml::node.
266 
267  @param name The new name for this xml::node.
268  */
269  void set_name(const char *name);
270 
271  /**
272  Get the name of this xml::node.
273 
274  This function may change in the future to return std::string.
275  Feedback is welcome.
276 
277  @return The name of this node.
278  */
279  const char* get_name() const;
280 
281  /**
282  Set the content of a node. If this node is an element node, this
283  function will remove all of its children nodes and replace them
284  with one text node set to the given string.
285 
286  @param content The content of the text node.
287 
288  @note @a content is supposed to be a piece of XML CDATA, so it allows
289  entity references, but XML special chars need to be escaped
290  first. In particular, the '&' character @em must be escaped
291  as "&amp;" unless it's part of entity reference. Not escaping
292  @a content may result in truncation of data. Use
293  set_text_content() if @a content may contain special characters.
294 
295  @see set_text_content()
296  */
297  void set_content(const char *content);
298 
299  /**
300  Set the content of a node to given text.
301 
302  In contrast to set_content(), @a content is raw text, so unescaped XML
303  special chars are allowed and entity references are not supported.
304 
305  If this node is an element node, this function will remove all of its
306  children nodes and replace them with one text node set to the given
307  string.
308 
309  @param content The content text.
310 
311  @see set_content()
312 
313  @since 0.7.0
314  */
315  void set_text_content(const char *content);
316 
317  /**
318  Get the content for this text node. If this node is not a text node
319  but it has children nodes that are text nodes, the contents of those
320  child nodes will be returned. If there is no content or these
321  conditions do not apply, zero will be returned.
322 
323  This function may change in the future to return std::string.
324  Feedback is welcome.
325 
326  @return The content or 0.
327  */
328  const char* get_content() const;
329 
330  /**
331  Get this node's "type". You can use that information to know what you
332  can and cannot do with it.
333 
334  @return The node's type.
335  */
336  node_type get_type() const;
337 
338  /**
339  Get the list of attributes. You can use the returned object to get
340  and set the attributes for this node. Make sure you use a reference
341  to this returned object, to prevent a copy.
342 
343  @return The xml::attributes object for this node.
344  */
345  xml::attributes& get_attributes();
346 
347  /**
348  Get the list of attributes. You can use the returned object to get
349  the attributes for this node. Make sure you use a reference to this
350  returned object, to prevent a copy.
351 
352  @return The xml::attributes object for this node.
353  */
354  const xml::attributes& get_attributes() const;
355 
356  /**
357  Get the namespace of this xml::node.
358 
359  @return The namespace of this node or NULL if no namespace is
360  associated.
361  @since 0.6.0
362  */
363  const char* get_namespace() const;
364 
365  /**
366  Find out if this node is a text node or something like a text node,
367  CDATA for example.
368 
369  @return True if this node is a text node; false otherwise.
370  */
371  bool is_text() const;
372 
373  /**
374  Add a child xml::node to this node.
375 
376  @param child The child xml::node to add.
377  */
378  void push_back(const node& child);
379 
380  /**
381  Swap this node with another one.
382 
383  @param other The other node to swap with.
384  */
385  void swap(node& other);
386 
387  class const_iterator; // forward declaration
388 
389  /**
390  The xml::node::iterator provides a way to access children nodes
391  similar to a standard C++ container. The nodes that are pointed to by
392  the iterator can be changed.
393  */
394  class iterator
395  {
396  public:
397  typedef node value_type;
398  typedef int difference_type;
399  typedef value_type* pointer;
400  typedef value_type& reference;
401  typedef std::forward_iterator_tag iterator_category;
402 
403  iterator() : pimpl_(0) {}
404  iterator(const iterator& other);
405  iterator& operator=(const iterator& other);
406  ~iterator();
407 
408  reference operator* () const;
409  pointer operator->() const;
410 
411  /// prefix increment
412  iterator& operator++();
413 
414  /// postfix increment (avoid if possible for better performance)
415  iterator operator++ (int);
416 
417  private:
418  impl::nipimpl *pimpl_;
419 
420  explicit iterator (void *data);
421  void* get_raw_node() const;
422  void swap (iterator &other);
423 
424  friend class node;
425  friend class document;
426  friend class const_iterator;
427  friend bool XMLWRAPP_API operator==(const iterator& lhs, const iterator& rhs);
428  };
429 
430  /**
431  The xml::node::const_iterator provides a way to access children nodes
432  similar to a standard C++ container. The nodes that are pointed to by
433  the const_iterator cannot be changed.
434  */
436  {
437  public:
438  typedef const node value_type;
439  typedef int difference_type;
440  typedef value_type* pointer;
441  typedef value_type& reference;
442  typedef std::forward_iterator_tag iterator_category;
443 
444  const_iterator() : pimpl_(0) {}
445  const_iterator(const const_iterator &other);
446  const_iterator(const iterator &other);
447  const_iterator& operator=(const const_iterator& other);
448  ~const_iterator();
449 
450  reference operator* () const;
451  pointer operator->() const;
452 
453  /// prefix increment
454  const_iterator& operator++();
455 
456  /// postfix increment (avoid if possible for better performance)
457  const_iterator operator++ (int);
458 
459  private:
460  impl::nipimpl *pimpl_;
461 
462  explicit const_iterator (void *data);
463  void* get_raw_node() const;
464  void swap (const_iterator &other);
465 
466  friend class document;
467  friend class node;
468  friend bool XMLWRAPP_API operator==(const const_iterator& lhs, const const_iterator& rhs);
469  };
470 
471  /**
472  Returns the number of children this nodes has. If you just want to
473  know how if this node has children or not, you should use
474  xml::node::empty() instead.
475 
476  @return The number of children this node has.
477  */
478  size_type size() const;
479 
480  /**
481  Find out if this node has any children. This is the same as
482  xml::node::size() == 0 except it is much faster.
483 
484  @return True if this node DOES NOT have any children.
485  @return False if this node does have children.
486  */
487  bool empty() const;
488 
489  /**
490  Get an iterator that points to the beginning of this node's children.
491 
492  @return An iterator that points to the beginning of the children.
493  */
494  iterator begin();
495 
496  /**
497  Get a const_iterator that points to the beginning of this node's
498  children.
499 
500  @return A const_iterator that points to the beginning of the children.
501  */
502  const_iterator begin() const;
503 
504  /**
505  Get an iterator that points one past the last child for this node.
506 
507  @return A "one past the end" iterator.
508  */
509  iterator end() { return iterator(); }
510 
511  /**
512  Get a const_iterator that points one past the last child for this
513  node.
514 
515  @return A "one past the end" const_iterator
516  */
517  const_iterator end() const { return const_iterator(); }
518 
519  /**
520  Get an iterator that points back at this node.
521 
522  @return An iterator that points at this node.
523  */
524  iterator self();
525 
526  /**
527  Get a const_iterator that points back at this node.
528 
529  @return A const_iterator that points at this node.
530  */
531  const_iterator self() const;
532 
533  /**
534  Get an iterator that points at the parent of this node. If this node
535  does not have a parent, this member function will return an "end"
536  iterator.
537 
538  @return An iterator that points to this nodes parent.
539  @return If no parent, returns the same iterator that xml::node::end() returns.
540  */
541  iterator parent();
542 
543  /**
544  Get a const_iterator that points at the parent of this node. If this
545  node does not have a parent, this member function will return an
546  "end" const_iterator.
547 
548  @return A const_iterator that points to this nodes parent.
549  @return If no parent, returns the same const_iterator that xml::node::end() returns.
550  */
551  const_iterator parent() const;
552 
553  /**
554  Find the first child node that has the given name. If no such node
555  can be found, this function will return the same iterator that end()
556  would return.
557 
558  This function is not recursive. That is, it will not search down the
559  tree for the requested node. Instead, it will only search one level
560  deep, only checking the children of this node.
561 
562  @param name The name of the node you want to find.
563  @return An iterator that points to the node if found.
564  @return An end() iterator if the node was not found.
565 
566  @see elements(const char*), find(const char*, iterator)
567  */
568  iterator find(const char *name);
569 
570  /**
571  Find the first child node that has the given name. If no such node
572  can be found, this function will return the same const_iterator that
573  end() would return.
574 
575  This function is not recursive. That is, it will not search down the
576  tree for the requested node. Instead, it will only search one level
577  deep, only checking the children of this node.
578 
579  @param name The name of the node you want to find.
580  @return A const_iterator that points to the node if found.
581  @return An end() const_iterator if the node was not found.
582 
583  @see elements(const char*) const,
584  find(const char*, const_iterator) const
585  */
586  const_iterator find(const char *name) const;
587 
588  /**
589  Find the first child node, starting with the given iterator, that has
590  the given name. If no such node can be found, this function will
591  return the same iterator that end() would return.
592 
593  This function should be given an iterator to one of this node's
594  children. The search will begin with that node and continue with all
595  its sibliings. This function will not recurse down the tree, it only
596  searches in one level.
597 
598  @param name The name of the node you want to find.
599  @param start Where to begin the search.
600  @return An iterator that points to the node if found.
601  @return An end() iterator if the node was not found.
602 
603  @see elements(const char*)
604  */
605  iterator find(const char *name, const iterator& start);
606 
607  /**
608  Find the first child node, starting with the given const_iterator,
609  that has the given name. If no such node can be found, this function
610  will return the same const_iterator that end() would return.
611 
612  This function should be given a const_iterator to one of this node's
613  children. The search will begin with that node and continue with all
614  its siblings. This function will not recurse down the tree, it only
615  searches in one level.
616 
617  @param name The name of the node you want to find.
618  @param start Where to begin the search.
619  @return A const_iterator that points to the node if found.
620  @return An end() const_iterator if the node was not found.
621 
622  @see elements(const char*) const
623  */
624  const_iterator find(const char *name, const const_iterator& start) const;
625 
626  /**
627  Returns view of child nodes of type type_element. If no such node
628  can be found, returns empty view.
629 
630  Example:
631  @code
632  xml::nodes_view view(root.elements());
633  for (xml::nodes_view::iterator i = view.begin(); i != view.end(); ++i)
634  {
635  ...
636  }
637  @endcode
638 
639  @return View with all child elements or empty view if there aren't any.
640  @since 0.6.0
641 
642  @see nodes_view
643  */
644  nodes_view elements();
645 
646  /**
647  Returns view of child nodes of type type_element. If no such node
648  can be found, returns empty view.
649 
650  Example:
651  @code
652  xml::const_nodes_view view(root.elements());
653  for (xml::const_nodes_view::const_iterator i = view.begin();
654  i != view.end();
655  ++i)
656  {
657  ...
658  }
659  @endcode
660 
661  @return View with all child elements or empty view if there aren't any.
662  @since 0.6.0
663 
664  @see const_nodes_view
665  */
666  const_nodes_view elements() const;
667 
668  /**
669  Returns view of child nodes of type type_element with name @a name.
670  If no such node can be found, returns empty view.
671 
672  Example:
673  @code
674  xml::nodes_view view(root.elements("person"));
675  for (xml::nodes_view::iterator i = view.begin(); i != view.end(); ++i)
676  {
677  ...
678  }
679  @endcode
680 
681  @param name Name of the elements to return.
682  @return View that contains only elements @a name.
683  @since 0.6.0
684  */
685  nodes_view elements(const char *name);
686 
687  /**
688  Returns view of child nodes of type type_element with name @a name.
689  If no such node can be found, returns empty view.
690 
691  Example:
692  @code
693  xml::const_nodes_view view(root.elements("person"));
694  for (xml::const_nodes_view::const_iterator i = view.begin();
695  i != view.end();
696  ++i)
697  {
698  ...
699  }
700  @endcode
701 
702  @param name Name of the elements to return.
703  @return View that contains only elements @a name.
704  @since 0.6.0
705  */
706  const_nodes_view elements(const char *name) const;
707 
708  /**
709  Insert a new child node. The new node will be inserted at the end of
710  the child list. This is similar to the xml::node::push_back member
711  function except that an iterator to the inserted node is returned.
712 
713  @param n The node to insert as a child of this node.
714  @return An iterator that points to the newly inserted node.
715  */
716  iterator insert(const node& n);
717 
718  /**
719  Insert a new child node. The new node will be inserted before the
720  node pointed to by the given iterator.
721 
722  @param position An iterator that points to the location where the new node should be inserted (before it).
723  @param n The node to insert as a child of this node.
724  @return An iterator that points to the newly inserted node.
725  */
726  iterator insert(const iterator& position, const node& n);
727 
728  /**
729  Replace the node pointed to by the given iterator with another node.
730  The old node will be removed, including all its children, and
731  replaced with the new node. This will invalidate any iterators that
732  point to the node to be replaced, or any pointers or references to
733  that node.
734 
735  @param old_node An iterator that points to the node that should be removed.
736  @param new_node The node to put in old_node's place.
737  @return An iterator that points to the new node.
738  */
739  iterator replace(const iterator& old_node, const node& new_node);
740 
741  /**
742  Erase the node that is pointed to by the given iterator. The node
743  and all its children will be removed from this node. This will
744  invalidate any iterators that point to the node to be erased, or any
745  pointers or references to that node.
746 
747  @param to_erase An iterator that points to the node to be erased.
748  @return An iterator that points to the node after the one being erased.
749  */
750  iterator erase(const iterator& to_erase);
751 
752  /**
753  Erase all nodes in the given range, from first to last. This will
754  invalidate any iterators that point to the nodes to be erased, or any
755  pointers or references to those nodes.
756 
757  @param first The first node in the range to be removed.
758  @param last An iterator that points one past the last node to erase. Think xml::node::end().
759  @return An iterator that points to the node after the last one being erased.
760  */
761  iterator erase(iterator first, const iterator& last);
762 
763  /**
764  Erase all children nodes with the given name. This will find all
765  nodes that have the given node name and remove them from this node.
766  This will invalidate any iterators that point to the nodes to be
767  erased, or any pointers or references to those nodes.
768 
769  @param name The name of nodes to remove.
770  @return The number of nodes removed.
771  */
772  size_type erase(const char *name);
773 
774  /**
775  Erases all children nodes.
776 
777  @since 0.7.0
778  */
779  void clear();
780 
781  /**
782  Sort all the children nodes of this node using one of their
783  attributes. Only nodes that are of xml::node::type_element will be
784  sorted, and they must have the given node_name.
785 
786  The sorting is done by calling std::strcmp on the value of the given
787  attribute.
788 
789  @param node_name The name of the nodes to sort.
790  @param attr_name The attribute to sort on.
791  */
792  void sort(const char *node_name, const char *attr_name);
793 
794  /**
795  Sort all the children nodes of this node using the given comparison
796  function object. All element type nodes will be considered for
797  sorting.
798 
799  @param compare The binary function object to call in order to sort all child nodes.
800  */
801  template <typename T> void sort (T compare)
802  { impl::sort_callback<T> cb(compare); sort_fo(cb); }
803 
804  /**
805  Convert the node and all its children into XML text and set the given
806  string to that text.
807 
808  @param xml The string to set the node's XML data to.
809  */
810  void node_to_string(std::string& xml) const;
811 
812  /**
813  Write a node and all of its children to the given stream.
814 
815  @param stream The stream to write the node as XML.
816  @param n The node to write to the stream.
817  @return The stream.
818  */
819  friend XMLWRAPP_API std::ostream& operator<< (std::ostream &stream, const node &n);
820 
821 private:
822  impl::node_impl *pimpl_;
823 
824  // private ctor to create uninitialized instance
825  explicit node(int);
826 
827  void set_node_data(void *data);
828  void* get_node_data();
829  void* release_node_data();
830 
831  void sort_fo(impl::cbfo_node_compare &fo);
832 
833  friend class tree_parser;
834  friend class impl::node_iterator;
835  friend class document;
836  friend struct impl::doc_impl;
837  friend struct impl::node_cmp;
838 };
839 
840 // Comparison operators for xml::node iterators
841 
842 inline bool XMLWRAPP_API operator==(const node::iterator& lhs,
843  const node::iterator& rhs)
844  { return lhs.get_raw_node() == rhs.get_raw_node(); }
845 inline bool XMLWRAPP_API operator!=(const node::iterator& lhs,
846  const node::iterator& rhs)
847  { return !(lhs == rhs); }
848 
849 inline bool XMLWRAPP_API operator==(const node::const_iterator& lhs,
850  const node::const_iterator& rhs)
851  { return lhs.get_raw_node() == rhs.get_raw_node(); }
852 inline bool XMLWRAPP_API operator!=(const node::const_iterator& lhs,
853  const node::const_iterator& rhs)
854  { return !(lhs == rhs); }
855 
856 } // namespace xml
857 
858 #endif // _xmlwrapp_node_h_