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