openMSX
XMLOutputStream.hh
Go to the documentation of this file.
1 #ifndef XMLOUTPUTSTREAM_HH
2 #define XMLOUTPUTSTREAM_HH
3 
4 #include "XMLEscape.hh"
5 #include <algorithm>
6 #include <string>
7 #include <string_view>
8 #include <vector>
9 
69 template<typename Operations>
71 {
72 public:
73  XMLOutputStream(Operations& ops_)
74  : ops(ops_) {}
75 
76  void begin(std::string_view tag);
77  void attribute(std::string_view name, std::string_view value);
78  void data(std::string_view value);
79  void end(std::string_view tag);
80 
81 private:
82  void writeSpaces(unsigned n);
83  void writeChar(char c);
84  void writeString(std::string_view s);
85  void writeEscapedString(std::string_view s);
86 
87 private:
88  Operations& ops;
89  unsigned level = 0;
90  enum State {
91  INDENT, // the next (begin or end) tag needs to be indented
92  CLOSE, // the begin tag still needs to be closed
93  DATA, // we got data, but no end-tag yet
94  };
95  State state = INDENT;
96 #ifdef DEBUG
97  std::vector<std::string> stack;
98 #endif
99 };
100 
101 
102 template<typename Writer>
103 void XMLOutputStream<Writer>::begin(std::string_view tag)
104 {
105 #ifdef DEBUG
106  stack.emplace_back(tag);
107 #endif
108  ops.check(state != DATA);
109  if (state == CLOSE) {
110  writeString(">\n");
111  }
112  writeSpaces(2 * level);
113  writeChar('<');
114  writeString(tag);
115  ++level;
116  state = CLOSE;
117 }
118 
119 template<typename Writer>
120 void XMLOutputStream<Writer>::attribute(std::string_view name, std::string_view value)
121 {
122  ops.check(level > 0);
123  ops.check(state == CLOSE);
124  writeChar(' ');
125  writeString(name);
126  writeString("=\"");
127  writeEscapedString(value);
128  writeChar('"');
129 }
130 
131 template<typename Writer>
132 void XMLOutputStream<Writer>::data(std::string_view value)
133 {
134  ops.check(level > 0);
135  ops.check(state == CLOSE);
136 
137  if (value.empty()) return;
138 
139  writeChar('>');
140  writeEscapedString(value);
141  state = DATA;
142 }
143 
144 template<typename Writer>
145 void XMLOutputStream<Writer>::end(std::string_view tag)
146 {
147 #ifdef DEBUG
148  ops.check(stack.size() == level);
149  ops.check(!stack.empty());
150  ops.check(stack.back() == tag);
151  stack.pop_back();
152 #endif
153  ops.check(level > 0);
154  --level;
155  if (state == CLOSE) {
156  writeString("/>\n");
157  } else {
158  if (state == INDENT) {
159  writeSpaces(2 * level);
160  }
161  writeString("</");
162  writeString(tag);
163  writeString(">\n");
164  }
165  state = INDENT;
166 }
167 
168 template<typename Writer>
170 {
171  static const char* buffer =
172  " "
173  " ";
174  while (n) {
175  auto t = std::min(64u, n);
176  ops.write(buffer, t);
177  n -= t;
178  }
179 }
180 
181 template<typename Writer>
183 {
184  ops.write1(c);
185 }
186 
187 template<typename Writer>
188 void XMLOutputStream<Writer>::writeString(std::string_view s)
189 {
190  ops.write(s.data(), s.size());
191 }
192 
193 template<typename Writer>
194 void XMLOutputStream<Writer>::writeEscapedString(std::string_view s)
195 {
196  XMLEscape(s, [&](std::string_view chunk) { writeString(chunk); });
197 }
198 
199 #endif
TclObject t
void XMLEscape(std::string_view s, Output output)
Definition: XMLEscape.hh:21
'XMLOutputStream' is a helper to write an XML file in a streaming way.
void attribute(std::string_view name, std::string_view value)
void begin(std::string_view tag)
XMLOutputStream(Operations &ops_)
void end(std::string_view tag)
void data(std::string_view value)
constexpr vecN< N, T > min(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:269