GammaLib  1.7.0.dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
GXmlNode.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * GXmlNode.cpp - Abstract XML node base class *
3  * ----------------------------------------------------------------------- *
4  * copyright (C) 2010-2018 by Juergen Knoedlseder *
5  * ----------------------------------------------------------------------- *
6  * *
7  * This program is free software: you can redistribute it and/or modify *
8  * it under the terms of the GNU General Public License as published by *
9  * the Free Software Foundation, either version 3 of the License, or *
10  * (at your option) any later version. *
11  * *
12  * This program is distributed in the hope that it will be useful, *
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15  * GNU General Public License for more details. *
16  * *
17  * You should have received a copy of the GNU General Public License *
18  * along with this program. If not, see <http://www.gnu.org/licenses/>. *
19  * *
20  ***************************************************************************/
21 /**
22  * @file GXmlNode.cpp
23  * @brief Abstract XML node base class implementation
24  * @author Juergen Knoedlseder
25  */
26 
27 /* __ Includes ___________________________________________________________ */
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 #include "GTools.hpp"
32 #include "GException.hpp"
33 #include "GXmlNode.hpp"
34 #include "GXmlElement.hpp"
35 #include "GXmlDocument.hpp"
36 
37 /* __ Method name definitions ____________________________________________ */
38 #define G_ACCESS "GXmlNode::operator[](int&)"
39 #define G_SET "GXmlNode::set(int&, GXmlNode&)"
40 #define G_APPEND1 "GXmlNode::append(std::string&)"
41 #define G_APPEND2 "GXmlNode::append(GXmlNode&)"
42 #define G_INSERT "GXmlNode::insert(int&, GXmlNode&)"
43 #define G_REMOVE "GXmlNode::remove(int&)"
44 #define G_ELEMENT1 "GXmlNode* GXmlNode::element(int&)"
45 #define G_ELEMENT2 "GXmlNode* GXmlNode::element(std::string&)"
46 #define G_ELEMENT3 "GXmlNode* GXmlNode::element(std::string&, int&)"
47 #define G_EXTRACT_INDEX "GXmlNode::extract_index(std::string&)"
48 
49 /* __ Macros _____________________________________________________________ */
50 
51 /* __ Coding definitions _________________________________________________ */
52 
53 /* __ Debug definitions __________________________________________________ */
54 
55 
56 /*==========================================================================
57  = =
58  = Constructors/destructors =
59  = =
60  ==========================================================================*/
61 
62 /***********************************************************************//**
63  * @brief Void constructor
64  ***************************************************************************/
66 {
67  // Initialise members
68  init_members();
69 
70  // Return
71  return;
72 }
73 
74 
75 /***********************************************************************//**
76  * @brief Copy constructor
77  *
78  * @param[in] node XML node.
79  ***************************************************************************/
81 {
82  // Initialise members
83  init_members();
84 
85  // Copy members
86  copy_members(node);
87 
88  // Return
89  return;
90 }
91 
92 
93 /***********************************************************************//**
94  * @brief Destructor
95  ***************************************************************************/
97 {
98  // Free members
99  free_members();
100 
101  // Return
102  return;
103 }
104 
105 
106 /*==========================================================================
107  = =
108  = Operators =
109  = =
110  ==========================================================================*/
111 
112 /***********************************************************************//**
113  * @brief Assignment operator
114  *
115  * @param[in] node XML node.
116  * @return XML node.
117  ***************************************************************************/
119 {
120  // Execute only if object is not identical
121  if (this != &node) {
122 
123  // Free members
124  free_members();
125 
126  // Initialise members
127  init_members();
128 
129  // Copy members
130  copy_members(node);
131 
132  } // endif: object was not identical
133 
134  // Return
135  return *this;
136 }
137 
138 
139 /***********************************************************************//**
140  * @brief Return pointer to XML child node
141  *
142  * @param[in] index Child node index [0,...,size()-1].
143  * @return Pointer to XML child node at @p index.
144  *
145  * @exception GException::out_of_range
146  * Child node index is out of range.
147  *
148  * Returns a pointer to the XML child node with the specified @p index.
149  ***************************************************************************/
150 GXmlNode* GXmlNode::operator[](const int& index)
151 {
152  // Compile option: raise exception if index is out of range
153  #if defined(G_RANGE_CHECK)
154  if (index < 0 || index >= size()) {
155  throw GException::out_of_range(G_ACCESS, index, 0, size()-1);
156  }
157  #endif
158 
159  // Return pointer
160  return m_nodes[index];
161 }
162 
163 
164 /***********************************************************************//**
165  * @brief Return pointer to XML child node (const version)
166  *
167  * @param[in] index Child node index [0,...,size()-1].
168  * @return Pointer to XML child node at @p index.
169  *
170  * @exception GException::out_of_range
171  * Child node index is out of range.
172  *
173  * Returns a const pointer to the XML child node with the specified @p index.
174  ***************************************************************************/
175 const GXmlNode* GXmlNode::operator[](const int& index) const
176 {
177  // Compile option: raise exception if index is out of range
178  #if defined(G_RANGE_CHECK)
179  if (index < 0 || index >= size()) {
180  throw GException::out_of_range(G_ACCESS, index, 0, size()-1);
181  }
182  #endif
183 
184  // Return pointer
185  return m_nodes[index];
186 }
187 
188 
189 /*==========================================================================
190  = =
191  = Public methods =
192  = =
193  ==========================================================================*/
194 
195 /***********************************************************************//**
196  * @brief Set XML child node
197  *
198  * @param[in] index Child node index [0,...,size()-1].
199  * @param[in] node XML child node.
200  * @return Pointer to deep copy of child node
201  *
202  * @exception GException::invalid_argument
203  * Not allowed to append root node.
204  * @exception GException::invalid_value
205  * Not allowed to append to a text, comment or PI node.
206  * @exception GException::out_of_range
207  * Child node index is out of range.
208  *
209  * Set XML child node. A deep copy of the node will be made and the pointer
210  * to this node will be stored.
211  ***************************************************************************/
212 GXmlNode* GXmlNode::set(const int& index, const GXmlNode& node)
213 {
214  // Make sure that node to append is not a root node as only one root node
215  // is allowed to exist in a document.
216  if (node.type() == NT_DOCUMENT) {
217  std::string msg = "Invalid attempt to append root note (GXmlDocument)"
218  " to a XML node. There can only be one root node in"
219  " an XML document.";
221  }
222 
223  // Make sure that the current node is not a text node as nothing can be
224  // appended to a text node.
225  if (this->type() == NT_TEXT) {
226  std::string msg = "Invalid attempt to append a XML node to a text node"
227  " (GXmlText). Nothing can be appended to a text node.";
228  throw GException::invalid_value(G_SET, msg);
229  }
230 
231  // Make sure that the current node is not a PI node as nothing can be
232  // appended to a PI node.
233  if (this->type() == NT_PI) {
234  std::string msg = "Invalid attempt to append a XML node to a processing"
235  " instruction node (GXmlPI). Nothing can be appended"
236  " to a processing instruction node.";
237  throw GException::invalid_value(G_SET, msg);
238  }
239 
240  // Make sure that the current node is not a comment node as nothing can be
241  // appended to a PI node.
242  if (this->type() == NT_COMMENT) {
243  std::string msg = "Invalid attempt to append a XML node to a comment"
244  " node (GXmlComment). Nothing can be appended"
245  " to a processing instruction node.";
246  throw GException::invalid_value(G_SET, msg);
247  }
248 
249  // Compile option: raise exception if index is out of range
250  #if defined(G_RANGE_CHECK)
251  if (index < 0 || index >= size()) {
252  throw GException::out_of_range(G_SET, index, 0, size()-1);
253  }
254  #endif
255 
256  // Free existing node only if it differs from current node. This
257  // prevents unintential deallocation of the argument
258  if ((m_nodes[index] != NULL) && (m_nodes[index] != &node)) {
259  delete m_nodes[index];
260  }
261 
262  // Assign new child node by cloning
263  m_nodes[index] = node.clone();
264 
265  // Return pointer
266  return m_nodes[index];
267 }
268 
269 
270 /***********************************************************************//**
271  * @brief Append XML child node
272  *
273  * @param[in] node XML child node.
274  * @return Pointer to appended child node
275  *
276  * @exception GException::invalid_argument
277  * Not allowed to append root node.
278  * @exception GException::invalid_value
279  * Not allowed to append to a text, comment or PI node.
280  *
281  * Appends XML child node by making a deep copy of the node and storing its
282  * pointer.
283  ***************************************************************************/
285 {
286  // Make sure that node to append is not a root node as only one root node
287  // is allowed to exist in a document.
288  if (node.type() == NT_DOCUMENT) {
289  std::string msg = "Invalid attempt to append root note (GXmlDocument)"
290  " to a XML node. There can only be one root node in"
291  " an XML document.";
293  }
294 
295  // Make sure that the current node is not a text node as nothing can be
296  // appended to a text node.
297  if (this->type() == NT_TEXT) {
298  std::string msg = "Invalid attempt to append a XML node to a text node"
299  " (GXmlText). Nothing can be appended to a text node.";
301  }
302 
303  // Make sure that the current node is not a PI node as nothing can be
304  // appended to a PI node.
305  if (this->type() == NT_PI) {
306  std::string msg = "Invalid attempt to append a XML node to a processing"
307  " instruction node (GXmlPI). Nothing can be appended"
308  " to a processing instruction node.";
310  }
311 
312  // Make sure that the current node is not a comment node as nothing can be
313  // appended to a PI node.
314  if (this->type() == NT_COMMENT) {
315  std::string msg = "Invalid attempt to append a XML node to a comment"
316  " node (GXmlComment). Nothing can be appended"
317  " to a processing instruction node.";
319  }
320 
321  // Clone child node
322  GXmlNode* ptr = node.clone();
323 
324  // Append deep copy of child node
325  m_nodes.push_back(ptr);
326 
327  // Return pointer
328  return ptr;
329 }
330 
331 
332 /***********************************************************************//**
333  * @brief Append XML element child node
334  *
335  * @param[in] segment XML child node.
336  * @return Pointer to appended child node
337  *
338  * @exception GException::invalid_value
339  * Not allowed to append to a text, comment or PI node.
340  *
341  * Appends XML element that is constructed from a text @p segment. The text
342  * segment is parsed and the element name and attributes are extracted using
343  * the GXmlElement::parse_start() method. The method returns a pointer to the
344  * XML element child node that has been appended.
345  ***************************************************************************/
346 GXmlElement* GXmlNode::append(const std::string& segment)
347 {
348  // Make sure that the current node is not a text node as nothing can be
349  // appended to a text node.
350  if (this->type() == NT_TEXT) {
351  std::string msg = "Invalid attempt to append the text segment \""+
352  segment+"\" to a text node (GXmlText). Nothing can"
353  " be appended to a text node.";
355  }
356 
357  // Make sure that the current node is not a PI node as nothing can be
358  // appended to a PI node.
359  if (this->type() == NT_PI) {
360  std::string msg = "Invalid attempt to append a XML node to a processing"
361  " instruction node (GXmlPI). Nothing can be appended"
362  " to a processing instruction node.";
364  }
365 
366  // Make sure that the current node is not a comment node as nothing can be
367  // appended to a PI node.
368  if (this->type() == NT_COMMENT) {
369  std::string msg = "Invalid attempt to append a XML node to a comment"
370  " node (GXmlComment). Nothing can be appended"
371  " to a processing instruction node.";
373  }
374 
375  // Create a new XML child element from the text segment
376  GXmlElement* ptr = new GXmlElement(segment);
377 
378  // Append child element to container
379  m_nodes.push_back(ptr);
380 
381  // Return child element
382  return ptr;
383 }
384 
385 
386 /***********************************************************************//**
387  * @brief Insert XML child node
388  *
389  * @param[in] index Child node index [0,...,size()-1].
390  * @param[in] node XML child node.
391  * @return Pointer to inserted child node
392  *
393  * @exception GException::invalid_argument
394  * Not allowed to append root node.
395  * @exception GException::invalid_value
396  * Not allowed to append to a text, comment or PI node.
397  * @exception GException::out_of_range
398  * Child node index is out of range.
399  *
400  * Inserts the XML child @p node before the node with the specified @p index.
401  * A deep copy of the node will be made and the pointer to this node will be
402  * stored.
403  ***************************************************************************/
404 GXmlNode* GXmlNode::insert(const int& index, const GXmlNode& node)
405 {
406  // Make sure that node to append is not a root node as only one root node
407  // is allowed to exist in a document.
408  if (node.type() == NT_DOCUMENT) {
409  std::string msg = "Invalid attempt to append root note (GXmlDocument)"
410  " to a XML node. There can only be one root node in"
411  " an XML document.";
413  }
414 
415  // Make sure that the current node is not a text node as nothing can be
416  // appended to a text node.
417  if (this->type() == NT_TEXT) {
418  std::string msg = "Invalid attempt to append a XML node to a text node"
419  " (GXmlText). Nothing can be appended to a text node.";
421  }
422 
423  // Make sure that the current node is not a PI node as nothing can be
424  // appended to a PI node.
425  if (this->type() == NT_PI) {
426  std::string msg = "Invalid attempt to append a XML node to a processing"
427  " instruction node (GXmlPI). Nothing can be appended"
428  " to a processing instruction node.";
430  }
431 
432  // Make sure that the current node is not a comment node as nothing can be
433  // appended to a PI node.
434  if (this->type() == NT_COMMENT) {
435  std::string msg = "Invalid attempt to append a XML node to a comment"
436  " node (GXmlComment). Nothing can be appended"
437  " to a processing instruction node.";
439  }
440 
441  // Compile option: raise exception if index is out of range
442  #if defined(G_RANGE_CHECK)
443  if (is_empty()) {
444  if (index > 0) {
445  throw GException::out_of_range(G_INSERT, index, 0, size()-1);
446  }
447  }
448  else {
449  if (index < 0 || index >= size()) {
450  throw GException::out_of_range(G_INSERT, index, 0, size()-1);
451  }
452  }
453  #endif
454 
455  // Clone child node
456  GXmlNode* ptr = node.clone();
457 
458  // Inserts deep copy of child node
459  m_nodes.insert(m_nodes.begin()+index, ptr);
460 
461  // Return pointer
462  return ptr;
463 }
464 
465 
466 /***********************************************************************//**
467  * @brief Remove XML child node
468  *
469  * @param[in] index Child node index [0,...,size()-1].
470  *
471  * @exception GException::out_of_range
472  * Child node index is out of range.
473  *
474  * Remove XML child node at @p index.
475  ***************************************************************************/
476 void GXmlNode::remove(const int& index)
477 {
478  // Compile option: raise exception if index is out of range
479  #if defined(G_RANGE_CHECK)
480  if (index < 0 || index >= size()) {
481  throw GException::out_of_range(G_REMOVE, index, 0, size()-1);
482  }
483  #endif
484 
485  // Delete node
486  delete m_nodes[index];
487 
488  // Erase child node from container
489  m_nodes.erase(m_nodes.begin() + index);
490 
491  // Return
492  return;
493 }
494 
495 
496 /***********************************************************************//**
497  * @brief Append all XML child nodes from another XML node
498  *
499  * @param[in] node XML node.
500  *
501  * Append all XML child nodes found in @p node to the actual object. Nodes
502  * are copied deeply so that they live now on their on in the actual object.
503  ***************************************************************************/
504 void GXmlNode::extend(const GXmlNode& node)
505 {
506  // Do nothing if node container is empty
507  if (!node.is_empty()) {
508 
509  // Get size. Note that we extract the size first to avoid an
510  // endless loop that arises when a container is appended to
511  // itself.
512  int num = node.size();
513 
514  // Reserve enough space
515  reserve(size() + num);
516 
517  // Loop over all child nodes and append pointers to deep copies
518  for (int i = 0; i < num; ++i) {
519  m_nodes.push_back(node[i]->clone());
520  }
521 
522  } // endif: node container was not empty
523 
524  // Return
525  return;
526 }
527 
528 
529 /***********************************************************************//**
530  * @brief Return filename of XML file
531  *
532  * @return Filename.
533  *
534  * Returns the file name of the XML file by moving up the XML file hierarchy
535  * to the root. In case that the XML node cannot move up to the root XML
536  * node an empty file name is returned (this may happen if the XML node
537  * is an orphan node). The file name will also be empty if the XML file has
538  * not been read from disk or written to disk.
539  ***************************************************************************/
541 {
542  // Initialise empty filename
544 
545  // Move up the XML document hierarchy until the root node has been
546  // found
547  GXmlNode* parent = this->parent();
548  while (parent != NULL) {
549 
550  // Cast parent into a root node
551  GXmlDocument* root = dynamic_cast<GXmlDocument*>(parent);
552 
553  // If the parent is a root node, recover the filename and exit the
554  // loop
555  if (root != NULL) {
556  filename = root->filename();
557  break;
558  }
559 
560  // ... otherwise move up the XML tree
561  else {
562  parent = parent->parent();
563  }
564 
565  } // endwhile: move up to the root document
566 
567  // Return filename
568  return filename;
569 }
570 
571 
572 /***********************************************************************//**
573  * @brief Return number of GXMLElement children of node
574  *
575  * @return Number of child elements.
576  *
577  * Returns the number of GXMLElement child elements of the XML node.
578  * GXMLElement child elements are nodes of type NT_ELEMENT.
579  ***************************************************************************/
580 int GXmlNode::elements(void) const
581 {
582  // Compute number of child elements in node
583  int elements = 0;
584  for (int i = 0; i < m_nodes.size(); ++i) {
585  if (m_nodes[i]->type() == NT_ELEMENT) {
586  elements++;
587  }
588  }
589 
590  // Return number of child elements
591  return elements;
592 }
593 
594 
595 /***********************************************************************//**
596  * @brief Return number of GXMLElement children with a given name
597  *
598  * @param[in] name Name of GXMLElement elements.
599  * @return Number of child elements with a given @p name.
600  *
601  * Returns the number of GXMLElement child elements of the XML node that
602  * have a given @p name. GXMLElement child elements are nodes of type
603  * NT_ELEMENT.
604  ***************************************************************************/
605 int GXmlNode::elements(const std::string& name) const
606 {
607  // Compute number of child elements in node
608  int elements = 0;
609  for (int i = 0; i < m_nodes.size(); ++i) {
610  if (m_nodes[i]->type() == NT_ELEMENT) {
611  if (static_cast<GXmlElement*>(m_nodes[i])->name() == name) {
612  elements++;
613  }
614  }
615  }
616 
617  // Return number of child elements
618  return elements;
619 }
620 
621 
622 /***********************************************************************//**
623  * @brief Return pointer to GXMLElement child
624  *
625  * @param[in] index Node index [0,...,elements()-1].
626  * @return Pointer to child element (NULL if element does not exist).
627  *
628  * @exception GException::out_of_range
629  * Child element index is out of range.
630  *
631  * Returns a pointer to the child number @p index of the XML node. An
632  * exception will be thrown if the @p index is not valid.
633  ***************************************************************************/
634 GXmlElement* GXmlNode::element(const int& index)
635 {
636  // If index is outside boundary then throw an error
637  if (index < 0 || index >= elements()) {
638  throw GException::out_of_range(G_ELEMENT1, index, 0, elements()-1);
639  }
640 
641  // Get the requested child element
642  GXmlElement* element = NULL;
643  int elements = 0;
644  for (int i = 0; i < m_nodes.size(); ++i) {
645  GXmlElement* src = dynamic_cast<GXmlElement*>(m_nodes[i]);
646  if (src != NULL) {
647  if (elements == index) {
648  element = src;
649  break;
650  }
651  elements++;
652  }
653  }
654 
655  // Return child element
656  return element;
657 }
658 
659 
660 /***********************************************************************//**
661  * @brief Return pointer to GXMLElement child (const variant)
662  *
663  * @param[in] index Node index [0,...,elements()-1].
664  * @return Pointer to child element (NULL if element does not exist).
665  *
666  * @exception GException::out_of_range
667  * Child element index is out of range.
668  *
669  * Returns a pointer to the child number @p index of the XML node. An
670  * exception will be thrown if the @p index is not valid.
671  ***************************************************************************/
672 const GXmlElement* GXmlNode::element(const int& index) const
673 {
674  // If index is outside boundary then throw an error
675  if (index < 0 || index >= elements()) {
676  throw GException::out_of_range(G_ELEMENT1, index, 0, elements()-1);
677  }
678 
679  // Get the requested child element
680  const GXmlElement* element = NULL;
681  int elements = 0;
682  for (int i = 0; i < m_nodes.size(); ++i) {
683  const GXmlElement* src = dynamic_cast<const GXmlElement*>(m_nodes[i]);
684  if (src != NULL) {
685  if (elements == index) {
686  element = src;
687  break;
688  }
689  elements++;
690  }
691  }
692 
693  // Return child element
694  return element;
695 }
696 
697 
698 /***********************************************************************//**
699  * @brief Return pointer on child walking down a hierarchy of tags
700  *
701  * @param[in] name Child element hierarchy.
702  * @return Pointer to child element (NULL if element does not exist).
703  *
704  * @exception GException::invalid_argument
705  * Hierarchy string invalid.
706  *
707  * Returns a pointer to the child element described by a hierarchy of the
708  * following syntax
709  *
710  * params > param[1] > value > struct
711  *
712  * The > symbols indicate subsequent hierarchy levels, the square brackets
713  * provides the index in case that multiple tags with the same name exist
714  * at a given hierarchy level. Omitting the index means that the first
715  * tag with the specified name is accessed.
716  *
717  * If the specified element does not exist the method returns a NULL pointer.
718  ***************************************************************************/
719 GXmlElement* GXmlNode::element(const std::string& name)
720 {
721  // Initialise child node pointer
722  GXmlElement* element = NULL;
723 
724  // Split name into tags
725  std::vector<std::string> tags = gammalib::split(name, ">");
726 
727  // Walk down the hierarchy
728  GXmlNode* current = this;
729  for (int i = 0; i < tags.size(); ++i) {
730 
731  // Get tag name and index
732  std::string tag = gammalib::strip_whitespace(tags[i]);
733  int index = extract_index(tag);
734 
735  // Break if the requested node does not exist
736  int n = current->elements(tag);
737  if (n < 1 || index < 0 || index >= n) {
738  element = NULL;
739  break;
740  }
741 
742  // Get node
743  element = current->element(tag, index);
744  current = element;
745 
746  // Break if node has not been found
747  if (current == NULL) {
748  element = NULL;
749  break;
750  }
751 
752  } // endfor: walked down hierarchy
753 
754  // Return child element
755  return element;
756 }
757 
758 
759 /***********************************************************************//**
760  * @brief Return pointer on child walking down a hierarchy of tags (const
761  * version)
762  *
763  * @param[in] name Child element hierarchy.
764  * @return Pointer to child element (NULL if element does not exist).
765  *
766  * @exception GException::invalid_argument
767  * Hierarchy string invalid.
768  *
769  * Returns a pointer to the child element described by a hierarchy of the
770  * following syntax
771  *
772  * params > param[1] > value > struct
773  *
774  * The > symbols indicate subsequent hierarchy levels, the square brackets
775  * provides the index in case that multiple tags with the same name exist
776  * at a given hierarchy level. Omitting the index means that the first
777  * tag with the specified name is accessed.
778  *
779  * If the specified element does not exist the method returns a NULL pointer.
780  ***************************************************************************/
781 const GXmlElement* GXmlNode::element(const std::string& name) const
782 {
783  // Initialise child node pointer
784  const GXmlElement* element = NULL;
785 
786  // Split name into tags
787  std::vector<std::string> tags = gammalib::split(name, ">");
788 
789  // Walk down the hierarchy
790  const GXmlNode* current = this;
791  for (int i = 0; i < tags.size(); ++i) {
792 
793  // Get tag name and index
794  std::string tag = gammalib::strip_whitespace(tags[i]);
795  int index = extract_index(tag);
796 
797  // Break if the requested node does not exist
798  int n = current->elements(tag);
799  if (n < 1 || index < 0 || index >= n) {
800  element = NULL;
801  break;
802  }
803 
804  // Get node
805  element = current->element(tag, index);
806  current = element;
807 
808  // Break if node has not been found
809  if (current == NULL) {
810  element = NULL;
811  break;
812  }
813 
814  } // endfor: walked down hierarchy
815 
816  // Return child element
817  return element;
818 }
819 
820 
821 /***********************************************************************//**
822  * @brief Return pointer on GXMLElement child of a given name
823  *
824  * @param[in] name Name of child element.
825  * @param[in] index Node index [0,...,elements()-1].
826  * @return Pointer to child element (NULL if element does not exist).
827  *
828  * @exception GException::xml_name_not_found
829  * Child element name not found.
830  * @exception GException::out_of_range
831  * Child element index is out of range.
832  *
833  * Returns a pointer to the child number @p index with @p name of the XML
834  * node. An exception will be thrown if the @p index is not valid.
835  ***************************************************************************/
836 GXmlElement* GXmlNode::element(const std::string& name, const int& index)
837 {
838  // Determine number of child elements
839  int n = elements(name);
840 
841  // Signal if no children exist
842  if (n < 1) {
844  }
845 
846  // If index is outside boundary then throw an error
847  if (index < 0 || index >= n) {
848  throw GException::out_of_range(G_ELEMENT3, index, 0, n-1);
849  }
850 
851  // Get the requested child element
852  GXmlElement* element = NULL;
853  int elements = 0;
854  for (int i = 0; i < m_nodes.size(); ++i) {
855  GXmlElement* src = dynamic_cast<GXmlElement*>(m_nodes[i]);
856  if (src != NULL) {
857  if (src->name() == name) {
858  if (elements == index) {
859  element = src;
860  break;
861  }
862  elements++;
863  }
864  }
865  }
866 
867  // Return child element
868  return element;
869 }
870 
871 
872 /***********************************************************************//**
873  * @brief Return pointer on GXMLElement child of a given name (const variant)
874  *
875  * @param[in] name Name of child element.
876  * @param[in] index Node index [0,...,elements()-1].
877  * @return Pointer to child element (NULL if element does not exist).
878  *
879  * @exception GException::xml_name_not_found
880  * Child element name not found.
881  * @exception GException::out_of_range
882  * Child element index is out of range.
883  *
884  * Returns a pointer to the child number @p index with @p name of the XML
885  * node. An exception will be thrown if the @p index is not valid.
886  ***************************************************************************/
887 const GXmlElement* GXmlNode::element(const std::string& name, const int& index) const
888 {
889  // Determine number of child elements
890  int n = elements(name);
891 
892  // Signal if no children exist
893  if (n < 1) {
895  }
896 
897  // If index is outside boundary then throw an error
898  if (index < 0 || index >= n) {
899  throw GException::out_of_range(G_ELEMENT3, index, 0, n-1);
900  }
901 
902  // Get the requested child element
903  const GXmlElement* element = NULL;
904  int elements = 0;
905  for (int i = 0; i < m_nodes.size(); ++i) {
906  const GXmlElement* src = dynamic_cast<const GXmlElement*>(m_nodes[i]);
907  if (src != NULL) {
908  if (src->name() == name) {
909  if (elements == index) {
910  element = src;
911  break;
912  }
913  elements++;
914  }
915  }
916  }
917 
918  // Return child element
919  return element;
920 }
921 
922 
923 /***********************************************************************//**
924  * @brief Print XML node in string
925  *
926  * @param[in] chatter Chattiness (defaults to NORMAL).
927  * @return String containing XML information.
928  ***************************************************************************/
929 std::string GXmlNode::print(const GChatter& chatter) const
930 {
931  // Set result string
932  std::string result = print(chatter, 0);
933 
934  // Return
935  return result;
936 }
937 
938 
939 /*==========================================================================
940  = =
941  = Private methods =
942  = =
943  ==========================================================================*/
944 
945 /***********************************************************************//**
946  * @brief Initialise class members
947  ***************************************************************************/
949 {
950  // Initialise members
951  m_nodes.clear();
952  m_parent = NULL;
953 
954  // Return
955  return;
956 }
957 
958 
959 /***********************************************************************//**
960  * @brief Copy class members
961  *
962  * @param[in] node XML node.
963  *
964  * @todo Is copying the parent node pointer correct?
965  ***************************************************************************/
967 {
968  // Copy members
969  m_parent = node.m_parent;
970 
971  // Copy nodes
972  m_nodes.clear();
973  for (int i = 0; i < node.m_nodes.size(); ++i) {
974  m_nodes.push_back((node.m_nodes[i]->clone()));
975  }
976 
977  // Return
978  return;
979 }
980 
981 
982 /***********************************************************************//**
983  * @brief Delete class members
984  *
985  * As container classes that hold pointers need to handle themselves the
986  * proper deallocation of memory, we loop here over all pointers and make
987  * sure that we deallocate the associated nodes.
988  ***************************************************************************/
990 {
991  // Free memory for all nodes
992  for (int i = 0; i < m_nodes.size(); ++i) {
993  delete m_nodes[i];
994  m_nodes[i] = NULL;
995  }
996 
997  // Return
998  return;
999 }
1000 
1001 
1002 /***********************************************************************//**
1003  * @brief Extract index from tag
1004  *
1005  * @param[in,out] tag Tag.
1006  * @return Index.
1007  *
1008  * @exception GException::invalid_argument
1009  * Tag string invalid.
1010  *
1011  * Extracts the index from a tag string of the following syntax
1012  *
1013  * param[1]
1014  *
1015  * The value within the squared brackets provides the index of the element.
1016  * If the squared brackets are omitted, an index of 0 will be returned.
1017  ***************************************************************************/
1018 int GXmlNode::extract_index(std::string& tag) const
1019 {
1020  // Initialise index
1021  int index = 0;
1022 
1023  // Search for squared brackets, extract index, and strip brackets
1024  // from tag
1025  size_t start = tag.find_first_of("[");
1026  if (start != std::string::npos) {
1027  size_t stop = tag.find_first_of("]", start);
1028  if (stop == std::string::npos) {
1029  std::string msg = "Tag specifier \""+tag+"\" is missing "
1030  "a ] bracket.";
1032  }
1033  else {
1034  size_t length = stop - start - 1;
1035  if (length < 1) {
1036  std::string msg = "Index value is missing for \""+tag+"\".";
1038  }
1039  else {
1040  index = gammalib::toint(tag.substr(start+1, length));
1041  tag = tag.substr(0, start);
1042  }
1043  }
1044  }
1045 
1046  // Return index
1047  return index;
1048 }
Abstract XML node base class.
Definition: GXmlNode.hpp:57
GXmlNode * parent(void) const
Return parent XML node.
Definition: GXmlNode.hpp:170
GXmlNode & operator=(const GXmlNode &node)
Assignment operator.
Definition: GXmlNode.cpp:118
GFilename filename(void) const
Return filename of XML file.
Definition: GXmlNode.cpp:540
std::vector< GXmlNode * > m_nodes
Pointer to child nodes.
Definition: GXmlNode.hpp:123
XML element node class interface definition.
virtual GXmlNode * set(const int &index, const GXmlNode &node)
Set XML child node.
Definition: GXmlNode.cpp:212
void init_members(void)
Initialise class members.
Definition: GXmlNode.cpp:948
XML element node class.
Definition: GXmlElement.hpp:47
#define G_EXTRACT_INDEX
Definition: GXmlNode.cpp:47
std::vector< std::string > split(const std::string &s, const std::string &sep)
Split string.
Definition: GTools.cpp:860
virtual int elements(void) const
Return number of GXMLElement children of node.
Definition: GXmlNode.cpp:580
Gammalib tools definition.
void free_members(void)
Delete class members.
Definition: GXmlNode.cpp:989
const std::string & name(void) const
Return XML element name.
std::string strip_whitespace(const std::string &arg)
Strip leading and trailing whitespace from string.
Definition: GTools.cpp:71
virtual void extend(const GXmlNode &node)
Append all XML child nodes from another XML node.
Definition: GXmlNode.cpp:504
virtual GXmlNode * insert(const int &index, const GXmlNode &node)
Insert XML child node.
Definition: GXmlNode.cpp:404
#define G_ELEMENT3
Definition: GXmlNode.cpp:46
virtual int size(void) const
Return number of child nodes.
Definition: GXmlNode.hpp:133
#define G_APPEND2
Definition: GXmlNode.cpp:41
#define G_ACCESS
Definition: GXmlNode.cpp:38
virtual GXmlNode * clone(void) const =0
Clones object.
#define G_REMOVE
Definition: GXmlNode.cpp:43
#define G_INSERT
Definition: GXmlNode.cpp:42
#define G_ELEMENT1
Definition: GXmlNode.cpp:44
Filename class.
Definition: GFilename.hpp:62
virtual void reserve(const int &num)
Reserve space for child nodes.
Definition: GXmlNode.hpp:157
GChatter
Definition: GTypemaps.hpp:33
virtual NodeType type(void) const =0
XML document node class interface definition.
GXmlNode * m_parent
Pointer on parent node.
Definition: GXmlNode.hpp:122
void copy_members(const GXmlNode &node)
Copy class members.
Definition: GXmlNode.cpp:966
XML document node class.
virtual std::string print(const GChatter &chatter=NORMAL, const int &indent=0) const =0
virtual GXmlElement * element(const int &index)
Return pointer to GXMLElement child.
Definition: GXmlNode.cpp:634
#define G_SET
Definition: GXmlNode.cpp:39
GXmlNode * operator[](const int &index)
Return pointer to XML child node.
Definition: GXmlNode.cpp:150
virtual bool is_empty(void) const
Signals if node has no child nodes.
Definition: GXmlNode.hpp:145
Exception handler interface definition.
int extract_index(std::string &tag) const
Extract index from tag.
Definition: GXmlNode.cpp:1018
int toint(const std::string &arg)
Convert string into integer value.
Definition: GTools.cpp:698
const GFilename & filename(void) const
Return filename.
virtual GXmlNode * append(const GXmlNode &node)
Append XML child node.
Definition: GXmlNode.cpp:284
#define G_APPEND1
Definition: GXmlNode.cpp:40
Abstract XML node base class interface definition.
GXmlNode(void)
Void constructor.
Definition: GXmlNode.cpp:65
virtual ~GXmlNode(void)
Destructor.
Definition: GXmlNode.cpp:96
virtual void remove(const int &index)
Remove XML child node.
Definition: GXmlNode.cpp:476