GammaLib  1.7.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-2018 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  * Loads a XML document from a file by reading from the file's Unified
528  * Resource Locator (URL). The read() method is invoked for this purpose.
529  *
530  * The method uses the GUrlFile file opening constructor to open the URL.
531  * This constructor will automatically expand any environment variables that
532  * are present in the filename.
533  *
534  * @todo Ideally, we would like to extract the URL type from the filename
535  * so that any kind of URL can be used for loading.
536  ***************************************************************************/
537 void GXml::load(const GFilename& filename)
538 {
539  // Throw an exception if file does not exist
540  if (!filename.exists()) {
541  throw GException::file_open_error(G_LOAD, filename);
542  }
543 
544  // Open XML URL as file for reading
545  GUrlFile url(filename.url().c_str(), "r");
546 
547  // Read XML document from URL
548  read(url);
549 
550  // Close URL
551  url.close();
552 
553  // Store filename in XML document
554  m_root.filename(filename);
555 
556  // Return
557  return;
558 }
559 
560 
561 /***********************************************************************//**
562  * @brief Save XML document into file
563  *
564  * @param[in] filename File name.
565  *
566  * Saves the XML document into a file by writing into the file's Unified
567  * Resource Locator (URL). The write() method is invoked for this purpose.
568  *
569  * The method uses the GUrlFile file opening constructor to open the URL.
570  * This constructor will automatically expand any environment variables that
571  * are present in the filename.
572  *
573  * @todo Ideally, we would like to extract the URL type from the filename
574  * so that any kind of URL can be used for loading.
575  ***************************************************************************/
576 void GXml::save(const GFilename& filename) const
577 {
578  // Open XML file for writing
579  GUrlFile url(filename.url().c_str(), "w");
580 
581  // Store filename in XML document (circumvent const correctness)
582  const_cast<GXmlDocument*>(&m_root)->filename(filename);
583 
584  // Write XML document
585  write(url, 0);
586 
587  // Close file
588  url.close();
589 
590  // Return
591  return;
592 }
593 
594 
595 /***********************************************************************//**
596  * @brief Read XML document from URL
597  *
598  * @param[in] url Unified Resource Locator.
599  *
600  * Reads in the XML document by parsing a Unified Resource Locator of any
601  * type.
602  ***************************************************************************/
603 void GXml::read(const GUrl& url)
604 {
605  // Clear object
606  clear();
607 
608  // Parse URL
609  parse(url);
610 
611  // Return
612  return;
613 }
614 
615 
616 /***********************************************************************//**
617  * @brief Write XML document into URL
618  *
619  * @param[in] url Unified Resource Locator.
620  * @param[in] indent Indentation (default = 0).
621  *
622  * Writes the XML document in a Unified Resource Locator. Formatting of the
623  * document can be adapted using the @p indent parameter.
624  ***************************************************************************/
625 void GXml::write(GUrl& url, const int& indent) const
626 {
627  // Write XML document
628  m_root.write(url);
629 
630  // Return
631  return;
632 }
633 
634 
635 /***********************************************************************//**
636  * @brief Print XML object
637  *
638  * @param[in] chatter Chattiness.
639  * @param[in] indent Text indentation.
640  * @return String containing XML object.
641  ***************************************************************************/
642 std::string GXml::print(const GChatter& chatter, const int& indent) const
643 {
644  // Initialise result string
645  std::string result;
646 
647  // Continue only if chatter is not silent
648  if (chatter != SILENT) {
649 
650  // Append header
651  result.append("=== GXml ===");
652 
653  // Append model
654  result.append("\n"+m_root.print(chatter, 0));
655 
656  } // endif: chatter was not silent
657 
658  // Return result
659  return result;
660 }
661 
662 
663 /***********************************************************************//**
664  * @brief Print XML object
665  *
666  * @param[in] chatter Chattiness.
667  * @return String containing XML object.
668  ***************************************************************************/
669 std::string GXml::print(const GChatter& chatter) const
670 {
671  // Set result string
672  std::string result = print(chatter, 0);
673 
674  // Return result
675  return result;
676 }
677 
678 
679 /*==========================================================================
680  = =
681  = Private methods =
682  = =
683  ==========================================================================*/
684 
685 /***********************************************************************//**
686  * @brief Initialise class members
687  ***************************************************************************/
689 {
690  // Initialise members
691  m_root.clear();
692 
693  // Return
694  return;
695 }
696 
697 
698 /***********************************************************************//**
699  * @brief Copy class members
700  *
701  * @param[in] xml Object from which members which should be copied.
702  ***************************************************************************/
703 void GXml::copy_members(const GXml& xml)
704 {
705  // Copy attributes
706  m_root = xml.m_root;
707 
708  // Return
709  return;
710 }
711 
712 
713 /***********************************************************************//**
714  * @brief Delete class members
715  ***************************************************************************/
717 {
718  // Return
719  return;
720 }
721 
722 
723 /***********************************************************************//**
724  * @brief Parse XML URL
725  *
726  * @param[in] url Unified Resource Locator.
727  *
728  * @exception GException::xml_syntax_error
729  * XML syntax error.
730  *
731  * Parses either a XML file or a XML text string and creates all associated
732  * nodes. The XML file is split into segments, made either of text or of
733  * tags.
734  ***************************************************************************/
735 void GXml::parse(const GUrl& url)
736 {
737  // Initialise parser
738  int c;
739  bool in_markup = false;
740  bool in_comment = false;
741  std::string segment;
742  GXmlNode* current = &m_root;
743 
744  // Main parsing loop
745  while ((c = url.get_char()) != EOF) {
746 
747  // Convert special characters into line feeds
748  if (c == '\x85' || c == L'\x2028') {
749  if (in_markup) {
750  throw GException::xml_syntax_error(G_PARSE, segment,
751  "invalid character encountered");
752  }
753  else {
754  c = '\x0a';
755  }
756  }
757 
758  // Skip all linefeeds (to avoid extra linefeeds in text segments)
759  if (c == '\x0a') {
760  continue;
761  }
762 
763  // If we are not within a markup and if a markup is reached then
764  // add the text segment to the nodes and switch to in_markup mode
765  if (in_markup == false) {
766 
767  // Markup start reached?
768  if (c == '<') {
769 
770  // Add text segment to nodes (ignores empty segments)
771  process_text(&current, segment);
772 
773  // Prepare new segment and signal that we are within tag
774  segment.clear();
775  segment.append(1, (char)c);
776  in_markup = true;
777 
778  }
779 
780  // Markup stop encountered?
781  else if (c == '>') {
782  segment.append(1, (char)c);
783  throw GException::xml_syntax_error(G_PARSE, segment,
784  "unexpected closing bracket \">\" encountered");
785  }
786 
787  // ... otherwise add character to segment
788  else {
789  segment.append(1, (char)c);
790  }
791  }
792 
793  // If we are within a markup and if a markup end is reached then
794  // process the markup and switch to not in_tag mode
795  else {
796 
797  // Markup stop reached?
798  if (c == '>') {
799 
800  // Append character to segment
801  segment.append(1, (char)c);
802 
803  // If we are in comment then check if this is the end of
804  // the comment
805  if (in_comment) {
806  int n = segment.length();
807  if (n > 2) {
808  if (segment.compare(n-3,3,"-->") == 0) {
809  in_comment = false;
810  }
811  }
812  }
813 
814  // If we are not in the comment, then process markup
815  if (!in_comment) {
816 
817  // Process markup
818  process_markup(&current, segment);
819 
820  // Prepare new segment and signal that we are not
821  // within markup
822  segment.clear();
823  in_markup = false;
824  }
825  }
826 
827  // Markup start encountered?
828  else if (!in_comment && c == '<') {
829 
830  // Append character to segment
831  segment.append(1, (char)c);
832 
833  // If we encounter an opening bracket then throw an exception
834  throw GException::xml_syntax_error(G_PARSE, segment,
835  "unexpected opening bracket \"<\" encountered");
836  }
837 
838  // ... otherwise add character to segment
839  else {
840  segment.append(1, (char)c);
841  if (!in_comment && segment == "<!--") {
842  in_comment = true;
843  }
844  }
845  }
846 
847  } // endwhile: main parsing loop
848 
849  // Process any pending segment
850  if (segment.size() > 0) {
851  if (in_markup) {
852  process_markup(&current, segment);
853  }
854  else {
855  process_text(&current, segment);
856  }
857  }
858 
859  // Verify that we are back to the root node
860  if (current != &m_root) {
861  std::string message = "closing tag ";
862  GXmlElement* element = dynamic_cast<GXmlElement*>(current);
863  if (element != NULL) {
864  message += "for GXmlElement \""+element->name()+"\"";
865  }
866  message += " is missing";
867  throw GException::xml_syntax_error(G_PARSE, "", message);
868  }
869 
870  // Return
871  return;
872 }
873 
874 
875 /***********************************************************************//**
876  * @brief Process markup segment
877  *
878  * @param[in] current Handle to current node.
879  * @param[in] segment Segment string.
880  *
881  * Process markup segment.
882  ***************************************************************************/
883 void GXml::process_markup(GXmlNode** current, const std::string& segment)
884 {
885  // Determine segment tag type
886  MarkupType type = get_markuptype(segment);
887 
888  // Do tag specific processing
889  switch (type) {
890 
891  // Handle element start tag
892  case MT_ELEMENT_START:
893  {
894  // Create new element node, set its parent, append it to the
895  // current node and make it the current node
896  GXmlElement element(segment);
897  element.parent(*current);
898  (*current)->append(element);
899  int last = (*current)->size() - 1;
900  (*current) = (*(*current))[last];
901  }
902  break;
903 
904  // Handle element end tag
905  case MT_ELEMENT_END:
906  {
907  // Check if we expect an element end tag
908  if ((*current)->type() != GXmlNode::NT_ELEMENT) {
910  "unexpected element end tag encountered");
911  }
912 
913  // Check if we have the correct end tag
914  GXmlElement* element = (GXmlElement*)(*current);
915  element->parse_stop(segment);
916 
917  // Set current node pointer back to parent of the current node
918  (*current) = element->parent();
919  }
920  break;
921 
922  // Append empty-element tag
923  case MT_ELEMENT_EMPTY:
924  {
925  GXmlElement element(segment.substr(1,segment.length()-3));
926  element.parent(*current);
927  (*current)->append(element);
928  }
929  break;
930 
931  // Append comment markup
932  case MT_COMMENT:
933  {
934  // Create a new comment node, set its parent and append it to the
935  // current node
936  GXmlComment comment(segment);
937  comment.parent(*current);
938  (*current)->append(comment);
939  }
940  break;
941 
942  // Declaration markup
943  case MT_DECLARATION:
944  {
945  // Verify if declaration tag is allowed
946  if (*current != &m_root) {
948  "unexpected declaration markup encountered");
949  }
950  if (!m_root.is_empty()) {
952  "declaration markup only allowed in first line");
953  }
954 
955  // Create temporary element to read in declaration attributes
956  GXmlElement* element = new GXmlElement(segment);
957  size_t pos = 5;
958  while (pos != std::string::npos) {
959  element->parse_attribute(&pos, segment);
960  }
961 
962  // Set attribute values
963  std::string version = element->attribute("version");
964  std::string encoding = element->attribute("encoding");
965  std::string standalone = element->attribute("standalone");
966  if (version.length() > 0) {
967  m_root.version(version);
968  }
969  if (encoding.length() > 0) {
970  m_root.encoding(encoding);
971  }
972  if (standalone.length() > 0) {
973  m_root.standalone(standalone);
974  }
975 
976  // Delete temporary element
977  delete element;
978  }
979  break;
980 
981  // Processing tag
982  case MT_PROCESSING:
983  {
984  // Create a new PI node, set its parent and append it to the
985  // current node
986  GXmlPI pi(segment);
987  pi.parent(*current);
988  (*current)->append(pi);
989  }
990  break;
991 
992  // Invalid tag, throw an error
993  case MT_INVALID:
994  throw GException::xml_syntax_error(G_PROCESS, segment, "invalid tag");
995  break;
996  }
997 
998  // Return
999  return;
1000 }
1001 
1002 
1003 /***********************************************************************//**
1004  * @brief Process text segment
1005  *
1006  * @param[in] current Handle to current node.
1007  * @param[in] segment Segment string.
1008  *
1009  * Process text segment.
1010  ***************************************************************************/
1011 void GXml::process_text(GXmlNode** current, const std::string& segment)
1012 {
1013  // Continue only if text segment is not empty
1014  if (segment.size() > 0) {
1015 
1016  // Continue only if non whitespace characters are found
1017  size_t pos = segment.find_first_not_of("\x20\x09\x0d\x0a\x85");
1018  if (pos != std::string::npos) {
1019 
1020  // Append node
1021  (*current)->append(GXmlText(segment));
1022 
1023  } // endif: there was not only whitespace
1024 
1025  } // endif: segment was not empty
1026 
1027  // Return
1028  return;
1029 }
1030 
1031 
1032 /***********************************************************************//**
1033  * @brief Get Markup type of segment
1034  *
1035  * @param[in] segment Segment for which Markup Type should be determined.
1036  *
1037  * Returns Markup Type of segment.
1038  ***************************************************************************/
1039 GXml::MarkupType GXml::get_markuptype(const std::string& segment) const
1040 {
1041  // Initialise with invalid Markup Type
1042  MarkupType type = MT_INVALID;
1043 
1044  // Get length of segment
1045  int n = segment.length();
1046 
1047  // Check for comment
1048  if (n >= 7 && (segment.compare(0,4,"<!--") == 0) &&
1049  (segment.compare(n-3,3,"-->") == 0)) {
1050  type = MT_COMMENT;
1051  }
1052 
1053  // Check for declaration
1054  else if (n >= 7 && (segment.compare(0,6,"<?xml ") == 0) &&
1055  (segment.compare(n-2,2,"?>") == 0)) {
1056  type = MT_DECLARATION;
1057  }
1058 
1059  // Check for processing instruction
1060  else if (n >= 4 && (segment.compare(0,2,"<?") == 0) &&
1061  (segment.compare(n-2,2,"?>") == 0)) {
1062  type = MT_PROCESSING;
1063  }
1064 
1065  // Check for empty element tag
1066  else if (n >= 3 && (segment.compare(0,1,"<") == 0) &&
1067  (segment.compare(n-2,2,"/>") == 0)) {
1068  type = MT_ELEMENT_EMPTY;
1069  }
1070 
1071  // Check for element end tag
1072  else if (n >= 3 && (segment.compare(0,2,"</") == 0) &&
1073  (segment.compare(n-1,1,">") == 0)) {
1074  type = MT_ELEMENT_END;
1075  }
1076 
1077  // Check for element start tag
1078  else if (n >= 2 && (segment.compare(0,1,"<") == 0) &&
1079  (segment.compare(n-1,1,">") == 0)) {
1080  type = MT_ELEMENT_START;
1081  }
1082 
1083  // Return type
1084  return type;
1085 }
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:603
void free_members(void)
Delete class members.
Definition: GXml.cpp:716
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:576
virtual GXmlNode * set(const int &index, const GXmlNode &node)
Set XML child node.
Definition: GXmlNode.cpp:212
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:669
XML element node class.
Definition: GXmlElement.hpp:47
#define G_LOAD
Definition: GXml.cpp:45
virtual int elements(void) const
Return number of GXMLElement children of node.
Definition: GXmlNode.cpp:580
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:537
void write(GUrl &url, const int &indent=0) const
Write XML document into URL.
Definition: GXml.cpp:625
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:504
virtual GXmlNode * insert(const int &index, const GXmlNode &node)
Insert XML child node.
Definition: GXmlNode.cpp:404
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:688
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:232
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:703
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:883
XML text node class interface definition.
XML document node class.
void parse(const GUrl &url)
Parse XML URL.
Definition: GXml.cpp:735
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:634
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:1039
const GFilename & filename(void) const
Return filename.
virtual GXmlNode * append(const GXmlNode &node)
Append XML child node.
Definition: GXmlNode.cpp:284
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:1011
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:476
#define G_PARSE
Definition: GXml.cpp:46