src/xml/GXml.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *                          GXml.cpp - XML 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 GXml.cpp
00023  * @brief XML 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 "GFilename.hpp"
00034 #include "GUrlFile.hpp"
00035 #include "GUrlString.hpp"
00036 #include "GXml.hpp"
00037 #include "GXmlNode.hpp"
00038 #include "GXmlDocument.hpp"
00039 #include "GXmlText.hpp"
00040 #include "GXmlElement.hpp"
00041 #include "GXmlComment.hpp"
00042 #include "GXmlPI.hpp"
00043 
00044 /* __ Method name definitions ____________________________________________ */
00045 #define G_LOAD                                     "GXml::load(std::string&)"
00046 #define G_PARSE                                          "GXml::parse(GUrl&)"
00047 #define G_PROCESS              "GXml::process(GXmlNode*, const 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 GXml::GXml(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] xml XML object.
00079  ***************************************************************************/
00080 GXml::GXml(const GXml& xml)
00081 {
00082     // Initialise members
00083     init_members();
00084 
00085     // Copy members
00086     copy_members(xml);
00087 
00088     // Return
00089     return;
00090 }
00091 
00092 
00093 /***********************************************************************//**
00094  * @brief XML document constructor
00095  *
00096  * @param[in] xml XML text string or file name.
00097  *
00098  * Constructs GXml object by either parsing a text string or a file. If the
00099  * @p xml argument starts with @p <?xml it is interpreted as a XML file and
00100  * parsed directly. Otherwise the constructor will interpret @p xml as a
00101  * filename, and opens the file for parsing.
00102  ***************************************************************************/
00103 GXml::GXml(const std::string& xml)
00104 {
00105     // Initialise members
00106     init_members();
00107 
00108     // If the string is an XML text then parse it directly
00109     if (xml.compare(0, 5, "<?xml") == 0) {
00110         GUrlString url(xml);
00111         read(url);
00112         url.close();
00113     }
00114 
00115     // ... otherwise interpret the string as a filename
00116     else {
00117         load(xml);
00118     }
00119 
00120     // Return
00121     return;
00122 }
00123 
00124 
00125 /***********************************************************************//**
00126  * @brief Destructor
00127  ***************************************************************************/
00128 GXml::~GXml(void)
00129 {
00130     // Free members
00131     free_members();
00132 
00133     // Return
00134     return;
00135 }
00136 
00137 
00138 /*==========================================================================
00139  =                                                                         =
00140  =                                Operators                                =
00141  =                                                                         =
00142  ==========================================================================*/
00143 
00144 /***********************************************************************//**
00145  * @brief Assignment operator
00146  *
00147  * @param[in] xml XML object.
00148  * @return XML object.
00149  ***************************************************************************/
00150 GXml& GXml::operator=(const GXml& xml)
00151 {
00152     // Execute only if object is not identical
00153     if (this != &xml) {
00154 
00155         // Free members
00156         free_members();
00157 
00158         // Initialise members
00159         init_members();
00160 
00161         // Copy members
00162         copy_members(xml);
00163 
00164     } // endif: object was not identical
00165 
00166     // Return
00167     return *this;
00168 }
00169 
00170 
00171 /***********************************************************************//**
00172  * @brief Return pointer to child of XML document root element
00173  *
00174  * @param[in] index Node index [0,...,size()-1].
00175  * @return Pointer to child of XML document root element.
00176  *
00177  * Returns a pointer to the child number @p index of the XML document root
00178  * element. An exception will be thrown if the @p index is not valid.
00179  ***************************************************************************/
00180 GXmlNode* GXml::operator[](const int& index)
00181 {
00182     // Return pointer
00183     return m_root[index];
00184 }
00185 
00186 
00187 /***********************************************************************//**
00188  * @brief Return pointer to child of XML document root element (const variant)
00189  *
00190  * @param[in] index Node index [0,...,size()-1].
00191  * @return Pointer to child of XML document root element.
00192  *
00193  * Returns a pointer to the child number @p index of the XML document root
00194  * element. An exception will be thrown if the @p index is not valid.
00195  ***************************************************************************/
00196 const GXmlNode* GXml::operator[](const int& index) const
00197 {
00198     // Return pointer
00199     return m_root[index];
00200 }
00201 
00202 
00203 /*==========================================================================
00204  =                                                                         =
00205  =                             Public methods                              =
00206  =                                                                         =
00207  ==========================================================================*/
00208 
00209 /***********************************************************************//**
00210  * @brief Clear XML object
00211  *
00212  * Resets XML object to a clean initial state.
00213  ***************************************************************************/
00214 void GXml::clear(void)
00215 {
00216     // Free memory and initialise members
00217     free_members();
00218     init_members();
00219 
00220     // Return
00221     return;
00222 }
00223 
00224 
00225 /***********************************************************************//**
00226  * @brief Clone XML object
00227  *
00228  * @return Pointer to deep copy of XML object.
00229  ***************************************************************************/
00230 GXml* GXml::clone(void) const
00231 {
00232     // Clone object
00233     return new GXml(*this);
00234 }
00235 
00236 
00237 /***********************************************************************//**
00238  * @brief Set child node in XML document root
00239  *
00240  * @param[in] index Child node index [0,...,size()-1].
00241  * @param[in] node XML child node.
00242  * @return Pointer to deep copy of child node.
00243  *
00244  * Set @p node with @p index of XML document root.
00245  ***************************************************************************/
00246 GXmlNode* GXml::set(const int& index, const GXmlNode& node)
00247 {
00248     // Set node and return pointer
00249     return (m_root.set(index, node));
00250 }
00251 
00252 
00253 /***********************************************************************//**
00254  * @brief Append child node to XML document root
00255  *
00256  * @param[in] node Child node.
00257  * @return Pointer to appended child node.
00258  *
00259  * Appends node to XML document root by making a deep copy of the @p node.
00260  ***************************************************************************/
00261 GXmlNode* GXml::append(const GXmlNode& node)
00262 {
00263     // Append node and return pointer
00264     return (m_root.append(node));
00265 }
00266 
00267 
00268 /***********************************************************************//**
00269  * @brief Append child node to XML document root
00270  *
00271  * @param[in] segment XML child node.
00272  * @return Pointer to appended child node.
00273  *
00274  * Appends XML element that is constructed from a text @p segment. The text
00275  * segment is parsed and the element name and attributes are extracted using
00276  * the GXmlElement::parse_start() method. The method returns a pointer to the
00277  * XML element child node that has been appended.
00278  ***************************************************************************/
00279 GXmlElement* GXml::append(const std::string& segment)
00280 {
00281     // Append node and return pointer
00282     return (m_root.append(segment));
00283 }
00284 
00285 
00286 /***********************************************************************//**
00287  * @brief Insert child node into XML document root
00288  *
00289  * @param[in] index Child node index [0,...,size()-1].
00290  * @param[in] node XML child node.
00291  * @return Pointer to inserted child node.
00292  *
00293  * Inserts the XML child @p node before the node with the specified @p index.
00294  * A deep copy of the node will be made and the pointer to this node will be
00295  * stored.
00296  ***************************************************************************/
00297 GXmlNode* GXml::insert(const int& index, const GXmlNode& node)
00298 {
00299     // Insert node and return pointer
00300     return (m_root.insert(index, node));
00301 }
00302 
00303 
00304 /***********************************************************************//**
00305  * @brief Remove child node from XML document root
00306  *
00307  * @param[in] index Child node index [0,...,size()-1].
00308  *
00309  * Remove XML child node at @p index from the XML document root.
00310  ***************************************************************************/
00311 void GXml::remove(const int& index)
00312 {
00313     // Remove node
00314     m_root.remove(index);
00315 
00316     // Return
00317     return;
00318 }
00319 
00320 
00321 /***********************************************************************//**
00322  * @brief Reserve space for child nodes in XML document root
00323  *
00324  * @param[in] num Number of nodes.
00325  *
00326  * Reserves space for @p num nodes in the XML document root.
00327  ***************************************************************************/
00328 void GXml::reserve(const int& num)
00329 {
00330     // Reservers space node
00331     m_root.reserve(num);
00332 
00333     // Return
00334     return;
00335 }
00336 
00337 
00338 /***********************************************************************//**
00339  * @brief Append all XML child nodes from another XML node in the XML
00340  *        document root
00341  *
00342  * @param[in] node XML child node.
00343  *
00344  * Append all XML child nodes found in @p node to the XML document root.
00345  * Nodes are copied deeply so that they live now on their on in the actual
00346  * object.
00347  ***************************************************************************/
00348 void GXml::extend(const GXmlNode& node)
00349 {
00350     // Extend node
00351     m_root.extend(node);
00352 
00353     // Return
00354     return;
00355 }
00356 
00357 
00358 /***********************************************************************//**
00359  * @brief Return number of child elements in XML document root
00360  *
00361  * @return Number of child elements in XML document root.
00362  *
00363  * Returns the number of GXmlElement child elements of the XML document root.
00364  * GXMLElement child elements are nodes of type NT_ELEMENT.
00365  ***************************************************************************/
00366 int GXml::elements(void) const
00367 {
00368     // Return number
00369     return m_root.elements();
00370 }
00371 
00372 
00373 /***********************************************************************//**
00374  * @brief Return number of child elements with a given name in XML
00375  *        document root
00376  *
00377  * @param[in] name Name of child elements.
00378  * @return Number of child elements with a given @p name in XML
00379  *         document root.
00380  *
00381  * Returns the number of GXMLElement child elements of the XML document root
00382  * that have a given @p name. GXmlElement child elements are nodes of type
00383  * NT_ELEMENT.
00384  ***************************************************************************/
00385 int GXml::elements(const std::string& name) const
00386 {
00387     // Return number
00388     return m_root.elements(name);
00389 }
00390 
00391 
00392 /***********************************************************************//**
00393  * @brief Return pointer to child element
00394  *
00395  * @param[in] index Node index [0,...,elements()-1].
00396  * @return Pointer to child element.
00397  *
00398  * Returns a pointer to the child number @p index of the XML document root.
00399  * An exception will be thrown if the @p index is not valid.
00400  ***************************************************************************/
00401 GXmlElement* GXml::element(const int& index)
00402 {
00403     // Return pointer
00404     return m_root.element(index);
00405 }
00406 
00407 
00408 /***********************************************************************//**
00409  * @brief Return pointer to child element (const variant)
00410  *
00411  * @param[in] index Node index [0,...,elements()-1].
00412  * @return Pointer to child element.
00413  *
00414  * Returns a pointer to the child number @p index of the XML document root.
00415  * An exception will be thrown if the @p index is not valid.
00416  ***************************************************************************/
00417 const GXmlElement* GXml::element(const int& index) const
00418 {
00419     // Return pointer
00420     return m_root.element(index);
00421 }
00422 
00423 
00424 /***********************************************************************//**
00425  * @brief Return pointer to child element by hierarchy
00426  *
00427  * @param[in] name Child element hierarchy.
00428  * @return Pointer to child element.
00429  *
00430  * Returns a pointer to the child element described by a hierarchy of the
00431  * following syntax
00432  *
00433  *     params > param[1] > value > struct
00434  *
00435  * The > symbols indicate subsequent hierarchy levels, the square brackets
00436  * provides the index in case that multiple tags with the same name exist
00437  * at a given hierarchy level. Omitting the index means that the first
00438  * tag with the specified name is accessed.
00439  ***************************************************************************/
00440 GXmlElement* GXml::element(const std::string& name)
00441 {
00442     // Return pointer
00443     return m_root.element(name);
00444 }
00445 
00446 
00447 /***********************************************************************//**
00448  * @brief Return pointer to child element by hierarchy (const version)
00449  *
00450  * @param[in] name Child element hierarchy.
00451  * @return Pointer to child element.
00452  *
00453  * Returns a pointer to the child element described by a hierarchy of the
00454  * following syntax
00455  *
00456  *     params > param[1] > value > struct
00457  *
00458  * The > symbols indicate subsequent hierarchy levels, the square brackets
00459  * provides the index in case that multiple tags with the same name exist
00460  * at a given hierarchy level. Omitting the index means that the first
00461  * tag with the specified name is accessed.
00462  ***************************************************************************/
00463 const GXmlElement* GXml::element(const std::string& name) const
00464 {
00465     // Return pointer
00466     return m_root.element(name);
00467 }
00468 
00469 
00470 /***********************************************************************//**
00471  * @brief Return pointer to child element of a given name
00472  *
00473  * @param[in] name Name of child element.
00474  * @param[in] index Node index [0,...,elements()-1].
00475  * @return Pointer to child element.
00476  *
00477  * Returns a pointer to the child number @p index with @p name of the XML
00478  * document root. An exception will be thrown if the @p index is not valid.
00479  ***************************************************************************/
00480 GXmlElement* GXml::element(const std::string& name, const int& index)
00481 {
00482     // Return pointer
00483     return m_root.element(name, index);
00484 }
00485 
00486 
00487 /***********************************************************************//**
00488  * @brief Return pointer to child element of a given name (const variant)
00489  *
00490  * @param[in] name Name of child element.
00491  * @param[in] index Node index [0,...,elements()-1].
00492  * @return Pointer to child element.
00493  *
00494  * Returns a pointer to the child number @p index with @p name of the XML
00495  * document root. An exception will be thrown if the @p index is not valid.
00496  ***************************************************************************/
00497 const GXmlElement* GXml::element(const std::string& name, const int& index) const
00498 {
00499     // Return pointer
00500     return m_root.element(name, index);
00501 }
00502 
00503 
00504 /***********************************************************************//**
00505  * @brief Load XML document from file
00506  *
00507  * @param[in] filename File name.
00508  *
00509  * Loads a XML document from a file by reading from the file's Unified
00510  * Resource Locator (URL). The read() method is invoked for this purpose.
00511  *
00512  * The method uses the GUrlFile file opening constructor to open the URL.
00513  * This constructor will automatically expand any environment variables that
00514  * are present in the filename.
00515  *
00516  * @todo Ideally, we would like to extract the URL type from the filename
00517  * so that any kind of URL can be used for loading.
00518  ***************************************************************************/
00519 void GXml::load(const GFilename& filename)
00520 {
00521     // Throw an exception if file does not exist
00522     if (!filename.exists()) {
00523         throw GException::file_open_error(G_LOAD, filename);
00524     }
00525 
00526     // Open XML URL as file for reading
00527     GUrlFile url(filename.url().c_str(), "r");
00528 
00529     // Read XML document from URL
00530     read(url);
00531 
00532     // Close URL
00533     url.close();
00534 
00535     // Store filename in XML document
00536     m_root.filename(filename);
00537 
00538     // Return
00539     return;
00540 }
00541 
00542 
00543 /***********************************************************************//**
00544  * @brief Save XML document into file
00545  *
00546  * @param[in] filename File name.
00547  *
00548  * Saves the XML document into a file by writing into the file's Unified
00549  * Resource Locator (URL). The write() method is invoked for this purpose.
00550  *
00551  * The method uses the GUrlFile file opening constructor to open the URL.
00552  * This constructor will automatically expand any environment variables that
00553  * are present in the filename.
00554  *
00555  * @todo Ideally, we would like to extract the URL type from the filename
00556  * so that any kind of URL can be used for loading.
00557  ***************************************************************************/
00558 void GXml::save(const GFilename& filename) const
00559 {
00560     // Open XML file for writing
00561     GUrlFile url(filename.url().c_str(), "w");
00562 
00563     // Store filename in XML document (circumvent const correctness)
00564     const_cast<GXmlDocument*>(&m_root)->filename(filename);
00565 
00566     // Write XML document
00567     write(url, 0);
00568 
00569     // Close file
00570     url.close();
00571 
00572     // Return
00573     return;
00574 }
00575 
00576 
00577 /***********************************************************************//**
00578  * @brief Read XML document from URL
00579  *
00580  * @param[in] url Unified Resource Locator.
00581  *
00582  * Reads in the XML document by parsing a Unified Resource Locator of any
00583  * type.
00584  ***************************************************************************/
00585 void GXml::read(const GUrl& url)
00586 {
00587     // Clear object
00588     clear();
00589 
00590     // Parse URL
00591     parse(url);
00592 
00593     // Return
00594     return;
00595 }
00596 
00597 
00598 /***********************************************************************//**
00599  * @brief Write XML document into URL
00600  *
00601  * @param[in] url Unified Resource Locator.
00602  * @param[in] indent Indentation (default = 0).
00603  *
00604  * Writes the XML document in a Unified Resource Locator. Formatting of the
00605  * document can be adapted using the @p indent parameter.
00606  ***************************************************************************/
00607 void GXml::write(GUrl& url, const int& indent) const
00608 {
00609     // Write XML document
00610     m_root.write(url);
00611 
00612     // Return
00613     return;
00614 }
00615 
00616 
00617 /***********************************************************************//**
00618  * @brief Print XML object
00619  *
00620  * @param[in] chatter Chattiness.
00621  * @param[in] indent Text indentation.
00622  * @return String containing XML object.
00623  ***************************************************************************/
00624 std::string GXml::print(const GChatter& chatter, const int& indent) const
00625 {
00626     // Initialise result string
00627     std::string result;
00628 
00629     // Continue only if chatter is not silent
00630     if (chatter != SILENT) {
00631 
00632         // Append header
00633         result.append("=== GXml ===");
00634 
00635         // Append model
00636         result.append("\n"+m_root.print(chatter, 0));
00637 
00638     } // endif: chatter was not silent
00639 
00640     // Return result
00641     return result;
00642 }
00643 
00644 
00645 /***********************************************************************//**
00646  * @brief Print XML object
00647  *
00648  * @param[in] chatter Chattiness.
00649  * @return String containing XML object.
00650  ***************************************************************************/
00651 std::string GXml::print(const GChatter& chatter) const
00652 {
00653     // Set result string
00654     std::string result = print(chatter, 0);
00655 
00656     // Return result
00657     return result;
00658 }
00659 
00660 
00661 /*==========================================================================
00662  =                                                                         =
00663  =                             Private methods                             =
00664  =                                                                         =
00665  ==========================================================================*/
00666 
00667 /***********************************************************************//**
00668  * @brief Initialise class members
00669  ***************************************************************************/
00670 void GXml::init_members(void)
00671 {
00672     // Initialise members
00673     m_root.clear();
00674 
00675     // Return
00676     return;
00677 }
00678 
00679 
00680 /***********************************************************************//**
00681  * @brief Copy class members
00682  *
00683  * @param[in] xml Object from which members which should be copied.
00684  ***************************************************************************/
00685 void GXml::copy_members(const GXml& xml)
00686 {
00687     // Copy attributes
00688     m_root = xml.m_root;
00689 
00690     // Return
00691     return;
00692 }
00693 
00694 
00695 /***********************************************************************//**
00696  * @brief Delete class members
00697  ***************************************************************************/
00698 void GXml::free_members(void)
00699 {
00700     // Return
00701     return;
00702 }
00703 
00704 
00705 /***********************************************************************//**
00706  * @brief Parse XML URL
00707  *
00708  * @param[in] url Unified Resource Locator.
00709  *
00710  * @exception GException::xml_syntax_error
00711  *            XML syntax error.
00712  *
00713  * Parses either a XML file or a XML text string and creates all associated
00714  * nodes. The XML file is split into segments, made either of text or of
00715  * tags.
00716  ***************************************************************************/
00717 void GXml::parse(const GUrl& url)
00718 {
00719     // Initialise parser
00720     int         c;
00721     bool        in_markup  = false;
00722     bool        in_comment = false;
00723     std::string segment;
00724     GXmlNode*   current = &m_root;
00725 
00726     // Main parsing loop
00727     while ((c = url.get_char()) != EOF) {
00728 
00729         // Convert special characters into line feeds
00730         if (c == '\x85' || c == L'\x2028') {
00731             if (in_markup) {
00732                  throw GException::xml_syntax_error(G_PARSE, segment,
00733                                    "invalid character encountered");
00734             }
00735             else {
00736                 c = '\x0a';
00737             }
00738         }
00739 
00740         // Skip all linefeeds (to avoid extra linefeeds in text segments)
00741         if (c == '\x0a') {
00742             continue;
00743         }
00744 
00745         // If we are not within a markup and if a markup is reached then
00746         // add the text segment to the nodes and switch to in_markup mode
00747         if (in_markup == false) {
00748 
00749             // Markup start reached?
00750             if (c == '<') {
00751 
00752                 // Add text segment to nodes (ignores empty segments)
00753                 process_text(&current, segment);
00754 
00755                 // Prepare new segment and signal that we are within tag
00756                 segment.clear();
00757                 segment.append(1, (char)c);
00758                 in_markup = true;
00759 
00760             }
00761 
00762             // Markup stop encountered?
00763             else if (c == '>') {
00764                  segment.append(1, (char)c);
00765                  throw GException::xml_syntax_error(G_PARSE, segment,
00766                        "unexpected closing bracket \">\" encountered");
00767             }
00768 
00769             // ... otherwise add character to segment
00770             else {
00771                 segment.append(1, (char)c);
00772             }
00773         }
00774 
00775         // If we are within a markup and if a markup end is reached then
00776         // process the markup and switch to not in_tag mode
00777         else {
00778 
00779             // Markup stop reached?
00780             if (c == '>') {
00781 
00782                 // Append character to segment
00783                 segment.append(1, (char)c);
00784 
00785                 // If we are in comment then check if this is the end of
00786                 // the comment
00787                 if (in_comment) {
00788                     int n = segment.length();
00789                     if (n > 2) {
00790                         if (segment.compare(n-3,3,"-->") == 0) {
00791                             in_comment = false;
00792                         }
00793                     }
00794                 }
00795 
00796                 // If we are not in the comment, then process markup
00797                 if (!in_comment) {
00798 
00799                     // Process markup
00800                     process_markup(&current, segment);
00801 
00802                     // Prepare new segment and signal that we are not
00803                     // within markup
00804                     segment.clear();
00805                     in_markup = false;
00806                 }
00807             }
00808 
00809             // Markup start encountered?
00810             else if (!in_comment && c == '<') {
00811 
00812                 // Append character to segment
00813                 segment.append(1, (char)c);
00814 
00815                 // If we encounter an opening bracket then throw an exception
00816                 throw GException::xml_syntax_error(G_PARSE, segment,
00817                       "unexpected opening bracket \"<\" encountered");
00818             }
00819 
00820             // ... otherwise add character to segment
00821             else {
00822                 segment.append(1, (char)c);
00823                 if (!in_comment && segment == "<!--") {
00824                     in_comment = true;
00825                 }
00826             }
00827         }
00828 
00829     } // endwhile: main parsing loop
00830 
00831     // Process any pending segment
00832     if (segment.size() > 0) {
00833         if (in_markup) {
00834             process_markup(&current, segment);
00835         }
00836         else {
00837             process_text(&current, segment);
00838         }
00839     }
00840 
00841     // Verify that we are back to the root node
00842     if (current != &m_root) {
00843         std::string message = "closing tag ";
00844         GXmlElement* element = dynamic_cast<GXmlElement*>(current);
00845         if (element != NULL) {
00846             message += "for GXmlElement \""+element->name()+"\"";
00847         }
00848         message += " is missing";
00849         throw GException::xml_syntax_error(G_PARSE, "", message);
00850     }
00851 
00852     // Return
00853     return;
00854 }
00855 
00856 
00857 /***********************************************************************//**
00858  * @brief Process markup segment
00859  *
00860  * @param[in] current Handle to current node.
00861  * @param[in] segment Segment string.
00862  *
00863  * Process markup segment.
00864  ***************************************************************************/
00865 void GXml::process_markup(GXmlNode** current, const std::string& segment)
00866 {
00867     // Determine segment tag type
00868     MarkupType type = get_markuptype(segment);
00869 
00870     // Do tag specific processing
00871     switch (type) {
00872 
00873     // Handle element start tag
00874     case MT_ELEMENT_START:
00875         {
00876             // Create new element node, set its parent, append it to the
00877             // current node and make it the current node
00878             GXmlElement element(segment);
00879             element.parent(*current);
00880             (*current)->append(element);
00881             int last = (*current)->size() - 1;
00882             (*current) = (*(*current))[last];
00883         }
00884         break;
00885 
00886     // Handle element end tag
00887     case MT_ELEMENT_END:
00888         {
00889             // Check if we expect an element end tag
00890             if ((*current)->type() != GXmlNode::NT_ELEMENT) {
00891                 throw GException::xml_syntax_error(G_PROCESS, segment,
00892                       "unexpected element end tag encountered");
00893             }
00894 
00895             // Check if we have the correct end tag
00896             GXmlElement* element = (GXmlElement*)(*current);
00897             element->parse_stop(segment);
00898 
00899             // Set current node pointer back to parent of the current node
00900             (*current) = element->parent();
00901         }
00902         break;
00903 
00904     // Append empty-element tag
00905     case MT_ELEMENT_EMPTY:
00906         {
00907             GXmlElement element(segment.substr(1,segment.length()-3));
00908             element.parent(*current);
00909             (*current)->append(element);
00910         }
00911         break;
00912 
00913     // Append comment markup
00914     case MT_COMMENT:
00915         {
00916             // Create a new comment node, set its parent and append it to the
00917             // current node
00918             GXmlComment comment(segment);
00919             comment.parent(*current);
00920             (*current)->append(comment);
00921         }
00922         break;
00923 
00924     // Declaration markup
00925     case MT_DECLARATION:
00926         {
00927             // Verify if declaration tag is allowed
00928             if (*current != &m_root) {
00929                 throw GException::xml_syntax_error(G_PROCESS, segment,
00930                       "unexpected declaration markup encountered");
00931             }
00932             if (!m_root.is_empty()) {
00933                 throw GException::xml_syntax_error(G_PROCESS, segment,
00934                       "declaration markup only allowed in first line");
00935             }
00936 
00937             // Create temporary element to read in declaration attributes
00938             GXmlElement* element = new GXmlElement(segment);
00939             size_t       pos     = 5;
00940             while (pos != std::string::npos) {
00941                 element->parse_attribute(&pos, segment);
00942             }
00943 
00944             // Set attribute values
00945             std::string version    = element->attribute("version");
00946             std::string encoding   = element->attribute("encoding");
00947             std::string standalone = element->attribute("standalone");
00948             if (version.length() > 0) {
00949                 m_root.version(version);
00950             }
00951             if (encoding.length() > 0) {
00952                 m_root.encoding(encoding);
00953             }
00954             if (standalone.length() > 0) {
00955                 m_root.standalone(standalone);
00956             }
00957 
00958             // Delete temporary element
00959             delete element;
00960         }
00961         break;
00962 
00963     // Processing tag
00964     case MT_PROCESSING:
00965         {
00966             // Create a new PI node, set its parent and append it to the
00967             // current node
00968             GXmlPI pi(segment);
00969             pi.parent(*current);
00970             (*current)->append(pi);
00971         }
00972         break;
00973 
00974     // Invalid tag, throw an error
00975     case MT_INVALID:
00976         throw GException::xml_syntax_error(G_PROCESS, segment, "invalid tag");
00977         break;
00978     }
00979 
00980     // Return
00981     return;
00982 }
00983 
00984 
00985 /***********************************************************************//**
00986  * @brief Process text segment
00987  *
00988  * @param[in] current Handle to current node.
00989  * @param[in] segment Segment string.
00990  *
00991  * Process text segment.
00992  ***************************************************************************/
00993 void GXml::process_text(GXmlNode** current, const std::string& segment)
00994 {
00995     // Continue only if text segment is not empty
00996     if (segment.size() > 0) {
00997 
00998         // Continue only if non whitespace characters are found
00999         size_t pos = segment.find_first_not_of("\x20\x09\x0d\x0a\x85");
01000         if (pos != std::string::npos) {
01001 
01002             // Append node
01003             (*current)->append(GXmlText(segment));
01004 
01005         } // endif: there was not only whitespace
01006 
01007     } // endif: segment was not empty
01008 
01009     // Return
01010     return;
01011 }
01012 
01013 
01014 /***********************************************************************//**
01015  * @brief Get Markup type of segment
01016  *
01017  * @param[in] segment Segment for which Markup Type should be determined.
01018  *
01019  * Returns Markup Type of segment.
01020  ***************************************************************************/
01021 GXml::MarkupType GXml::get_markuptype(const std::string& segment) const
01022 {
01023     // Initialise with invalid Markup Type
01024     MarkupType type = MT_INVALID;
01025 
01026     // Get length of segment
01027     int n = segment.length();
01028 
01029     // Check for comment
01030     if (n >= 7 && (segment.compare(0,4,"<!--") == 0) &&
01031                   (segment.compare(n-3,3,"-->") == 0)) {
01032         type = MT_COMMENT;
01033     }
01034 
01035     // Check for declaration
01036     else if (n >= 7 && (segment.compare(0,6,"<?xml ") == 0) &&
01037                        (segment.compare(n-2,2,"?>") == 0)) {
01038         type = MT_DECLARATION;
01039     }
01040 
01041     // Check for processing instruction
01042     else if (n >= 4 && (segment.compare(0,2,"<?") == 0) &&
01043                        (segment.compare(n-2,2,"?>") == 0)) {
01044         type = MT_PROCESSING;
01045     }
01046 
01047     // Check for empty element tag
01048     else if (n >= 3 && (segment.compare(0,1,"<") == 0) &&
01049                        (segment.compare(n-2,2,"/>") == 0)) {
01050         type = MT_ELEMENT_EMPTY;
01051     }
01052 
01053     // Check for element end tag
01054     else if (n >= 3 && (segment.compare(0,2,"</") == 0) &&
01055                        (segment.compare(n-1,1,">") == 0)) {
01056         type = MT_ELEMENT_END;
01057     }
01058 
01059     // Check for element start tag
01060     else if (n >= 2 && (segment.compare(0,1,"<") == 0) &&
01061                        (segment.compare(n-1,1,">") == 0)) {
01062         type = MT_ELEMENT_START;
01063     }
01064 
01065     // Return type
01066     return type;
01067 }

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