src/xml/GXmlNode.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *                GXmlNode.cpp - Abstract XML node base class              *
00003  * ----------------------------------------------------------------------- *
00004  *  copyright (C) 2010-2016 by Juergen Knoedlseder                         *
00005  * ----------------------------------------------------------------------- *
00006  *                                                                         *
00007  *  This program is free software: you can redistribute it and/or modify   *
00008  *  it under the terms of the GNU General Public License as published by   *
00009  *  the Free Software Foundation, either version 3 of the License, or      *
00010  *  (at your option) any later version.                                    *
00011  *                                                                         *
00012  *  This program is distributed in the hope that it will be useful,        *
00013  *  but WITHOUT ANY WARRANTY; without even the implied warranty of         *
00014  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
00015  *  GNU General Public License for more details.                           *
00016  *                                                                         *
00017  *  You should have received a copy of the GNU General Public License      *
00018  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.  *
00019  *                                                                         *
00020  ***************************************************************************/
00021 /**
00022  * @file GXmlNode.cpp
00023  * @brief Abstract XML node base class implementation
00024  * @author Juergen Knoedlseder
00025  */
00026 
00027 /* __ Includes ___________________________________________________________ */
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031 #include "GTools.hpp"
00032 #include "GException.hpp"
00033 #include "GXmlNode.hpp"
00034 #include "GXmlElement.hpp"
00035 #include "GXmlDocument.hpp"
00036 
00037 /* __ Method name definitions ____________________________________________ */
00038 #define G_ACCESS                                 "GXmlNode::operator[](int&)"
00039 #define G_SET                                "GXmlNode::set(int&, GXmlNode&)"
00040 #define G_APPEND1                            "GXmlNode::append(std::string&)"
00041 #define G_APPEND2                               "GXmlNode::append(GXmlNode&)"
00042 #define G_INSERT                          "GXmlNode::insert(int&, GXmlNode&)"
00043 #define G_REMOVE                                     "GXmlNode::remove(int&)"
00044 #define G_ELEMENT1                        "GXmlNode* GXmlNode::element(int&)"
00045 #define G_ELEMENT2                "GXmlNode* GXmlNode::element(std::string&)"
00046 #define G_ELEMENT3          "GXmlNode* GXmlNode::element(std::string&, int&)"
00047 #define G_EXTRACT_INDEX               "GXmlNode::extract_index(std::string&)"
00048 
00049 /* __ Macros _____________________________________________________________ */
00050 
00051 /* __ Coding definitions _________________________________________________ */
00052 
00053 /* __ Debug definitions __________________________________________________ */
00054 
00055 
00056 /*==========================================================================
00057  =                                                                         =
00058  =                         Constructors/destructors                        =
00059  =                                                                         =
00060  ==========================================================================*/
00061 
00062 /***********************************************************************//**
00063  * @brief Void constructor
00064  ***************************************************************************/
00065 GXmlNode::GXmlNode(void)
00066 {
00067     // Initialise members
00068     init_members();
00069 
00070     // Return
00071     return;
00072 }
00073 
00074 
00075 /***********************************************************************//**
00076  * @brief Copy constructor
00077  *
00078  * @param[in] node XML node.
00079  ***************************************************************************/
00080 GXmlNode::GXmlNode(const GXmlNode& node)
00081 {
00082     // Initialise members
00083     init_members();
00084 
00085     // Copy members
00086     copy_members(node);
00087 
00088     // Return
00089     return;
00090 }
00091 
00092 
00093 /***********************************************************************//**
00094  * @brief Destructor
00095  ***************************************************************************/
00096 GXmlNode::~GXmlNode(void)
00097 {
00098     // Free members
00099     free_members();
00100 
00101     // Return
00102     return;
00103 }
00104 
00105 
00106 /*==========================================================================
00107  =                                                                         =
00108  =                                Operators                                =
00109  =                                                                         =
00110  ==========================================================================*/
00111 
00112 /***********************************************************************//**
00113  * @brief Assignment operator
00114  *
00115  * @param[in] node XML node.
00116  * @return XML node.
00117  ***************************************************************************/
00118 GXmlNode& GXmlNode::operator=(const GXmlNode& node)
00119 {
00120     // Execute only if object is not identical
00121     if (this != &node) {
00122 
00123         // Free members
00124         free_members();
00125 
00126         // Initialise members
00127         init_members();
00128 
00129         // Copy members
00130         copy_members(node);
00131 
00132     } // endif: object was not identical
00133 
00134     // Return
00135     return *this;
00136 }
00137 
00138 
00139 /***********************************************************************//**
00140  * @brief Return pointer to XML child node
00141  *
00142  * @param[in] index Child node index [0,...,size()-1].
00143  * @return Pointer to XML child node at @p index.
00144  *
00145  * @exception GException::out_of_range
00146  *            Child node index is out of range.
00147  *
00148  * Returns a pointer to the XML child node with the specified @p index.
00149  ***************************************************************************/
00150 GXmlNode* GXmlNode::operator[](const int& index)
00151 {
00152     // Compile option: raise exception if index is out of range
00153     #if defined(G_RANGE_CHECK)
00154     if (index < 0 || index >= size()) {
00155         throw GException::out_of_range(G_ACCESS, index, 0, size()-1);
00156     }
00157     #endif
00158 
00159     // Return pointer
00160     return m_nodes[index];
00161 }
00162 
00163 
00164 /***********************************************************************//**
00165  * @brief Return pointer to XML child node (const version)
00166  *
00167  * @param[in] index Child node index [0,...,size()-1].
00168  * @return Pointer to XML child node at @p index.
00169  *
00170  * @exception GException::out_of_range
00171  *            Child node index is out of range.
00172  *
00173  * Returns a const pointer to the XML child node with the specified @p index.
00174  ***************************************************************************/
00175 const GXmlNode* GXmlNode::operator[](const int& index) const
00176 {
00177     // Compile option: raise exception if index is out of range
00178     #if defined(G_RANGE_CHECK)
00179     if (index < 0 || index >= size()) {
00180         throw GException::out_of_range(G_ACCESS, index, 0, size()-1);
00181     }
00182     #endif
00183 
00184     // Return pointer
00185     return m_nodes[index];
00186 }
00187 
00188 
00189 /*==========================================================================
00190  =                                                                         =
00191  =                             Public methods                              =
00192  =                                                                         =
00193  ==========================================================================*/
00194 
00195 /***********************************************************************//**
00196  * @brief Set XML child node
00197  *
00198  * @param[in] index Child node index [0,...,size()-1].
00199  * @param[in] node XML child node.
00200  * @return Pointer to deep copy of child node
00201  *
00202  * @exception GException::invalid_argument
00203  *            Not allowed to append root node.
00204  * @exception GException::invalid_value
00205  *            Not allowed to append to a text, comment or PI node.
00206  * @exception GException::out_of_range
00207  *            Child node index is out of range.
00208  *
00209  * Set XML child node. A deep copy of the node will be made and the pointer
00210  * to this node will be stored.
00211  ***************************************************************************/
00212 GXmlNode* GXmlNode::set(const int& index, const GXmlNode& node)
00213 {
00214     // Make sure that node to append is not a root node as only one root node
00215     // is allowed to exist in a document.
00216     if (node.type() == NT_DOCUMENT) {
00217         std::string msg = "Invalid attempt to append root note (GXmlDocument)"
00218                           " to a XML node. There can only be one root node in"
00219                           " an XML document.";
00220         throw GException::invalid_argument(G_SET, msg);
00221     }
00222 
00223     // Make sure that the current node is not a text node as nothing can be
00224     // appended to a text node.
00225     if (this->type() == NT_TEXT) {
00226         std::string msg = "Invalid attempt to append a XML node to a text node"
00227                           " (GXmlText). Nothing can be appended to a text node.";
00228         throw GException::invalid_value(G_SET, msg);
00229     }
00230 
00231     // Make sure that the current node is not a PI node as nothing can be
00232     // appended to a PI node.
00233     if (this->type() == NT_PI) {
00234         std::string msg = "Invalid attempt to append a XML node to a processing"
00235                           " instruction node (GXmlPI). Nothing can be appended"
00236                           " to a processing instruction node.";
00237         throw GException::invalid_value(G_SET, msg);
00238     }
00239 
00240     // Make sure that the current node is not a comment node as nothing can be
00241     // appended to a PI node.
00242     if (this->type() == NT_COMMENT) {
00243         std::string msg = "Invalid attempt to append a XML node to a comment"
00244                           " node (GXmlComment). Nothing can be appended"
00245                           " to a processing instruction node.";
00246         throw GException::invalid_value(G_SET, msg);
00247     }
00248 
00249     // Compile option: raise exception if index is out of range
00250     #if defined(G_RANGE_CHECK)
00251     if (index < 0 || index >= size()) {
00252         throw GException::out_of_range(G_SET, index, 0, size()-1);
00253     }
00254     #endif
00255 
00256     // Delete any existing node
00257     if (m_nodes[index] != NULL) delete m_nodes[index];
00258 
00259     // Assign new child node by cloning
00260     m_nodes[index] = node.clone();
00261 
00262     // Return pointer
00263     return m_nodes[index];
00264 }
00265 
00266 
00267 /***********************************************************************//**
00268  * @brief Append XML child node
00269  *
00270  * @param[in] node XML child node.
00271  * @return Pointer to appended child node
00272  *
00273  * @exception GException::invalid_argument
00274  *            Not allowed to append root node.
00275  * @exception GException::invalid_value
00276  *            Not allowed to append to a text, comment or PI node.
00277  *
00278  * Appends XML child node by making a deep copy of the node and storing its
00279  * pointer.
00280  ***************************************************************************/
00281 GXmlNode* GXmlNode::append(const GXmlNode& node)
00282 {
00283     // Make sure that node to append is not a root node as only one root node
00284     // is allowed to exist in a document.
00285     if (node.type() == NT_DOCUMENT) {
00286         std::string msg = "Invalid attempt to append root note (GXmlDocument)"
00287                           " to a XML node. There can only be one root node in"
00288                           " an XML document.";
00289         throw GException::invalid_argument(G_APPEND2, msg);
00290     }
00291 
00292     // Make sure that the current node is not a text node as nothing can be
00293     // appended to a text node.
00294     if (this->type() == NT_TEXT) {
00295         std::string msg = "Invalid attempt to append a XML node to a text node"
00296                           " (GXmlText). Nothing can be appended to a text node.";
00297         throw GException::invalid_value(G_APPEND2, msg);
00298     }
00299 
00300     // Make sure that the current node is not a PI node as nothing can be
00301     // appended to a PI node.
00302     if (this->type() == NT_PI) {
00303         std::string msg = "Invalid attempt to append a XML node to a processing"
00304                           " instruction node (GXmlPI). Nothing can be appended"
00305                           " to a processing instruction node.";
00306         throw GException::invalid_value(G_APPEND2, msg);
00307     }
00308 
00309     // Make sure that the current node is not a comment node as nothing can be
00310     // appended to a PI node.
00311     if (this->type() == NT_COMMENT) {
00312         std::string msg = "Invalid attempt to append a XML node to a comment"
00313                           " node (GXmlComment). Nothing can be appended"
00314                           " to a processing instruction node.";
00315         throw GException::invalid_value(G_APPEND2, msg);
00316     }
00317 
00318     // Clone child node
00319     GXmlNode* ptr = node.clone();
00320 
00321     // Append deep copy of child node
00322     m_nodes.push_back(ptr);
00323 
00324     // Return pointer
00325     return ptr;
00326 }
00327 
00328 
00329 /***********************************************************************//**
00330  * @brief Append XML element child node
00331  *
00332  * @param[in] segment XML child node.
00333  * @return Pointer to appended child node
00334  *
00335  * @exception GException::invalid_value
00336  *            Not allowed to append to a text, comment or PI node.
00337  *
00338  * Appends XML element that is constructed from a text @p segment. The text
00339  * segment is parsed and the element name and attributes are extracted using
00340  * the GXmlElement::parse_start() method. The method returns a pointer to the
00341  * XML element child node that has been appended.
00342  ***************************************************************************/
00343 GXmlElement* GXmlNode::append(const std::string& segment)
00344 {
00345     // Make sure that the current node is not a text node as nothing can be
00346     // appended to a text node.
00347     if (this->type() == NT_TEXT) {
00348         std::string msg = "Invalid attempt to append the text segment \""+
00349                           segment+"\" to a text node (GXmlText). Nothing can"
00350                           " be appended to a text node.";
00351         throw GException::invalid_value(G_APPEND1, msg);
00352     }
00353 
00354     // Make sure that the current node is not a PI node as nothing can be
00355     // appended to a PI node.
00356     if (this->type() == NT_PI) {
00357         std::string msg = "Invalid attempt to append a XML node to a processing"
00358                           " instruction node (GXmlPI). Nothing can be appended"
00359                           " to a processing instruction node.";
00360         throw GException::invalid_value(G_APPEND1, msg);
00361     }
00362 
00363     // Make sure that the current node is not a comment node as nothing can be
00364     // appended to a PI node.
00365     if (this->type() == NT_COMMENT) {
00366         std::string msg = "Invalid attempt to append a XML node to a comment"
00367                           " node (GXmlComment). Nothing can be appended"
00368                           " to a processing instruction node.";
00369         throw GException::invalid_value(G_APPEND1, msg);
00370     }
00371 
00372     // Create a new XML child element from the text segment
00373     GXmlElement* ptr = new GXmlElement(segment);
00374 
00375     // Append child element to container
00376     m_nodes.push_back(ptr);
00377 
00378     // Return child element
00379     return ptr;
00380 }
00381 
00382 
00383 /***********************************************************************//**
00384  * @brief Insert XML child node
00385  *
00386  * @param[in] index Child node index [0,...,size()-1].
00387  * @param[in] node XML child node.
00388  * @return Pointer to inserted child node
00389  *
00390  * @exception GException::invalid_argument
00391  *            Not allowed to append root node.
00392  * @exception GException::invalid_value
00393  *            Not allowed to append to a text, comment or PI node.
00394  * @exception GException::out_of_range
00395  *            Child node index is out of range.
00396  *
00397  * Inserts the XML child @p node before the node with the specified @p index.
00398  * A deep copy of the node will be made and the pointer to this node will be
00399  * stored.
00400  ***************************************************************************/
00401 GXmlNode* GXmlNode::insert(const int& index, const GXmlNode& node)
00402 {
00403     // Make sure that node to append is not a root node as only one root node
00404     // is allowed to exist in a document.
00405     if (node.type() == NT_DOCUMENT) {
00406         std::string msg = "Invalid attempt to append root note (GXmlDocument)"
00407                           " to a XML node. There can only be one root node in"
00408                           " an XML document.";
00409         throw GException::invalid_argument(G_INSERT, msg);
00410     }
00411 
00412     // Make sure that the current node is not a text node as nothing can be
00413     // appended to a text node.
00414     if (this->type() == NT_TEXT) {
00415         std::string msg = "Invalid attempt to append a XML node to a text node"
00416                           " (GXmlText). Nothing can be appended to a text node.";
00417         throw GException::invalid_value(G_INSERT, msg);
00418     }
00419 
00420     // Make sure that the current node is not a PI node as nothing can be
00421     // appended to a PI node.
00422     if (this->type() == NT_PI) {
00423         std::string msg = "Invalid attempt to append a XML node to a processing"
00424                           " instruction node (GXmlPI). Nothing can be appended"
00425                           " to a processing instruction node.";
00426         throw GException::invalid_value(G_INSERT, msg);
00427     }
00428 
00429     // Make sure that the current node is not a comment node as nothing can be
00430     // appended to a PI node.
00431     if (this->type() == NT_COMMENT) {
00432         std::string msg = "Invalid attempt to append a XML node to a comment"
00433                           " node (GXmlComment). Nothing can be appended"
00434                           " to a processing instruction node.";
00435         throw GException::invalid_value(G_INSERT, msg);
00436     }
00437 
00438     // Compile option: raise exception if index is out of range
00439     #if defined(G_RANGE_CHECK)
00440     if (is_empty()) {
00441         if (index > 0) {
00442             throw GException::out_of_range(G_INSERT, index, 0, size()-1);
00443         }
00444     }
00445     else {
00446         if (index < 0 || index >= size()) {
00447             throw GException::out_of_range(G_INSERT, index, 0, size()-1);
00448         }
00449     }
00450     #endif
00451 
00452     // Clone child node
00453     GXmlNode* ptr = node.clone();
00454 
00455     // Inserts deep copy of child node
00456     m_nodes.insert(m_nodes.begin()+index, ptr);
00457 
00458     // Return pointer
00459     return ptr;
00460 }
00461 
00462 
00463 /***********************************************************************//**
00464  * @brief Remove XML child node
00465  *
00466  * @param[in] index Child node index [0,...,size()-1].
00467  *
00468  * @exception GException::out_of_range
00469  *            Child node index is out of range.
00470  *
00471  * Remove XML child node at @p index.
00472  ***************************************************************************/
00473 void GXmlNode::remove(const int& index)
00474 {
00475     // Compile option: raise exception if index is out of range
00476     #if defined(G_RANGE_CHECK)
00477     if (index < 0 || index >= size()) {
00478         throw GException::out_of_range(G_REMOVE, index, 0, size()-1);
00479     }
00480     #endif
00481 
00482     // Delete node
00483     delete m_nodes[index];
00484     
00485     // Erase child node from container
00486     m_nodes.erase(m_nodes.begin() + index);
00487     
00488     // Return
00489     return;
00490 }
00491 
00492 
00493 /***********************************************************************//**
00494  * @brief Append all XML child nodes from another XML node
00495  *
00496  * @param[in] node XML node.
00497  *
00498  * Append all XML child nodes found in @p node to the actual object. Nodes
00499  * are copied deeply so that they live now on their on in the actual object.
00500  ***************************************************************************/
00501 void GXmlNode::extend(const GXmlNode& node)
00502 {
00503     // Do nothing if node container is empty
00504     if (!node.is_empty()) {
00505 
00506         // Get size. Note that we extract the size first to avoid an
00507         // endless loop that arises when a container is appended to
00508         // itself.
00509         int num = node.size();
00510 
00511         // Reserve enough space
00512         reserve(size() + num);
00513 
00514         // Loop over all child nodes and append pointers to deep copies 
00515         for (int i = 0; i < num; ++i) {
00516             m_nodes.push_back(node[i]->clone());
00517         }
00518 
00519     } // endif: node container was not empty
00520     
00521     // Return
00522     return;
00523 }
00524 
00525 
00526 /***********************************************************************//**
00527  * @brief Return filename of XML file
00528  *
00529  * @return Filename.
00530  *
00531  * Returns the file name of the XML file by moving up the XML file hierarchy
00532  * to the root. In case that the XML node cannot move up to the root XML
00533  * node an empty file name is returned (this may happen if the XML node
00534  * is an orphan node). The file name will also be empty if the XML file has
00535  * not been read from disk or written to disk.
00536  ***************************************************************************/
00537 GFilename GXmlNode::filename(void) const
00538 {
00539     // Initialise empty filename
00540     GFilename filename;
00541 
00542     // Move up the XML document hierarchy until the root node has been
00543     // found
00544     GXmlNode* parent = this->parent();
00545     while (parent != NULL) {
00546 
00547         // Cast parent into a root node
00548         GXmlDocument* root = dynamic_cast<GXmlDocument*>(parent);
00549 
00550         // If the parent is a root node, recover the filename and exit the
00551         // loop
00552         if (root != NULL) {
00553             filename = root->filename();
00554             break;
00555         }
00556 
00557         // ... otherwise move up the XML tree
00558         else {
00559             parent = parent->parent();
00560         }
00561 
00562     } // endwhile: move up to the root document
00563 
00564     // Return filename
00565     return filename;
00566 }
00567 
00568 
00569 /***********************************************************************//**
00570  * @brief Return number of GXMLElement children of node
00571  *
00572  * @return Number of child elements.
00573  *
00574  * Returns the number of GXMLElement child elements of the XML node.
00575  * GXMLElement child elements are nodes of type NT_ELEMENT.
00576  ***************************************************************************/
00577 int GXmlNode::elements(void) const
00578 {
00579     // Compute number of child elements in node
00580     int elements = 0;
00581     for (int i = 0; i < m_nodes.size(); ++i) {
00582         if (m_nodes[i]->type() == NT_ELEMENT) {
00583             elements++;
00584         }
00585     }
00586 
00587     // Return number of child elements
00588     return elements;
00589 }
00590 
00591 
00592 /***********************************************************************//**
00593  * @brief Return number of GXMLElement children with a given name
00594  *
00595  * @param[in] name Name of GXMLElement elements.
00596  * @return Number of child elements with a given @p name.
00597  *
00598  * Returns the number of GXMLElement child elements of the XML node that
00599  * have a given @p name. GXMLElement child elements are nodes of type
00600  * NT_ELEMENT.
00601  ***************************************************************************/
00602 int GXmlNode::elements(const std::string& name) const
00603 {
00604     // Compute number of child elements in node
00605     int elements = 0;
00606     for (int i = 0; i < m_nodes.size(); ++i) {
00607         if (m_nodes[i]->type() == NT_ELEMENT) {
00608             if (static_cast<GXmlElement*>(m_nodes[i])->name() == name) {
00609                 elements++;
00610             }
00611         }
00612     }
00613 
00614     // Return number of child elements
00615     return elements;
00616 }
00617 
00618 
00619 /***********************************************************************//**
00620  * @brief Return pointer to GXMLElement child
00621  *
00622  * @param[in] index Node index [0,...,elements()-1].
00623  * @return Pointer to child element (NULL if element does not exist).
00624  *
00625  * @exception GException::out_of_range
00626  *            Child element index is out of range.
00627  *
00628  * Returns a pointer to the child number @p index of the XML node. An
00629  * exception will be thrown if the @p index is not valid.
00630  ***************************************************************************/
00631 GXmlElement* GXmlNode::element(const int& index)
00632 {
00633     // If index is outside boundary then throw an error
00634     if (index < 0 || index >= elements()) {
00635         throw GException::out_of_range(G_ELEMENT1, index, 0, elements()-1);
00636     }
00637 
00638     // Get the requested child element
00639     GXmlElement* element  = NULL;
00640     int          elements = 0;
00641     for (int i = 0; i < m_nodes.size(); ++i) {
00642         GXmlElement* src = dynamic_cast<GXmlElement*>(m_nodes[i]);
00643         if (src != NULL) {
00644             if (elements == index) {
00645                 element = src;
00646                 break;
00647             }
00648             elements++;
00649         }
00650     }
00651 
00652     // Return child element
00653     return element;
00654 }
00655 
00656 
00657 /***********************************************************************//**
00658  * @brief Return pointer to GXMLElement child (const variant)
00659  *
00660  * @param[in] index Node index [0,...,elements()-1].
00661  * @return Pointer to child element (NULL if element does not exist).
00662  *
00663  * @exception GException::out_of_range
00664  *            Child element index is out of range.
00665  *
00666  * Returns a pointer to the child number @p index of the XML node. An
00667  * exception will be thrown if the @p index is not valid.
00668  ***************************************************************************/
00669 const GXmlElement* GXmlNode::element(const int& index) const
00670 {
00671     // If index is outside boundary then throw an error
00672     if (index < 0 || index >= elements()) {
00673         throw GException::out_of_range(G_ELEMENT1, index, 0, elements()-1);
00674     }
00675 
00676     // Get the requested child element
00677     const GXmlElement* element  = NULL;
00678     int                elements = 0;
00679     for (int i = 0; i < m_nodes.size(); ++i) {
00680         const GXmlElement* src = dynamic_cast<const GXmlElement*>(m_nodes[i]);
00681         if (src != NULL) {
00682             if (elements == index) {
00683                 element = src;
00684                 break;
00685             }
00686             elements++;
00687         }
00688     }
00689 
00690     // Return child element
00691     return element;
00692 }
00693 
00694 
00695 /***********************************************************************//**
00696  * @brief Return pointer on child walking down a hierarchy of tags
00697  *
00698  * @param[in] name Child element hierarchy.
00699  * @return Pointer to child element (NULL if element does not exist).
00700  *
00701  * @exception GException::invalid_argument
00702  *            Hierarchy string invalid.
00703  *
00704  * Returns a pointer to the child element described by a hierarchy of the
00705  * following syntax
00706  *
00707  *     params > param[1] > value > struct
00708  *
00709  * The > symbols indicate subsequent hierarchy levels, the square brackets
00710  * provides the index in case that multiple tags with the same name exist
00711  * at a given hierarchy level. Omitting the index means that the first
00712  * tag with the specified name is accessed.
00713  *
00714  * If the specified element does not exist the method returns a NULL pointer.
00715  ***************************************************************************/
00716 GXmlElement* GXmlNode::element(const std::string& name)
00717 {
00718     // Initialise child node pointer
00719     GXmlElement* element = NULL;
00720 
00721     // Split name into tags
00722     std::vector<std::string> tags = gammalib::split(name, ">");
00723 
00724     // Walk down the hierarchy
00725     GXmlNode* current = this;
00726     for (int i = 0; i < tags.size(); ++i) {
00727 
00728         // Get tag name and index
00729         std::string tag   = gammalib::strip_whitespace(tags[i]);
00730         int         index = extract_index(tag);
00731 
00732         // Break if the requested node does not exist
00733         int n = current->elements(tag);
00734         if (n < 1 || index < 0 || index >= n) {
00735             element = NULL;
00736             break;
00737         }
00738 
00739         // Get node
00740         element = current->element(tag, index);
00741         current = element;
00742 
00743         // Break if node has not been found
00744         if (current == NULL) {
00745             element = NULL;
00746             break;
00747         }
00748         
00749     } // endfor: walked down hierarchy
00750 
00751     // Return child element
00752     return element;
00753 }
00754 
00755 
00756 /***********************************************************************//**
00757  * @brief Return pointer on child walking down a hierarchy of tags (const
00758  *        version)
00759  *
00760  * @param[in] name Child element hierarchy.
00761  * @return Pointer to child element (NULL if element does not exist).
00762  *
00763  * @exception GException::invalid_argument
00764  *            Hierarchy string invalid.
00765  *
00766  * Returns a pointer to the child element described by a hierarchy of the
00767  * following syntax
00768  *
00769  *     params > param[1] > value > struct
00770  *
00771  * The > symbols indicate subsequent hierarchy levels, the square brackets
00772  * provides the index in case that multiple tags with the same name exist
00773  * at a given hierarchy level. Omitting the index means that the first
00774  * tag with the specified name is accessed.
00775  *
00776  * If the specified element does not exist the method returns a NULL pointer.
00777  ***************************************************************************/
00778 const GXmlElement* GXmlNode::element(const std::string& name) const
00779 {
00780     // Initialise child node pointer
00781     const GXmlElement* element = NULL;
00782 
00783     // Split name into tags
00784     std::vector<std::string> tags = gammalib::split(name, ">");
00785 
00786     // Walk down the hierarchy
00787     const GXmlNode* current = this;
00788     for (int i = 0; i < tags.size(); ++i) {
00789 
00790         // Get tag name and index
00791         std::string tag   = gammalib::strip_whitespace(tags[i]);
00792         int         index = extract_index(tag);
00793 
00794         // Break if the requested node does not exist
00795         int n = current->elements(tag);
00796         if (n < 1 || index < 0 || index >= n) {
00797             element = NULL;
00798             break;
00799         }
00800 
00801         // Get node
00802         element = current->element(tag, index);
00803         current = element;
00804 
00805         // Break if node has not been found
00806         if (current == NULL) {
00807             element = NULL;
00808             break;
00809         }
00810         
00811     } // endfor: walked down hierarchy
00812 
00813     // Return child element
00814     return element;
00815 }
00816 
00817 
00818 /***********************************************************************//**
00819  * @brief Return pointer on GXMLElement child of a given name
00820  *
00821  * @param[in] name Name of child element.
00822  * @param[in] index Node index [0,...,elements()-1].
00823  * @return Pointer to child element (NULL if element does not exist).
00824  *
00825  * @exception GException::xml_name_not_found
00826  *            Child element name not found.
00827  * @exception GException::out_of_range
00828  *            Child element index is out of range.
00829  *
00830  * Returns a pointer to the child number @p index with @p name of the XML
00831  * node. An exception will be thrown if the @p index is not valid.
00832  ***************************************************************************/
00833 GXmlElement* GXmlNode::element(const std::string& name, const int& index)
00834 {
00835     // Determine number of child elements
00836     int n = elements(name);
00837 
00838     // Signal if no children exist
00839     if (n < 1) {
00840         throw GException::xml_name_not_found(G_ELEMENT3, name);
00841     }
00842 
00843     // If index is outside boundary then throw an error
00844     if (index < 0 || index >= n) {
00845         throw GException::out_of_range(G_ELEMENT3, index, 0, n-1);
00846     }
00847 
00848     // Get the requested child element
00849     GXmlElement* element  = NULL;
00850     int          elements = 0;
00851     for (int i = 0; i < m_nodes.size(); ++i) {
00852         GXmlElement* src = dynamic_cast<GXmlElement*>(m_nodes[i]);
00853         if (src != NULL) {
00854             if (src->name() == name) {
00855                 if (elements == index) {
00856                     element = src;
00857                     break;
00858                 }
00859                 elements++;
00860             }
00861         }
00862     }
00863 
00864     // Return child element
00865     return element;
00866 }
00867 
00868 
00869 /***********************************************************************//**
00870  * @brief Return pointer on GXMLElement child of a given name (const variant)
00871  *
00872  * @param[in] name Name of child element.
00873  * @param[in] index Node index [0,...,elements()-1].
00874  * @return Pointer to child element (NULL if element does not exist).
00875  *
00876  * @exception GException::xml_name_not_found
00877  *            Child element name not found.
00878  * @exception GException::out_of_range
00879  *            Child element index is out of range.
00880  *
00881  * Returns a pointer to the child number @p index with @p name of the XML
00882  * node. An exception will be thrown if the @p index is not valid.
00883  ***************************************************************************/
00884 const GXmlElement* GXmlNode::element(const std::string& name, const int& index) const
00885 {
00886     // Determine number of child elements
00887     int n = elements(name);
00888 
00889     // Signal if no children exist
00890     if (n < 1) {
00891         throw GException::xml_name_not_found(G_ELEMENT3, name);
00892     }
00893 
00894     // If index is outside boundary then throw an error
00895     if (index < 0 || index >= n) {
00896         throw GException::out_of_range(G_ELEMENT3, index, 0, n-1);
00897     }
00898 
00899     // Get the requested child element
00900     const GXmlElement* element  = NULL;
00901     int                elements = 0;
00902     for (int i = 0; i < m_nodes.size(); ++i) {
00903         const GXmlElement* src = dynamic_cast<const GXmlElement*>(m_nodes[i]);
00904         if (src != NULL) {
00905             if (src->name() == name) {
00906                 if (elements == index) {
00907                     element = src;
00908                     break;
00909                 }
00910                 elements++;
00911             }
00912         }
00913     }
00914 
00915     // Return child element
00916     return element;
00917 }
00918 
00919 
00920 /***********************************************************************//**
00921  * @brief Print XML node in string
00922  *
00923  * @param[in] chatter Chattiness (defaults to NORMAL).
00924  * @return String containing XML information.
00925  ***************************************************************************/
00926 std::string GXmlNode::print(const GChatter& chatter) const
00927 {
00928     // Set result string
00929     std::string result = print(chatter, 0);
00930 
00931     // Return
00932     return result;
00933 }
00934 
00935 
00936 /*==========================================================================
00937  =                                                                         =
00938  =                             Private methods                             =
00939  =                                                                         =
00940  ==========================================================================*/
00941 
00942 /***********************************************************************//**
00943  * @brief Initialise class members
00944  ***************************************************************************/
00945 void GXmlNode::init_members(void)
00946 {
00947     // Initialise members
00948     m_nodes.clear();
00949     m_parent = NULL;
00950 
00951     // Return
00952     return;
00953 }
00954 
00955 
00956 /***********************************************************************//**
00957  * @brief Copy class members
00958  *
00959  * @param[in] node XML node.
00960  *
00961  * @todo Is copying the parent node pointer correct?
00962  ***************************************************************************/
00963 void GXmlNode::copy_members(const GXmlNode& node)
00964 {
00965     // Copy members
00966     m_parent = node.m_parent;
00967 
00968     // Copy nodes
00969     m_nodes.clear();
00970     for (int i = 0; i < node.m_nodes.size(); ++i) {
00971         m_nodes.push_back((node.m_nodes[i]->clone()));
00972     }
00973 
00974     // Return
00975     return;
00976 }
00977 
00978 
00979 /***********************************************************************//**
00980  * @brief Delete class members
00981  *
00982  * As container classes that hold pointers need to handle themselves the
00983  * proper deallocation of memory, we loop here over all pointers and make
00984  * sure that we deallocate the associated nodes.
00985  ***************************************************************************/
00986 void GXmlNode::free_members(void)
00987 {
00988     // Free memory for all nodes
00989     for (int i = 0; i < m_nodes.size(); ++i) {
00990         delete m_nodes[i];
00991         m_nodes[i] = NULL;
00992     }
00993 
00994     // Return
00995     return;
00996 }
00997 
00998 
00999 /***********************************************************************//**
01000  * @brief Extract index from tag
01001  *
01002  * @param[in,out] tag Tag.
01003  * @return Index.
01004  *
01005  * @exception GException::invalid_argument
01006  *            Tag string invalid.
01007  *
01008  * Extracts the index from a tag string of the following syntax
01009  *
01010  *     param[1]
01011  *
01012  * The value within the squared brackets provides the index of the element.
01013  * If the squared brackets are omitted, an index of 0 will be returned.
01014  ***************************************************************************/
01015 int GXmlNode::extract_index(std::string& tag) const
01016 {
01017     // Initialise index
01018     int index = 0;
01019 
01020     // Search for squared brackets, extract index, and strip brackets
01021     // from tag
01022     size_t      start = tag.find_first_of("[");
01023     if (start != std::string::npos) {
01024         size_t stop = tag.find_first_of("]", start);
01025         if (stop == std::string::npos) {
01026             std::string msg = "Tag specifier \""+tag+"\" is missing "
01027                               "a ] bracket.";
01028             throw GException::invalid_argument(G_EXTRACT_INDEX, msg);
01029         }
01030         else {
01031             size_t length = stop - start - 1;
01032             if (length < 1) {
01033                 std::string msg = "Index value is missing for \""+tag+"\".";
01034                 throw GException::invalid_argument(G_EXTRACT_INDEX, msg);
01035             }
01036             else {
01037                 index = gammalib::toint(tag.substr(start+1, length));
01038                 tag   = tag.substr(0, start);
01039             }
01040         }
01041     }
01042 
01043     // Return index
01044     return index;
01045 }

Generated on Tue Jan 24 12:37:25 2017 for GammaLib by  doxygen 1.4.7