neoGFX
Cross-platform C++ app/game engine
Loading...
Searching...
No Matches
xml.inl
Go to the documentation of this file.
1// xml.inl
2/*
3 * NoFussXML v5.3.3
4 *
5 * Copyright (c) 2007 Leigh Johnston.
6 *
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are
11 * met:
12 *
13 * * Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * * Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * * Neither the name of Leigh Johnston nor the names of any
21 * other contributors to this software may be used to endorse or
22 * promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
26 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
27 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
29 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36*/
37
38#include <neolib/neolib.hpp>
39#include <string>
40#include <sstream>
41#include <algorithm>
42#include <cstdlib>
43#include <cwchar>
45
46namespace neolib
47{
48 namespace
49 {
50 template <typename>
51 struct characters {};
52 template <>
53 struct characters<char>
54 {
55 static const char sTabChar = '\t';
56 static const char sSpaceChar = ' ';
57 static const char sNewLineChar = '\n';
58 static const char sCarriageReturnChar = '\r';
59 static const char sLessThanChar = '<';
60 static const char sGreaterThanChar = '>';
61 static const char sEqualsChar = '=';
62 static const char sForwardSlashChar = '/';
63 static const char sAmpersandChar = '&';
64 static const char sSemicolonChar = ';';
65 static const char sHashChar = '#';
66 static const char sHexChar = 'x';
67 static const char sQuoteChar = '\"';
68 static const char sSingleQuoteChar = '\'';
69 static const char sElementTagStart = '<';
70 static const char sElementTagEnd= '>';
71 };
72 const char characters<char>::sTabChar;
73 const char characters<char>::sSpaceChar;
74 const char characters<char>::sNewLineChar;
75 const char characters<char>::sCarriageReturnChar;
76 const char characters<char>::sLessThanChar;
77 const char characters<char>::sGreaterThanChar;
78 const char characters<char>::sEqualsChar;
79 const char characters<char>::sForwardSlashChar;
80 const char characters<char>::sAmpersandChar;
81 const char characters<char>::sSemicolonChar;
82 const char characters<char>::sHashChar;
83 const char characters<char>::sHexChar;
84 const char characters<char>::sQuoteChar;
85 const char characters<char>::sSingleQuoteChar;
86 const char characters<char>::sElementTagStart;
87 const char characters<char>::sElementTagEnd;
88 template <>
89 struct characters<wchar_t>
90 {
91 static const wchar_t sTabChar = L'\t';
92 static const wchar_t sSpaceChar = L' ';
93 static const wchar_t sNewLineChar = L'\n';
94 static const wchar_t sCarriageReturnChar = L'\r';
95 static const wchar_t sLessThanChar = L'<';
96 static const wchar_t sGreaterThanChar = L'>';
97 static const wchar_t sEqualsChar = L'=';
98 static const wchar_t sForwardSlashChar = L'/';
99 static const wchar_t sAmpersandChar = L'&';
100 static const wchar_t sSemicolonChar = L';';
101 static const wchar_t sHashChar = L'#';
102 static const wchar_t sHexChar = L'x';
103 static const wchar_t sQuoteChar = L'\"';
104 static const wchar_t sSingleQuoteChar = L'\'';
105 static const wchar_t sElementTagStart = L'<';
106 static const wchar_t sElementTagEnd= L'>';
107 };
108 const wchar_t characters<wchar_t>::sTabChar;
109 const wchar_t characters<wchar_t>::sSpaceChar;
110 const wchar_t characters<wchar_t>::sNewLineChar;
111 const wchar_t characters<wchar_t>::sCarriageReturnChar;
112 const wchar_t characters<wchar_t>::sLessThanChar;
113 const wchar_t characters<wchar_t>::sGreaterThanChar;
114 const wchar_t characters<wchar_t>::sEqualsChar;
115 const wchar_t characters<wchar_t>::sForwardSlashChar;
116 const wchar_t characters<wchar_t>::sAmpersandChar;
117 const wchar_t characters<wchar_t>::sSemicolonChar;
118 const wchar_t characters<wchar_t>::sHashChar;
119 const wchar_t characters<wchar_t>::sHexChar;
120 const wchar_t characters<wchar_t>::sQuoteChar;
121 const wchar_t characters<wchar_t>::sSingleQuoteChar;
122 const wchar_t characters<wchar_t>::sElementTagStart;
123 const wchar_t characters<wchar_t>::sElementTagEnd;
124
125 template <typename CharT>
126 struct predefined_entities;
127 template <>
128 struct predefined_entities<char>
129 {
130 enum { PredefinedEntityCount = 5 };
131 typedef std::pair<const char*, const char*> entity;
132 static const entity sPredefinedEntities[PredefinedEntityCount];
133 };
134 const predefined_entities<char>::entity predefined_entities<char>::sPredefinedEntities[predefined_entities<char>::PredefinedEntityCount] =
135 {
136 std::make_pair("amp", "&"),
137 std::make_pair("lt", "<"),
138 std::make_pair("gt", ">"),
139 std::make_pair("apos", "\'"),
140 std::make_pair("quot", "\"")
141 };
142 template <>
143 struct predefined_entities<wchar_t>
144 {
145 enum { PredefinedEntityCount = 5 };
146 typedef std::pair<const wchar_t*, const wchar_t*> entity;
147 static const entity sPredefinedEntities[PredefinedEntityCount];
148 };
149 const predefined_entities<wchar_t>::entity predefined_entities<wchar_t>::sPredefinedEntities[predefined_entities<wchar_t>::PredefinedEntityCount] =
150 {
151 std::make_pair(L"amp", L"&"),
152 std::make_pair(L"lt", L"<"),
153 std::make_pair(L"gt", L">"),
154 std::make_pair(L"apos", L"\'"),
155 std::make_pair(L"quot", L"\"")
156 };
157
158 template <typename CharT>
159 struct parsing_bits {};
160 template <>
161 struct parsing_bits<char>
162 {
163 typedef std::string string;
164 typedef basic_character_map<char> character_map;
165 static const character_map sNameDelimeter;
166 static const character_map sNameBadDelimeter;
167 static const character_map sAttributeValueDelimeter;
168 static const character_map sAttributeValueInvalidOne;
169 static const character_map sAttributeValueInvalidTwo;
170 static const character_map sTagDelimeter;
171 static const character_map sWhitespace;
172 static const string sCommentStart;
173 static const string sCommentEnd;
174 static const string sCdataStart;
175 static const string sCdataEnd;
176 static const string sDtdStart;
177 static const string sDtdEnd;
178 static const string sDeclarationStart;
179 static const string sDeclarationEnd;
180 static const string sEmptyTagWithAttributes;
181 static const string sEmptyTag;
182 };
183 const parsing_bits<char>::character_map parsing_bits<char>::sNameDelimeter = std::string("<>/=\"\'");
184 const parsing_bits<char>::character_map parsing_bits<char>::sNameBadDelimeter = std::string("<=\"\'");
185 const parsing_bits<char>::character_map parsing_bits<char>::sAttributeValueDelimeter = std::string("\"\'");
186 const parsing_bits<char>::character_map parsing_bits<char>::sAttributeValueInvalidOne = std::string("<>\"");
187 const parsing_bits<char>::character_map parsing_bits<char>::sAttributeValueInvalidTwo = std::string("<>\'");
188 const parsing_bits<char>::character_map parsing_bits<char>::sTagDelimeter = std::string("<>");
189 const parsing_bits<char>::character_map parsing_bits<char>::sWhitespace = std::string(" \t\r\n");
190 const parsing_bits<char>::string parsing_bits<char>::sCommentStart = "!--";
191 const parsing_bits<char>::string parsing_bits<char>::sCommentEnd = "-->";
192 const parsing_bits<char>::string parsing_bits<char>::sCdataStart = "![CDATA[";
193 const parsing_bits<char>::string parsing_bits<char>::sCdataEnd = "]]>";
194 const parsing_bits<char>::string parsing_bits<char>::sDtdStart = "!DOCTYPE";
195 const parsing_bits<char>::string parsing_bits<char>::sDtdEnd = ">";
196 const parsing_bits<char>::string parsing_bits<char>::sDeclarationStart = "?";
197 const parsing_bits<char>::string parsing_bits<char>::sDeclarationEnd = "?>";
198 const parsing_bits<char>::string parsing_bits<char>::sEmptyTagWithAttributes = " />";
199 const parsing_bits<char>::string parsing_bits<char>::sEmptyTag = "/>";
200 template <>
201 struct parsing_bits<wchar_t>
202 {
203 typedef std::wstring string;
204 typedef basic_character_map<wchar_t> character_map;
205 static const character_map sNameDelimeter;
206 static const character_map sNameBadDelimeter;
207 static const character_map sAttributeValueDelimeter;
208 static const character_map sAttributeValueInvalidOne;
209 static const character_map sAttributeValueInvalidTwo;
210 static const character_map sTagDelimeter;
211 static const character_map sWhitespace;
212 static const string sCommentStart;
213 static const string sCommentEnd;
214 static const string sCdataStart;
215 static const string sCdataEnd;
216 static const string sDtdStart;
217 static const string sDtdEnd;
218 static const string sDeclarationStart;
219 static const string sDeclarationEnd;
220 static const string sEmptyTagWithAttributes;
221 static const string sEmptyTag;
222 };
223 const parsing_bits<wchar_t>::character_map parsing_bits<wchar_t>::sNameDelimeter = std::wstring(L"<>/=\"\'");
224 const parsing_bits<wchar_t>::character_map parsing_bits<wchar_t>::sNameBadDelimeter = std::wstring(L"<=\"\'");
225 const parsing_bits<wchar_t>::character_map parsing_bits<wchar_t>::sAttributeValueDelimeter = std::wstring(L"\"\'");
226 const parsing_bits<wchar_t>::character_map parsing_bits<wchar_t>::sAttributeValueInvalidOne = std::wstring(L"<>\"");
227 const parsing_bits<wchar_t>::character_map parsing_bits<wchar_t>::sAttributeValueInvalidTwo = std::wstring(L"<>\'");
228 const parsing_bits<wchar_t>::character_map parsing_bits<wchar_t>::sTagDelimeter = std::wstring(L"<>");
229 const parsing_bits<wchar_t>::character_map parsing_bits<wchar_t>::sWhitespace = std::wstring(L" \t\r\n");
230 const parsing_bits<wchar_t>::string parsing_bits<wchar_t>::sCommentStart = L"!--";
231 const parsing_bits<wchar_t>::string parsing_bits<wchar_t>::sCommentEnd = L"-->";
232 const parsing_bits<wchar_t>::string parsing_bits<wchar_t>::sCdataStart = L"![CDATA[";
233 const parsing_bits<wchar_t>::string parsing_bits<wchar_t>::sCdataEnd = L"]]>";
234 const parsing_bits<wchar_t>::string parsing_bits<wchar_t>::sDtdStart = L"!DOCTYPE";
235 const parsing_bits<wchar_t>::string parsing_bits<wchar_t>::sDtdEnd = L">";
236 const parsing_bits<wchar_t>::string parsing_bits<wchar_t>::sDeclarationStart = L"?";
237 const parsing_bits<wchar_t>::string parsing_bits<wchar_t>::sDeclarationEnd = L"?>";
238 const parsing_bits<wchar_t>::string parsing_bits<wchar_t>::sEmptyTagWithAttributes = L" />";
239 const parsing_bits<wchar_t>::string parsing_bits<wchar_t>::sEmptyTag = L"/>";
240 }
241
242 template <typename CharT, typename Alloc>
243 const basic_character_map<CharT> basic_xml<CharT, Alloc>::sNameDelimeter = parsing_bits<CharT>::sNameDelimeter;
244 template <typename CharT, typename Alloc>
245 const basic_character_map<CharT> basic_xml<CharT, Alloc>::sNameBadDelimeter = parsing_bits<CharT>::sNameBadDelimeter;
246 template <typename CharT, typename Alloc>
247 const basic_character_map<CharT> basic_xml<CharT, Alloc>::sAttributeValueDelimeter = parsing_bits<CharT>::sAttributeValueDelimeter;
248 template <typename CharT, typename Alloc>
249 const basic_character_map<CharT> basic_xml<CharT, Alloc>::sAttributeValueInvalidOne = parsing_bits<CharT>::sAttributeValueInvalidOne;
250 template <typename CharT, typename Alloc>
251 const basic_character_map<CharT> basic_xml<CharT, Alloc>::sAttributeValueInvalidTwo = parsing_bits<CharT>::sAttributeValueInvalidTwo;
252 template <typename CharT, typename Alloc>
253 const basic_character_map<CharT> basic_xml<CharT, Alloc>::sTagDelimeter = parsing_bits<CharT>::sTagDelimeter;
254 template <typename CharT, typename Alloc>
255 const basic_character_map<CharT> basic_xml<CharT, Alloc>::sWhitespace = parsing_bits<CharT>::sWhitespace;
256 template <typename CharT, typename Alloc>
257 const typename basic_xml<CharT, Alloc>::string basic_xml<CharT, Alloc>::sCommentStart = parsing_bits<CharT>::sCommentStart;
258 template <typename CharT, typename Alloc>
259 const typename basic_xml<CharT, Alloc>::string basic_xml<CharT, Alloc>::sCommentEnd = parsing_bits<CharT>::sCommentEnd;
260 template <typename CharT, typename Alloc>
261 const typename basic_xml<CharT, Alloc>::string basic_xml<CharT, Alloc>::sCdataStart = parsing_bits<CharT>::sCdataStart;
262 template <typename CharT, typename Alloc>
263 const typename basic_xml<CharT, Alloc>::string basic_xml<CharT, Alloc>::sCdataEnd = parsing_bits<CharT>::sCdataEnd;
264 template <typename CharT, typename Alloc>
265 const typename basic_xml<CharT, Alloc>::string basic_xml<CharT, Alloc>::sDtdStart = parsing_bits<CharT>::sDtdStart;
266 template <typename CharT, typename Alloc>
267 const typename basic_xml<CharT, Alloc>::string basic_xml<CharT, Alloc>::sDtdEnd = parsing_bits<CharT>::sDtdEnd;
268 template <typename CharT, typename Alloc>
269 const typename basic_xml<CharT, Alloc>::string basic_xml<CharT, Alloc>::sDeclarationStart = parsing_bits<CharT>::sDeclarationStart;
270 template <typename CharT, typename Alloc>
271 const typename basic_xml<CharT, Alloc>::string basic_xml<CharT, Alloc>::sDeclarationEnd = parsing_bits<CharT>::sDeclarationEnd;
272 template <typename CharT, typename Alloc>
273 const typename basic_xml<CharT, Alloc>::string basic_xml<CharT, Alloc>::sEmptyTagWithAttributes = parsing_bits<CharT>::sEmptyTagWithAttributes;
274 template <typename CharT, typename Alloc>
275 const typename basic_xml<CharT, Alloc>::string basic_xml<CharT, Alloc>::sEmptyTag = parsing_bits<CharT>::sEmptyTag;
276
277 template <typename CharT, typename Alloc>
279 {
280 for (typename node_list::const_iterator i = iContent.begin(); i != iContent.end(); ++i)
281 if ((**i).type() & aFilter)
282 return const_iterator(*this, i, aFilter);
283 return end(aFilter);
284 }
285
286 template <typename CharT, typename Alloc>
288 {
289 return const_iterator(*this, iContent.end(), aFilter);
290 }
291
292 template <typename CharT, typename Alloc>
294 {
295 for (typename node_list::iterator i = iContent.begin(); i != iContent.end(); ++i)
296 if ((**i).type() & aFilter)
297 return iterator(*this, i, aFilter);
298 return end(aFilter);
299 }
300
301 template <typename CharT, typename Alloc>
303 {
304 return iterator(*this, iContent.end(), aFilter);
305 }
306
307 template <typename CharT, typename Alloc>
309 {
310 for (typename node::const_iterator i = begin(); i != end(); ++i)
311 if (i->type() == node::Element && static_cast<const xml_element<CharT, Alloc>&>(*i).name() == aName)
312 return i;
313 return end();
314 }
315
316 template <typename CharT, typename Alloc>
317 std::optional<typename xml_node<CharT, Alloc>::const_iterator> xml_node<CharT, Alloc>::find_maybe(const string& aName) const
318 {
319 auto result = find(aName);
320 if (result != end())
321 return result;
322 else
323 return {};
324 }
325
326 template <typename CharT, typename Alloc>
328 {
329 for (typename node::iterator i = begin(); i != end(); ++i)
330 if (i->type() == node::Element && static_cast<xml_element<CharT, Alloc>&>(*i).name() == aName)
331 return i;
332 return end();
333 }
334
335 template <typename CharT, typename Alloc>
336 std::optional<typename xml_node<CharT, Alloc>::iterator> xml_node<CharT, Alloc>::find_maybe(const string& aName)
337 {
338 auto result = find(aName);
339 if (result != end())
340 return result;
341 else
342 return {};
343 }
344
345 template <typename CharT, typename Alloc>
347 {
348 for (typename node::iterator i = begin(); i != end(); ++i)
349 if (i->type() == node::Element && static_cast<xml_element<CharT, Alloc>&>(*i).name() == aName)
350 return i;
351 insert(end(), new xml_element<CharT, Alloc>(aName));
352 typename node::iterator newNode = end();
353 return --newNode;
354 }
355
356 template <typename CharT, typename Alloc>
357 template <typename Exception>
359 {
360 typename node::const_iterator i = find(aName);
361 if (i != end())
362 return i;
363 throw Exception();
364 }
365
366 template <typename CharT, typename Alloc>
367 template <typename Exception>
369 {
370 typename node::iterator i = find(aName);
371 if (i != end())
372 return i;
373 throw Exception();
374 }
375
376 template <typename CharT, typename Alloc>
377 bool xml_element<CharT, Alloc>::has_attribute(const string& aAttributeName) const
378 {
379 return iAttributes.find(aAttributeName) != iAttributes.end();
380 }
381
382 template <typename CharT, typename Alloc>
383 const typename xml_element<CharT, Alloc>::string& xml_element<CharT, Alloc>::attribute_value(const string& aAttributeName) const
384 {
385 typename attribute_list::const_iterator a = iAttributes.find(aAttributeName);
386 if (a != iAttributes.end())
387 return a->second;
388 static const string null;
389 return null;
390 }
391
392 template <typename CharT, typename Alloc>
393 const typename xml_element<CharT, Alloc>::string& xml_element<CharT, Alloc>::attribute_value(const string& aNewAttributeName, const string& aOldAttributeName) const
394 {
395 if (has_attribute(aNewAttributeName))
396 return attribute_value(aNewAttributeName);
397 else
398 return attribute_value(aOldAttributeName);
399 }
400
401 template <typename CharT, typename Alloc>
403 {
404 iText.clear();
405 for (typename node::const_iterator i = node::begin(); i != node::end(); ++i)
406 if (i->type() == node::Text)
407 iText += static_cast<const xml_text<CharT, Alloc>&>(*i).content();
408 return iText;
409 }
410
411 template <typename CharT, typename Alloc>
412 void xml_element<CharT, Alloc>::set_attribute(const string& aAttributeName, const string& aAttributeValue)
413 {
414 iAttributes[aAttributeName] = aAttributeValue;
415 }
416
417 template <typename CharT, typename Alloc>
419 {
420 node::push_back(new xml_text<CharT, Alloc>(aText));
421 }
422
423 template <typename CharT, typename Alloc>
424 template <typename T>
426 {
427 if (!iLastWasNewLine)
428 iStream << aData;
429 iLastWasNewLine = false;
430 return *this;
431 }
432 template <typename CharT, typename Alloc>
433 typename basic_xml<CharT, Alloc>::node_writer& basic_xml<CharT, Alloc>::node_writer::operator<<(const string& aData)
434 {
435 iStream << aData.to_std_string_view();
436 if (aData.size() && aData[aData.size() - 1] == characters<CharT>::sNewLineChar)
437 iLastWasNewLine = true;
438 else
439 iLastWasNewLine = false;
440 return *this;
441 }
442
443 template <typename CharT, typename Alloc>
444 basic_xml<CharT, Alloc>::basic_xml(bool aStripWhitespace) :
445 endl(std::endl), iError(false), iIndentChar(characters<CharT>::sTabChar), iIndentCount(1), iStripWhitespace(aStripWhitespace)
446 {
447 for (std::size_t entityIndex = 0; entityIndex < predefined_entities<CharT>::PredefinedEntityCount; ++entityIndex)
448 iEntities.push_back(predefined_entities<CharT>::sPredefinedEntities[entityIndex]);
449 }
450
451 template <typename CharT, typename Alloc>
452 basic_xml<CharT, Alloc>::basic_xml(const std::string& aPath, bool aStripWhitespace) :
453 endl(std::endl), iError(false), iIndentChar(characters<CharT>::sTabChar), iIndentCount(1), iStripWhitespace(aStripWhitespace)
454 {
455 for (std::size_t entityIndex = 0; entityIndex < predefined_entities<CharT>::PredefinedEntityCount; ++entityIndex)
456 iEntities.push_back(predefined_entities<CharT>::sPredefinedEntities[entityIndex]);
457 std::ifstream input(aPath);
458 if (!input)
459 throw failed_to_open_file();
460 read(input);
461 }
462
463 template <typename CharT, typename Alloc>
465 {
466 iDocument.clear();
467 iDocumentText.clear();
468 iError = false;
469 }
470
471 template <typename CharT, typename Alloc>
473 {
474 return iDocument;
475 }
476
477 template <typename CharT, typename Alloc>
479 {
480 return iDocument;
481 }
482
483 template <typename CharT, typename Alloc>
485 {
486 for (typename node::const_iterator i = iDocument.begin(); i != iDocument.end(); ++i)
487 if (i->type() == node::Element)
488 return static_cast<const element&>(*i);
489 iError = true;
490 throw error_no_root();
491 }
492
493 template <typename CharT, typename Alloc>
495 {
496 for (typename node::iterator i = iDocument.begin(); i != iDocument.end(); ++i)
497 if (i->type() == node::Element)
498 return static_cast<element&>(*i);
499 iDocument.push_back(new element());
500 return static_cast<element&>(iDocument.back());
501 }
502
503 template <typename CharT, typename Alloc>
505 {
506 for (typename node::const_iterator i = iDocument.begin(); i != iDocument.end(); ++i)
507 if (i->type() == node::Element)
508 return true;
509 return false;
510 }
511
512 template <typename CharT, typename Alloc>
514 {
515 tag nextTag;
516 nextTag.first = std::find(aNext, aDocumentEnd, CharT(characters<CharT>::sElementTagStart));
517 if (nextTag.first != aDocumentEnd)
518 ++nextTag.first;
519 nextTag.second = std::find(nextTag.first, aDocumentEnd, CharT(characters<CharT>::sElementTagEnd));
520 if (static_cast<typename string::size_type>(nextTag.second - nextTag.first) >= sCommentStart.size() && std::equal(nextTag.first, nextTag.first+sCommentStart.size(), sCommentStart.begin()))
521 {
522 nextTag.iType = node::Comment;
523 nextTag.first += sCommentStart.size();
524 nextTag.second = std::search(nextTag.first, aDocumentEnd, sCommentEnd.begin(), sCommentEnd.end());
525 if (nextTag.second == aDocumentEnd)
526 nextTag.first = aDocumentEnd;
527 }
528 else if (static_cast<typename string::size_type>(nextTag.second - nextTag.first) >= sDeclarationStart.size() && std::equal(nextTag.first, nextTag.first+sDeclarationStart.size(), sDeclarationStart.begin()))
529 {
530 nextTag.iType = node::Declaration;
531 nextTag.first += sDeclarationStart.size();
532 nextTag.second = std::search(nextTag.first, aDocumentEnd, sDeclarationEnd.begin(), sDeclarationEnd.end());
533 if (nextTag.second == aDocumentEnd)
534 nextTag.first = aDocumentEnd;
535 }
536 else if (static_cast<typename string::size_type>(nextTag.second - nextTag.first) >= sCdataStart.size() && std::equal(nextTag.first, nextTag.first+sCdataStart.size(), sCdataStart.begin()))
537 {
538 nextTag.iType = node::Cdata;
539 nextTag.first += sCdataStart.size();
540 nextTag.second = std::search(nextTag.first, aDocumentEnd, sCdataEnd.begin(), sCdataEnd.end());
541 if (nextTag.second == aDocumentEnd)
542 nextTag.first = aDocumentEnd;
543 }
544 else if (static_cast<typename string::size_type>(nextTag.second - nextTag.first) >= sDtdStart.size() + 1 && std::equal(nextTag.first, nextTag.first+sDtdStart.size(), sDtdStart.begin()) &&
545 sWhitespace.find(*(nextTag.first + sDtdStart.size())))
546 {
547 nextTag.iType = node::Dtd;
548 nextTag.first += sDtdStart.size();
549 nextTag.second = nextTag.first;
550 std::size_t nest = 1;
551 while(nextTag.second != aDocumentEnd)
552 {
553 if (*nextTag.second == characters<CharT>::sLessThanChar)
554 ++nest;
555 if (*nextTag.second == characters<CharT>::sGreaterThanChar)
556 --nest;
557 if (nest == 0)
558 break;
559 ++nextTag.second;
560 }
561 if (nextTag.second == aDocumentEnd)
562 nextTag.first = aDocumentEnd;
563 }
564 return nextTag;
565 }
566
567 template <typename CharT, typename Alloc>
568 typename basic_xml<CharT, Alloc>::string::view_const_iterator basic_xml<CharT, Alloc>::parse(node& aNode, const tag& aStartTag, typename basic_xml<CharT, Alloc>::string::view_const_iterator aDocumentEnd)
569 {
570 if (aStartTag.first == aDocumentEnd || aStartTag.first >= aStartTag.second)
571 return aDocumentEnd;
572
573 switch(aStartTag.type())
574 {
575 case node::Element:
576 {
577 if (aNode.type() == node::Document && got_root())
578 {
579 iError = true;
580 return aDocumentEnd;
581 }
582 element& theElement = aNode.type() == node::Element ? static_cast<element&>(aNode) : root();
583
584 /* get element name */
585 token elementName = next_token(sNameDelimeter, false, aStartTag.first, aStartTag.second);
586 if (elementName.first == aStartTag.second)
587 {
588 iError = true;
589 return aDocumentEnd;
590 }
591 theElement.name() = string(elementName.first, elementName.second);
592
593 typename string::view_const_iterator next = elementName.second;
594
595 /* get element attributes */
596 while(next != aStartTag.second)
597 {
598 token attributeName = next_token(sNameDelimeter, false, next, aStartTag.second);
599 if (attributeName.first == attributeName.second)
600 {
601 if (attributeName.first != aStartTag.second &&
602 sNameBadDelimeter.find(*attributeName.first))
603 {
604 iError = true;
605 return aDocumentEnd;
606 }
607 next = aStartTag.second;
608 break;
609 }
610 token attributeEquals = next_token(sAttributeValueDelimeter, false, attributeName.second, aStartTag.second);
611 if (attributeEquals.second - attributeEquals.first != 1 || *attributeEquals.first != characters<CharT>::sEqualsChar)
612 {
613 iError = true;
614 return aDocumentEnd;
615 }
616 token attributeStart = next_token(sAttributeValueDelimeter, false, attributeEquals.second, aStartTag.second);
617 if (attributeStart.first != attributeStart.second ||
618 attributeStart.first == aStartTag.second ||
619 !sAttributeValueDelimeter.find(*attributeStart.first))
620 {
621 iError = true;
622 return aDocumentEnd;
623 }
624 token attributeValue = next_token(*attributeStart.first == characters<CharT>::sQuoteChar ? sAttributeValueInvalidOne : sAttributeValueInvalidTwo, true, attributeStart.second + 1, aStartTag.second);
625 if (attributeValue.first == aStartTag.second ||
626 attributeValue.second == aStartTag.second ||
627 !sAttributeValueDelimeter.find(*attributeValue.second))
628 {
629 iError = true;
630 return aDocumentEnd;
631 }
632 next = attributeValue.second + 1;
633 typename attribute_list::iterator a = theElement.attributes().insert(std::make_pair(string(attributeName.first, attributeName.second), attributeValue.iHasEntities ? parse_entities(string(attributeValue.first, attributeValue.second)) : string(attributeValue.first, attributeValue.second))).first;
634 strip_if(a->second);
635 }
636
637 if (*(aStartTag.second-1) == characters<CharT>::sForwardSlashChar) // empty tag
638 return next+1;
639
640 ++next;
641
642 /* get element content */
643 while(next != aDocumentEnd)
644 {
645 token contentToken = next_token(sTagDelimeter, true, next, aDocumentEnd);
646 next = contentToken.second;
647 if (next == aDocumentEnd)
648 return next;
649 string content(contentToken.first, contentToken.second);
650 strip_if(content);
651 bool hasContent = false;
652 for (typename string::view_const_iterator i = content.cbegin(); !hasContent && i != content.cend(); ++i)
653 {
654 switch(*i)
655 {
656 case characters<CharT>::sTabChar:
657 case characters<CharT>::sSpaceChar:
658 case characters<CharT>::sNewLineChar:
659 case characters<CharT>::sCarriageReturnChar:
660 break;
661 default:
662 hasContent = true;
663 }
664 }
665 if (!hasContent)
666 content = string();
667 if (!content.empty())
668 {
669 if (contentToken.iHasEntities)
670 content = parse_entities(content);
671 theElement.push_back(new text(content));
672 }
673 tag nextTag = next_tag(next, aDocumentEnd);
674 if (nextTag.first > nextTag.second)
675 return next;
676 if (nextTag.first == nextTag.second)
677 {
678 next= nextTag.first;
679 continue;
680 }
681 switch (nextTag.type())
682 {
683 case node::Element:
684 if (*nextTag.first == characters<CharT>::sForwardSlashChar)
685 {
686 if (theElement.name() != string(nextTag.first+1, nextTag.second))
687 {
688 iError = true;
689 return aDocumentEnd;
690 }
691 theElement.set_use_empty_element_tag(false);
692 return nextTag.second+1;
693 }
694 theElement.push_back(new element());
695 break;
696 case node::Comment:
697 theElement.push_back(new comment());
698 break;
699 case node::Declaration:
700 theElement.push_back(new declaration());
701 break;
702 case node::Cdata:
703 theElement.push_back(new cdata());
704 break;
705 case node::Dtd:
706 theElement.push_back(new dtd());
707 break;
708 default:
709 break;
710 }
711 next = parse(theElement.back(), nextTag, aDocumentEnd);
712 }
713 return next;
714 }
715 // no break required here due to return above (warning dampening)
716 case node::Comment:
717 if (aNode.type() == node::Comment)
718 static_cast<comment&>(aNode).content() = string(aStartTag.first, aStartTag.second);
719 else
720 aNode.push_back(new comment(string(aStartTag.first, aStartTag.second)));
721 return aStartTag.second + aStartTag.end_skip();
722 case node::Declaration:
723 if (aNode.type() == node::Declaration)
724 static_cast<declaration&>(aNode).content() = string(aStartTag.first, aStartTag.second);
725 else
726 aNode.push_back(new declaration(string(aStartTag.first, aStartTag.second)));
727 return aStartTag.second + aStartTag.end_skip();
728 case node::Cdata:
729 if (aNode.type() == node::Cdata)
730 static_cast<cdata&>(aNode).content() = string(aStartTag.first, aStartTag.second);
731 else
732 aNode.push_back(new cdata(string(aStartTag.first, aStartTag.second)));
733 return aStartTag.second + aStartTag.end_skip();
734 case node::Dtd:
735 if (aNode.type() == node::Dtd)
736 static_cast<dtd&>(aNode).content() = string(aStartTag.first, aStartTag.second);
737 else
738 aNode.push_back(new dtd(string(aStartTag.first, aStartTag.second)));
739 return aStartTag.second + aStartTag.end_skip();
740 default:
741 iError = true;
742 return aDocumentEnd;
743 }
744 }
745
746 template <typename CharT, typename Alloc>
747 bool basic_xml<CharT, Alloc>::read(std::basic_istream<CharT>& aStream)
748 {
749 iError = false;
750
751 clear();
752
753 if (!aStream)
754 return false;
755
756 typename std::basic_istream<CharT>::pos_type count = 0;
757 aStream.seekg(0, std::ios::end);
758 if (aStream)
759 {
760 count = static_cast<long>(aStream.tellg());
761 if (count == typename std::basic_istream<CharT>::pos_type(-1))
762 count = 0;
763 aStream.seekg(0, std::ios::beg);
764 }
765 else
766 aStream.clear();
767
768 string& document = iDocumentText;
769
770 if (count != typename std::basic_istream<CharT>::pos_type(0))
771 {
772 document.resize(static_cast<typename string::size_type>(count));
773 aStream.read(&document[0], count);
774 document.resize(static_cast<typename string::size_type>(aStream.gcount()));
775 }
776 else
777 {
778 string line;
779 CharT buffer[1024];
780 while(aStream.read(buffer, 1024))
781 document.append(buffer, static_cast<typename string::size_type>(aStream.gcount()));
782 if (aStream.eof())
783 document.append(buffer, static_cast<typename string::size_type>(aStream.gcount()));
784 }
785
786 tag nextTag = next_tag(document.cbegin(), document.cend());
787 while (nextTag.first != document.cend())
788 {
789 while(nextTag.first != document.cend() && nextTag.first == nextTag.second)
790 nextTag = next_tag(nextTag.first, document.cend());
791 nextTag = next_tag(parse(iDocument, nextTag, document.cend()), document.cend());
792 };
793
794 return got_root();
795 }
796
797 template <typename CharT, typename Alloc>
798 bool basic_xml<CharT, Alloc>::write(std::basic_ostream<CharT>& aStream)
799 {
800 iError = false;
801 std::ostringstream buffer;
802 node_writer theWriter(buffer);
803 write_node(theWriter, iDocument, 0);
804 aStream.write(buffer.str().c_str(), buffer.str().length());
805 return true;
806 }
807
808 template <typename CharT, typename Alloc>
809 void basic_xml<CharT, Alloc>::set_indent(CharT aIndentChar, std::size_t aIndentCount)
810 {
811 iIndentChar = aIndentChar;
812 iIndentCount = aIndentCount;
813 }
814
815 template <typename CharT, typename Alloc>
817 {
818 iStripWhitespace = aStripWhitespace;
819 }
820
821 template <typename CharT, typename Alloc>
822 void basic_xml<CharT, Alloc>::write_node(node_writer& aStream, const node& aNode, std::size_t aIndent) const
823 {
824 switch(aNode.type())
825 {
826 case node::Document:
827 for (typename node::const_iterator i = aNode.begin(); i != aNode.end(); ++i)
828 {
829 write_node(aStream, *i, aIndent);
830 aStream << endl;
831 }
832 break;
833 case node::Element:
834 {
835 const element& theElement = static_cast<const element&>(aNode);
836
837 if (&theElement != &root())
838 aStream << endl;
839 aStream << string(aIndent*iIndentCount, iIndentChar);
840 aStream << characters<CharT>::sLessThanChar;
841 aStream << theElement.name();
842
843 if (!theElement.attributes().empty())
844 for (typename attribute_list::const_iterator i = theElement.attributes().begin(); i != theElement.attributes().end(); ++i)
845 aStream << characters<CharT>::sSpaceChar << i->first << characters<CharT>::sEqualsChar << characters<CharT>::sQuoteChar << generate_entities(i->second) << characters<CharT>::sQuoteChar;
846
847 if (!aNode.empty())
848 {
849 aStream << characters<CharT>::sGreaterThanChar;
850 for (typename node::const_iterator i = aNode.begin(); i != aNode.end(); ++i)
851 {
852 switch(i->type())
853 {
854 case node::Text:
855 if (i != aNode.begin())
856 {
857 if (iStripWhitespace)
858 {
859 aStream << endl;
860 aStream << string((aIndent+1)*iIndentCount, iIndentChar);
861 }
862 }
863 break;
864 case node::Comment:
865 case node::Declaration:
866 aStream << endl;
867 aStream << string((aIndent+1)*iIndentCount, iIndentChar);
868 break;
869 case node::Cdata:
870 case node::Dtd:
871 aStream << endl;
872 break;
873 default:
874 break;
875 }
876 write_node(aStream, *i, aIndent+1);
877 }
878 if (aNode.back().type() != node::Text)
879 aStream << endl << string(aIndent*iIndentCount, iIndentChar);
880 aStream << characters<CharT>::sLessThanChar << characters<CharT>::sForwardSlashChar << theElement.name() << characters<CharT>::sGreaterThanChar;
881 }
882 else if (theElement.use_empty_element_tag())
883 aStream << (theElement.attributes().size() ? sEmptyTagWithAttributes : sEmptyTag);
884 else
885 aStream << characters<CharT>::sGreaterThanChar << characters<CharT>::sLessThanChar << characters<CharT>::sForwardSlashChar << theElement.name() << characters<CharT>::sGreaterThanChar;
886 }
887 break;
888 case node::Text:
889 aStream << generate_entities(static_cast<const text&>(aNode).content());
890 break;
891 case node::Comment:
892 aStream << characters<CharT>::sLessThanChar << sCommentStart << static_cast<const comment&>(aNode).content() << sCommentEnd;
893 break;
894 case node::Declaration:
895 aStream << characters<CharT>::sLessThanChar << sDeclarationStart << static_cast<const declaration&>(aNode).content() << sDeclarationEnd;
896 break;
897 case node::Cdata:
898 aStream << characters<CharT>::sLessThanChar << sCdataStart << static_cast<const cdata&>(aNode).content() << sCdataEnd;
899 break;
900 case node::Dtd:
901 aStream << characters<CharT>::sLessThanChar << sDtdStart << static_cast<const dtd&>(aNode).content() << sDtdEnd;
902 break;
903 default:
904 break;
905 }
906 }
907
908 template <typename CharT, typename Alloc>
909 typename basic_xml<CharT, Alloc>::node::iterator basic_xml<CharT, Alloc>::insert(node& aParent, typename node::iterator aPosition, const CharT* aName)
910 {
911 return aParent.insert(aPosition, new element(aName));
912 }
913
914 template <typename CharT, typename Alloc>
916 {
917 return static_cast<typename basic_xml<CharT, Alloc>::element&>(*insert(aParent, aParent.end(), aName));
918 }
919
920 template <typename CharT, typename Alloc>
921 void basic_xml<CharT, Alloc>::erase(node& aParent, typename node::iterator aPosition)
922 {
923 aParent.erase(aPosition);
924 }
925
926 template <typename CharT, typename Alloc>
928 {
929 return aParent.find(aName);
930 }
931
932 template <typename CharT, typename Alloc>
934 {
935 return aParent.find(aName);
936 }
937
938 template <typename CharT, typename Alloc>
940 {
941 return aParent.find_or_append(aName);
942 }
943
944 template <typename CharT, typename Alloc>
946 {
947 string newString = aString;
948 typename string::size_type pos = 0;
949 while((pos = newString.find(characters<CharT>::sAmpersandChar, pos)) != string::npos)
950 {
951 typename string::size_type endPos = newString.find(characters<CharT>::sSemicolonChar, pos);
952 if (endPos == string::npos || (pos+1 == endPos))
953 {
954 iError = true;
955 return aString;
956 }
957 bool replaced = false;
958 if (const_cast<const string&>(newString)[pos+1] == characters<CharT>::sHashChar)
959 {
960 string characterValue = newString.substr(pos+2, endPos - (pos + 2));
961 string character;
962 struct converter
963 {
964 static long string_to_integer(const typename basic_xml<char>::string& aString, int aBase)
965 {
966 return strtol(aString.c_str(), 0, aBase);
967 }
968 static long string_to_integer(const typename basic_xml<wchar_t>::string& aString, int aBase)
969 {
970 return wcstol(aString.c_str(), 0, aBase);
971 }
972 };
973 if (characterValue[0] != characters<CharT>::sHexChar)
974 character += static_cast<CharT>(converter::string_to_integer(characterValue, 10));
975 else
976 {
977 characterValue.erase(0, 1);
978 character += static_cast<CharT>(converter::string_to_integer(characterValue, 16));
979 }
980 newString.replace(pos, (endPos - pos) + 1, character);
981 ++pos;
982 replaced = true;
983 }
984 else
985 {
986 for(typename entity_list::const_iterator i = iEntities.begin(); i != iEntities.end(); ++i)
987 {
988 string placeholder;
989 placeholder += characters<CharT>::sAmpersandChar;
990 placeholder += i->first;
991 placeholder += characters<CharT>::sSemicolonChar;
992 if (placeholder.size() != endPos - pos + 1)
993 continue;
994 if (std::equal(placeholder.cbegin(), placeholder.cend(), newString.cbegin() + pos))
995 {
996 newString.replace(pos, placeholder.size(), i->second);
997 pos += i->second.size();
998 replaced = true;
999 break;
1000 }
1001 }
1002 }
1003 if (!replaced)
1004 newString.erase(pos, (endPos - pos) + 1);
1005 }
1006 return newString;
1007 }
1008
1009 template <typename CharT, typename Alloc>
1010 typename basic_xml<CharT, Alloc>::string basic_xml<CharT, Alloc>::generate_entities(const string& aString) const
1011 {
1012 string newString = aString;
1013 for(typename entity_list::const_iterator i = iEntities.begin(); i != iEntities.end(); ++i)
1014 {
1015 string placeholder;
1016 placeholder += characters<CharT>::sAmpersandChar;
1017 placeholder += i->first;
1018 placeholder += characters<CharT>::sSemicolonChar;
1019 typename string::size_type pos = 0;
1020 while((pos = newString.find(i->second, pos)) != string::npos)
1021 {
1022 newString.replace(pos, i->second.size(), placeholder);
1023 pos += placeholder.size();
1024 }
1025 }
1026 return newString;
1027 }
1028
1029 template <typename CharT, typename Alloc>
1030 void basic_xml<CharT, Alloc>::strip(string& aString) const
1031 {
1032 typename string::size_type start = 0;
1033 bool foundPrintable = false;
1034 while (!foundPrintable && start < aString.size())
1035 {
1036 switch(aString[start])
1037 {
1038 case characters<CharT>::sTabChar:
1039 case characters<CharT>::sSpaceChar:
1040 case characters<CharT>::sNewLineChar:
1041 case characters<CharT>::sCarriageReturnChar:
1042 ++start;
1043 break;
1044 default:
1045 foundPrintable = true;
1046 break;
1047 }
1048 }
1049 if (foundPrintable)
1050 {
1051 if (start > 0)
1052 aString.erase(0, start);
1053 }
1054 else
1055 aString = string();
1056 if (aString.empty())
1057 return;
1058 typename string::size_type end = aString.size() - 1;
1059 foundPrintable = false;
1060 while (!foundPrintable && end != string::npos)
1061 {
1062 switch(aString[end])
1063 {
1064 case characters<CharT>::sTabChar:
1065 case characters<CharT>::sSpaceChar:
1066 case characters<CharT>::sNewLineChar:
1067 case characters<CharT>::sCarriageReturnChar:
1068 if (end == 0)
1069 end = string::npos;
1070 else
1071 --end;
1072 break;
1073 default:
1074 foundPrintable = true;
1075 break;
1076 }
1077 }
1078 if (end != string::npos)
1079 aString.erase(end+1, aString.size() - (end+1));
1080 typename string::iterator src = aString.begin();
1081 typename string::iterator dest = aString.begin();
1082 bool found = false;
1083 while(src != aString.end())
1084 {
1085 CharT srcChar = *src++;
1086 switch(srcChar)
1087 {
1088 case characters<CharT>::sTabChar:
1089 case characters<CharT>::sSpaceChar:
1090 case characters<CharT>::sNewLineChar:
1091 case characters<CharT>::sCarriageReturnChar:
1092 if (dest != aString.begin() && *(dest-1) != characters<CharT>::sSpaceChar)
1093 *dest++ = characters<CharT>::sSpaceChar;
1094 break;
1095 default:
1096 if (!found)
1097 {
1098 src = static_cast<string&>(aString).begin();
1099 dest = static_cast<string&>(aString).begin();
1100 found = true;
1101 continue;
1102 }
1103 else
1104 *dest++ = srcChar;
1105 }
1106 }
1107 if (found && dest != aString.end())
1108 aString.erase(dest, aString.end());
1109 }
1110
1111 template <typename CharT, typename Alloc>
1112 void basic_xml<CharT, Alloc>::strip_if(string& aString) const
1113 {
1114 if (iStripWhitespace)
1115 strip(aString);
1116 }
1117
1118 template <typename CharT, typename Alloc>
1119 typename basic_xml<CharT, Alloc>::token basic_xml<CharT, Alloc>::next_token(const basic_character_map<CharT>& aDelimeters, bool aIgnoreWhitespace, typename basic_xml<CharT, Alloc>::string::view_const_iterator aCurrent, typename basic_xml<CharT, Alloc>::string::view_const_iterator aEnd) const
1120 {
1121 if (!aIgnoreWhitespace)
1122 {
1123 while (aCurrent != aEnd)
1124 {
1125 switch(*aCurrent)
1126 {
1127 case characters<CharT>::sTabChar:
1128 case characters<CharT>::sSpaceChar:
1129 case characters<CharT>::sNewLineChar:
1130 case characters<CharT>::sCarriageReturnChar:
1131 ++aCurrent;
1132 break;
1133 default:
1134 goto doneStart;
1135 }
1136 }
1137 }
1138 doneStart:
1139 token ret;
1140 ret.first = aCurrent;
1141 while (aCurrent != aEnd)
1142 {
1143 CharT current =*aCurrent;
1144 if (!aIgnoreWhitespace)
1145 {
1146 switch(current)
1147 {
1148 case characters<CharT>::sTabChar:
1149 case characters<CharT>::sSpaceChar:
1150 case characters<CharT>::sNewLineChar:
1151 case characters<CharT>::sCarriageReturnChar:
1152 goto doneEnd;
1153 default:
1154 break;
1155 }
1156 }
1157 if (current == characters<CharT>::sAmpersandChar)
1158 ret.iHasEntities = true;
1159 if (aDelimeters.find(current))
1160 break;
1161 ++aCurrent;
1162 }
1163 doneEnd:
1164 ret.second = aCurrent;
1165 return ret;
1166 }
1167} // namespace neolib
1168
const element & root() const
Definition xml.inl:484
basic_xml(bool aStripWhitespace=false)
Definition xml.inl:444
node::const_iterator find(const node &aParent, const CharT *aName) const
Definition xml.inl:927
bool write(std::basic_ostream< CharT > &aStream)
Definition xml.inl:798
xml_element< CharT, allocator_type > element
Definition xml.hpp:427
node::iterator insert(node &aParent, typename node::iterator aPosition, const CharT *aName)
Definition xml.inl:909
node::iterator find_or_append(node &aParent, const CharT *aName)
Definition xml.inl:939
void set_strip_whitespace(bool aStripWhitespace)
Definition xml.inl:816
element & append(node &aParent, const CharT *aName)
Definition xml.inl:915
node::string string
Definition xml.hpp:425
bool got_root() const
Definition xml.inl:504
bool read(std::basic_istream< CharT > &aStream)
Definition xml.inl:747
const node & document() const
Definition xml.inl:472
void set_indent(CharT aIndentChar, std::size_t aIndentCount=1)
Definition xml.inl:809
void erase(node &aParent, typename node::iterator aPosition)
Definition xml.inl:921
abstract_iterator::iterator_wrapper iterator
size_type size() const noexcept final
Definition string.hpp:90
void clear() final
Definition string.hpp:92
const string & name() const
Definition xml.hpp:254
const string & text() const
Definition xml.inl:402
bool has_attribute(const string &aAttributeName) const
Definition xml.inl:377
void set_attribute(const string &aAttributeName, const string &aAttributeValue)
Definition xml.inl:412
void append_text(const string &aText)
Definition xml.inl:418
const string & attribute_value(const string &aAttributeName) const
Definition xml.inl:383
iterator find_or_append(const string &aName)
Definition xml.inl:346
const_iterator find_or_throw(const string &aName) const
Definition xml.inl:358
void erase(iterator aIterator)
Definition xml.hpp:190
iterator insert(iterator aIterator, node_ptr aNode)
Definition xml.hpp:183
std::optional< const_iterator > find_maybe(const string &aName) const
Definition xml.inl:317
const_iterator find(const string &aName) const
Definition xml.inl:308
const_iterator end(type_e aFilter=All) const
Definition xml.inl:287
const_iterator begin(type_e aFilter=All) const
Definition xml.inl:278
const string & content() const
Definition xml.hpp:302
const endl_t endl
Definition i_logger.hpp:77
Definition plf_hive.h:79
it_type next(it_type it, const typename iterator_traits< it_type >::difference_type distance=1)
Definition plf_hive.h:89