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