GammaLib  2.1.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-2021 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()[.
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, "Child node index",
156  index, size());
157  }
158  #endif
159 
160  // Return pointer
161  return m_nodes[index];
162 }
163 
164 
165 /***********************************************************************//**
166  * @brief Return pointer to XML child node (const version)
167  *
168  * @param[in] index Child node index [0,...,size()[.
169  * @return Pointer to XML child node at @p index.
170  *
171  * @exception GException::out_of_range
172  * Child node index is out of range.
173  *
174  * Returns a const pointer to the XML child node with the specified @p index.
175  ***************************************************************************/
176 const GXmlNode* GXmlNode::operator[](const int& index) const
177 {
178  // Compile option: raise exception if index is out of range
179  #if defined(G_RANGE_CHECK)
180  if (index < 0 || index >= size()) {
181  throw GException::out_of_range(G_ACCESS, "Child node index",
182  index, size());
183  }
184  #endif
185 
186  // Return pointer
187  return m_nodes[index];
188 }
189 
190 
191 /*==========================================================================
192  = =
193  = Public methods =
194  = =
195  ==========================================================================*/
196 
197 /***********************************************************************//**
198  * @brief Set XML child node
199  *
200  * @param[in] index Child node index [0,...,size()[.
201  * @param[in] node XML child node.
202  * @return Pointer to deep copy of child node
203  *
204  * @exception GException::invalid_argument
205  * Not allowed to append root node.
206  * @exception GException::invalid_value
207  * Not allowed to append to a text, comment or PI node.
208  * @exception GException::out_of_range
209  * Child node index is out of range.
210  *
211  * Set XML child node. A deep copy of the node will be made and the pointer
212  * to this node will be stored.
213  ***************************************************************************/
214 GXmlNode* GXmlNode::set(const int& index, const GXmlNode& node)
215 {
216  // Make sure that node to append is not a root node as only one root node
217  // is allowed to exist in a document.
218  if (node.type() == NT_DOCUMENT) {
219  std::string msg = "Invalid attempt to append root note (GXmlDocument)"
220  " to a XML node. There can only be one root node in"
221  " an XML document.";
223  }
224 
225  // Make sure that the current node is not a text node as nothing can be
226  // appended to a text node.
227  if (this->type() == NT_TEXT) {
228  std::string msg = "Invalid attempt to append a XML node to a text node"
229  " (GXmlText). Nothing can be appended to a text node.";
230  throw GException::invalid_value(G_SET, msg);
231  }
232 
233  // Make sure that the current node is not a PI node as nothing can be
234  // appended to a PI node.
235  if (this->type() == NT_PI) {
236  std::string msg = "Invalid attempt to append a XML node to a processing"
237  " instruction node (GXmlPI). Nothing can be appended"
238  " to a processing instruction node.";
239  throw GException::invalid_value(G_SET, msg);
240  }
241 
242  // Make sure that the current node is not a comment node as nothing can be
243  // appended to a PI node.
244  if (this->type() == NT_COMMENT) {
245  std::string msg = "Invalid attempt to append a XML node to a comment"
246  " node (GXmlComment). Nothing can be appended"
247  " to a processing instruction node.";
248  throw GException::invalid_value(G_SET, msg);
249  }
250 
251  // Compile option: raise exception if index is out of range
252  #if defined(G_RANGE_CHECK)
253  if (index < 0 || index >= size()) {
254  throw GException::out_of_range(G_SET, "Child node index",
255  index, size());
256  }
257  #endif
258 
259  // Free existing node only if it differs from current node. This
260  // prevents unintential deallocation of the argument
261  if ((m_nodes[index] != NULL) && (m_nodes[index] != &node)) {
262  delete m_nodes[index];
263  }
264 
265  // Assign new child node by cloning
266  m_nodes[index] = node.clone();
267 
268  // Return pointer
269  return m_nodes[index];
270 }
271 
272 
273 /***********************************************************************//**
274  * @brief Append XML child node
275  *
276  * @param[in] node XML child node.
277  * @return Pointer to appended child node
278  *
279  * @exception GException::invalid_argument
280  * Not allowed to append root node.
281  * @exception GException::invalid_value
282  * Not allowed to append to a text, comment or PI node.
283  *
284  * Appends XML child node by making a deep copy of the node and storing its
285  * pointer.
286  ***************************************************************************/
288 {
289  // Make sure that node to append is not a root node as only one root node
290  // is allowed to exist in a document.
291  if (node.type() == NT_DOCUMENT) {
292  std::string msg = "Invalid attempt to append root note (GXmlDocument)"
293  " to a XML node. There can only be one root node in"
294  " an XML document.";
296  }
297 
298  // Make sure that the current node is not a text node as nothing can be
299  // appended to a text node.
300  if (this->type() == NT_TEXT) {
301  std::string msg = "Invalid attempt to append a XML node to a text node"
302  " (GXmlText). Nothing can be appended to a text node.";
304  }
305 
306  // Make sure that the current node is not a PI node as nothing can be
307  // appended to a PI node.
308  if (this->type() == NT_PI) {
309  std::string msg = "Invalid attempt to append a XML node to a processing"
310  " instruction node (GXmlPI). Nothing can be appended"
311  " to a processing instruction node.";
313  }
314 
315  // Make sure that the current node is not a comment node as nothing can be
316  // appended to a PI node.
317  if (this->type() == NT_COMMENT) {
318  std::string msg = "Invalid attempt to append a XML node to a comment"
319  " node (GXmlComment). Nothing can be appended"
320  " to a processing instruction node.";
322  }
323 
324  // Clone child node
325  GXmlNode* ptr = node.clone();
326 
327  // Append deep copy of child node
328  m_nodes.push_back(ptr);
329 
330  // Return pointer
331  return ptr;
332 }
333 
334 
335 /***********************************************************************//**
336  * @brief Append XML element child node
337  *
338  * @param[in] segment XML child node.
339  * @return Pointer to appended child node
340  *
341  * @exception GException::invalid_value
342  * Not allowed to append to a text, comment or PI node.
343  *
344  * Appends XML element that is constructed from a text @p segment. The text
345  * segment is parsed and the element name and attributes are extracted using
346  * the GXmlElement::parse_start() method. The method returns a pointer to the
347  * XML element child node that has been appended.
348  ***************************************************************************/
349 GXmlElement* GXmlNode::append(const std::string& segment)
350 {
351  // Make sure that the current node is not a text node as nothing can be
352  // appended to a text node.
353  if (this->type() == NT_TEXT) {
354  std::string msg = "Invalid attempt to append the text segment \""+
355  segment+"\" to a text node (GXmlText). Nothing can"
356  " be appended to a text node.";
358  }
359 
360  // Make sure that the current node is not a PI node as nothing can be
361  // appended to a PI node.
362  if (this->type() == NT_PI) {
363  std::string msg = "Invalid attempt to append a XML node to a processing"
364  " instruction node (GXmlPI). Nothing can be appended"
365  " to a processing instruction node.";
367  }
368 
369  // Make sure that the current node is not a comment node as nothing can be
370  // appended to a PI node.
371  if (this->type() == NT_COMMENT) {
372  std::string msg = "Invalid attempt to append a XML node to a comment"
373  " node (GXmlComment). Nothing can be appended"
374  " to a processing instruction node.";
376  }
377 
378  // Create a new XML child element from the text segment
379  GXmlElement* ptr = new GXmlElement(segment);
380 
381  // Append child element to container
382  m_nodes.push_back(ptr);
383 
384  // Return child element
385  return ptr;
386 }
387 
388 
389 /***********************************************************************//**
390  * @brief Insert XML child node
391  *
392  * @param[in] index Child node index [0,...,size()[.
393  * @param[in] node XML child node.
394  * @return Pointer to inserted child node
395  *
396  * @exception GException::invalid_argument
397  * Not allowed to append root node.
398  * @exception GException::invalid_value
399  * Not allowed to append to a text, comment or PI node.
400  * @exception GException::out_of_range
401  * Child node index is out of range.
402  *
403  * Inserts the XML child @p node before the node with the specified @p index.
404  * A deep copy of the node will be made and the pointer to this node will be
405  * stored.
406  ***************************************************************************/
407 GXmlNode* GXmlNode::insert(const int& index, const GXmlNode& node)
408 {
409  // Make sure that node to append is not a root node as only one root node
410  // is allowed to exist in a document.
411  if (node.type() == NT_DOCUMENT) {
412  std::string msg = "Invalid attempt to append root note (GXmlDocument)"
413  " to a XML node. There can only be one root node in"
414  " an XML document.";
416  }
417 
418  // Make sure that the current node is not a text node as nothing can be
419  // appended to a text node.
420  if (this->type() == NT_TEXT) {
421  std::string msg = "Invalid attempt to append a XML node to a text node"
422  " (GXmlText). Nothing can be appended to a text node.";
424  }
425 
426  // Make sure that the current node is not a PI node as nothing can be
427  // appended to a PI node.
428  if (this->type() == NT_PI) {
429  std::string msg = "Invalid attempt to append a XML node to a processing"
430  " instruction node (GXmlPI). Nothing can be appended"
431  " to a processing instruction node.";
433  }
434 
435  // Make sure that the current node is not a comment node as nothing can be
436  // appended to a PI node.
437  if (this->type() == NT_COMMENT) {
438  std::string msg = "Invalid attempt to append a XML node to a comment"
439  " node (GXmlComment). Nothing can be appended"
440  " to a processing instruction node.";
442  }
443 
444  // Compile option: raise exception if index is out of range
445  #if defined(G_RANGE_CHECK)
446  if (is_empty()) {
447  if (index > 0) {
448  throw GException::out_of_range(G_INSERT, "Child node index",
449  index, size());
450  }
451  }
452  else {
453  if (index < 0 || index >= size()) {
454  throw GException::out_of_range(G_INSERT, "Child node index",
455  index, size());
456  }
457  }
458  #endif
459 
460  // Clone child node
461  GXmlNode* ptr = node.clone();
462 
463  // Inserts deep copy of child node
464  m_nodes.insert(m_nodes.begin()+index, ptr);
465 
466  // Return pointer
467  return ptr;
468 }
469 
470 
471 /***********************************************************************//**
472  * @brief Remove XML child node
473  *
474  * @param[in] index Child node index [0,...,size()[.
475  *
476  * @exception GException::out_of_range
477  * Child node index is out of range.
478  *
479  * Remove XML child node at @p index.
480  ***************************************************************************/
481 void GXmlNode::remove(const int& index)
482 {
483  // Compile option: raise exception if index is out of range
484  #if defined(G_RANGE_CHECK)
485  if (index < 0 || index >= size()) {
486  throw GException::out_of_range(G_REMOVE, "Child node index",
487  index, size());
488  }
489  #endif
490 
491  // Delete node
492  delete m_nodes[index];
493 
494  // Erase child node from container
495  m_nodes.erase(m_nodes.begin() + index);
496 
497  // Return
498  return;
499 }
500 
501 
502 /***********************************************************************//**
503  * @brief Append all XML child nodes from another XML node
504  *
505  * @param[in] node XML node.
506  *
507  * Append all XML child nodes found in @p node to the actual object. Nodes
508  * are copied deeply so that they live now on their on in the actual object.
509  ***************************************************************************/
510 void GXmlNode::extend(const GXmlNode& node)
511 {
512  // Do nothing if node container is empty
513  if (!node.is_empty()) {
514 
515  // Get size. Note that we extract the size first to avoid an
516  // endless loop that arises when a container is appended to
517  // itself.
518  int num = node.size();
519 
520  // Reserve enough space
521  reserve(size() + num);
522 
523  // Loop over all child nodes and append pointers to deep copies
524  for (int i = 0; i < num; ++i) {
525  m_nodes.push_back(node[i]->clone());
526  }
527 
528  } // endif: node container was not empty
529 
530  // Return
531  return;
532 }
533 
534 
535 /***********************************************************************//**
536  * @brief Return filename of XML file
537  *
538  * @return Filename.
539  *
540  * Returns the file name of the XML file by moving up the XML file hierarchy
541  * to the root. In case that the XML node cannot move up to the root XML
542  * node an empty file name is returned (this may happen if the XML node
543  * is an orphan node). The file name will also be empty if the XML file has
544  * not been read from disk or written to disk.
545  ***************************************************************************/
547 {
548  // Initialise empty filename
550 
551  // Move up the XML document hierarchy until the root node has been
552  // found
553  GXmlNode* parent = this->parent();
554  while (parent != NULL) {
555 
556  // Cast parent into a root node
557  GXmlDocument* root = dynamic_cast<GXmlDocument*>(parent);
558 
559  // If the parent is a root node, recover the filename and exit the
560  // loop
561  if (root != NULL) {
562  filename = root->filename();
563  break;
564  }
565 
566  // ... otherwise move up the XML tree
567  else {
568  parent = parent->parent();
569  }
570 
571  } // endwhile: move up to the root document
572 
573  // Return filename
574  return filename;
575 }
576 
577 
578 /***********************************************************************//**
579  * @brief Return number of GXMLElement children of node
580  *
581  * @return Number of child elements.
582  *
583  * Returns the number of GXMLElement child elements of the XML node.
584  * GXMLElement child elements are nodes of type NT_ELEMENT.
585  ***************************************************************************/
586 int GXmlNode::elements(void) const
587 {
588  // Compute number of child elements in node
589  int elements = 0;
590  for (int i = 0; i < m_nodes.size(); ++i) {
591  if (m_nodes[i]->type() == NT_ELEMENT) {
592  elements++;
593  }
594  }
595 
596  // Return number of child elements
597  return elements;
598 }
599 
600 
601 /***********************************************************************//**
602  * @brief Return number of GXMLElement children with a given name
603  *
604  * @param[in] name Name of GXMLElement elements.
605  * @return Number of child elements with a given @p name.
606  *
607  * Returns the number of GXMLElement child elements of the XML node that
608  * have a given @p name. GXMLElement child elements are nodes of type
609  * NT_ELEMENT.
610  ***************************************************************************/
611 int GXmlNode::elements(const std::string& name) const
612 {
613  // Compute number of child elements in node
614  int elements = 0;
615  for (int i = 0; i < m_nodes.size(); ++i) {
616  if (m_nodes[i]->type() == NT_ELEMENT) {
617  if (static_cast<GXmlElement*>(m_nodes[i])->name() == name) {
618  elements++;
619  }
620  }
621  }
622 
623  // Return number of child elements
624  return elements;
625 }
626 
627 
628 /***********************************************************************//**
629  * @brief Return pointer to GXMLElement child
630  *
631  * @param[in] index Node index [0,...,elements()-1].
632  * @return Pointer to child element (NULL if element does not exist).
633  *
634  * @exception GException::out_of_range
635  * Child element index is out of range.
636  *
637  * Returns a pointer to the child number @p index of the XML node. An
638  * exception will be thrown if the @p index is not valid.
639  ***************************************************************************/
640 GXmlElement* GXmlNode::element(const int& index)
641 {
642  // Return child element using const method
643  return const_cast<GXmlElement*>(static_cast<const GXmlNode*>(this)->element(index));
644 }
645 
646 
647 /***********************************************************************//**
648  * @brief Return pointer to GXMLElement child (const variant)
649  *
650  * @param[in] index Node index [0,...,elements()[.
651  * @return Pointer to child element (NULL if element does not exist).
652  *
653  * @exception GException::out_of_range
654  * Child element index is out of range.
655  *
656  * Returns a pointer to the child number @p index of the XML node. An
657  * exception will be thrown if the @p index is not valid.
658  ***************************************************************************/
659 const GXmlElement* GXmlNode::element(const int& index) const
660 {
661  // If index is outside boundary then throw an error
662  if (index < 0 || index >= elements()) {
663  throw GException::out_of_range(G_ELEMENT1, "Node index",
664  index, elements());
665  }
666 
667  // Get the requested child element
668  const GXmlElement* element = NULL;
669  int elements = 0;
670  for (int i = 0; i < m_nodes.size(); ++i) {
671  if (m_nodes[i]->type() == NT_ELEMENT) {
672  GXmlElement* src = static_cast<GXmlElement*>(m_nodes[i]);
673  if (elements == index) {
674  element = src;
675  break;
676  }
677  elements++;
678  }
679  }
680 
681  // Return child element
682  return element;
683 }
684 
685 
686 /***********************************************************************//**
687  * @brief Return pointer on child walking down a hierarchy of tags
688  *
689  * @param[in] name Child element hierarchy.
690  * @return Pointer to child element (NULL if element does not exist).
691  *
692  * @exception GException::invalid_argument
693  * Hierarchy string invalid.
694  *
695  * Returns a pointer to the child element described by a hierarchy of the
696  * following syntax
697  *
698  * params > param[1] > value > struct
699  *
700  * The > symbols indicate subsequent hierarchy levels, the square brackets
701  * provides the index in case that multiple tags with the same name exist
702  * at a given hierarchy level. Omitting the index means that the first
703  * tag with the specified name is accessed.
704  *
705  * If the specified element does not exist the method returns a NULL pointer.
706  ***************************************************************************/
707 GXmlElement* GXmlNode::element(const std::string& name)
708 {
709  // Return child element using const method
710  return const_cast<GXmlElement*>(static_cast<const GXmlNode*>(this)->element(name));
711 }
712 
713 
714 /***********************************************************************//**
715  * @brief Return pointer on child walking down a hierarchy of tags (const
716  * version)
717  *
718  * @param[in] name Child element hierarchy.
719  * @return Pointer to child element (NULL if element does not exist).
720  *
721  * @exception GException::invalid_argument
722  * Hierarchy string invalid.
723  *
724  * Returns a pointer to the child element described by a hierarchy of the
725  * following syntax
726  *
727  * params > param[1] > value > struct
728  *
729  * The > symbols indicate subsequent hierarchy levels, the square brackets
730  * provides the index in case that multiple tags with the same name exist
731  * at a given hierarchy level. Omitting the index means that the first
732  * tag with the specified name is accessed.
733  *
734  * If the specified element does not exist the method returns a NULL pointer.
735  ***************************************************************************/
736 const GXmlElement* GXmlNode::element(const std::string& name) const
737 {
738  // Initialise child node pointer
739  const GXmlElement* element = NULL;
740 
741  // Split name into tags
742  std::vector<std::string> tags = gammalib::split(name, ">");
743 
744  // Walk down the hierarchy
745  const GXmlNode* current = this;
746  for (int i = 0; i < tags.size(); ++i) {
747 
748  // Get tag name and index
749  std::string tag = gammalib::strip_whitespace(tags[i]);
750  int index = extract_index(tag);
751 
752  // Break if the requested node does not exist
753  int n = current->elements(tag);
754  if (n < 1 || index < 0 || index >= n) {
755  element = NULL;
756  break;
757  }
758 
759  // Get node
760  element = current->element(tag, index);
761  current = element;
762 
763  // Break if node has not been found
764  if (current == NULL) {
765  element = NULL;
766  break;
767  }
768 
769  } // endfor: walked down hierarchy
770 
771  // Return child element
772  return element;
773 }
774 
775 
776 /***********************************************************************//**
777  * @brief Return pointer on GXMLElement child of a given name
778  *
779  * @param[in] name Name of child element.
780  * @param[in] index Node index [0,...,elements(name)[.
781  * @return Pointer to child element (NULL if element does not exist).
782  *
783  * @exception GException::xml_name_not_found
784  * Child element name not found.
785  * @exception GException::out_of_range
786  * Child element index is out of range.
787  *
788  * Returns a pointer to the child number @p index with @p name of the XML
789  * node. An exception will be thrown if the @p index is not valid.
790  ***************************************************************************/
791 GXmlElement* GXmlNode::element(const std::string& name, const int& index)
792 {
793  // Return child element using const method
794  return const_cast<GXmlElement*>(static_cast<const GXmlNode*>(this)->element(name, index));
795 }
796 
797 
798 /***********************************************************************//**
799  * @brief Return pointer on GXMLElement child of a given name (const variant)
800  *
801  * @param[in] name Name of child element.
802  * @param[in] index Node index [0,...,elements(name)[.
803  * @return Pointer to child element (NULL if element does not exist).
804  *
805  * @exception GException::invalid_value
806  * Child element name not found.
807  * @exception GException::out_of_range
808  * Child element index is out of range.
809  *
810  * Returns a pointer to the child number @p index with @p name of the XML
811  * node. An exception will be thrown if the @p index is not valid.
812  ***************************************************************************/
813 const GXmlElement* GXmlNode::element(const std::string& name,
814  const int& index) const
815 {
816  // Initialise number of elements with given name to determine the
817  // number of child elements on the fly
818  int n = 0;
819 
820  // Get the requested child element
821  const GXmlElement* element = NULL;
822  int elements = 0;
823  for (int i = 0; i < m_nodes.size(); ++i) {
824  if (m_nodes[i]->type() == NT_ELEMENT) {
825  GXmlElement* src = static_cast<GXmlElement*>(m_nodes[i]);
826  if (src->name() == name) {
827  n++;
828  if (elements == index) {
829  element = src;
830  break;
831  }
832  elements++;
833  }
834  }
835  }
836 
837  // Signal if no children exist
838  if (n < 1) {
839  std::string msg = "XML node has no element with name \""+name+
840  "\". Please verify the XML format.";
842  }
843 
844  // If index is outside boundary then throw an error
845  if (index < 0 || index >= n) {
846  throw GException::out_of_range(G_ELEMENT3, "Node index",
847  index, n);
848  }
849 
850  // Return child element
851  return element;
852 }
853 
854 
855 /***********************************************************************//**
856  * @brief Print XML node in string
857  *
858  * @param[in] chatter Chattiness.
859  * @return String containing XML information.
860  ***************************************************************************/
861 std::string GXmlNode::print(const GChatter& chatter) const
862 {
863  // Set result string
864  std::string result = print(chatter, 0);
865 
866  // Return
867  return result;
868 }
869 
870 
871 /*==========================================================================
872  = =
873  = Private methods =
874  = =
875  ==========================================================================*/
876 
877 /***********************************************************************//**
878  * @brief Initialise class members
879  ***************************************************************************/
881 {
882  // Initialise members
883  m_nodes.clear();
884  m_parent = NULL;
885 
886  // Return
887  return;
888 }
889 
890 
891 /***********************************************************************//**
892  * @brief Copy class members
893  *
894  * @param[in] node XML node.
895  *
896  * @todo Is copying the parent node pointer correct?
897  ***************************************************************************/
899 {
900  // Copy members
901  m_parent = node.m_parent;
902 
903  // Copy nodes
904  m_nodes.clear();
905  for (int i = 0; i < node.m_nodes.size(); ++i) {
906  m_nodes.push_back((node.m_nodes[i]->clone()));
907  }
908 
909  // Return
910  return;
911 }
912 
913 
914 /***********************************************************************//**
915  * @brief Delete class members
916  *
917  * As container classes that hold pointers need to handle themselves the
918  * proper deallocation of memory, we loop here over all pointers and make
919  * sure that we deallocate the associated nodes.
920  ***************************************************************************/
922 {
923  // Free memory for all nodes
924  for (int i = 0; i < m_nodes.size(); ++i) {
925  delete m_nodes[i];
926  m_nodes[i] = NULL;
927  }
928 
929  // Return
930  return;
931 }
932 
933 
934 /***********************************************************************//**
935  * @brief Extract index from tag
936  *
937  * @param[in,out] tag Tag.
938  * @return Index.
939  *
940  * @exception GException::invalid_argument
941  * Tag string invalid.
942  *
943  * Extracts the index from a tag string of the following syntax
944  *
945  * param[1]
946  *
947  * The value within the squared brackets provides the index of the element.
948  * If the squared brackets are omitted, an index of 0 will be returned.
949  ***************************************************************************/
950 int GXmlNode::extract_index(std::string& tag) const
951 {
952  // Initialise index
953  int index = 0;
954 
955  // Search for squared brackets, extract index, and strip brackets
956  // from tag
957  size_t start = tag.find_first_of("[");
958  if (start != std::string::npos) {
959  size_t stop = tag.find_first_of("]", start);
960  if (stop == std::string::npos) {
961  std::string msg = "Tag specifier \""+tag+"\" is missing "
962  "a ] bracket.";
964  }
965  else {
966  size_t length = stop - start - 1;
967  if (length < 1) {
968  std::string msg = "Index value is missing for \""+tag+"\".";
970  }
971  else {
972  index = gammalib::toint(tag.substr(start+1, length));
973  tag = tag.substr(0, start);
974  }
975  }
976  }
977 
978  // Return index
979  return index;
980 }
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:546
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:214
void init_members(void)
Initialise class members.
Definition: GXmlNode.cpp:880
XML element node class.
Definition: GXmlElement.hpp:48
#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:983
virtual int elements(void) const
Return number of GXMLElement children of node.
Definition: GXmlNode.cpp:586
Gammalib tools definition.
void free_members(void)
Delete class members.
Definition: GXmlNode.cpp:921
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:80
virtual void extend(const GXmlNode &node)
Append all XML child nodes from another XML node.
Definition: GXmlNode.cpp:510
virtual GXmlNode * insert(const int &index, const GXmlNode &node)
Insert XML child node.
Definition: GXmlNode.cpp:407
#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:898
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:640
#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:950
int toint(const std::string &arg)
Convert string into integer value.
Definition: GTools.cpp:821
const GFilename & filename(void) const
Return filename.
virtual GXmlNode * append(const GXmlNode &node)
Append XML child node.
Definition: GXmlNode.cpp:287
#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:481