libcrn  3.9.5
A document image processing library
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
CRNXml.cpp
Go to the documentation of this file.
1 /* Copyright 2012-2016 CoReNum, INSA-Lyon
2  *
3  * This file is part of libcrn.
4  *
5  * libcrn is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU Lesser General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * libcrn is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with libcrn. If not, see <http://www.gnu.org/licenses/>.
17  *
18  * file: CRNXml.cpp
19  * \author Yann LEYDIER
20  */
21 
23 #include <CRNXml/CRNXml.h>
25 #include <CRNException.h>
26 #include <CRNi18n.h>
27 
28 using namespace crn;
29 using namespace xml;
30 
31 static void xmlerror(int err, const char *str1, const char *str2)
32 {
33  StringUTF8 msg;
34  if (str1)
35  {
36  msg += "\n";
37  msg += str1;
38  }
39  if (str2)
40  {
41  msg += "\n";
42  msg += str2;
43  }
44  switch (err)
45  {
46  //case tinyxml2::XML_NO_ERROR:
48  return;
50  throw ExceptionNotFound(_("Cannot find attribute.") + msg);
52  throw ExceptionDomain(_("Wrong attribute type.") + msg);
54  throw ExceptionNotFound(_("File not found.") + msg);
56  throw ExceptionIO(_("File could not be opened.") + msg);
58  throw ExceptionRuntime(_("File read error.") + msg);
61  throw ExceptionRuntime(_("Element mismatch.") + msg);
63  throw ExceptionRuntime(_("Could not parse element.") + msg);
65  throw ExceptionRuntime(_("Could not parse attribute.") + msg);
67  throw ExceptionRuntime(_("Could not identify tag.") + msg);
69  throw ExceptionRuntime(_("Could not parse text.") + msg);
71  throw ExceptionRuntime(_("Could not parse CDATA.") + msg);
73  throw ExceptionRuntime(_("Could not parse comment.") + msg);
75  throw ExceptionRuntime(_("Could not parse declaration.") + msg);
77  throw ExceptionRuntime(_("Could not parse unknown item.") + msg);
79  throw ExceptionRuntime(_("Empty document.") + msg);
81  throw ExceptionRuntime(_("Parse error.") + msg);
83  throw ExceptionRuntime(_("Cannot convert text.") + msg);
85  throw ExceptionNotFound(_("No text node.") + msg);
86  }
87 }
88 
90 // Node
92 
97 Node::Node(tinyxml2::XMLNode *n, const SCharsetConverter &c):
98  conv(c),
99  node(n)
100 { }
101 
104 {
105  if (!node)
106  return false;
107  return node->ToElement() != nullptr;
108 }
109 
112 {
113  if (!node)
114  return false;
115  return node->ToComment() != nullptr;
116 }
117 
120 {
121  if (!node)
122  return false;
123  return node->ToText() != nullptr;
124 }
125 
131 {
132  if (!node)
133  throw ExceptionDomain(_("Not an element."));
134  tinyxml2::XMLElement *el = node->ToElement();
135  if (!el)
136  throw ExceptionDomain(_("Not an element."));
137  return Element(el, conv);
138 }
139 
145 {
146  if (!node)
147  throw ExceptionDomain(_("Not a comment."));
148  tinyxml2::XMLComment *c = node->ToComment();
149  if (!c)
150  throw ExceptionDomain(_("Not a comment."));
151  return Comment(c, conv);
152 }
153 
159 {
160  if (!node)
161  throw ExceptionDomain(_("Not a text."));
162  tinyxml2::XMLText *t = node->ToText();
163  if (!t)
164  throw ExceptionDomain(_("Not a text."));
165  return Text(t, conv);
166 }
167 
172 {
173  return conv->ToUTF8(node->Value());
174 }
175 
182 {
183  node->SetValue(conv->FromUTF8(s).c_str());
184 }
185 
190 {
191  tinyxml2::XMLNode *par = const_cast<tinyxml2::XMLNode*>(node->Parent());
192  return Node(par, conv);
193 }
194 
199 {
200  return Node(node->PreviousSibling(), conv);
201 }
202 
207 {
208  return Node(node->NextSibling(), conv);
209 }
210 
215 {
216  *this = GetNextSibling();
217  return *this;
218 }
219 
224 {
225  Node bak(*this);
226  *this = GetNextSibling();
227  return bak;
228 }
229 
237 {
238  return Element(node->PreviousSiblingElement(name.IsEmpty() ? nullptr : conv->FromUTF8(name).c_str()), conv);
239 }
240 
248 {
249  return Element(node->NextSiblingElement(name.IsEmpty() ? nullptr : conv->FromUTF8(name).c_str()), conv);
250 }
251 
253 // Element
255 
260 Element::Element(tinyxml2::XMLElement *el, const SCharsetConverter &c):
261  Node(el, c),
262  element(el)
263 {
264  count_subnondes();
265 }
266 
268 void Element::count_subnondes()
269 {
270  nb_subnodes = 0;
271  nb_subelems = 0;
272  if (element)
273  {
274  for (tinyxml2::XMLNode *sn = element->FirstChild(); sn != nullptr; sn = sn->NextSibling())
275  nb_subnodes += 1;
276  for (tinyxml2::XMLElement *se = element->FirstChildElement(); se != nullptr; se = se->NextSiblingElement())
277  nb_subelems += 1;
278  }
279 }
280 
285 {
286  *this = GetNextSiblingElement();
287  return *this;
288 }
289 
294 {
295  Element bak(*this);
296  ++(*this);
297  return bak;
298 }
299 
304 {
305  return Node(element->FirstChild(), conv);
306 }
307 
312 {
313  return Node(element->LastChild(), conv);
314 }
315 
321 {
322  return Element(element->FirstChildElement(name.IsEmpty() ? nullptr : name.CStr()), conv);
323 }
324 
330 {
331  return Element(element->LastChildElement(name.IsEmpty() ? nullptr : name.CStr()), conv);
332 }
333 
340 {
341  Node n(GetFirstChild());
342  if (!n)
343  throw ExceptionNotFound(StringUTF8("const StringUTF8 Element::GetFirstChildText(): ") + _("No child node."));
344  Text t(n.AsText()); // may throw
345  return t.GetValue();
346 }
347 
356 {
357  if (name.IsEmpty())
358  throw ExceptionInvalidArgument(_("Empty element name."));
359  tinyxml2::XMLElement *el = element->GetDocument()->NewElement(conv->FromUTF8(name).c_str());
360  element->InsertEndChild(el);
361  nb_subnodes += 1;
362  nb_subelems += 1;
363  return Element(el, conv);
364 }
365 
374 {
375  if (name.IsEmpty())
376  throw ExceptionInvalidArgument(_("Empty element name."));
377  tinyxml2::XMLElement *el = element->GetDocument()->NewElement(conv->FromUTF8(name).c_str());
378  element->InsertFirstChild(el);
379  nb_subnodes += 1;
380  nb_subelems += 1;
381  return Element(el, conv);
382 }
383 
394 {
395  if (!n)
396  throw ExceptionInvalidArgument(_("Null node."));
397  if (name.IsEmpty())
398  throw ExceptionInvalidArgument(_("Empty element name."));
399  tinyxml2::XMLElement *el = element->GetDocument()->NewElement(conv->FromUTF8(name).c_str());
400  if (!element->InsertAfterChild(n.node, el))
401  {
402  element->GetDocument()->DeleteNode(el);
403  throw ExceptionNotFound(_("Node not found."));
404  }
405  nb_subnodes += 1;
406  nb_subelems += 1;
407  return Element(el, conv);
408 }
409 
417 {
418  tinyxml2::XMLComment *c = element->GetDocument()->NewComment(conv->FromUTF8(text).c_str());
419  element->InsertEndChild(c);
420  nb_subnodes += 1;
421  return Comment(c, conv);
422 }
423 
431 {
432  tinyxml2::XMLComment *c = element->GetDocument()->NewComment(conv->FromUTF8(text).c_str());
433  element->InsertFirstChild(c);
434  nb_subnodes += 1;
435  return Comment(c, conv);
436 }
437 
447 {
448  if (!n)
449  throw ExceptionInvalidArgument(_("Null node."));
450  tinyxml2::XMLComment *c = element->GetDocument()->NewComment(conv->FromUTF8(text).c_str());
451  if (!element->InsertAfterChild(n.node, c))
452  {
453  element->GetDocument()->DeleteNode(c);
454  throw ExceptionNotFound(_("Node not found."));
455  }
456  nb_subnodes += 1;
457  return Comment(c, conv);
458 }
459 
467 Text Element::PushBackText(const StringUTF8 &text, bool cdata)
468 {
469  tinyxml2::XMLText *t = element->GetDocument()->NewText(cdata ? text.CStr() : conv->FromUTF8(text).c_str());
470  t->SetCData(cdata);
471  element->InsertEndChild(t);
472  nb_subnodes += 1;
473  return Text(t, conv);
474 }
475 
483 Text Element::PushFrontText(const StringUTF8 &text, bool cdata)
484 {
485  tinyxml2::XMLText *t = element->GetDocument()->NewText(cdata ? text.CStr() : conv->FromUTF8(text).c_str());
486  t->SetCData(cdata);
487  element->InsertFirstChild(t);
488  nb_subnodes += 1;
489  return Text(t, conv);
490 }
491 
502 Text Element::InsertText(Node &n, const StringUTF8 &text, bool cdata)
503 {
504  if (!n)
505  throw ExceptionInvalidArgument(_("Null node."));
506  tinyxml2::XMLText *t = element->GetDocument()->NewText(cdata ? text.CStr() : conv->FromUTF8(text).c_str());
507  t->SetCData(cdata);
508  if (!element->InsertAfterChild(n.node, t))
509  {
510  element->GetDocument()->DeleteNode(t);
511  throw ExceptionNotFound(_("Node not found."));
512  }
513  nb_subnodes += 1;
514  return Text(t, conv);
515 }
516 
523 Node Element::PushBackClone(Node &n, bool recursive)
524 {
525  if (!n)
526  throw ExceptionInvalidArgument(_("Null node."));
527  // element?
528  try
529  {
530  Element el(n.AsElement());
531  Element newel(PushBackElement(el.GetName()));
532  for (Element::Attribute a = el.BeginAttribute(); a != el.EndAttribute(); ++a)
533  newel.SetAttribute(a.GetName(), a.GetValue<StringUTF8>());
534  if (recursive)
535  {
536  for (Node sn = el.BeginNode(); sn != el.EndNode(); ++sn)
537  newel.PushBackClone(sn, recursive);
538  }
539  return newel;
540  }
541  catch (ExceptionDomain &) { }
542  // comment?
543  try
544  {
545  Comment c(n.AsComment());
546  return PushBackComment(c.GetValue());
547  }
548  catch (ExceptionDomain &) { }
549  // text?
550  try
551  {
552  Text t(n.AsText());
553  return PushBackText(t.GetValue(), t.IsCData());
554  }
555  catch (ExceptionDomain &) { }
556  // other
557  // - declaration: not possible in an element
558  // - unknown
559  tinyxml2::XMLUnknown *un = n.node->ToUnknown();
560  if (un)
561  {
562  tinyxml2::XMLUnknown *nun = element->GetDocument()->NewUnknown(un->Value());
563  element->InsertEndChild(nun);
564  nb_subnodes += 1;
565  return Node(nun, conv);
566  }
567  else
568  throw ExceptionInvalidArgument(_("Invalid node."));
569 }
570 
573 {
574  element->DeleteChildren();
575  count_subnondes();
576 }
577 
582 {
583  element->DeleteChild(n.node);
584  n.node = nullptr;
585  count_subnondes();
586 }
587 
595 void Element::SetAttribute(const StringUTF8 &name, const StringUTF8 &value)
596 {
597  if (name.IsEmpty())
598  throw ExceptionInvalidArgument(_("Empty attribute name."));
599  element->SetAttribute(conv->FromUTF8(name).c_str(), conv->FromUTF8(value).c_str());
600 }
601 
609 {
610  if (name.IsEmpty())
611  throw ExceptionInvalidArgument(_("Empty attribute name."));
612  element->DeleteAttribute(conv->FromUTF8(name).c_str());
613 }
614 
619 {
620  return Attribute(const_cast<tinyxml2::XMLAttribute*>(element->FirstAttribute()), conv);
621 }
622 
627 {
628  return Attribute(nullptr, conv);
629 }
630 
639 void Element::queryAttribute(const StringUTF8 &name, StringUTF8 &value) const
640 {
641  if (name.IsEmpty())
642  throw ExceptionInvalidArgument(_("Empty attribute name."));
643  const char *val = element->Attribute(conv->FromUTF8(name).c_str());
644  if (!val)
645  throw ExceptionNotFound(_("Cannot find attribute: ") + name);
646  value = conv->ToUTF8(val);
647 }
648 
658 void Element::queryAttribute(const StringUTF8 &name, int &value) const
659 {
660  if (name.IsEmpty())
661  throw ExceptionInvalidArgument(_("Empty attribute name."));
662  int res = element->QueryIntAttribute(conv->FromUTF8(name).c_str(), &value);
663  xmlerror(res, element->GetDocument()->GetErrorStr1(), element->GetDocument()->GetErrorStr2());
664 }
665 
675 void Element::queryAttribute(const StringUTF8 &name, unsigned int &value) const
676 {
677  if (name.IsEmpty())
678  throw ExceptionInvalidArgument(_("Empty attribute name."));
679  int res = element->QueryUnsignedAttribute(conv->FromUTF8(name).c_str(), &value);
680  xmlerror(res, element->GetDocument()->GetErrorStr1(), element->GetDocument()->GetErrorStr2());
681 }
682 
692 void Element::queryAttribute(const StringUTF8 &name, bool &value) const
693 {
694  if (name.IsEmpty())
695  throw ExceptionInvalidArgument(_("Empty attribute name."));
696  int res = element->QueryBoolAttribute(conv->FromUTF8(name).c_str(), &value);
697  xmlerror(res, element->GetDocument()->GetErrorStr1(), element->GetDocument()->GetErrorStr2());
698 }
699 
709 void Element::queryAttribute(const StringUTF8 &name, double &value) const
710 {
711  if (name.IsEmpty())
712  throw ExceptionInvalidArgument(_("Empty attribute name."));
713  int res = element->QueryDoubleAttribute(conv->FromUTF8(name).c_str(), &value);
714  xmlerror(res, element->GetDocument()->GetErrorStr1(), element->GetDocument()->GetErrorStr2());
715 }
716 
726 void Element::queryAttribute(const StringUTF8 &name, float &value) const
727 {
728  if (name.IsEmpty())
729  throw ExceptionInvalidArgument(_("Empty attribute name."));
730  int res = element->QueryFloatAttribute(conv->FromUTF8(name).c_str(), &value);
731  xmlerror(res, element->GetDocument()->GetErrorStr1(), element->GetDocument()->GetErrorStr2());
732 }
733 
735 // Attribute
737 
742 Element::Attribute::Attribute(tinyxml2::XMLAttribute *a, const SCharsetConverter &c):
743  attr(a),
744  conv(c)
745 { }
746 
751 {
752  attr = const_cast<tinyxml2::XMLAttribute*>(attr->Next());
753  return *this;
754 }
755 
760 {
761  Attribute bak(*this);
762  attr = const_cast<tinyxml2::XMLAttribute*>(attr->Next());
763  return bak;
764 }
765 
770 {
771  return Attribute(const_cast<tinyxml2::XMLAttribute*>(attr->Next()), conv);
772 }
773 
778 {
779  return conv->ToUTF8(attr->Name());
780 }
781 
788 {
789  attr->SetAttribute(conv->FromUTF8(value).c_str());
790 }
791 
795 void Element::Attribute::queryValue(StringUTF8 &value) const
796 {
797  const char *val = attr->Value();
798  value = conv->ToUTF8(val);
799 }
800 
805 void Element::Attribute::queryValue(int &value) const
806 {
807  int res = attr->QueryIntValue(&value);
808  xmlerror(res, nullptr, nullptr);
809 }
810 
815 void Element::Attribute::queryValue(unsigned int &value) const
816 {
817  int res = attr->QueryUnsignedValue(&value);
818  xmlerror(res, nullptr, nullptr);
819 }
820 
825 void Element::Attribute::queryValue(bool &value) const
826 {
827  int res = attr->QueryBoolValue(&value);
828  xmlerror(res, nullptr, nullptr);
829 }
830 
835 void Element::Attribute::queryValue(double &value) const
836 {
837  int res = attr->QueryDoubleValue(&value);
838  xmlerror(res, nullptr, nullptr);
839 }
840 
845 void Element::Attribute::queryValue(float &value) const
846 {
847  int res = attr->QueryFloatValue(&value);
848  xmlerror(res, nullptr, nullptr);
849 }
850 
852 // Comment
854 
859 Comment::Comment(tinyxml2::XMLComment *c, const SCharsetConverter &co):
860  Node(c, co),
861  comment(c)
862 { }
863 
865 // Text
867 
872 Text::Text(tinyxml2::XMLText *t, const SCharsetConverter &c):
873  Node(t, c),
874  text(t)
875 { }
876 
880 bool Text::IsCData() const
881 {
882  return text->CData();
883 }
884 
889 {
890  if (text->CData())
891  return text->Value();
892  else
893  return conv->ToUTF8(text->Value());
894 }
895 
897 // Document
899 
907 Document::Document(const StringUTF8 &encoding, const StringUTF8 &version, bool char_conversion_throws):
908  doc(std::make_unique<tinyxml2::XMLDocument>()),
909  enc(encoding),
910  ver(version),
911  conv(std::make_shared<CharsetConverter>(encoding.Std(), true, char_conversion_throws))
912 {
913  StringUTF8 decl = "xml version=\"" + version + "\" encoding=\"" + encoding + "\"";
914  doc->InsertEndChild(doc->NewDeclaration(conv->FromUTF8(decl).c_str()));
915 }
916 
924 Document::Document(const Path &fname, bool char_conversion_throws):
925  doc(std::make_unique<tinyxml2::XMLDocument>()),
926  filename(fname)
927 {
928  int res = doc->LoadFile(fname.CStr());
929  if (res)
930  {
931  crn::StringUTF8 s1, s2;
932  if (doc->GetErrorStr1())
933  s1 = doc->GetErrorStr1();
934  if (doc->GetErrorStr2())
935  s2 = doc->GetErrorStr2();
936  doc.reset();
937  xmlerror(res, s1.IsEmpty() ? nullptr : s1.CStr(), s2.IsEmpty() ? nullptr : s2.CStr());
938  }
939  tinyxml2::XMLNode *node = doc->FirstChild();
940  while (node)
941  {
942  tinyxml2::XMLDeclaration *decl = node->ToDeclaration();
943  if (decl)
944  {
945  StringUTF8 val = decl->Value();
946  StringUTF8 ekey = "encoding=";
947  size_t beg = val.Find(ekey);
948  if (beg == StringUTF8::NPos())
949  enc = "UTF-8";
950  else
951  {
952  beg += ekey.Size();
953  char sep = val[beg];
954  beg += 1;
955  size_t en = val.Find(sep, beg);
956  if (en == StringUTF8::NPos())
957  enc = "UTF-8";
958  else
959  enc = val.SubString(beg, en - beg);
960  }
961  StringUTF8 vkey = "version=";
962  beg = val.Find(vkey);
963  if (beg == StringUTF8::NPos())
964  ver = "1.0";
965  else
966  {
967  beg += vkey.Size();
968  char sep = val[beg];
969  beg += 1;
970  size_t en = val.Find(sep, beg);
971  if (en == StringUTF8::NPos())
972  ver = "1.0";
973  else
974  ver = val.SubString(beg, en - beg);
975  }
976  }
977  node = node->NextSibling();
978  }
979  conv = std::make_shared<CharsetConverter>(enc.Std(), true, char_conversion_throws);
980 }
981 
987 Document::Document(const char *content, bool char_conversion_throws):
988  doc(std::make_unique<tinyxml2::XMLDocument>()),
989  enc("UTF-8"),
990  ver("1.0"),
991  conv(std::make_shared<CharsetConverter>("UTF-8", true, char_conversion_throws))
992 {
993  int res = doc->Parse(content);
994  xmlerror(res, doc->GetErrorStr1(), doc->GetErrorStr2());
995 }
996 
998 Document::~Document() = default;
999 
1000 Document::Document(Document&&) = default;
1001 Document& Document::operator=(Document&&) = default;
1002 
1009 void Document::Save(const Path &fname)
1010 {
1011  int res = doc->SaveFile(fname.CStr());
1012  xmlerror(res, doc->GetErrorStr1(), doc->GetErrorStr2());
1013  filename = fname;
1014 }
1015 
1023 {
1024  if (filename.IsEmpty())
1025  throw ExceptionUninitialized(_("Empty filename."));
1026  int res = doc->SaveFile(filename.CStr());
1027  xmlerror(res, doc->GetErrorStr1(), doc->GetErrorStr2());
1028 }
1029 
1035 {
1036  Element el(BeginElement());
1037  if (el == EndElement())
1038  throw ExceptionNotFound(_("No element in the XML."));
1039  return el;
1040 }
1041 
1046 {
1047  return Node(doc->FirstChild(), conv);
1048 }
1049 
1054 {
1055  return Node(doc->LastChild(), conv);
1056 }
1057 
1065 {
1066  return Element(doc->FirstChildElement(name.IsEmpty() ? nullptr : conv->FromUTF8(name).c_str()), conv);
1067 }
1068 
1076 {
1077  return Element(doc->LastChildElement(name.IsEmpty() ? nullptr : conv->FromUTF8(name).c_str()), conv);
1078 }
1079 
1088 {
1089  if (name.IsEmpty())
1090  throw ExceptionInvalidArgument(_("Empty element name."));
1091  tinyxml2::XMLElement *el = doc->NewElement(conv->FromUTF8(name).c_str());
1092  doc->InsertEndChild(el);
1093  return Element(el, conv);
1094 }
1095 
1106 {
1107  if (!n)
1108  throw ExceptionInvalidArgument(_("Null node."));
1109  if (name.IsEmpty())
1110  throw ExceptionInvalidArgument(_("Empty element name."));
1111  tinyxml2::XMLElement *el = doc->NewElement(conv->FromUTF8(name).c_str());
1112  if (!doc->InsertAfterChild(n.node, el))
1113  {
1114  doc->GetDocument()->DeleteNode(el);
1115  throw ExceptionNotFound(_("Node not found."));
1116  }
1117  return Element(el, conv);
1118 }
1119 
1127 {
1128  tinyxml2::XMLComment *c = doc->NewComment(conv->FromUTF8(text).c_str());
1129  doc->InsertEndChild(c);
1130  return Comment(c, conv);
1131 }
1132 
1142 {
1143  if (!n)
1144  throw ExceptionInvalidArgument(_("Null node."));
1145  tinyxml2::XMLComment *c = doc->NewComment(conv->FromUTF8(text).c_str());
1146  if (!doc->InsertAfterChild(n.node, c))
1147  {
1148  doc->GetDocument()->DeleteNode(c);
1149  throw ExceptionNotFound(_("Node not found."));
1150  }
1151  return Comment(c, conv);
1152 }
1153 
1160 Node Document::PushBackClone(Node &n, bool recursive)
1161 {
1162  if (!n)
1163  throw ExceptionInvalidArgument(_("Null node."));
1164  // element?
1165  try
1166  {
1167  Element el(n.AsElement());
1168  Element newel(PushBackElement(el.GetName()));
1169  for (Element::Attribute a = el.BeginAttribute(); a != el.EndAttribute(); ++a)
1170  newel.SetAttribute(a.GetName(), a.GetValue<StringUTF8>());
1171  if (recursive)
1172  {
1173  for (Node sn = el.BeginNode(); sn != el.EndNode(); ++sn)
1174  newel.PushBackClone(sn, recursive);
1175  }
1176  return newel;
1177  }
1178  catch (ExceptionDomain &) { }
1179  // comment?
1180  try
1181  {
1182  Comment c(n.AsComment());
1183  return PushBackComment(c.GetValue());
1184  }
1185  catch (ExceptionDomain &) { }
1186  // text?
1187  try
1188  {
1189  Text t(n.AsText());
1190  tinyxml2::XMLText *tx = doc->NewText(t.IsCData() ? t.GetValue().CStr() : conv->FromUTF8(t.GetValue()).c_str());
1191  tx->SetCData(t.IsCData());
1192  doc->InsertEndChild(tx);
1193  return Text(tx, conv);
1194  }
1195  catch (ExceptionDomain &) { }
1196  // declaration?
1197  tinyxml2::XMLDeclaration *de = n.node->ToDeclaration();
1198  if (de)
1199  {
1200  tinyxml2::XMLDeclaration *nde = doc->NewDeclaration(de->Value());
1201  doc->InsertEndChild(nde);
1202  return Node(nde, conv);
1203  }
1204  // unknown?
1205  tinyxml2::XMLUnknown *un = n.node->ToUnknown();
1206  if (un)
1207  {
1208  tinyxml2::XMLUnknown *nun = doc->NewUnknown(un->Value());
1209  doc->InsertEndChild(nun);
1210  return Node(nun, conv);
1211  }
1212  throw ExceptionInvalidArgument(_("Invalid node."));
1213 }
1214 
1219 {
1221  doc->Print(&pr);
1222  return pr.CStr();
1223 }
1224 
void SetValue(const char *val, bool staticMem=false)
Definition: tinyxml2.cpp:727
Attribute & operator++()
Move to next attribute.
Definition: CRNXml.cpp:750
friend class Element
Definition: CRNXml.h:124
void Save()
Saves to file.
Definition: CRNXml.cpp:1022
bool CData() const
Returns true if this is a CDATA text element.
Definition: tinyxml2.h:913
const XMLNode * Parent() const
Get the parent of this node on the DOM.
Definition: tinyxml2.h:691
bool IsText()
Checks if the node is a text.
Definition: CRNXml.cpp:119
virtual StringUTF8 GetValue() const override
Gets the content of the node.
Definition: CRNXml.cpp:888
Comment PushFrontComment(const StringUTF8 &text)
Adds a comment at the front of the children list.
Definition: CRNXml.cpp:430
Node PushBackClone(Node &n, bool recursive=false)
Adds a copy of a node at the end of the children list.
Definition: CRNXml.cpp:523
XMLNode * InsertEndChild(XMLNode *addThis)
Definition: tinyxml2.cpp:784
void Clear()
Removes all children.
Definition: CRNXml.cpp:572
Text(const Text &)=default
XMLError QueryBoolAttribute(const char *name, bool *value) const
See QueryIntAttribute()
Definition: tinyxml2.h:1254
virtual XMLElement * ToElement()
Safely cast to an Element, or null.
Definition: tinyxml2.h:631
virtual XMLText * ToText()
Safely cast to Text, or null.
Definition: tinyxml2.h:635
Comment PushBackComment(const StringUTF8 &text)
Adds a comment at the end of the children list.
Definition: CRNXml.cpp:1126
const char * Value() const
Definition: tinyxml2.cpp:719
XMLText * NewText(const char *text)
Definition: tinyxml2.cpp:1843
XML comment.
Definition: CRNXml.h:364
XML element.
Definition: CRNXml.h:135
A generic runtime error.
Definition: CRNException.h:131
void DeleteChildren()
Definition: tinyxml2.cpp:738
XMLComment * NewComment(const char *comment)
Definition: tinyxml2.cpp:1833
const XMLNode * LastChild() const
Get the last child node, or null if none exists.
Definition: tinyxml2.h:723
SCharsetConverter conv
Definition: CRNXml.h:118
#define _(String)
Definition: CRNi18n.h:51
void SetCData(bool isCData)
Declare whether this should be CDATA or standard text.
Definition: tinyxml2.h:909
bool IsComment()
Checks if the node is a comment.
Definition: CRNXml.cpp:111
Element EndElement()
Gets a null node.
Definition: CRNXml.h:481
Element(const Element &)=default
Text AsText()
Converts to text.
Definition: CRNXml.cpp:158
Unintialized object error.
Definition: CRNException.h:155
Element GetRoot()
Gets the first element.
Definition: CRNXml.cpp:1034
XMLError QueryUnsignedAttribute(const char *name, unsigned int *value) const
See QueryIntAttribute()
Definition: tinyxml2.h:1246
Element PushBackElement(const StringUTF8 &name)
Adds an element at the end of the children list.
Definition: CRNXml.cpp:1087
Element AsElement()
Converts to element.
Definition: CRNXml.cpp:130
Attribute EndAttribute()
Gets the null attribute.
Definition: CRNXml.cpp:626
Element InsertElement(Node &n, const StringUTF8 &name)
Inserts an element after a node.
Definition: CRNXml.cpp:393
Element GetLastElement(const StringUTF8 &name="")
Gets the last child element.
Definition: CRNXml.cpp:1075
Element GetNextSiblingElement(const StringUTF8 &name="")
Gets the next sibling element.
Definition: CRNXml.cpp:247
void DeleteNode(XMLNode *node)
Definition: tinyxml2.cpp:1888
const char * Attribute(const char *name, const char *value=0) const
Definition: tinyxml2.cpp:1404
void DeleteChild(XMLNode *node)
Definition: tinyxml2.cpp:774
XMLError QueryFloatAttribute(const char *name, float *value) const
See QueryIntAttribute()
Definition: tinyxml2.h:1270
Text PushBackText(const StringUTF8 &text, bool cdata=false)
Adds a text at the end of the children list.
Definition: CRNXml.cpp:467
Element GetLastChildElement(const StringUTF8 &name="")
Gets the last child element.
Definition: CRNXml.cpp:329
Text PushFrontText(const StringUTF8 &text, bool cdata=false)
Adds a text at the front of the children list.
Definition: CRNXml.cpp:483
Node GetLastNode()
Gets the last child node.
Definition: CRNXml.cpp:1053
Comment(const Comment &)=default
A generic domain error.
Definition: CRNException.h:83
const XMLElement * NextSiblingElement(const char *name=0) const
Get the next (right) sibling element of this node, with an optionally supplied name.
Definition: tinyxml2.cpp:904
Node GetParent()
Gets the parent node if any.
Definition: CRNXml.cpp:189
Comment InsertComment(Node &n, const StringUTF8 &text)
Inserts a comment after a node.
Definition: CRNXml.cpp:1141
StringUTF8 SubString(size_t pos, size_t n=0) const
Extracts a part of the string.
Document & operator=(const Document &)=delete
const char * CStr() const noexcept
Conversion to UTF8 cstring.
Element GetFirstChildElement(const StringUTF8 &name="")
Gets the first child element.
Definition: CRNXml.cpp:320
Node GetLastChild()
Gets the last child node.
Definition: CRNXml.cpp:311
bool IsEmpty() const noexcept
Checks if the string is empty.
A convenience class for file paths.
Definition: CRNPath.h:39
const XMLElement * PreviousSiblingElement(const char *name=0) const
Get the previous (left) sibling element of this node, with an optionally supplied name...
Definition: tinyxml2.cpp:917
bool IsElement()
Checks if the node is an element.
Definition: CRNXml.cpp:103
XML text.
Definition: CRNXml.h:394
const XMLDocument * GetDocument() const
Get the XMLDocument that owns this XMLNode.
Definition: tinyxml2.h:620
virtual StringUTF8 GetValue() const
Gets the content of the node.
Definition: CRNXml.cpp:171
Element GetPreviousSiblingElement(const StringUTF8 &name="")
Gets the previous sibling element.
Definition: CRNXml.cpp:236
Node GetFirstNode()
Gets the first child node.
Definition: CRNXml.cpp:1045
void SetValue(const StringUTF8 &s)
Sets the content of the node.
Definition: CRNXml.cpp:181
Element BeginElement()
Gets the first child element.
Definition: CRNXml.h:479
Document(const StringUTF8 &encoding="UTF-8", const StringUTF8 &version="1.0", bool char_conversion_throws=true)
Constructor.
void SetAttribute(const StringUTF8 &name, const StringUTF8 &value)
Sets the value of an attribute.
Definition: CRNXml.cpp:595
#define true
Definition: ConvertUTF.cpp:57
static size_t NPos() noexcept
Last position in a string.
const XMLNode * NextSibling() const
Get the next (right) sibling node of this node.
Definition: tinyxml2.h:757
StringUTF8 AsString()
Exports the document to a string.
Definition: CRNXml.cpp:1218
Element & operator++()
Moves to the next sibling element.
Definition: CRNXml.cpp:284
XMLElement * NewElement(const char *name)
Definition: tinyxml2.cpp:1823
void SetValue(const StringUTF8 &value)
Sets the value of the attribute.
Definition: CRNXml.cpp:787
StringUTF8 GetName() const
Gets the name of the attribute.
Definition: CRNXml.cpp:777
const char * GetErrorStr2() const
Return a possibly helpful secondary diagnostic location or string.
Definition: tinyxml2.h:1691
Node GetFirstChild()
Gets the first child node.
Definition: CRNXml.cpp:303
Element GetFirstElement(const StringUTF8 &name="")
Gets the first child element.
Definition: CRNXml.cpp:1064
void SetAttribute(const char *name, const char *value)
Sets the named attribute to value.
Definition: tinyxml2.h:1317
Comment PushBackComment(const StringUTF8 &text)
Adds a comment at the end of the children list.
Definition: CRNXml.cpp:416
const char * CStr() const
Definition: tinyxml2.h:2042
XMLError QueryIntAttribute(const char *name, int *value) const
Definition: tinyxml2.h:1238
Attribute Next()
Gets next attribute.
Definition: CRNXml.cpp:769
Text InsertText(Node &n, const StringUTF8 &text, bool cdata=false)
Inserts a text after a node.
Definition: CRNXml.cpp:502
Character set converter.
const XMLAttribute * Next() const
The next attribute in the list.
Definition: tinyxml2.h:1055
const char * GetErrorStr1() const
Return a possibly helpful diagnostic location or string.
Definition: tinyxml2.h:1687
const XMLElement * LastChildElement(const char *name=0) const
Definition: tinyxml2.cpp:890
Node & operator++()
Moves to the next sibling node.
Definition: CRNXml.cpp:214
Node GetPreviousSibling()
Gets the previous sibling node.
Definition: CRNXml.cpp:198
XMLUnknown * NewUnknown(const char *text)
Definition: tinyxml2.cpp:1863
Node GetNextSibling()
Gets the next sibling node.
Definition: CRNXml.cpp:206
Attribute BeginAttribute()
Gets the first attribute.
Definition: CRNXml.cpp:618
const XMLNode * PreviousSibling() const
Get the previous (left) sibling node of this node.
Definition: tinyxml2.h:741
StringUTF8 GetFirstChildText()
Gets the first child as text.
Definition: CRNXml.cpp:339
const XMLElement * FirstChildElement(const char *name=0) const
Definition: tinyxml2.cpp:876
Element InsertElement(Node &n, const StringUTF8 &name)
Inserts an element after a node.
Definition: CRNXml.cpp:1105
size_t Size() const noexcept
Returns the number of bytes in the string.
XMLNode * InsertAfterChild(XMLNode *afterThis, XMLNode *addThis)
Definition: tinyxml2.cpp:845
void DeleteAttribute(const char *name)
Definition: tinyxml2.cpp:1571
Element PushFrontElement(const StringUTF8 &name)
Adds an element at the front of the children list.
Definition: CRNXml.cpp:373
Comment AsComment()
Converts to comment.
Definition: CRNXml.cpp:144
A character string class.
Definition: CRNStringUTF8.h:49
size_t Find(const StringUTF8 &s, size_t from_pos=0) const
Finds the first occurrence of a string.
Node PushBackClone(Node &n, bool recursive=false)
Adds a copy of a node at the end of the children list.
Definition: CRNXml.cpp:1160
Node(const Node &)=default
bool IsCData() const
Is the text a CData?
Definition: CRNXml.cpp:880
virtual XMLUnknown * ToUnknown()
Safely cast to an Unknown, or null.
Definition: tinyxml2.h:651
XMLError QueryDoubleAttribute(const char *name, double *value) const
See QueryIntAttribute()
Definition: tinyxml2.h:1262
virtual ~Document()
Destructor.
const XMLNode * FirstChild() const
Get the first child node, or null if none exists.
Definition: tinyxml2.h:705
I/O error.
Definition: CRNException.h:179
friend class Node
Definition: CRNXml.h:332
virtual XMLDeclaration * ToDeclaration()
Safely cast to a Declaration, or null.
Definition: tinyxml2.h:647
Element PushBackElement(const StringUTF8 &name)
Adds an element at the end of the children list.
Definition: CRNXml.cpp:355
const XMLAttribute * FirstAttribute() const
Return the first attribute in the list.
Definition: tinyxml2.h:1353
void RemoveChild(Node &n)
Removes a child node.
Definition: CRNXml.cpp:581
Comment InsertComment(Node &n, const StringUTF8 &text)
Inserts a comment after a node.
Definition: CRNXml.cpp:446
XML node.
Definition: CRNXml.h:60
Invalid argument error (e.g.: nullptr pointer)
Definition: CRNException.h:107
Attribute(const Attribute &)=default
An item was not found in a container.
Definition: CRNException.h:95
void RemoveAttribute(const StringUTF8 &name)
Removes an attribute.
Definition: CRNXml.cpp:608
XMLNode * InsertFirstChild(XMLNode *addThis)
Definition: tinyxml2.cpp:814
virtual XMLComment * ToComment()
Safely cast to a Comment, or null.
Definition: tinyxml2.h:639
Document utility class.
Definition: CRNDocument.h:52