Cantera  2.0
xml.h
Go to the documentation of this file.
1 /**
2  * @file xml.h
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 #ifndef CT_XML_H
10 #define CT_XML_H
11 
12 #include "ctexceptions.h"
13 #include "ct_defs.h"
14 #include "global.h"
15 
16 #include <string>
17 #include <vector>
18 #include <iostream>
19 
20 //@{
21 #define XML_INDENT 4
22 //@}
23 namespace Cantera
24 {
25 
26 
27 //! Class XML_Reader reads an XML file into an XML_Node object.
28 /*!
29  *
30  * Class XML_Reader is designed for internal use.
31  */
33 {
34 public:
35 
36  //! Sole Constructor for the XML_Reader class
37  /*!
38  * @param input Reference to the istream object containing
39  * the XML file
40  */
41  XML_Reader(std::istream& input);
42 
43  //! Read a single character from the input stream and returns it
44  /*!
45  * All low level reads occur through this function.
46  * The function also keeps track of the line numbers.
47  *
48  * @param ch Character to be returned.
49  */
50  void getchr(char& ch);
51 
52  //! Returns string 'aline' stripped of leading and trailing white
53  //! space.
54  /*!
55  * White space is defined by the ISO C function isspace(), and
56  * includes tabs, spaces, \\n. \\r, \\v, and \\f.
57  *
58  * @param aline Input line to be stripped
59  *
60  * @return Returns a string stripped of leading and trailing white
61  * space.
62  *
63  * @deprecated Use stripws (in stringUtils.h)
64  */
65  DEPRECATED(std::string strip(const std::string& aline) const);
66 
67  //! Looks for a substring within 'aline' enclosed in double
68  //! quotes, and returns this substring (without the quotes) if
69  //! found. If not, an empty string is returned.
70  /*!
71  *
72  * @param aline This is the input string to be searched
73  *
74  * @deprecated why is this a class method?
75  */
76  DEPRECATED(std::string inquotes(const std::string& aline) const);
77 
78  //! Searches a string for the first occurrence of a valid
79  //! quoted string.
80  /*!
81  * Quotes can start with either a single
82  * quote or a double quote, but must also end with the same
83  * type. Quotes may be commented out by preceding with a
84  * backslash character, '\\'.
85  *
86  * @param aline This is the input string to be searched
87  * @param rstring Return value of the string that is found.
88  * The quotes are stripped from the string.
89  *
90  * @return Returns the integer position just after
91  * the quoted string.
92  */
93  int findQuotedString(const std::string& aline, std::string& rstring) const;
94 
95  //! parseTag parses XML tags, i.e., the XML elements that are
96  //! in between angle brackets.
97  /*!
98  * @param tag Tag to be parsed - input
99  *
100  * @param name Output string containing name
101  * of the XML
102  * @param attribs map of attribute name and
103  * attribute value - output
104  */
105  void parseTag(std::string tag, std::string& name,
106  std::map<std::string, std::string>& attribs) const;
107 
108  //! Reads an XML tag into a string
109  /*!
110  * This function advances the input streams pointer
111  *
112  * @param attribs map of attribute name and
113  * attribute value - output
114  *
115  * @return Output string containing name
116  * of the XML
117  */
118  std::string readTag(std::map<std::string, std::string>& attribs);
119 
120  //! Return the value portion of an XML element
121  /*!
122  * This function advances the input streams pointer
123  */
124  std::string readValue();
125 
126 protected:
127 
128  //! Input stream containing the XML file
129  std::istream& m_s;
130 
131 public:
132 
133  //! Line count
134  int m_line;
135 };
136 
137 
138 ////////////////////////// XML_Node /////////////////////////////////
139 
140 //! Class XML_Node is a tree-based representation of the contents of an XML file
141 /*!
142  * Class XML_Node is a tree-based representation of the contents of an XML file.
143  *
144  * There are routines for adding to the tree.
145  *
146  * There are routines for querying and searching the tree.
147  *
148  * Additionally, there are routines for writing the tree out to an output file.
149  *
150  */
151 class XML_Node
152 {
153 public:
154  //! Default constructor for XML_Node, representing a tree structure
155  /*!
156  * Constructor for an XML_Node, which is a node in a tree-like structure
157  * representing an XML file.
158  *
159  * @param cnm Name of the node.
160  * The default name of the node is "--"
161  */
162  XML_Node(const char* cnm = 0);
163 
164 
165  //! Default constructor for XML_Node, representing a tree structure
166  /*!
167  * Constructor for an XML_Node, which is a node in a tree-like structure
168  * representing an XML file.
169  *
170  * @param nm Name of the node.
171  * The default name of the node is "--"
172  *
173  * @param parent Pointer to the parent for this node in the tree.
174  * A value of 0 indicates this is the top of the tree.
175  */
176  XML_Node(const std::string nm, XML_Node* const parent);
177 
178  //! Copy constructor
179  /*!
180  * @param right Object to be copied
181  */
182  XML_Node(const XML_Node& right);
183 
184  //! Assignment operator for XML trees
185  /*!
186  * @param right XML tree to copy
187  */
188  XML_Node& operator=(const XML_Node& right);
189 
190  //! Destructor for the object
191  virtual ~XML_Node();
192 
193  //! Add a child node to the current node containing a comment
194  /*!
195  * Child node will have the name, comment.
196  *
197  * @param comment Content of the comment
198  */
199  void addComment(const std::string& comment);
200 
201  //! Merge an existing node as a child node to the current node
202  /*!
203  * This will merge an XML_Node as a child to the current node.
204  * Note, this actually adds the node. Therefore, the current node is changed.
205  * There is no copy made of the child node. The child node should not be deleted in the future
206  *
207  * @param node Reference to a child XML_Node object
208  *
209  * @return Returns a reference to the added child node
210  */
212 
213  // Add a child node to the current node by making a copy of an existing node tree
214  /*
215  * This will add an XML_Node as a child to the current node.
216  * Note, this actually adds the node. Therefore, node is changed.
217  * A copy is made of the underlying tree
218  *
219  * @param node Reference to a child XML_Node object
220  *
221  * @return returns a reference to the added node
222  */
223  XML_Node& addChild(const XML_Node& node);
224 
225 
226  //! Add a child node to the current node with a specified name
227  /*!
228  * This will add an XML_Node as a child to the current node.
229  * The node will be blank except for the specified name.
230  *
231  * @param sname Name of the new child
232  *
233  * @return Returns a reference to the added node
234  */
235  XML_Node& addChild(const std::string& sname);
236 
237  //! Add a child node to the current node with a specified name
238  /*!
239  * This will add an XML_Node as a child to the current node.
240  * The node will be blank except for the specified name.
241  *
242  * @param cstring Name of the new child as a c string
243  *
244  * @return Returns a reference to the added node
245  */
246  XML_Node& addChild(const char* cstring);
247 
248  //! Add a child node to the current xml node, and at the
249  //! same time add a value to the child
250  /*!
251  * Resulting XML string:
252  * <name> value </name>
253  *
254  * @param name Name of the child XML_Node object
255  * @param value Value of the XML_Node - string
256  * @return Returns a reference to the created child XML_Node object
257  */
258  XML_Node& addChild(const std::string& name, const std::string& value);
259 
260  //! Add a child node to the current xml node, and at the
261  //! same time add a formatted value to the child
262  /*!
263  * This version supplies a formatting string (printf format)
264  * to the output of the value.
265  *
266  * Resulting XML string:
267  * <name> value </name>
268  *
269  * @param name Name of the child XML_Node object
270  * @param value Value of the XML_Node - double.
271  * @param fmt Format of the output for value
272  *
273  * @return Returns a reference to the created child XML_Node object
274  */
275  XML_Node& addChild(const std::string& name, const doublereal value,
276  const std::string fmt="%g");
277 
278  //! Remove a child from this node's list of children
279  /*!
280  * This function removes an XML_Node from the children of this node.
281  *
282  * @param node Pointer to the node to be removed. Note, this node
283  * isn't modified in any way.
284  */
285  void removeChild(const XML_Node* const node);
286 
287  //! Modify the value for the current node
288  /*!
289  * This functions fills in the m_value field of the current node
290  *
291  * @param val string Value that the node will be assigned
292  */
293  void addValue(const std::string& val);
294 
295  //! Modify the value for the current node
296  /*!
297  * This functions fills in the m_value field of the current node
298  * with a formatted double value
299  *
300  * @param val double Value that the node will be assigned
301  * @param fmt Format of the printf string conversion of the double.
302  * Default is "%g". Must be less than 63 chars
303  */
304  void addValue(const doublereal val, const std::string fmt="%g");
305 
306  //! Return the value of an XML node as a string
307  /*!
308  * This is a simple accessor routine
309  */
310  std::string value() const;
311 
312  //! Overloaded parenthesis operator returns the value of the Node
313  /*!
314  * @return Returns the value of the node as a string.
315  */
316  std::string operator()() const;
317 
318  //! Return the value of an XML child node as a string
319  /*!
320  * @param cname Name of the child node to the current
321  * node, for which you want the value
322  */
323  std::string value(const std::string& cname) const;
324 
325  //! The Overloaded parenthesis operator with one augment
326  //! returns the value of an XML child node as a string
327  /*!
328  * @param cname Name of the child node to the current
329  * node, for which you want the value
330  */
331  std::string operator()(std::string cname) const;
332 
333  //! Return the value of an XML node as a single double
334  /*!
335  * This accesses the value string, and then tries to
336  * interpret it as a single double value.
337  */
338  doublereal fp_value() const;
339 
340  //! Return the value of an XML node as a single int
341  /*!
342  * This accesses the value string, and then tries to
343  * interpret it as a single int value.
344  */
345  integer int_value() const;
346 
347  //! Add or modify an attribute of the current node
348  /*!
349  * This functions fills in the m_value field of the current node
350  * with a string value
351  *
352  * @param attrib String name for the attribute to be assigned
353  * @param value String value that the attribute will have
354  */
355  void addAttribute(const std::string& attrib, const std::string& value);
356 
357  //! Add or modify an attribute to the double, value
358  /*!
359  * This functions fills in the attribute field, named attrib,
360  * with the double value, value. A formatting string is used.
361  *
362  * @param attrib String name for the attribute to be assigned
363  * @param value double Value that the node will be assigned
364  * @param fmt Format of the printf string conversion of the double.
365  * Default is "%g".
366  */
367  void addAttribute(const std::string& attrib, const doublereal value,
368  const std::string fmt="%g");
369 
370  //! The operator[] is overloaded to provide a lookup capability
371  //! on attributes for the current XML element.
372  /*!
373  * For example
374  * xmlNode["id"]
375  * will return the value of the attribute "id" for the current
376  * XML element. It will return the blank std::string if there isn't
377  * an attribute with that name.
378  *
379  * @param attr attribute string to look up
380  *
381  * @return Returns a string representing the value of the attribute
382  * within the XML node. If there is no attribute
383  * with the given name, it returns the null string.
384  */
385  std::string operator[](const std::string& attr) const;
386 
387  //! Function returns the value of an attribute
388  /*!
389  * This function searches the attributes vector for the parameter
390  * std::string attribute. If a match is found, the attribute value
391  * is returned as a string. If no match is found, the empty string
392  * is returned.
393  *
394  * @param attr Std::String containing the attribute to be searched for.
395  *
396  * @return Returns If a match is found, the attribute value
397  * is returned as a string. If no match is found, the empty string
398  * is returned.
399  */
400  std::string attrib(const std::string& attr) const;
401 
402  //! Clear the current node and everything under it
403  /*!
404  * The value, attributes and children are all zeroed. The name and the
405  * parent information is kept.
406  */
407  void clear();
408 
409 private:
410 
411  //! Returns a changeable value of the attributes map for the current node
412  /*!
413  * Note this is a simple accessor routine. And, it is a private function.
414  * It's used in some internal copy and assignment routines
415  */
416  std::map<std::string,std::string>& attribs();
417 
418 public:
419 
420  //! Returns an unchangeable value of the attributes map for the current node
421  /*!
422  *
423  * @return Returns an unchangeable reference to the attributes map
424  */
425  const std::map<std::string,std::string>& attribsConst() const;
426 
427  //! Set the line number
428  /*!
429  * @param n the member data m_linenum is set to n
430  */
431  void setLineNumber(const int n);
432 
433  //! Return the line number
434  /*!
435  * @return returns the member data m_linenum
436  */
437  int lineNumber() const;
438 
439  //! Returns a pointer to the parent node of the current node
440  XML_Node* parent() const;
441 
442  //! Sets the pointer for the parent node of the current node
443  /*!
444  * @param p Pointer to the parent node
445  *
446  * @return Returns the pointer p
447  */
448  XML_Node* setParent(XML_Node* const p);
449 
450  //! Tests whether the current node has a child node with a particular name
451  /*!
452  * @param ch Name of the child node to test
453  *
454  * @return Returns true if the child node exists, false otherwise.
455  */
456  bool hasChild(const std::string ch) const;
457 
458  //! Tests whether the current node has an attribute with a particular name
459  /*!
460  * @param a Name of the attribute to test
461  *
462  * @return Returns true if the attribute exists, false otherwise.
463  */
464  bool hasAttrib(std::string a) const;
465 
466  //! Returns the name of the XML node
467  /*!
468  * The name is the XML node is the XML node name
469  */
470  std::string name() const {
471  return m_name;
472  }
473 
474  //! Sets the name of the XML node
475  /*!
476  * @param name The name of the XML node
477  */
478  void setName(std::string name) {
479  m_name = name;
480  }
481 
482  //! Return the id attribute, if present
483  /*!
484  * Returns the id attribute if present. If not
485  * it return the empty string
486  */
487  std::string id() const;
488 
489  //! Return a changeable reference to the n'th child of the current node
490  /*!
491  * @param n Number of the child to return
492  */
493  XML_Node& child(const size_t n) const ;
494 
495  //! Return an unchangeable reference to the vector of children of the current node
496  /*!
497  * Each of the individual XML_Node child pointers, however,
498  * is to a changeable xml node object.
499  *
500  */
501  const std::vector<XML_Node*>& children() const;
502 
503  //! Return the number of children
504  /*!
505  * @param discardComments If true comments are discarded when adding up the number of children.
506  * Defaults to false.
507  */
508  size_t nChildren(bool discardComments = false) const;
509 
510  //! Boolean function indicating whether a comment
511  bool isComment() const;
512 
513  //! Require that the current xml node have an attribute named
514  //! by the first argument, a, and that this attribute have the
515  //! the string value listed in the second argument, v.
516  /*!
517  * @param a attribute name
518  * @param v required value of the attribute
519  *
520  * If the condition is not true, an exception is thrown
521  */
522  void _require(const std::string& a, const std::string& v) const;
523 
524  //! This routine carries out a recursive search for an XML node based
525  //! on both the xml element name and the attribute ID.
526  /*!
527  * If exact matches are found for both fields, the pointer
528  * to the matching XML Node is returned.
529  *
530  * The ID attribute may be defaulted by setting it to "".
531  * In this case the pointer to the first xml element matching the name
532  * only is returned.
533  *
534  * @param nameTarget Name of the XML Node that is being searched for
535  * @param idTarget "id" attribute of the XML Node that the routine
536  * looks for
537  *
538  * @return Returns the pointer to the XML node that fits the criteria
539  *
540  * @internal
541  * This algorithm does a lateral search of first generation children
542  * first before diving deeper into each tree branch.
543  */
544  XML_Node* findNameID(const std::string& nameTarget,
545  const std::string& idTarget) const;
546 
547  //! This routine carries out a search for an XML node based
548  //! on both the xml element name and the attribute ID and an integer index.
549  /*!
550  * If exact matches are found for all fields, the pointer
551  * to the matching XML Node is returned. The search is only carried out on
552  * the current element and the child elements of the current element.
553  *
554  * The "id" attribute may be defaulted by setting it to "".
555  * In this case the pointer to the first xml element matching the name
556  * only is returned.
557  *
558  * @param nameTarget Name of the XML Node that is being searched for
559  * @param idTarget "id" attribute of the XML Node that the routine
560  * looks for
561  * @param index Integer describing the index. The index is an
562  * attribute of the form index = "3"
563  *
564  * @return Returns the pointer to the XML node that fits the criteria
565  *
566  */
567  XML_Node* findNameIDIndex(const std::string& nameTarget,
568  const std::string& idTarget, const int index) const;
569 
570  //! This routine carries out a recursive search for an XML node based
571  //! on the xml element attribute, "id"
572  /*!
573  * If exact match is found, the pointer
574  * to the matching XML Node is returned. If not, 0 is returned.
575  *
576  * The ID attribute may be defaulted by setting it to "".
577  * In this case the pointer to the first xml element matching the name
578  * only is returned.
579  *
580  * @param id "id" attribute of the XML Node that the routine
581  * looks for
582  * @param depth Depth of the search.
583  *
584  * @return Returns the pointer to the XML node that fits the criteria
585  *
586  * @internal
587  * This algorithm does a lateral search of first generation children
588  * first before diving deeper into each tree branch.
589  */
590  XML_Node* findID(const std::string& id, const int depth=100) const;
591 
592 
593  //! This routine carries out a recursive search for an XML node based
594  //! on an attribute of each XML node
595  /*!
596  * If exact match is found with respect to the attribute name and
597  * value of the attribute, the pointer
598  * to the matching XML Node is returned. If not, 0 is returned.
599  *
600  *
601  * @param attr Attribute of the XML Node that the routine
602  * looks for
603  * @param val Value of the attribute
604  * @param depth Depth of the search. A value of 1 means that only the
605  * immediate children are searched.
606  *
607  * @return Returns the pointer to the XML node that fits the criteria
608  *
609  */
610  XML_Node* findByAttr(const std::string& attr, const std::string& val,
611  int depth = 100000) const;
612 
613  //! This routine carries out a recursive search for an XML node based
614  //! on the name of the node.
615  /*!
616  * If exact match is found with respect to XML_Node name, the pointer
617  * to the matching XML Node is returned. If not, 0 is returned.
618  * This is the const version of the routine.
619  *
620  * @param nm Name of the XML node
621  * @param depth Depth of the search. A value of 1 means that only the
622  * immediate children are searched.
623  *
624  * @return Returns the pointer to the XML node that fits the criteria
625  */
626  const XML_Node* findByName(const std::string& nm, int depth = 100000) const;
627 
628  //! This routine carries out a recursive search for an XML node based
629  //! on the name of the node.
630  /*!
631  * If exact match is found with respect to XML_Node name, the pointer
632  * to the matching XML Node is returned. If not, 0 is returned.
633  * This is the non-const version of the routine.
634  *
635  * @param nm Name of the XML node
636  * @param depth Depth of the search. A value of 1 means that only the
637  * immediate children are searched.
638  *
639  * @return Returns the pointer to the XML node that fits the criteria
640  */
641  XML_Node* findByName(const std::string& nm, int depth = 100000);
642 
643  //! Get a vector of pointers to XML_Node containing all of the children
644  //! of the current node which matches the input name
645  /*!
646  * @param name Name of the XML_Node children to search on
647  *
648  * @param children output vector of pointers to XML_Node children
649  * with the matching name
650  */
651  void getChildren(const std::string& name, std::vector<XML_Node*>& children) const;
652 
653  //! Return a changeable reference to a child of the current node, named by the argument
654  /*!
655  * Note the underlying data allows for more than one XML element with the same name.
656  * This routine returns the first child with the given name.
657  *
658  * @param loc Name of the child to return
659  */
660  XML_Node& child(const std::string& loc) const;
661 
662  //! Write the header to the xml file to the specified ostream
663  /*!
664  * @param s ostream to write the output to
665  */
666  void writeHeader(std::ostream& s);
667 
668 
669  //! Write an XML subtree to an output stream.
670  /*!
671  * This is a
672  * wrapper around the static routine write_int(). All this
673  * does is add an endl on to the output stream. write_int() is
674  * fine, but the last endl wasn't being written.
675  * It also checks for the special name "--". If found and we
676  * are at the root of the xml tree, then the block
677  * is skipped and the children are processed. "--" is used
678  * to denote the top of the tree.
679  *
680  * @param s ostream to write to
681  * @param level Indentation level to work from
682  * @param numRecursivesAllowed Number of recursive calls allowed
683  */
684  void write(std::ostream& s, const int level = 0, int numRecursivesAllowed = 60000) const;
685 
686  //! Return the root of the current XML_Node tree
687  /*!
688  * Returns a reference to the root of the current
689  * XML tree
690  */
691  XML_Node& root() const;
692 
693  //! Set the root XML_Node value within the current node
694  /*!
695  * @param root Value of the root XML_Node.
696  */
697  void setRoot(const XML_Node& root);
698 
699  //! Main routine to create an tree-like representation of an XML file
700  /*!
701  * Given an input stream, this routine will read matched XML tags
702  * representing the ctml file until an EOF is read from the file.
703  * This routine is called by the root XML_Node object.
704  *
705  * @param f Input stream containing the ascii input file
706  */
707  void build(std::istream& f);
708 
709  //! Copy all of the information in the current XML_Node tree
710  //! into the destination XML_Node tree, doing a union operation as
711  //! we go
712  /*!
713  * Note this is a const function because the current XML_Node and
714  * its children isn't altered by this operation.
715  * copyUnion() doesn't duplicate existing entries in the
716  * destination XML_Node tree.
717  *
718  * @param node_dest This is the XML node to receive the information
719  *
720  */
721  void copyUnion(XML_Node* const node_dest) const;
722 
723  //! Copy all of the information in the current XML_Node tree
724  //! into the destination XML_Node tree, doing a complete copy
725  //! as we go.
726  /*!
727  * Note this is a const function because the current XML_Node and
728  * its children isn't altered by this operation.
729  *
730  * @param node_dest This is the XML node to receive the information
731  */
732  void copy(XML_Node* const node_dest) const;
733 
734  //! Set the lock for this node and all of its children
735  void lock();
736 
737  //! Unset the lock for this node and all of its children
738  void unlock();
739 
740 private:
741 
742 
743  //! Write an XML subtree to an output stream.
744  /*!
745  * This is the main recursive routine. It doesn't put a final endl
746  * on. This is fixed up in the public method. A method to only write out a limited
747  * amount of the xml tree has been added.
748  *
749  * @param s ostream to write to
750  * @param level Indentation level to work from
751  * @param numRecursivesAllowed Number of recursive calls allowed
752  */
753  void write_int(std::ostream& s, int level = 0, int numRecursivesAllowed = 60000) const;
754 
755 protected:
756 
757  //! XML node name of the node.
758  /*!
759  * For example, if we were in the XML_Node where
760  * @verbatim
761  * <phase dim="3" id="gas">
762  * </phase>
763  * @endverbatim
764  * Then, this string would be equal to "phase". "dim" and "id"
765  * are attributes of the XML_Node.
766  */
767  std::string m_name;
768 
769  //! Value of the xml node
770  /*!
771  * This is the string contents of the XML node. For
772  * example. The xml node named eps:
773  *
774  * <eps>
775  * valueString
776  * </eps>
777  *
778  * has a m_value string containing "valueString".
779  */
780  std::string m_value;
781 
782  //! Map containing an index between the node name and the
783  //! pointer to the node
784  /*!
785  * m_childindex[node.name()] = XML_Node *pointer
786  *
787  * This object helps to speed up searches.
788  */
789  std::multimap<std::string, XML_Node*> m_childindex;
790 
791  //! Storage of attributes for a node
792  /*!
793  * m_attribs[attribName] = attribValue
794  */
795  std::map<std::string, std::string> m_attribs;
796 
797  //! Pointer to the parent XML_Node for the current node
798  /*!
799  * Note, the top node has a parent value of 0
800  */
802 
803  //! Pointer to the root XML_Node for the current node
804  /*!
805  * Note, the top node has a root value equal to itself
806  */
808 
809  //! Lock for this node
810  /*!
811  * Currently, unimplemented functionality. If locked,
812  * it means you can't delete this node.
813  */
814  bool m_locked;
815 
816  //! Vector of pointers to child nodes
817  std::vector<XML_Node*> m_children;
818 
819  //! Number of children of this node
820  size_t m_nchildren;
821 
822  //! True if the current node is a comment node
824 
825  //! The member data m_linenum
826  /*!
827  * Currently, unimplemented functionality
828  */
830 };
831 
832 //! Search an XML_Node tree for a named phase XML_Node
833 /*!
834  * Search for a phase Node matching a name.
835  *
836  * @param root Starting XML_Node* pointer for the search
837  * @param phaseName Name of the phase to search for
838  *
839  * @return Returns the XML_Node pointer if the phase is found.
840  * If the phase is not found, it returns 0
841  */
842 XML_Node* findXMLPhase(XML_Node* root, const std::string& phaseName);
843 
844 }
845 
846 #endif
847