first check-in of feisty meow codebase. many things broken still due to recent
[feisty_meow.git] / core / library / textual / xml_generator.h
1 #ifndef XML_GENERATOR_CLASS
2 #define XML_GENERATOR_CLASS
3
4 /*****************************************************************************\
5 *                                                                             *
6 *  Name   : xml_generator                                                     *
7 *  Author : Chris Koeritz                                                     *
8 *                                                                             *
9 *******************************************************************************
10 * Copyright (c) 2007-$now By Author.  This program is free software; you can  *
11 * redistribute it and/or modify it under the terms of the GNU General Public  *
12 * License as published by the Free Software Foundation; either version 2 of   *
13 * the License or (at your option) any later version.  This is online at:      *
14 *     http://www.fsf.org/copyleft/gpl.html                                    *
15 * Please send any updates to: fred@gruntose.com                               *
16 \*****************************************************************************/
17
18 #include <basis/astring.h>
19 #include <basis/contracts.h>
20 #include <structures/string_table.h>
21
22 namespace textual {
23
24 class tag_info;
25 class tag_stack;
26
27 //! Supports simple XML output with consistency checking.
28
29 class xml_generator
30 {
31 public:
32   enum behavioral_mods {
33     HUMAN_READABLE = 0x1,
34     CLEAN_ILLEGAL_CHARS = 0x2
35   };
36
37   xml_generator(int modifiers = HUMAN_READABLE | CLEAN_ILLEGAL_CHARS);
38     //!< creates an xml generator with the specified behavior.
39
40   virtual ~xml_generator();
41
42   DEFINE_CLASS_NAME("xml_generator");
43
44   //! the possible ways that operations here can complete.
45   enum outcomes {
46     OKAY = basis::common::OKAY,
47     NOT_FOUND = basis::common::NOT_FOUND,
48     ERRONEOUS_TAG = basis::common::INVALID //temporary until we can shed a compatibility concern.
49 //    DEF INE_OUTCOME(ERRONEOUS_TAG, -75, "The most recently opened tag must be "
50 //        "closed before a new tag can be opened and before any other tag can "
51 //        "be closed"),
52   };
53
54   static const char *outcome_name(const basis::outcome &to_name);
55     //!< reports the string version of "to_name".
56
57   void reset();  //!< throws out all accumulated information.
58
59   basis::astring generate();
60     //!< writes the current state into a string and returns it.
61     /*!< if there was an error during generation, the string will be empty.
62     note that unclosed tags are not considered an error; they will simply be
63     closed.  note that the accumulated string is not cleared after the
64     generate() invocation.  use reset() to clear out all prior state. */
65
66   void generate(basis::astring &generated);
67     //!< synonym method, writes the current state into "generated".
68
69   basis::outcome add_header(const basis::astring &tag_name, const structures::string_table &attributes);
70     //!< adds an xml style header with the "tag_name" and "attributes".
71     /*!< headers can be located anywhere in the file. */
72
73   basis::outcome open_tag(const basis::astring &tag_name, const structures::string_table &attributes);
74     //!< adds a tag with "tag_name" and the "attributes", if any.
75     /*!< this adds an item into the output string in the form: @code
76        <tag_name attrib1="value1" attrib2="value2"...> @endcode
77     it is required that you close the tag later on, after the tag's contents
78     have been added. */
79
80   basis::outcome open_tag(const basis::astring &tag_name);
81     //!< adds a tag with "tag_name" without any attributes.
82
83   basis::outcome close_tag(const basis::astring &tag_name);
84     //!< closes a previously added "tag_name".
85     /*!< this will generate xml code like so: @code
86        </tag_name> @endcode
87     note that it is an error to try to close any tag but the most recently
88     opened one. */
89
90   void close_all_tags();
91     //!< a wide-bore method that closes all outstanding tags.
92
93   basis::outcome add_content(const basis::astring &content);
94     //!< stores content into the currently opened tag.
95     /*!< it is an error to add content when no tag is open. */
96
97   void set_indentation(int to_indent);
98     //!< sets the number of spaces to indent for the human readable form.
99
100   static basis::astring clean_reserved(const basis::astring &to_modify,
101           bool replace_spaces = false);
102     //!< returns a cleaned version of "to_modify" to make it XML appropriate.
103     /*!< if "replace_spaces" is true, then any spaces will be turned into
104     their html code equivalent; this helps in attribute names. */
105
106   static void clean_reserved_mod(basis::astring &to_modify,
107           bool replace_spaces = false);
108     //!< ensures that "to_modify" contains only characters valid for XML.
109     /*!< this is only different from the other clean method because this
110     one modifies the string in place. */
111
112 private:
113   tag_stack *_tags;  //!< the already opened tags.
114   basis::astring *_accumulator;  //!< stores our output.
115   bool _human_read;  //!< true if the output should be human readable.
116   bool _clean_chars;  //!< true if strings should be validated and repaired.
117   int _indentation;  //!< number of spaces per level of xml.
118
119   enum open_types { NORMAL_TAG, HEADER_TAG };
120   void print_open_tag(const tag_info &to_print, int type = NORMAL_TAG);
121     //!< opens the tag for to_print by showing the tag name and attributes.
122   void print_close_tag(const basis::astring &tag_name);
123     //!< closes the tag for "tag_name" in the output string.
124 };
125
126 } //namespace.
127
128 #endif
129