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