GammaLib  2.1.0.dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
GXml.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * GXml.cpp - XML 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 GXml.cpp
23  * @brief XML 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 "GFilename.hpp"
34 #include "GUrlFile.hpp"
35 #include "GUrlString.hpp"
36 #include "GXml.hpp"
37 #include "GXmlNode.hpp"
38 #include "GXmlDocument.hpp"
39 #include "GXmlText.hpp"
40 #include "GXmlElement.hpp"
41 #include "GXmlComment.hpp"
42 #include "GXmlPI.hpp"
43 
44 /* __ Method name definitions ____________________________________________ */
45 #define G_LOAD "GXml::load(std::string&)"
46 #define G_PARSE "GXml::parse(GUrl&)"
47 #define G_PROCESS "GXml::process(GXmlNode*, const std::string&)"
48 
49 /* __ Macros _____________________________________________________________ */
50 
51 /* __ Coding definitions _________________________________________________ */
52 
53 /* __ Debug definitions __________________________________________________ */
54 
55 
56 /*==========================================================================
57  = =
58  = Constructors/destructors =
59  = =
60  ==========================================================================*/
61 
62 /***********************************************************************//**
63  * @brief Void constructor
64  ***************************************************************************/
66 {
67  // Initialise members
68  init_members();
69 
70  // Return
71  return;
72 }
73 
74 
75 /***********************************************************************//**
76  * @brief Copy constructor
77  *
78  * @param[in] xml XML object.
79  ***************************************************************************/
80 GXml::GXml(const GXml& xml)
81 {
82  // Initialise members
83  init_members();
84 
85  // Copy members
86  copy_members(xml);
87 
88  // Return
89  return;
90 }
91 
92 
93 /***********************************************************************//**
94  * @brief XML document constructor
95  *
96  * @param[in] xml XML text string or file name.
97  *
98  * Constructs GXml object by either parsing a text string or a file. If the
99  * @p xml argument starts with @p <?xml it is interpreted as a XML file and
100  * parsed directly. Otherwise the constructor will interpret @p xml as a
101  * filename, and opens the file for parsing.
102  ***************************************************************************/
103 GXml::GXml(const std::string& xml)
104 {
105  // Initialise members
106  init_members();
107 
108  // If the string is an XML text then parse it directly
109  if (xml.compare(0, 5, "<?xml") == 0) {
110  GUrlString url(xml);
111  read(url);
112  url.close();
113  }
114 
115  // ... otherwise interpret the string as a filename
116  else {
117  load(xml);
118  }
119 
120  // Return
121  return;
122 }
123 
124 
125 /***********************************************************************//**
126  * @brief Document constructor
127  *
128  * @param[in] root Root document.
129  ***************************************************************************/
131 {
132  // Initialise members
133  init_members();
134 
135  // Set document root
136  this->root(root);
137 
138  // Return
139  return;
140 }
141 
142 
143 /***********************************************************************//**
144  * @brief Destructor
145  ***************************************************************************/
147 {
148  // Free members
149  free_members();
150 
151  // Return
152  return;
153 }
154 
155 
156 /*==========================================================================
157  = =
158  = Operators =
159  = =
160  ==========================================================================*/
161 
162 /***********************************************************************//**
163  * @brief Assignment operator
164  *
165  * @param[in] xml XML object.
166  * @return XML object.
167  ***************************************************************************/
169 {
170  // Execute only if object is not identical
171  if (this != &xml) {
172 
173  // Free members
174  free_members();
175 
176  // Initialise members
177  init_members();
178 
179  // Copy members
180  copy_members(xml);
181 
182  } // endif: object was not identical
183 
184  // Return
185  return *this;
186 }
187 
188 
189 /***********************************************************************//**
190  * @brief Return pointer to child of XML document root element
191  *
192  * @param[in] index Node index [0,...,size()-1].
193  * @return Pointer to child of XML document root element.
194  *
195  * Returns a pointer to the child number @p index of the XML document root
196  * element. An exception will be thrown if the @p index is not valid.
197  ***************************************************************************/
198 GXmlNode* GXml::operator[](const int& index)
199 {
200  // Return pointer
201  return m_root[index];
202 }
203 
204 
205 /***********************************************************************//**
206  * @brief Return pointer to child of XML document root element (const variant)
207  *
208  * @param[in] index Node index [0,...,size()-1].
209  * @return Pointer to child of XML document root element.
210  *
211  * Returns a pointer to the child number @p index of the XML document root
212  * element. An exception will be thrown if the @p index is not valid.
213  ***************************************************************************/
214 const GXmlNode* GXml::operator[](const int& index) const
215 {
216  // Return pointer
217  return m_root[index];
218 }
219 
220 
221 /*==========================================================================
222  = =
223  = Public methods =
224  = =
225  ==========================================================================*/
226 
227 /***********************************************************************//**
228  * @brief Clear XML object
229  *
230  * Resets XML object to a clean initial state.
231  ***************************************************************************/
232 void GXml::clear(void)
233 {
234  // Free memory and initialise members
235  free_members();
236  init_members();
237 
238  // Return
239  return;
240 }
241 
242 
243 /***********************************************************************//**
244  * @brief Clone XML object
245  *
246  * @return Pointer to deep copy of XML object.
247  ***************************************************************************/
248 GXml* GXml::clone(void) const
249 {
250  // Clone object
251  return new GXml(*this);
252 }
253 
254 
255 /***********************************************************************//**
256  * @brief Set child node in XML document root
257  *
258  * @param[in] index Child node index [0,...,size()-1].
259  * @param[in] node XML child node.
260  * @return Pointer to deep copy of child node.
261  *
262  * Set @p node with @p index of XML document root.
263  ***************************************************************************/
264 GXmlNode* GXml::set(const int& index, const GXmlNode& node)
265 {
266  // Set node and return pointer
267  return (m_root.set(index, node));
268 }
269 
270 
271 /***********************************************************************//**
272  * @brief Append child node to XML document root
273  *
274  * @param[in] node Child node.
275  * @return Pointer to appended child node.
276  *
277  * Appends node to XML document root by making a deep copy of the @p node.
278  ***************************************************************************/
280 {
281  // Append node and return pointer
282  return (m_root.append(node));
283 }
284 
285 
286 /***********************************************************************//**
287  * @brief Append child node to XML document root
288  *
289  * @param[in] segment XML child node.
290  * @return Pointer to appended child node.
291  *
292  * Appends XML element that is constructed from a text @p segment. The text
293  * segment is parsed and the element name and attributes are extracted using
294  * the GXmlElement::parse_start() method. The method returns a pointer to the
295  * XML element child node that has been appended.
296  ***************************************************************************/
297 GXmlElement* GXml::append(const std::string& segment)
298 {
299  // Append node and return pointer
300  return (m_root.append(segment));
301 }
302 
303 
304 /***********************************************************************//**
305  * @brief Insert child node into XML document root
306  *
307  * @param[in] index Child node index [0,...,size()-1].
308  * @param[in] node XML child node.
309  * @return Pointer to inserted child node.
310  *
311  * Inserts the XML child @p node before the node with the specified @p index.
312  * A deep copy of the node will be made and the pointer to this node will be
313  * stored.
314  ***************************************************************************/
315 GXmlNode* GXml::insert(const int& index, const GXmlNode& node)
316 {
317  // Insert node and return pointer
318  return (m_root.insert(index, node));
319 }
320 
321 
322 /***********************************************************************//**
323  * @brief Remove child node from XML document root
324  *
325  * @param[in] index Child node index [0,...,size()-1].
326  *
327  * Remove XML child node at @p index from the XML document root.
328  ***************************************************************************/
329 void GXml::remove(const int& index)
330 {
331  // Remove node
332  m_root.remove(index);
333 
334  // Return
335  return;
336 }
337 
338 
339 /***********************************************************************//**
340  * @brief Reserve space for child nodes in XML document root
341  *
342  * @param[in] num Number of nodes.
343  *
344  * Reserves space for @p num nodes in the XML document root.
345  ***************************************************************************/
346 void GXml::reserve(const int& num)
347 {
348  // Reservers space node
349  m_root.reserve(num);
350 
351  // Return
352  return;
353 }
354 
355 
356 /***********************************************************************//**
357  * @brief Append all XML child nodes from another XML node in the XML
358  * document root
359  *
360  * @param[in] node XML child node.
361  *
362  * Append all XML child nodes found in @p node to the XML document root.
363  * Nodes are copied deeply so that they live now on their on in the actual
364  * object.
365  ***************************************************************************/
366 void GXml::extend(const GXmlNode& node)
367 {
368  // Extend node
369  m_root.extend(node);
370 
371  // Return
372  return;
373 }
374 
375 
376 /***********************************************************************//**
377  * @brief Return number of child elements in XML document root
378  *
379  * @return Number of child elements in XML document root.
380  *
381  * Returns the number of GXmlElement child elements of the XML document root.
382  * GXMLElement child elements are nodes of type NT_ELEMENT.
383  ***************************************************************************/
384 int GXml::elements(void) const
385 {
386  // Return number
387  return m_root.elements();
388 }
389 
390 
391 /***********************************************************************//**
392  * @brief Return number of child elements with a given name in XML
393  * document root
394  *
395  * @param[in] name Name of child elements.
396  * @return Number of child elements with a given @p name in XML
397  * document root.
398  *
399  * Returns the number of GXMLElement child elements of the XML document root
400  * that have a given @p name. GXmlElement child elements are nodes of type
401  * NT_ELEMENT.
402  ***************************************************************************/
403 int GXml::elements(const std::string& name) const
404 {
405  // Return number
406  return m_root.elements(name);
407 }
408 
409 
410 /***********************************************************************//**
411  * @brief Return pointer to child element
412  *
413  * @param[in] index Node index [0,...,elements()-1].
414  * @return Pointer to child element.
415  *
416  * Returns a pointer to the child number @p index of the XML document root.
417  * An exception will be thrown if the @p index is not valid.
418  ***************************************************************************/
419 GXmlElement* GXml::element(const int& index)
420 {
421  // Return pointer
422  return m_root.element(index);
423 }
424 
425 
426 /***********************************************************************//**
427  * @brief Return pointer to child element (const variant)
428  *
429  * @param[in] index Node index [0,...,elements()-1].
430  * @return Pointer to child element.
431  *
432  * Returns a pointer to the child number @p index of the XML document root.
433  * An exception will be thrown if the @p index is not valid.
434  ***************************************************************************/
435 const GXmlElement* GXml::element(const int& index) const
436 {
437  // Return pointer
438  return m_root.element(index);
439 }
440 
441 
442 /***********************************************************************//**
443  * @brief Return pointer to child element by hierarchy
444  *
445  * @param[in] name Child element hierarchy.
446  * @return Pointer to child element.
447  *
448  * Returns a pointer to the child element described by a hierarchy of the
449  * following syntax
450  *
451  * params > param[1] > value > struct
452  *
453  * The > symbols indicate subsequent hierarchy levels, the square brackets
454  * provides the index in case that multiple tags with the same name exist
455  * at a given hierarchy level. Omitting the index means that the first
456  * tag with the specified name is accessed.
457  ***************************************************************************/
458 GXmlElement* GXml::element(const std::string& name)
459 {
460  // Return pointer
461  return m_root.element(name);
462 }
463 
464 
465 /***********************************************************************//**
466  * @brief Return pointer to child element by hierarchy (const version)
467  *
468  * @param[in] name Child element hierarchy.
469  * @return Pointer to child element.
470  *
471  * Returns a pointer to the child element described by a hierarchy of the
472  * following syntax
473  *
474  * params > param[1] > value > struct
475  *
476  * The > symbols indicate subsequent hierarchy levels, the square brackets
477  * provides the index in case that multiple tags with the same name exist
478  * at a given hierarchy level. Omitting the index means that the first
479  * tag with the specified name is accessed.
480  ***************************************************************************/
481 const GXmlElement* GXml::element(const std::string& name) const
482 {
483  // Return pointer
484  return m_root.element(name);
485 }
486 
487 
488 /***********************************************************************//**
489  * @brief Return pointer to child element of a given name
490  *
491  * @param[in] name Name of child element.
492  * @param[in] index Node index [0,...,elements()-1].
493  * @return Pointer to child element.
494  *
495  * Returns a pointer to the child number @p index with @p name of the XML
496  * document root. An exception will be thrown if the @p index is not valid.
497  ***************************************************************************/
498 GXmlElement* GXml::element(const std::string& name, const int& index)
499 {
500  // Return pointer
501  return m_root.element(name, index);
502 }
503 
504 
505 /***********************************************************************//**
506  * @brief Return pointer to child element of a given name (const variant)
507  *
508  * @param[in] name Name of child element.
509  * @param[in] index Node index [0,...,elements()-1].
510  * @return Pointer to child element.
511  *
512  * Returns a pointer to the child number @p index with @p name of the XML
513  * document root. An exception will be thrown if the @p index is not valid.
514  ***************************************************************************/
515 const GXmlElement* GXml::element(const std::string& name, const int& index) const
516 {
517  // Return pointer
518  return m_root.element(name, index);
519 }
520 
521 
522 /***********************************************************************//**
523  * @brief Load XML document from file
524  *
525  * @param[in] filename File name.
526  *
527  * @exception GException::file_error
528  * Unable to open file.
529  *
530  * Loads a XML document from a file by reading from the file's Unified
531  * Resource Locator (URL). The read() method is invoked for this purpose.
532  *
533  * The method uses the GUrlFile file opening constructor to open the URL.
534  * This constructor will automatically expand any environment variables that
535  * are present in the filename.
536  *
537  * @todo Ideally, we would like to extract the URL type from the filename
538  * so that any kind of URL can be used for loading.
539  ***************************************************************************/
540 void GXml::load(const GFilename& filename)
541 {
542  // Throw an exception if file does not exist
543  if (!filename.exists()) {
544  std::string msg = "Unable to open file \""+filename.url()+"\". Please "
545  "specify a valid file name.";
546  throw GException::file_error(G_LOAD, msg);
547  }
548 
549  // Open XML URL as file for reading
550  GUrlFile url(filename.url().c_str(), "r");
551 
552  // Read XML document from URL
553  read(url);
554 
555  // Close URL
556  url.close();
557 
558  // Store filename in XML document
559  m_root.filename(filename);
560 
561  // Return
562  return;
563 }
564 
565 
566 /***********************************************************************//**
567  * @brief Save XML document into file
568  *
569  * @param[in] filename File name.
570  *
571  * Saves the XML document into a file by writing into the file's Unified
572  * Resource Locator (URL). The write() method is invoked for this purpose.
573  *
574  * The method uses the GUrlFile file opening constructor to open the URL.
575  * This constructor will automatically expand any environment variables that
576  * are present in the filename.
577  *
578  * @todo Ideally, we would like to extract the URL type from the filename
579  * so that any kind of URL can be used for loading.
580  ***************************************************************************/
581 void GXml::save(const GFilename& filename) const
582 {
583  // Open XML file for writing
584  GUrlFile url(filename.url().c_str(), "w");
585 
586  // Store filename in XML document (circumvent const correctness)
587  const_cast<GXmlDocument*>(&m_root)->filename(filename);
588 
589  // Write XML document
590  write(url, 0);
591 
592  // Close file
593  url.close();
594 
595  // Return
596  return;
597 }
598 
599 
600 /***********************************************************************//**
601  * @brief Read XML document from URL
602  *
603  * @param[in] url Unified Resource Locator.
604  *
605  * Reads in the XML document by parsing a Unified Resource Locator of any
606  * type.
607  ***************************************************************************/
608 void GXml::read(const GUrl& url)
609 {
610  // Clear object
611  clear();
612 
613  // Parse URL
614  parse(url);
615 
616  // Return
617  return;
618 }
619 
620 
621 /***********************************************************************//**
622  * @brief Write XML document into URL
623  *
624  * @param[in] url Unified Resource Locator.
625  * @param[in] indent Indentation (default = 0).
626  *
627  * Writes the XML document in a Unified Resource Locator. Formatting of the
628  * document can be adapted using the @p indent parameter.
629  ***************************************************************************/
630 void GXml::write(GUrl& url, const int& indent) const
631 {
632  // Write XML document
633  m_root.write(url);
634 
635  // Return
636  return;
637 }
638 
639 
640 /***********************************************************************//**
641  * @brief Print XML object
642  *
643  * @param[in] chatter Chattiness.
644  * @param[in] indent Text indentation.
645  * @return String containing XML object.
646  ***************************************************************************/
647 std::string GXml::print(const GChatter& chatter, const int& indent) const
648 {
649  // Initialise result string
650  std::string result;
651 
652  // Continue only if chatter is not silent
653  if (chatter != SILENT) {
654 
655  // Append header
656  result.append("=== GXml ===");
657 
658  // Append model
659  result.append("\n"+m_root.print(chatter, 0));
660 
661  } // endif: chatter was not silent
662 
663  // Return result
664  return result;
665 }
666 
667 
668 /***********************************************************************//**
669  * @brief Print XML object
670  *
671  * @param[in] chatter Chattiness.
672  * @return String containing XML object.
673  ***************************************************************************/
674 std::string GXml::print(const GChatter& chatter) const
675 {
676  // Set result string
677  std::string result = print(chatter, 0);
678 
679  // Return result
680  return result;
681 }
682 
683 
684 /*==========================================================================
685  = =
686  = Private methods =
687  = =
688  ==========================================================================*/
689 
690 /***********************************************************************//**
691  * @brief Initialise class members
692  ***************************************************************************/
694 {
695  // Initialise members
696  m_root.clear();
697 
698  // Return
699  return;
700 }
701 
702 
703 /***********************************************************************//**
704  * @brief Copy class members
705  *
706  * @param[in] xml Object from which members which should be copied.
707  ***************************************************************************/
708 void GXml::copy_members(const GXml& xml)
709 {
710  // Copy attributes
711  m_root = xml.m_root;
712 
713  // Return
714  return;
715 }
716 
717 
718 /***********************************************************************//**
719  * @brief Delete class members
720  ***************************************************************************/
722 {
723  // Return
724  return;
725 }
726 
727 
728 /***********************************************************************//**
729  * @brief Parse XML URL
730  *
731  * @param[in] url Unified Resource Locator.
732  *
733  * @exception GException::invalid_value
734  * XML syntax error.
735  *
736  * Parses either a XML file or a XML text string and creates all associated
737  * nodes. The XML file is split into segments, made either of text or of
738  * tags.
739  ***************************************************************************/
740 void GXml::parse(const GUrl& url)
741 {
742  // Initialise parser
743  int c;
744  bool in_markup = false;
745  bool in_comment = false;
746  std::string segment;
747  GXmlNode* current = &m_root;
748 
749  // Main parsing loop
750  while ((c = url.get_char()) != EOF) {
751 
752  // Convert special characters into line feeds
753  if (c == '\x85' || c == L'\x2028') {
754  if (in_markup) {
755  std::string msg = "Invalid character with ASCII code "+
756  gammalib::str(c)+" encountered in XML "
757  "segment \""+segment+"\". Please verify "
758  "the XML format.";
760  }
761  else {
762  c = '\x0a';
763  }
764  }
765 
766  // Skip all linefeeds (to avoid extra linefeeds in text segments)
767  if (c == '\x0a') {
768  continue;
769  }
770 
771  // If we are not within a markup and if a markup is reached then
772  // add the text segment to the nodes and switch to in_markup mode
773  if (in_markup == false) {
774 
775  // Markup start reached?
776  if (c == '<') {
777 
778  // Add text segment to nodes (ignores empty segments)
779  process_text(&current, segment);
780 
781  // Prepare new segment and signal that we are within tag
782  segment.clear();
783  segment.append(1, (char)c);
784  in_markup = true;
785 
786  }
787 
788  // Markup stop encountered?
789  else if (c == '>') {
790  segment.append(1, (char)c);
791  std::string msg = "Unexpected closing bracket \">\" "
792  "encountered in XML segment \""+segment+
793  "\". Please verify the XML format.";
795  }
796 
797  // ... otherwise add character to segment
798  else {
799  segment.append(1, (char)c);
800  }
801  }
802 
803  // If we are within a markup and if a markup end is reached then
804  // process the markup and switch to not in_tag mode
805  else {
806 
807  // Markup stop reached?
808  if (c == '>') {
809 
810  // Append character to segment
811  segment.append(1, (char)c);
812 
813  // If we are in comment then check if this is the end of
814  // the comment
815  if (in_comment) {
816  int n = segment.length();
817  if (n > 2) {
818  if (segment.compare(n-3,3,"-->") == 0) {
819  in_comment = false;
820  }
821  }
822  }
823 
824  // If we are not in the comment, then process markup
825  if (!in_comment) {
826 
827  // Process markup
828  process_markup(&current, segment);
829 
830  // Prepare new segment and signal that we are not
831  // within markup
832  segment.clear();
833  in_markup = false;
834  }
835  }
836 
837  // Markup start encountered?
838  else if (!in_comment && c == '<') {
839 
840  // Append character to segment
841  segment.append(1, (char)c);
842 
843  // Throw an exception
844  std::string msg = "Unexpected opening bracket \"<\" "
845  "encountered in XML segment \""+segment+
846  "\". Please verify the XML format.";
848  }
849 
850  // ... otherwise add character to segment
851  else {
852  segment.append(1, (char)c);
853  if (!in_comment && segment == "<!--") {
854  in_comment = true;
855  }
856  }
857  }
858 
859  } // endwhile: main parsing loop
860 
861  // Process any pending segment
862  if (segment.size() > 0) {
863  if (in_markup) {
864  process_markup(&current, segment);
865  }
866  else {
867  process_text(&current, segment);
868  }
869  }
870 
871  // Verify that we are back to the root node
872  if (current != &m_root) {
873  std::string msg = "Closing tag ";
874  GXmlElement* element = dynamic_cast<GXmlElement*>(current);
875  if (element != NULL) {
876  msg += "for GXmlElement \""+element->name()+"\"";
877  }
878  msg += " is missing. Please verify the XML format.";
880  }
881 
882  // Return
883  return;
884 }
885 
886 
887 /***********************************************************************//**
888  * @brief Process markup segment
889  *
890  * @param[in] current Handle to current node.
891  * @param[in] segment Segment string.
892  *
893  * @exception GException::invalid_value
894  * XML syntax error encoutered.
895  *
896  * Process markup segment.
897  ***************************************************************************/
898 void GXml::process_markup(GXmlNode** current, const std::string& segment)
899 {
900  // Determine segment tag type
901  MarkupType type = get_markuptype(segment);
902 
903  // Do tag specific processing
904  switch (type) {
905 
906  // Handle element start tag
907  case MT_ELEMENT_START:
908  {
909  // Create new element node, set its parent, append it to the
910  // current node and make it the current node
911  GXmlElement element(segment);
912  element.parent(*current);
913  (*current)->append(element);
914  int last = (*current)->size() - 1;
915  (*current) = (*(*current))[last];
916  }
917  break;
918 
919  // Handle element end tag
920  case MT_ELEMENT_END:
921  {
922  // Check if we expect an element end tag
923  if ((*current)->type() != GXmlNode::NT_ELEMENT) {
924  std::string msg = "Unexpected element end tag encountered "
925  "in XML segment \""+segment+"\". Please "
926  "verify the XML format.";
928  }
929 
930  // Check if we have the correct end tag
931  GXmlElement* element = (GXmlElement*)(*current);
932  element->parse_stop(segment);
933 
934  // Set current node pointer back to parent of the current node
935  (*current) = element->parent();
936  }
937  break;
938 
939  // Append empty-element tag
940  case MT_ELEMENT_EMPTY:
941  {
942  GXmlElement element(segment.substr(1,segment.length()-3));
943  element.parent(*current);
944  (*current)->append(element);
945  }
946  break;
947 
948  // Append comment markup
949  case MT_COMMENT:
950  {
951  // Create a new comment node, set its parent and append it to the
952  // current node
953  GXmlComment comment(segment);
954  comment.parent(*current);
955  (*current)->append(comment);
956  }
957  break;
958 
959  // Declaration markup
960  case MT_DECLARATION:
961  {
962  // Verify if declaration tag is allowed
963  if (*current != &m_root) {
964  std::string msg = "Unexpected declaration markup encountered "
965  "in XML segment \""+segment+"\". Please "
966  "verify the XML format.";
968  }
969  if (!m_root.is_empty()) {
970  std::string msg = "Declaration markup encountered in a line "
971  "different from the first line in XML "
972  "segment \""+segment+"\". Please "
973  "verify the XML format.";
975  }
976 
977  // Create temporary element to read in declaration attributes
978  GXmlElement* element = new GXmlElement(segment);
979  size_t pos = 5;
980  while (pos != std::string::npos) {
981  element->parse_attribute(&pos, segment);
982  }
983 
984  // Set attribute values
985  std::string version = element->attribute("version");
986  std::string encoding = element->attribute("encoding");
987  std::string standalone = element->attribute("standalone");
988  if (version.length() > 0) {
989  m_root.version(version);
990  }
991  if (encoding.length() > 0) {
992  m_root.encoding(encoding);
993  }
994  if (standalone.length() > 0) {
995  m_root.standalone(standalone);
996  }
997 
998  // Delete temporary element
999  delete element;
1000  }
1001  break;
1002 
1003  // Processing tag
1004  case MT_PROCESSING:
1005  {
1006  // Create a new PI node, set its parent and append it to the
1007  // current node
1008  GXmlPI pi(segment);
1009  pi.parent(*current);
1010  (*current)->append(pi);
1011  }
1012  break;
1013 
1014  // Invalid tag, throw an error
1015  case MT_INVALID:
1016  std::string msg = "Invalid tag in XML segment \""+segment+"\". Please "
1017  "verify the XML format.";
1019  break;
1020  }
1021 
1022  // Return
1023  return;
1024 }
1025 
1026 
1027 /***********************************************************************//**
1028  * @brief Process text segment
1029  *
1030  * @param[in] current Handle to current node.
1031  * @param[in] segment Segment string.
1032  *
1033  * Process text segment.
1034  ***************************************************************************/
1035 void GXml::process_text(GXmlNode** current, const std::string& segment)
1036 {
1037  // Continue only if text segment is not empty
1038  if (segment.size() > 0) {
1039 
1040  // Continue only if non whitespace characters are found
1041  size_t pos = segment.find_first_not_of("\x20\x09\x0d\x0a\x85");
1042  if (pos != std::string::npos) {
1043 
1044  // Append node
1045  (*current)->append(GXmlText(segment));
1046 
1047  } // endif: there was not only whitespace
1048 
1049  } // endif: segment was not empty
1050 
1051  // Return
1052  return;
1053 }
1054 
1055 
1056 /***********************************************************************//**
1057  * @brief Get Markup type of segment
1058  *
1059  * @param[in] segment Segment for which Markup Type should be determined.
1060  *
1061  * Returns Markup Type of segment.
1062  ***************************************************************************/
1063 GXml::MarkupType GXml::get_markuptype(const std::string& segment) const
1064 {
1065  // Initialise with invalid Markup Type
1066  MarkupType type = MT_INVALID;
1067 
1068  // Get length of segment
1069  int n = segment.length();
1070 
1071  // Check for comment
1072  if (n >= 7 && (segment.compare(0,4,"<!--") == 0) &&
1073  (segment.compare(n-3,3,"-->") == 0)) {
1074  type = MT_COMMENT;
1075  }
1076 
1077  // Check for declaration
1078  else if (n >= 7 && (segment.compare(0,6,"<?xml ") == 0) &&
1079  (segment.compare(n-2,2,"?>") == 0)) {
1080  type = MT_DECLARATION;
1081  }
1082 
1083  // Check for processing instruction
1084  else if (n >= 4 && (segment.compare(0,2,"<?") == 0) &&
1085  (segment.compare(n-2,2,"?>") == 0)) {
1086  type = MT_PROCESSING;
1087  }
1088 
1089  // Check for empty element tag
1090  else if (n >= 3 && (segment.compare(0,1,"<") == 0) &&
1091  (segment.compare(n-2,2,"/>") == 0)) {
1092  type = MT_ELEMENT_EMPTY;
1093  }
1094 
1095  // Check for element end tag
1096  else if (n >= 3 && (segment.compare(0,2,"</") == 0) &&
1097  (segment.compare(n-1,1,">") == 0)) {
1098  type = MT_ELEMENT_END;
1099  }
1100 
1101  // Check for element start tag
1102  else if (n >= 2 && (segment.compare(0,1,"<") == 0) &&
1103  (segment.compare(n-1,1,">") == 0)) {
1104  type = MT_ELEMENT_START;
1105  }
1106 
1107  // Return type
1108  return type;
1109 }
Abstract XML node base class.
Definition: GXmlNode.hpp:57
GXmlNode * parent(void) const
Return parent XML node.
Definition: GXmlNode.hpp:170
XML comment node class interface definition.
void read(const GUrl &url)
Read XML document from URL.
Definition: GXml.cpp:608
void free_members(void)
Delete class members.
Definition: GXml.cpp:721
XML Processing Instruction node class.
Definition: GXmlPI.hpp:43
XML element node class interface definition.
void save(const GFilename &filename) const
Save XML document into file.
Definition: GXml.cpp:581
virtual GXmlNode * set(const int &index, const GXmlNode &node)
Set XML child node.
Definition: GXmlNode.cpp:214
const double pi
Definition: GMath.hpp:35
MarkupType
Definition: GXml.hpp:225
XML class interface definition.
String URL class.
Definition: GUrlString.hpp:42
std::string standalone(void) const
Return standalone.
GXmlDocument m_root
Root document node.
Definition: GXml.hpp:245
std::string print(const GChatter &chatter=NORMAL) const
Print XML object.
Definition: GXml.cpp:674
XML element node class.
Definition: GXmlElement.hpp:48
#define G_LOAD
Definition: GXml.cpp:45
virtual int elements(void) const
Return number of GXMLElement children of node.
Definition: GXmlNode.cpp:586
void clear(void)
Clear XML object.
Definition: GXml.cpp:232
Gammalib tools definition.
virtual void write(GUrl &url, const int &indent=0) const
Write XML document into URL.
XML PI node class interface definition.
void reserve(const int &num)
Reserve space for child nodes in XML document root.
Definition: GXml.cpp:346
void load(const GFilename &filename)
Load XML document from file.
Definition: GXml.cpp:540
void write(GUrl &url, const int &indent=0) const
Write XML document into URL.
Definition: GXml.cpp:630
File URL class interface definition.
const std::string & name(void) const
Return XML element name.
GXmlNode * insert(const int &index, const GXmlNode &node)
Insert child node into XML document root.
Definition: GXml.cpp:315
virtual void extend(const GXmlNode &node)
Append all XML child nodes from another XML node.
Definition: GXmlNode.cpp:510
virtual GXmlNode * insert(const int &index, const GXmlNode &node)
Insert XML child node.
Definition: GXmlNode.cpp:407
Abstract URL base class.
Definition: GUrl.hpp:44
void extend(const GXmlNode &node)
Append all XML child nodes from another XML node in the XML document root.
Definition: GXml.cpp:366
virtual int size(void) const
Return number of child nodes.
Definition: GXmlNode.hpp:133
void parse_attribute(size_t *pos, const std::string &segment)
Parse element attribute.
GXmlElement * element(const int &index)
Return pointer to child element.
Definition: GXml.cpp:419
int elements(void) const
Return number of child elements in XML document root.
Definition: GXml.cpp:384
const GXmlAttribute * attribute(const int &index) const
Return attribute.
void init_members(void)
Initialise class members.
Definition: GXml.cpp:693
File URL class.
Definition: GUrlFile.hpp:41
XML class.
Definition: GXml.hpp:172
Filename class.
Definition: GFilename.hpp:62
virtual void reserve(const int &num)
Reserve space for child nodes.
Definition: GXmlNode.hpp:157
bool exists(void) const
Checks whether file exists.
Definition: GFilename.cpp:223
std::string version(void) const
Return version.
virtual void close(void)
Close file.
Definition: GUrlFile.cpp:234
GXmlNode * set(const int &index, const GXmlNode &node)
Set child node in XML document root.
Definition: GXml.cpp:264
virtual void close(void)
Close file.
Definition: GUrlString.cpp:214
GChatter
Definition: GTypemaps.hpp:33
#define G_PROCESS
Definition: GXml.cpp:47
GXmlNode * operator[](const int &index)
Return pointer to child of XML document root element.
Definition: GXml.cpp:198
void remove(const int &index)
Remove child node from XML document root.
Definition: GXml.cpp:329
XML document node class interface definition.
void copy_members(const GXml &xml)
Copy class members.
Definition: GXml.cpp:708
const GXmlDocument & root(void) const
Return document root.
Definition: GXml.hpp:291
void process_markup(GXmlNode **current, const std::string &segment)
Process markup segment.
Definition: GXml.cpp:898
XML text node class interface definition.
XML document node class.
void parse(const GUrl &url)
Parse XML URL.
Definition: GXml.cpp:740
virtual int get_char(void) const =0
std::string url(void) const
Return Uniform Resource Locator (URL)
Definition: GFilename.hpp:189
GXml * clone(void) const
Clone XML object.
Definition: GXml.cpp:248
virtual GXmlElement * element(const int &index)
Return pointer to GXMLElement child.
Definition: GXmlNode.cpp:640
friend class GXmlText
Definition: GXml.hpp:177
GXml(void)
Void constructor.
Definition: GXml.cpp:65
std::string encoding(void) const
Return encoding.
virtual bool is_empty(void) const
Signals if node has no child nodes.
Definition: GXmlNode.hpp:145
GXml & operator=(const GXml &xml)
Assignment operator.
Definition: GXml.cpp:168
XML comment node class.
Definition: GXmlComment.hpp:44
Exception handler interface definition.
MarkupType get_markuptype(const std::string &segment) const
Get Markup type of segment.
Definition: GXml.cpp:1063
const GFilename & filename(void) const
Return filename.
virtual GXmlNode * append(const GXmlNode &node)
Append XML child node.
Definition: GXmlNode.cpp:287
void parse_stop(const std::string &segment)
Parse element stop segment string.
virtual ~GXml(void)
Destructor.
Definition: GXml.cpp:146
virtual std::string print(const GChatter &chatter=NORMAL, const int &indent=0) const
Print XML document.
Abstract XML node base class interface definition.
virtual void clear(void)
Clear XML document.
String URL class interface definition.
void process_text(GXmlNode **current, const std::string &segment)
Process text segment.
Definition: GXml.cpp:1035
Filename class interface definition.
GXmlNode * append(const GXmlNode &node)
Append child node to XML document root.
Definition: GXml.cpp:279
virtual void remove(const int &index)
Remove XML child node.
Definition: GXmlNode.cpp:481
std::string str(const unsigned short int &value)
Convert unsigned short integer value into string.
Definition: GTools.cpp:489
#define G_PARSE
Definition: GXml.cpp:46