GammaLib 2.0.0
Loading...
Searching...
No Matches
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
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
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
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 ***************************************************************************/
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 ***************************************************************************/
176const 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 ***************************************************************************/
214GXmlNode* 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.";
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.";
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.";
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 ***************************************************************************/
349GXmlElement* 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 ***************************************************************************/
407GXmlNode* 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 ***************************************************************************/
481void 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 ***************************************************************************/
510void 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 ***************************************************************************/
586int 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 ***************************************************************************/
611int 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 ***************************************************************************/
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 ***************************************************************************/
659const 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 ***************************************************************************/
707GXmlElement* 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 ***************************************************************************/
736const 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 ***************************************************************************/
791GXmlElement* 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 ***************************************************************************/
813const 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 ***************************************************************************/
861std::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 ***************************************************************************/
950int 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}
#define G_ACCESS
#define G_SET
Definition GEnergies.cpp:46
Exception handler interface definition.
#define G_INSERT
#define G_REMOVE
Gammalib tools definition.
GChatter
Definition GTypemaps.hpp:33
XML document node class interface definition.
XML element node class interface definition.
#define G_ELEMENT3
Definition GXmlNode.cpp:46
#define G_ELEMENT1
Definition GXmlNode.cpp:44
#define G_EXTRACT_INDEX
Definition GXmlNode.cpp:47
#define G_APPEND2
Definition GXmlNode.cpp:41
#define G_APPEND1
Definition GXmlNode.cpp:40
Abstract XML node base class interface definition.
Filename class.
Definition GFilename.hpp:62
XML document node class.
const GFilename & filename(void) const
Return filename.
XML element node class.
const std::string & name(void) const
Return XML element name.
Abstract XML node base class.
Definition GXmlNode.hpp:57
virtual GXmlNode * append(const GXmlNode &node)
Append XML child node.
Definition GXmlNode.cpp:287
virtual GXmlNode * clone(void) const =0
Clones object.
virtual NodeType type(void) const =0
GXmlNode & operator=(const GXmlNode &node)
Assignment operator.
Definition GXmlNode.cpp:118
virtual std::string print(const GChatter &chatter=NORMAL, const int &indent=0) const =0
virtual void remove(const int &index)
Remove XML child node.
Definition GXmlNode.cpp:481
virtual GXmlNode * insert(const int &index, const GXmlNode &node)
Insert XML child node.
Definition GXmlNode.cpp:407
std::vector< GXmlNode * > m_nodes
Pointer to child nodes.
Definition GXmlNode.hpp:123
virtual GXmlElement * element(const int &index)
Return pointer to GXMLElement child.
Definition GXmlNode.cpp:640
void free_members(void)
Delete class members.
Definition GXmlNode.cpp:921
GXmlNode * m_parent
Pointer on parent node.
Definition GXmlNode.hpp:122
GXmlNode(void)
Void constructor.
Definition GXmlNode.cpp:65
virtual void extend(const GXmlNode &node)
Append all XML child nodes from another XML node.
Definition GXmlNode.cpp:510
virtual void reserve(const int &num)
Reserve space for child nodes.
Definition GXmlNode.hpp:157
void copy_members(const GXmlNode &node)
Copy class members.
Definition GXmlNode.cpp:898
virtual bool is_empty(void) const
Signals if node has no child nodes.
Definition GXmlNode.hpp:145
int extract_index(std::string &tag) const
Extract index from tag.
Definition GXmlNode.cpp:950
@ NT_DOCUMENT
Definition GXmlNode.hpp:72
GXmlNode * operator[](const int &index)
Return pointer to XML child node.
Definition GXmlNode.cpp:150
GFilename filename(void) const
Return filename of XML file.
Definition GXmlNode.cpp:546
virtual GXmlNode * set(const int &index, const GXmlNode &node)
Set XML child node.
Definition GXmlNode.cpp:214
virtual ~GXmlNode(void)
Destructor.
Definition GXmlNode.cpp:96
virtual int size(void) const
Return number of child nodes.
Definition GXmlNode.hpp:133
GXmlNode * parent(void) const
Return parent XML node.
Definition GXmlNode.hpp:170
virtual int elements(void) const
Return number of GXMLElement children of node.
Definition GXmlNode.cpp:586
void init_members(void)
Initialise class members.
Definition GXmlNode.cpp:880
int toint(const std::string &arg)
Convert string into integer value.
Definition GTools.cpp:821
std::string strip_whitespace(const std::string &arg)
Strip leading and trailing whitespace from string.
Definition GTools.cpp:80
std::vector< std::string > split(const std::string &s, const std::string &sep)
Split string.
Definition GTools.cpp:983