Cantera 2.6.0
xml.cpp
Go to the documentation of this file.
1/**
2 * @file xml.cpp
3 * Classes providing support for XML data files. These classes
4 * implement only those aspects of XML required to read, write, and
5 * manipulate CTML data files.
6 */
7
8// This file is part of Cantera. See License.txt in the top-level directory or
9// at https://cantera.org/license.txt for license and copyright information.
10
11#include "cantera/base/xml.h"
13#include "cantera/base/global.h"
16
17#include <sstream>
18#include <fstream>
19
20using namespace std;
21
22namespace Cantera
23{
24////////////////////// exceptions ////////////////////////////
25
26//! Class representing a generic XML error condition
27class XML_Error : public CanteraError
28{
29protected:
30 //! Constructor
31 /*!
32 * Note, we don't actually post the error in this class. Therefore, this
33 * class can't be used externally. Therefore, it's a protected constructor.
34 *
35 * @param file Name of the XML file being processed
36 * @param line Number number where the error occurred.
37 */
38 XML_Error(const std::string& file, int line) {
39 m_msg = fmt::format("Error in XML file '{}' at line {}.\n", file, line);
40 }
41
42 virtual std::string getMessage() const {
43 return m_msg;
44 }
45
46 //! destructor
47 virtual ~XML_Error() throw() {
48 }
49
50 //! String message for the error
51 std::string m_msg;
52};
53
54//! Class representing a specific type of XML file formatting error
55/*!
56 * An XML tag is not matched
57 */
59{
60public:
61 //! Constructor
62 /*!
63 * An XML element must have the same opening and closing name.
64 *
65 * @param opentag String representing the opening of the XML bracket
66 * @param closetag String representing the closing of the XML bracket
67 * @param filename Name of the XML file being processed
68 * @param line Line number where the error occurred.
69 */
70 XML_TagMismatch(const std::string& opentag, const std::string& closetag,
71 const std::string& filename, int line) :
72 XML_Error(filename, line) {
73 m_msg += fmt::format("<{}> paired with </{}>.\n", opentag, closetag);
74 }
75
76 virtual std::string getClass() const {
77 return "XML_TagMismatch";
78 }
79};
80
81//! Class representing a specific type of XML file formatting error
82/*!
83 * An XML_Node doesn't have a required child node
84 */
85class XML_NoChild : public XML_Error
86{
87public:
88 //! Constructor
89 /*!
90 * An XML element doesn't have the required child node
91 *
92 * @param p XML_Node to write a string error message
93 * @param parent Name of the parent node
94 * @param child Name of the required child node
95 * @param filename Name of the XML file being processed
96 * @param line Line number where the error occurred.
97 */
98 XML_NoChild(const XML_Node* p, const std::string& parent,
99 std::string child, const std::string& filename, int line) :
100 XML_Error(filename, line) {
101 m_msg += fmt::format("The XML Node <{}> does not contain a required "
102 "child node named <{}>.\nExisting children are named:\n",
103 parent, child);
104 for (auto cnode : p->children()) {
105 m_msg += fmt::format(" <{}>\n", cnode->name());
106 }
107 }
108
109 virtual std::string getClass() const {
110 return "XML_NoChild";
111 }
112};
113
114//////////////////// XML_Reader methods ///////////////////////
115
116XML_Reader::XML_Reader(std::istream& input) :
117 m_s(input),
118 m_line(0)
119{
120}
121
122void XML_Reader::getchr(char& ch)
123{
124 m_s.get(ch);
125 if (ch == '\n') {
126 m_line++;
127 }
128}
129
130//! Find the first position of a character, q, in string, s, which is not
131//! immediately preceded by the backslash character
132/*!
133 * @param s Input string
134 * @param q Search for this character
135 * @param istart Defaults to 0
136 */
137static string::size_type findUnbackslashed(const std::string& s, const char q,
138 std::string::size_type istart = 0)
139{
140 size_t icurrent = istart;
141 while (true) {
142 size_t iloc = s.find(q, icurrent);
143 if (iloc == string::npos || iloc == 0) {
144 return iloc;
145 }
146 char cm1 = s[iloc-1];
147 if (cm1 == '\\') {
148 if (iloc >= (s.size() -1)) {
149 return string::npos;
150 }
151 icurrent = iloc + 1;
152 } else {
153 return iloc;
154 }
155 }
156}
157
158int XML_Reader::findQuotedString(const std::string& s, std::string& rstring) const
159{
160 const char q1 = '\'';
161 const char q2 = '"';
162 rstring = "";
163 char qtype = ' ';
164 string::size_type iloc1, iloc2, ilocStart = 0;
165 iloc1 = findUnbackslashed(s, q1);
166 iloc2 = findUnbackslashed(s, q2);
167 if (iloc2 != string::npos) {
168 ilocStart = iloc2;
169 qtype = q2;
170 }
171 if (iloc1 != string::npos && iloc1 < ilocStart) {
172 ilocStart = iloc1;
173 qtype = q1;
174 }
175 if (qtype == ' ') {
176 return 0;
177 }
178
179 iloc1 = findUnbackslashed(s, qtype, ilocStart+1);
180
181 if (iloc1 == string::npos) {
182 return 0;
183 }
184
185 // Define the return string by the two endpoints. Strip the surrounding
186 // quotes as well
187 rstring = s.substr(ilocStart + 1, iloc1 - 1);
188
189 // Return the first character position past the quotes
190 return static_cast<int>(iloc1)+1;
191}
192
193void XML_Reader::parseTag(const std::string& tag, std::string& name,
194 std::map<std::string, std::string>& attribs) const
195{
196 string s = trimCopy(tag);
197 size_t iloc = s.find(' ');
198 if (iloc != string::npos) {
199 name = s.substr(0, iloc);
200 s = trimCopy(s.substr(iloc+1,s.size()));
201 if (s[s.size()-1] == '/') {
202 name += "/";
203 }
204
205 // get attributes
206 while (true) {
207 iloc = s.find('=');
208 if (iloc == string::npos) {
209 break;
210 }
211 string attr = trimCopy(s.substr(0,iloc));
212 if (attr == "") {
213 break;
214 }
215 s = trimCopy(s.substr(iloc+1,s.size()));
216 string val;
217 iloc = findQuotedString(s, val);
218 attribs[attr] = val;
219 if (iloc != string::npos) {
220 if (iloc < s.size()) {
221 s = trimCopy(s.substr(iloc,s.size()));
222 } else {
223 break;
224 }
225 }
226 }
227 } else {
228 name = s;
229 }
230}
231
232std::string XML_Reader::readTag(std::map<std::string, std::string>& attribs)
233{
234 string tag = "";
235 bool incomment = false;
236 char ch = '-';
237 while (true) {
238 if (m_s.eof() || (getchr(ch), ch == '<')) {
239 break;
240 }
241 }
242 char ch1 = ' ', ch2 = ' ';
243 while (true) {
244 if (m_s.eof()) {
245 tag = "EOF";
246 break;
247 }
248 ch2 = ch1;
249 ch1 = ch;
250 getchr(ch);
251 if (ch == '-') {
252 if (ch1 == '-' && ch2 == '!') {
253 incomment = true;
254 tag = "-";
255 }
256 } else if (ch == '>') {
257 if (incomment) {
258 if (ch1 == '-' && ch2 == '-') {
259 break;
260 }
261 } else {
262 break;
263 }
264 }
265 if (isprint(ch)) {
266 tag += ch;
267 }
268 }
269 if (incomment) {
270 attribs.clear();
271 return tag;
272 } else {
273 string name;
274 parseTag(tag, name, attribs);
275 return name;
276 }
277}
278
280{
281 string tag = "";
282 char ch = '\n';
283 bool front = true;
284 while (true) {
285 if (m_s.eof()) {
286 break;
287 }
288 char lastch = ch;
289 getchr(ch);
290 if (ch == '\n') {
291 front = true;
292 } else if (ch != ' ') {
293 front = false;
294 }
295 if (ch == '<') {
296 m_s.putback(ch);
297 break;
298 }
299 if (front && lastch == ' ' && ch == ' ') {
300 ;
301 } else {
302 tag += ch;
303 }
304 }
305 return trimCopy(tag);
306}
307
308////////////////////////// XML_Node /////////////////////////////////
309
310XML_Node::XML_Node(const std::string& nm, XML_Node* const parent_) :
311 m_name(nm),
312 m_parent(parent_),
313 m_root(0),
314 m_locked(false),
315 m_iscomment(false),
316 m_linenum(0)
317{
318 if (!parent_) {
319 m_root = this;
320 } else {
321 m_root = &parent_->root();
322 }
323}
324
325XML_Node::XML_Node(const XML_Node& right) :
326 m_parent(0),
327 m_root(0),
328 m_locked(false),
329 m_iscomment(right.m_iscomment),
330 m_linenum(right.m_linenum)
331{
332 m_root = this;
333 m_name = right.m_name;
334 m_value = right.m_value;
335 right.copy(this);
336}
337
338XML_Node& XML_Node::operator=(const XML_Node& right)
339{
340 if (&right != this) {
341 for (size_t i = 0; i < m_children.size(); i++) {
342 if (m_children[i] && m_children[i]->parent() == this) {
343 delete m_children[i];
344 m_children[i] = 0;
345 }
346 }
347 m_children.resize(0);
348 right.copy(this);
349 }
350 return *this;
351}
352
353XML_Node::~XML_Node()
354{
355 if (m_locked) {
356 writelog("XML_Node::~XML_Node: deleted a locked XML_Node: "+name());
357 }
358 for (size_t i = 0; i < m_children.size(); i++) {
359 if (m_children[i] && m_children[i]->parent() == this) {
360 delete m_children[i];
361 m_children[i] = 0;
362 }
363 }
364}
365
367{
368 for (size_t i = 0; i < m_children.size(); i++) {
369 if (m_children[i] && m_children[i]->parent() == this) {
370 delete m_children[i];
371 m_children[i] = 0;
372 }
373 }
374 m_value.clear();
375 m_childindex.clear();
376 m_attribs.clear();
377 m_children.clear();
378
379 m_iscomment = false;
380 m_linenum = 0;
381}
382
384{
385 m_children.push_back(&node);
386 m_childindex.insert({node.name(), m_children.back()});
387 node.setRoot(root());
388 node.setParent(this);
389 return *m_children.back();
390}
391
392XML_Node& XML_Node::addChild(const XML_Node& node)
393{
394 return mergeAsChild(*(new XML_Node(node)));
395}
396
397XML_Node& XML_Node::addChild(const std::string& sname)
398{
399 return mergeAsChild(*(new XML_Node(sname, this)));
400}
401
402XML_Node& XML_Node::addChild(const std::string& name, const std::string& value)
403{
404 XML_Node& c = addChild(name);
405 c.addValue(value);
406 return c;
407}
408
409XML_Node& XML_Node::addChild(const std::string& name, const doublereal value,
410 const std::string& fmt)
411{
412 XML_Node& c = addChild(name);
413 c.addValue(value, fmt);
414 return c;
415}
416
417void XML_Node::removeChild(const XML_Node* const node)
418{
419 auto i = find(m_children.begin(), m_children.end(), node);
420 m_children.erase(i);
421 m_childindex.erase(node->name());
422}
423
424void XML_Node::addComment(const std::string& comment)
425{
426 addChild("comment", comment);
427}
428
429void XML_Node::addValue(const std::string& val)
430{
431 m_value = val;
432 if (m_name == "comment") {
433 m_iscomment = true;
434 }
435}
436
437void XML_Node::addValue(const doublereal val, const std::string& fmt)
438{
439 m_value = trimCopy(fmt::sprintf(fmt, val));
440}
441
442std::string XML_Node::value() const
443{
444 return m_value;
445}
446
447std::string XML_Node::value(const std::string& cname) const
448{
449 return child(cname).value();
450}
451
452std::string XML_Node::operator()(const std::string& cname) const
453{
454 return value(cname);
455}
456
457doublereal XML_Node::fp_value() const
458{
459 return fpValueCheck(m_value);
460}
461
462integer XML_Node::int_value() const
463{
464 return std::atoi(m_value.c_str());
465}
466
467void XML_Node::addAttribute(const std::string& attrib, const std::string& value)
468{
470}
471
472void XML_Node::addAttribute(const std::string& attrib,
473 const doublereal vvalue, const std::string& fmt)
474{
475 m_attribs[attrib] = fmt::sprintf(fmt, vvalue);
476}
477
478void XML_Node::addAttribute(const std::string& aattrib, const int vvalue)
479{
480 m_attribs[aattrib] = fmt::format("{}", vvalue);
481}
482
483void XML_Node::addAttribute(const std::string& aattrib, const size_t vvalue)
484{
485 m_attribs[aattrib] = fmt::format("{}", vvalue);
486}
487
488std::string XML_Node::operator[](const std::string& attr) const
489{
490 return attrib(attr);
491}
492
493std::string XML_Node::attrib(const std::string& attr) const
494{
495 return getValue<string,string>(m_attribs, attr, "");
496}
497
498std::map<std::string,std::string>& XML_Node::attribs()
499{
500 return m_attribs;
501}
502
503const std::map<std::string,std::string>& XML_Node::attribsConst() const
504{
505 return m_attribs;
506}
507
508void XML_Node::setLineNumber(const int n)
509{
510 m_linenum = n;
511}
512
514{
515 return m_linenum;
516}
517
519{
520 return m_parent;
521}
522
524{
525 m_parent = p;
526 return p;
527}
528
529bool XML_Node::hasChild(const std::string& ch) const
530{
531 return (m_childindex.find(ch) != m_childindex.end());
532}
533
534bool XML_Node::hasAttrib(const std::string& a) const
535{
536 return (m_attribs.find(a) != m_attribs.end());
537}
538
539std::string XML_Node::id() const
540{
541 if (hasAttrib("id")) {
542 return attrib("id");
543 }
544 return "";
545}
546
547XML_Node& XML_Node::child(const size_t n) const
548{
549 return *m_children[n];
550}
551
552const std::vector<XML_Node*>& XML_Node::children() const
553{
554 return m_children;
555}
556
557size_t XML_Node::nChildren(const bool discardComments) const
558{
559 if (discardComments) {
560 size_t count = 0;
561 for (size_t i = 0; i < m_children.size(); i++) {
562 XML_Node* xc = m_children[i];
563 if (!(xc->isComment())) {
564 count++;
565 }
566 }
567 return count;
568 }
569 return m_children.size();
570}
571
573{
574 return m_iscomment;
575}
576
577void XML_Node::_require(const std::string& a, const std::string& v) const
578{
579 if (hasAttrib(a) && attrib(a) == v) {
580 return;
581 }
582 string msg="XML_Node "+name()+" is required to have an attribute named " + a +
583 " with the value \"" + v +"\", but instead the value is \"" + attrib(a);
584 throw CanteraError("XML_Node::_require", msg);
585}
586
587XML_Node* XML_Node::findNameID(const std::string& nameTarget,
588 const std::string& idTarget) const
589{
590 XML_Node* scResult = 0;
591 std::string idattrib = id();
592 if (name() == nameTarget && (idTarget == "" || idTarget == idattrib)) {
593 return const_cast<XML_Node*>(this);
594 }
595 for (size_t n = 0; n < m_children.size(); n++) {
596 XML_Node* sc = m_children[n];
597 if (sc->name() == nameTarget) {
598 if (idTarget == "") {
599 return sc;
600 }
601 idattrib = sc->id();
602 if (idTarget == idattrib) {
603 return sc;
604 }
605 }
606 }
607 for (size_t n = 0; n < m_children.size(); n++) {
608 XML_Node* sc = m_children[n];
609 scResult = sc->findNameID(nameTarget, idTarget);
610 if (scResult) {
611 return scResult;
612 }
613 }
614 return scResult;
615}
616
617XML_Node* XML_Node::findNameIDIndex(const std::string& nameTarget,
618 const std::string& idTarget, const int index_i) const
619{
620 XML_Node* scResult = 0;
621 std::string idattrib = id();
622 std::string ii = attrib("index");
623 std::string index_s = fmt::format("{}", index_i);
624 int iMax = -1000000;
625 if (name() == nameTarget && (idTarget == "" || idTarget == idattrib) && index_s == ii) {
626 return const_cast<XML_Node*>(this);
627 }
628 for (size_t n = 0; n < m_children.size(); n++) {
629 XML_Node* sc = m_children[n];
630 if (sc->name() == nameTarget) {
631 ii = sc->attrib("index");
632 int indexR = atoi(ii.c_str());
633 idattrib = sc->id();
634 if ((idTarget == idattrib || idTarget == "") && index_s == ii) {
635 return sc;
636 }
637 if (indexR > iMax) {
638 scResult = sc;
639 iMax = indexR;
640 }
641 }
642 }
643 return scResult;
644}
645
646XML_Node* XML_Node::findID(const std::string& id_, const int depth) const
647{
648 if (hasAttrib("id") && attrib("id") == id_) {
649 return const_cast<XML_Node*>(this);
650 }
651 if (depth > 0) {
652 for (size_t i = 0; i < nChildren(); i++) {
653 XML_Node* r = m_children[i]->findID(id_, depth-1);
654 if (r != 0) {
655 return r;
656 }
657 }
658 }
659 return 0;
660}
661
662XML_Node* XML_Node::findByAttr(const std::string& attr,
663 const std::string& val, int depth) const
664{
665 if (hasAttrib(attr) && attrib(attr) == val) {
666 return const_cast<XML_Node*>(this);
667 }
668 if (depth > 0) {
669 size_t n = nChildren();
670 for (size_t i = 0; i < n; i++) {
671 XML_Node* r = m_children[i]->findByAttr(attr, val, depth - 1);
672 if (r != 0) {
673 return r;
674 }
675 }
676 }
677 return 0;
678}
679
680const XML_Node* XML_Node::findByName(const std::string& nm, int depth) const
681{
682 if (name() == nm) {
683 return const_cast<XML_Node*>(this);
684 }
685 if (depth > 0) {
686 for (size_t i = 0; i < nChildren(); i++) {
687 XML_Node* r = m_children[i]->findByName(nm);
688 if (r != 0) {
689 return r;
690 }
691 }
692 }
693 return 0;
694}
695
696XML_Node* XML_Node::findByName(const std::string& nm, int depth)
697{
698 if (name() == nm) {
699 return this;
700 }
701 if (depth > 0) {
702 for (size_t i = 0; i < nChildren(); i++) {
703 XML_Node* r = m_children[i]->findByName(nm);
704 if (r != 0) {
705 return r;
706 }
707 }
708 }
709 return 0;
710}
711
712std::vector<XML_Node*> XML_Node::getChildren(const std::string& nm) const
713{
714 std::vector<XML_Node*> children_;
715 for (size_t i = 0; i < nChildren(); i++) {
716 if (caseInsensitiveEquals(child(i).name(), nm)) {
717 children_.push_back(&child(i));
718 }
719 }
720 return children_;
721}
722
723XML_Node& XML_Node::child(const std::string& aloc) const
724{
725 string loc = aloc;
726 while (true) {
727 size_t iloc = loc.find('/');
728 if (iloc != string::npos) {
729 string cname = loc.substr(0,iloc);
730 loc = loc.substr(iloc+1, loc.size());
731 auto i = m_childindex.find(cname);
732 if (i != m_childindex.end()) {
733 return i->second->child(loc);
734 } else {
735 throw XML_NoChild(this, m_name, cname, root().m_filename,
736 lineNumber());
737 }
738 } else {
739 auto i = m_childindex.find(loc);
740 if (i != m_childindex.end()) {
741 return *(i->second);
742 } else {
743 throw XML_NoChild(this, m_name, loc, root().m_filename,
744 lineNumber());
745 }
746 }
747 }
748}
749
751{
752 return *m_root;
753}
754
755void XML_Node::setRoot(const XML_Node& newRoot)
756{
757 m_root = const_cast<XML_Node*>(&newRoot);
758 for (size_t i = 0; i < m_children.size(); i++) {
759 m_children[i]->setRoot(newRoot);
760 }
761}
762
763void XML_Node::build(const std::string& filename)
764{
765 ifstream fin(filename);
766 if (!fin) {
767 throw CanteraError("XML_Node::build",
768 "Unable to open file '{}' for reading.", filename);
769 }
770 build(fin, filename);
771}
772
773void XML_Node::build(std::istream& f, const std::string& filename)
774{
775 warn_deprecated("XML_Node::build",
776 "\nThe CTI and XML input file formats are deprecated and will be removed in\n"
777 "Cantera 3.0. Use 'cti2yaml.py' or 'ctml2yaml.py' to convert CTI or XML input\n"
778 "files to the YAML format. See https://cantera.org/tutorials/legacy2yaml.html\n"
779 "for more information.");
780 m_filename = filename;
781 XML_Reader r(f);
782 XML_Node* node = this;
783 bool first = true;
784 while (!f.eof()) {
785 map<string, string> node_attribs;
786 string nm = r.readTag(node_attribs);
787
788 if (nm == "EOF") {
789 break;
790 }
791 if (nm == "--" && m_name == "--" && m_root == this) {
792 continue;
793 }
794 int lnum = r.m_line;
795 if (nm[nm.size() - 1] == '/') {
796 string nm2 = nm.substr(0,nm.size()-1);
797 if (first) {
798 node->setName(nm2);
799 first = false;
800 } else {
801 node = &node->addChild(nm2);
802 }
803 node->addValue("");
804 node->attribs() = node_attribs;
805 node->setLineNumber(lnum);
806 node = node->parent();
807 } else if (nm[0] != '/') {
808 if (nm[0] != '!' && nm[0] != '-' && nm[0] != '?') {
809 if (first) {
810 node->setName(nm);
811 first = false;
812 } else {
813 node = &node->addChild(nm);
814 }
815 node->addValue(r.readValue());
816 node->attribs() = node_attribs;
817 node->setLineNumber(lnum);
818 } else if (nm.substr(0,2) == "--") {
819 if (nm.substr(nm.size()-2,2) == "--") {
820 node->addComment(nm.substr(2,nm.size()-4));
821 }
822 }
823 } else {
824 if (node->name() != nm.substr(1,nm.size()-1)) {
825 throw XML_TagMismatch(node->name(), nm.substr(1,nm.size()-1),
826 root().m_filename, lnum);
827 }
828 node = node->parent();
829 }
830 }
831}
832
833void XML_Node::copyUnion(XML_Node* const node_dest) const
834{
835 node_dest->addValue(m_value);
836 if (m_name == "") {
837 return;
838 }
839 for (const auto& attr : m_attribs) {
840 if (!node_dest->hasAttrib(attr.first)) {
841 node_dest->addAttribute(attr.first, attr.second);
842 }
843 }
844 const vector<XML_Node*> &vsc = node_dest->children();
845 for (size_t n = 0; n < m_children.size(); n++) {
846 XML_Node* sc = m_children[n];
847 size_t ndc = node_dest->nChildren();
848 XML_Node* dc = 0;
849 if (! sc->m_iscomment) {
850 for (size_t idc = 0; idc < ndc; idc++) {
851 XML_Node* dcc = vsc[idc];
852 if (dcc->name() == sc->name()) {
853 if (sc->hasAttrib("id") && sc->attrib("id") != dcc->attrib("id")) {
854 break;
855 }
856 if (sc->hasAttrib("name") && sc->attrib("name") != dcc->attrib("name")) {
857 break;
858 }
859 if (sc->hasAttrib("model") && sc->attrib("model") != dcc->attrib("model")) {
860 break;
861 }
862 if (sc->hasAttrib("title") && sc->attrib("title") != dcc->attrib("title")) {
863 break;
864 }
865 dc = vsc[idc];
866 }
867 }
868 }
869 if (!dc) {
870 node_dest->addChild(sc->name());
871 dc = vsc[ndc];
872 }
873 sc->copyUnion(dc);
874 }
875}
876
877void XML_Node::copy(XML_Node* const node_dest) const
878{
879 node_dest->addValue(m_value);
880 node_dest->setName(m_name);
881 node_dest->setLineNumber(m_linenum);
882 if (m_name == "") {
883 return;
884 }
885 for (const auto& attr : m_attribs) {
886 node_dest->addAttribute(attr.first, attr.second);
887 }
888 const vector<XML_Node*> &vsc = node_dest->children();
889
890 for (size_t n = 0; n < m_children.size(); n++) {
891 XML_Node* sc = m_children[n];
892 size_t ndc = node_dest->nChildren();
893 // Here is where we create the child node.
894 node_dest->addChild(sc->name());
895 XML_Node* dc = vsc[ndc];
896 sc->copy(dc);
897 }
898}
899
901{
902 m_locked = true;
903 for (size_t i = 0; i < m_children.size(); i++) {
904 m_children[i]->lock();
905 }
906}
907
909{
910 m_locked = false;
911 for (size_t i = 0; i < m_children.size(); i++) {
912 m_children[i]->unlock();
913 }
914}
915
916void XML_Node::writeHeader(std::ostream& s)
917{
918 s << "<?xml version=\"1.0\"?>" << endl;
919}
920
921void XML_Node::write_int(std::ostream& s, int level, int numRecursivesAllowed) const
922{
923 if (m_name == "") {
924 return;
925 }
926
927 string indent(level, ' ');
928 if (m_iscomment) {
929 // In the comment section, we test to see if there already is a space
930 // beginning and ending the comment. If there already is one, we don't
931 // add another one.
932 s << endl << indent << "<!--";
933 if (! isspace(m_value[0])) {
934 s << " ";
935 }
936 s << m_value;
937 if (! isspace(m_value[m_value.size()-1])) {
938 s << " ";
939 }
940 s << "-->";
941 return;
942 }
943
944 s << indent << "<" << m_name;
945 for (const auto& attr : m_attribs) {
946 s << " " << attr.first << "=\"" << attr.second << "\"";
947 }
948 if (m_value == "" && m_children.empty()) {
949 s << "/>";
950 } else {
951 s << ">";
952
953 if (m_value != "") {
954 string vv = m_value;
955 string::size_type ieol = vv.find('\n');
956 if (ieol != string::npos) {
957 while (true) {
958 ieol = vv.find('\n');
959 if (ieol != string::npos) {
960 if (ieol == 0) {
961 s << endl << indent << " ";
962 } else {
963 size_t jf = ieol - 1;
964 for (int j = 0; j < (int) ieol; j++) {
965 if (! isspace(vv[j])) {
966 jf = j;
967 break;
968 }
969 }
970 s << endl << indent << " " << vv.substr(jf,ieol-jf);
971 }
972 vv = vv.substr(ieol+1);
973 } else {
974 size_t lll = vv.size() - 1;
975 if (lll != npos) {
976 size_t jf = lll;
977 for (size_t j = 0; j < lll; j++) {
978 if (! isspace(vv[j])) {
979 jf = j;
980 break;
981 }
982 }
983 if (jf < lll) {
984 s << endl << indent << " " << vv.substr(jf);
985 }
986 }
987 break;
988 }
989 }
990 s << endl << indent;
991 } else {
992 bool doSpace = true;
993 bool doNewLine = false;
994 size_t ll = m_value.size() - 1;
995 if (ll > 25) {
996 doNewLine = true;
997 }
998 if (m_name == "floatArray") {
999 doNewLine = true;
1000 }
1001 if (doNewLine) {
1002 doSpace = false;
1003 }
1004
1005 if (doNewLine) {
1006 s << endl << indent << " ";
1007 }
1008
1009 // Put spaces around a raw value field for readability
1010 if (doSpace && (! isspace(m_value[0]))) {
1011 s << " ";
1012 }
1013
1014 // Write out the value
1015 s << m_value;
1016
1017 if (doSpace && (! isspace(m_value[ll]))) {
1018 s << " ";
1019 }
1020 if (doNewLine) {
1021 s << endl << indent;
1022 }
1023 }
1024 }
1025 if (numRecursivesAllowed > 0) {
1026 for (size_t i = 0; i < m_children.size(); i++) {
1027 s << endl;
1028 m_children[i]->write_int(s,level + 2, numRecursivesAllowed - 1);
1029 }
1030 }
1031 if (!m_children.empty()) {
1032 s << endl << indent;
1033 }
1034 s << "</" << m_name << ">";
1035 }
1036}
1037
1038void XML_Node::write(std::ostream& s, const int level, int numRecursivesAllowed) const
1039{
1040 warn_deprecated("XML_Node::write",
1041 "\nThe CTI and XML input file formats are deprecated and will be removed in\n"
1042 "Cantera 3.0. Use 'cti2yaml.py' or 'ctml2yaml.py' to convert CTI or XML input\n"
1043 "files to the YAML format. See https://cantera.org/tutorials/legacy2yaml.html\n"
1044 "for more information.");
1045 write_int(s, level, numRecursivesAllowed);
1046 s << endl;
1047}
1048
1050 const std::string& phaseId)
1051{
1052 XML_Node* scResult = 0;
1053 if (!root) {
1054 return 0;
1055 }
1056 if (root->name() == "phase") {
1057 if (phaseId == "") {
1058 return root;
1059 }
1060 if (phaseId == root->id()) {
1061 return root;
1062 }
1063 }
1064
1065 const vector<XML_Node*> &vsc = root->children();
1066 for (size_t n = 0; n < root->nChildren(); n++) {
1067 XML_Node* sc = vsc[n];
1068 if (sc->name() == "phase") {
1069 if (phaseId == "") {
1070 return sc;
1071 }
1072 if (phaseId == sc->id()) {
1073 return sc;
1074 }
1075 }
1076 }
1077 for (size_t n = 0; n < root->nChildren(); n++) {
1078 XML_Node* sc = vsc[n];
1079 scResult = findXMLPhase(sc, phaseId);
1080 if (scResult) {
1081 return scResult;
1082 }
1083 }
1084 return scResult;
1085}
1086
1087}
Base class for exceptions thrown by Cantera classes.
Definition: ctexceptions.h:61
Class representing a generic XML error condition.
Definition: xml.cpp:28
virtual std::string getMessage() const
Method overridden by derived classes to format the error message.
Definition: xml.cpp:42
virtual ~XML_Error()
destructor
Definition: xml.cpp:47
std::string m_msg
String message for the error.
Definition: xml.cpp:51
XML_Error(const std::string &file, int line)
Constructor.
Definition: xml.cpp:38
Class representing a specific type of XML file formatting error.
Definition: xml.cpp:86
virtual std::string getClass() const
Method overridden by derived classes to indicate their type.
Definition: xml.cpp:109
XML_NoChild(const XML_Node *p, const std::string &parent, std::string child, const std::string &filename, int line)
Constructor.
Definition: xml.cpp:98
Class XML_Node is a tree-based representation of the contents of an XML file.
Definition: xml.h:103
void removeChild(const XML_Node *const node)
Remove a child from this node's list of children.
Definition: xml.cpp:417
std::map< std::string, std::string > m_attribs
Storage of attributes for a node.
Definition: xml.h:669
XML_Node * findByAttr(const std::string &attr, const std::string &val, int depth=100000) const
This routine carries out a recursive search for an XML node based on an attribute of each XML node.
Definition: xml.cpp:662
void setName(const std::string &name_)
Sets the name of the XML node.
Definition: xml.h:379
std::string attrib(const std::string &attr) const
Function returns the value of an attribute.
Definition: xml.cpp:493
XML_Node(const std::string &nm="--", XML_Node *const parent=0)
Constructor for XML_Node, representing a tree structure.
Definition: xml.cpp:310
void copy(XML_Node *const node_dest) const
Copy all of the information in the current XML_Node tree into the destination XML_Node tree,...
Definition: xml.cpp:877
std::string name() const
Returns the name of the XML node.
Definition: xml.h:371
bool hasChild(const std::string &ch) const
Tests whether the current node has a child node with a particular name.
Definition: xml.cpp:529
int lineNumber() const
Return the line number.
Definition: xml.cpp:513
void build(const std::string &filename)
Populate the XML tree from an input file.
Definition: xml.cpp:763
std::string operator()(const std::string &cname) const
The Overloaded parenthesis operator with one augment returns the value of an XML child node as a stri...
Definition: xml.cpp:452
XML_Node * m_root
Pointer to the root XML_Node for the current node.
Definition: xml.h:681
XML_Node & mergeAsChild(XML_Node &node)
Merge an existing node as a child node to the current node.
Definition: xml.cpp:383
void write_int(std::ostream &s, int level=0, int numRecursivesAllowed=60000) const
Write an XML subtree to an output stream.
Definition: xml.cpp:921
std::string id() const
Return the id attribute, if present.
Definition: xml.cpp:539
XML_Node & root() const
Return the root of the current XML_Node tree.
Definition: xml.cpp:750
void addValue(const std::string &val)
Modify the value for the current node.
Definition: xml.cpp:429
std::map< std::string, std::string > & attribs()
Returns a changeable value of the attributes map for the current node.
Definition: xml.cpp:498
int m_linenum
The member data m_linenum.
Definition: xml.h:700
XML_Node * m_parent
Pointer to the parent XML_Node for the current node.
Definition: xml.h:675
void addAttribute(const std::string &attrib, const std::string &value)
Add or modify an attribute of the current node.
Definition: xml.cpp:467
bool m_locked
Lock for this node.
Definition: xml.h:688
void copyUnion(XML_Node *const node_dest) const
Copy all of the information in the current XML_Node tree into the destination XML_Node tree,...
Definition: xml.cpp:833
bool m_iscomment
True if the current node is a comment node.
Definition: xml.h:694
const XML_Node * findByName(const std::string &nm, int depth=100000) const
This routine carries out a recursive search for an XML node based on the name of the node.
Definition: xml.cpp:680
integer int_value() const
Return the value of an XML node as a single int.
Definition: xml.cpp:462
void unlock()
Unset the lock for this node and all of its children.
Definition: xml.cpp:908
void write(std::ostream &s, const int level=0, int numRecursivesAllowed=60000) const
Write an XML subtree to an output stream.
Definition: xml.cpp:1038
void _require(const std::string &a, const std::string &v) const
Require that the current XML node has an attribute named by the first argument, a,...
Definition: xml.cpp:577
doublereal fp_value() const
Return the value of an XML node as a single double.
Definition: xml.cpp:457
void writeHeader(std::ostream &s)
Write the header to the XML file to the specified ostream.
Definition: xml.cpp:916
void lock()
Set the lock for this node and all of its children.
Definition: xml.cpp:900
XML_Node * findID(const std::string &id, const int depth=100) const
This routine carries out a recursive search for an XML node based on the XML element attribute "id".
Definition: xml.cpp:646
std::multimap< std::string, XML_Node * > m_childindex
Map containing an index between the node name and the pointer to the node.
Definition: xml.h:663
const std::vector< XML_Node * > & children() const
Return an unchangeable reference to the vector of children of the current node.
Definition: xml.cpp:552
XML_Node * findNameIDIndex(const std::string &nameTarget, const std::string &idTarget, const int index) const
This routine carries out a search for an XML node based on the XML element name, the attribute ID and...
Definition: xml.cpp:617
void setLineNumber(const int n)
Set the line number.
Definition: xml.cpp:508
XML_Node * parent() const
Returns a pointer to the parent node of the current node.
Definition: xml.cpp:518
std::string m_filename
Name of the file from which this XML node was read.
Definition: xml.h:654
void clear()
Clear the current node and everything under it.
Definition: xml.cpp:366
void addComment(const std::string &comment)
Add a child node to the current node containing a comment.
Definition: xml.cpp:424
const std::map< std::string, std::string > & attribsConst() const
Returns an unchangeable value of the attributes map for the current node.
Definition: xml.cpp:503
std::vector< XML_Node * > getChildren(const std::string &name) const
Get a vector of pointers to XML_Node containing all of the children of the current node which match t...
Definition: xml.cpp:712
std::string value() const
Return the value of an XML node as a string.
Definition: xml.cpp:442
XML_Node * findNameID(const std::string &nameTarget, const std::string &idTarget) const
This routine carries out a recursive search for an XML node based on both the XML element name and th...
Definition: xml.cpp:587
std::string operator[](const std::string &attr) const
The operator[] is overloaded to provide a lookup capability on attributes for the current XML element...
Definition: xml.cpp:488
std::string m_value
Value of the XML node.
Definition: xml.h:650
size_t nChildren(bool discardComments=false) const
Return the number of children.
Definition: xml.cpp:557
XML_Node * setParent(XML_Node *const p)
Sets the pointer for the parent node of the current node.
Definition: xml.cpp:523
std::string m_name
XML node name of the node.
Definition: xml.h:637
XML_Node & child(const size_t n) const
Return a changeable reference to the n'th child of the current node.
Definition: xml.cpp:547
void setRoot(const XML_Node &root)
Set the root XML_Node value within the current node.
Definition: xml.cpp:755
std::vector< XML_Node * > m_children
Vector of pointers to child nodes.
Definition: xml.h:691
bool isComment() const
Boolean function indicating whether a comment.
Definition: xml.cpp:572
bool hasAttrib(const std::string &a) const
Tests whether the current node has an attribute with a particular name.
Definition: xml.cpp:534
Class XML_Reader reads an XML file into an XML_Node object.
Definition: xml.h:30
std::string readTag(std::map< std::string, std::string > &attribs)
Reads an XML tag into a string.
Definition: xml.cpp:232
int m_line
Line count.
Definition: xml.h:91
void getchr(char &ch)
Read a single character from the input stream and returns it.
Definition: xml.cpp:122
int findQuotedString(const std::string &aline, std::string &rstring) const
Searches a string for the first occurrence of a valid quoted string.
Definition: xml.cpp:158
void parseTag(const std::string &tag, std::string &name, std::map< std::string, std::string > &attribs) const
parseTag parses XML tags, i.e., the XML elements that are in between angle brackets.
Definition: xml.cpp:193
XML_Reader(std::istream &input)
Sole Constructor for the XML_Reader class.
Definition: xml.cpp:116
std::istream & m_s
Input stream containing the XML file.
Definition: xml.h:87
std::string readValue()
Return the value portion of an XML element.
Definition: xml.cpp:279
Class representing a specific type of XML file formatting error.
Definition: xml.cpp:59
XML_TagMismatch(const std::string &opentag, const std::string &closetag, const std::string &filename, int line)
Constructor.
Definition: xml.cpp:70
virtual std::string getClass() const
Method overridden by derived classes to indicate their type.
Definition: xml.cpp:76
Definitions for the classes that are thrown when Cantera experiences an error condition (also contain...
This file contains definitions for utility functions and text for modules, inputfiles,...
void writelog(const std::string &fmt, const Args &... args)
Write a formatted message to the screen.
Definition: global.h:164
Namespace for the Cantera kernel.
Definition: AnyMap.h:29
const size_t npos
index returned by functions to indicate "no position"
Definition: ct_defs.h:192
XML_Node * findXMLPhase(XML_Node *root, const std::string &phaseId)
Search an XML_Node tree for a named phase XML_Node.
Definition: xml.cpp:1049
bool caseInsensitiveEquals(const std::string &input, const std::string &test)
Case insensitive equality predicate.
void warn_deprecated(const std::string &source, const AnyBase &node, const std::string &message)
A deprecation warning for syntax in an input file.
Definition: AnyMap.cpp:1901
std::string trimCopy(const std::string &input)
Trim.
static string::size_type findUnbackslashed(const std::string &s, const char q, std::string::size_type istart=0)
Find the first position of a character, q, in string, s, which is not immediately preceded by the bac...
Definition: xml.cpp:137
doublereal fpValueCheck(const std::string &val)
Translate a string into one doublereal value, with error checking.
Versions 6.2.0 and 6.2.1 of fmtlib do not include this define before they include windows....
Definition: fmt.h:31
Contains declarations for string manipulation functions within Cantera.
Various templated functions that carry out common vector operations (see Templated Utility Functions)...
Classes providing support for XML data files.