GammaLib 2.0.0
Loading...
Searching...
No Matches
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
69
70 // Return
71 return;
72}
73
74
75/***********************************************************************//**
76 * @brief Copy constructor
77 *
78 * @param[in] xml XML object.
79 ***************************************************************************/
80GXml::GXml(const GXml& xml)
81{
82 // Initialise 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 ***************************************************************************/
103GXml::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 ***************************************************************************/
198GXmlNode* 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 ***************************************************************************/
214const 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 ***************************************************************************/
232void 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 ***************************************************************************/
248GXml* 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 ***************************************************************************/
264GXmlNode* 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 ***************************************************************************/
297GXmlElement* 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 ***************************************************************************/
315GXmlNode* 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 ***************************************************************************/
329void 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 ***************************************************************************/
346void 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 ***************************************************************************/
366void 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 ***************************************************************************/
384int 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 ***************************************************************************/
403int 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 ***************************************************************************/
419GXmlElement* 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 ***************************************************************************/
435const 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 ***************************************************************************/
458GXmlElement* 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 ***************************************************************************/
481const 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 ***************************************************************************/
498GXmlElement* 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 ***************************************************************************/
515const 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 ***************************************************************************/
540void 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 ***************************************************************************/
581void 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 ***************************************************************************/
608void 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 ***************************************************************************/
630void 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 ***************************************************************************/
647std::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 ***************************************************************************/
674std::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 ***************************************************************************/
708void 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 ***************************************************************************/
740void 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 ***************************************************************************/
898void 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 ***************************************************************************/
1035void 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 ***************************************************************************/
1063GXml::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}
#define G_PARSE
Exception handler interface definition.
Filename class interface definition.
#define G_LOAD
Gammalib tools definition.
GChatter
Definition GTypemaps.hpp:33
@ SILENT
Definition GTypemaps.hpp:34
File URL class interface definition.
String URL class interface definition.
XML comment node class interface definition.
XML document node class interface definition.
XML element node class interface definition.
Abstract XML node base class interface definition.
XML PI node class interface definition.
XML text node class interface definition.
#define G_PROCESS
Definition GXml.cpp:47
XML class interface definition.
Filename class.
Definition GFilename.hpp:62
std::string url(void) const
Return Uniform Resource Locator (URL)
bool exists(void) const
Checks whether file exists.
File URL class.
Definition GUrlFile.hpp:41
virtual void close(void)
Close file.
Definition GUrlFile.cpp:234
String URL class.
virtual void close(void)
Close file.
Abstract URL base class.
Definition GUrl.hpp:44
virtual int get_char(void) const =0
XML comment node class.
XML document node class.
std::string encoding(void) const
Return encoding.
virtual void clear(void)
Clear XML document.
virtual std::string print(const GChatter &chatter=NORMAL, const int &indent=0) const
Print XML document.
std::string version(void) const
Return version.
virtual void write(GUrl &url, const int &indent=0) const
Write XML document into URL.
std::string standalone(void) const
Return standalone.
const GFilename & filename(void) const
Return filename.
XML element node class.
void parse_stop(const std::string &segment)
Parse element stop segment string.
const GXmlAttribute * attribute(const int &index) const
Return attribute.
void parse_attribute(size_t *pos, const std::string &segment)
Parse element attribute.
const std::string & name(void) const
Return XML element name.
Abstract XML node base class.
Definition GXmlNode.hpp:57
virtual GXmlNode * append(const GXmlNode &node)
Append XML child node.
Definition GXmlNode.cpp:287
virtual void remove(const int &index)
Remove XML child node.
Definition GXmlNode.cpp:481
virtual GXmlNode * insert(const int &index, const GXmlNode &node)
Insert XML child node.
Definition GXmlNode.cpp:407
virtual GXmlElement * element(const int &index)
Return pointer to GXMLElement child.
Definition GXmlNode.cpp:640
virtual void extend(const GXmlNode &node)
Append all XML child nodes from another XML node.
Definition GXmlNode.cpp:510
virtual void reserve(const int &num)
Reserve space for child nodes.
Definition GXmlNode.hpp:157
virtual bool is_empty(void) const
Signals if node has no child nodes.
Definition GXmlNode.hpp:145
virtual GXmlNode * set(const int &index, const GXmlNode &node)
Set XML child node.
Definition GXmlNode.cpp:214
virtual int size(void) const
Return number of child nodes.
Definition GXmlNode.hpp:133
GXmlNode * parent(void) const
Return parent XML node.
Definition GXmlNode.hpp:170
virtual int elements(void) const
Return number of GXMLElement children of node.
Definition GXmlNode.cpp:586
XML Processing Instruction node class.
Definition GXmlPI.hpp:43
XML class.
Definition GXml.hpp:172
GXmlDocument m_root
Root document node.
Definition GXml.hpp:245
void parse(const GUrl &url)
Parse XML URL.
Definition GXml.cpp:740
void extend(const GXmlNode &node)
Append all XML child nodes from another XML node in the XML document root.
Definition GXml.cpp:366
friend class GXmlText
Definition GXml.hpp:177
void process_text(GXmlNode **current, const std::string &segment)
Process text segment.
Definition GXml.cpp:1035
void clear(void)
Clear XML object.
Definition GXml.cpp:232
void free_members(void)
Delete class members.
Definition GXml.cpp:721
void copy_members(const GXml &xml)
Copy class members.
Definition GXml.cpp:708
void reserve(const int &num)
Reserve space for child nodes in XML document root.
Definition GXml.cpp:346
void save(const GFilename &filename) const
Save XML document into file.
Definition GXml.cpp:581
GXmlNode * operator[](const int &index)
Return pointer to child of XML document root element.
Definition GXml.cpp:198
MarkupType
Definition GXml.hpp:225
@ MT_ELEMENT_START
Definition GXml.hpp:226
@ MT_DECLARATION
Definition GXml.hpp:230
@ MT_PROCESSING
Definition GXml.hpp:231
@ MT_COMMENT
Definition GXml.hpp:229
@ MT_ELEMENT_EMPTY
Definition GXml.hpp:228
@ MT_ELEMENT_END
Definition GXml.hpp:227
@ MT_INVALID
Definition GXml.hpp:232
GXmlElement * element(const int &index)
Return pointer to child element.
Definition GXml.cpp:419
void remove(const int &index)
Remove child node from XML document root.
Definition GXml.cpp:329
GXmlNode * append(const GXmlNode &node)
Append child node to XML document root.
Definition GXml.cpp:279
GXmlNode * set(const int &index, const GXmlNode &node)
Set child node in XML document root.
Definition GXml.cpp:264
void process_markup(GXmlNode **current, const std::string &segment)
Process markup segment.
Definition GXml.cpp:898
void load(const GFilename &filename)
Load XML document from file.
Definition GXml.cpp:540
virtual ~GXml(void)
Destructor.
Definition GXml.cpp:146
const GXmlDocument & root(void) const
Return document root.
Definition GXml.hpp:291
GXml(void)
Void constructor.
Definition GXml.cpp:65
void read(const GUrl &url)
Read XML document from URL.
Definition GXml.cpp:608
void write(GUrl &url, const int &indent=0) const
Write XML document into URL.
Definition GXml.cpp:630
void init_members(void)
Initialise class members.
Definition GXml.cpp:693
int elements(void) const
Return number of child elements in XML document root.
Definition GXml.cpp:384
std::string print(const GChatter &chatter=NORMAL) const
Print XML object.
Definition GXml.cpp:674
GXml & operator=(const GXml &xml)
Assignment operator.
Definition GXml.cpp:168
MarkupType get_markuptype(const std::string &segment) const
Get Markup type of segment.
Definition GXml.cpp:1063
GXmlNode * insert(const int &index, const GXmlNode &node)
Insert child node into XML document root.
Definition GXml.cpp:315
GXml * clone(void) const
Clone XML object.
Definition GXml.cpp:248
std::string str(const unsigned short int &value)
Convert unsigned short integer value into string.
Definition GTools.cpp:489