00001 /** 00002 * @file xml.h 00003 * Classes providing support for XML data files. These classes 00004 * implement only those aspects of XML required to read, write, and 00005 * manipulate CTML data files. 00006 */ 00007 00008 /* 00009 * $Revision: 387 $ 00010 * $Date: 2010-01-17 13:17:55 -0500 (Sun, 17 Jan 2010) $ 00011 */ 00012 00013 // Copyright 2001 California Institute of Technology 00014 00015 #ifndef CT_XML_H 00016 #define CT_XML_H 00017 00018 #include "ctexceptions.h" 00019 #include "ct_defs.h" 00020 #include "global.h" 00021 00022 00023 #include <string> 00024 #include <vector> 00025 #include <iostream> 00026 00027 //@{ 00028 #define XML_INDENT 4 00029 //@} 00030 namespace Cantera { 00031 00032 00033 //! Class XML_Reader reads an XML file into an XML_Node object. 00034 /*! 00035 * 00036 * Class XML_Reader is designed for internal use. 00037 */ 00038 class XML_Reader { 00039 public: 00040 00041 //! Sole Constructor for the XML_Reader class 00042 /*! 00043 * @param input Reference to the istream object containing 00044 * the XML file 00045 */ 00046 XML_Reader(std::istream& input); 00047 00048 //! Read a single character from the input stream 00049 //! and return it 00050 /*! 00051 * All low level reads occur through this function. 00052 * The function also keeps track of the line numbers. 00053 * 00054 * @param ch Character to be returned. 00055 */ 00056 void getchr(char& ch); 00057 00058 //! Returns string 'aline' stripped of leading and trailing white 00059 //! space. 00060 /*! 00061 * White space is defined by the ISO C function isspace(), and 00062 * includes tabs, spaces, \\n. \\r, \\v, and \\f. 00063 * 00064 * @param aline Input line to be stripped 00065 * 00066 * @return Returns a string stripped of leading and trailing white 00067 * space. 00068 * 00069 * @todo why is this a class method? 00070 */ 00071 std::string strip(const std::string& aline) const; 00072 00073 //! Looks for a substring within 'aline' enclosed in double 00074 //! quotes, and returns this substring (without the quotes) if 00075 //! found. If not, an empty string is returned. 00076 /*! 00077 * 00078 * @param aline This is the input string to be searched 00079 * 00080 * @todo why is this a class method? 00081 */ 00082 std::string inquotes(const std::string& aline) const; 00083 00084 //! Searches a string for the first occurrence of a valid 00085 //! quoted string. 00086 /*! 00087 * Quotes can start with either a single 00088 * quote or a double quote, but must also end with the same 00089 * type. Quotes may be commented out by preceding with a 00090 * backslash character, '\\'. 00091 * 00092 * @param aline This is the input string to be searched 00093 * @param rstring Return value of the string that is found. 00094 * The quotes are stripped from the string. 00095 * 00096 * @return Returns the integer position just after 00097 * the quoted string. 00098 */ 00099 int findQuotedString(const std::string& aline, std::string &rstring) const; 00100 00101 //! parseTag parses XML tags, i.e., the XML elements that are 00102 //! inbetween angle brackets. 00103 /*! 00104 * @param tag Tag to be parsed - input 00105 * 00106 * @param name Output string containing name 00107 * of the XML 00108 * @param attribs map of attribute name and 00109 * attribute value - output 00110 */ 00111 void parseTag(std::string tag, std::string& name, 00112 std::map<std::string, std::string>& attribs) const; 00113 00114 //! Reads an XML tag into a string 00115 /*! 00116 * This function advances the input streams pointer 00117 * 00118 * @param attribs map of attribute name and 00119 * attribute value - output 00120 * 00121 * @return Output string containing name 00122 * of the XML 00123 */ 00124 std::string readTag(std::map<std::string, std::string>& attribs); 00125 00126 //! Return the value portion of an XML element 00127 /*! 00128 * This function advances the input streams pointer 00129 */ 00130 std::string readValue(); 00131 00132 protected: 00133 //! Input Stream containing the XML file 00134 std::istream& m_s; 00135 00136 public: 00137 //! Line count 00138 int m_line; 00139 00140 }; 00141 00142 00143 ////////////////////////// XML_Node ///////////////////////////////// 00144 00145 //! Class XML_Node is a tree-based representation of the contents of an XML file 00146 /*! 00147 * Class XML_Node is a tree-based representation of the contents of an XML file. 00148 * 00149 * There are routines for adding to the tree. 00150 * 00151 * There are routines for querying and searching the tree. 00152 * 00153 * Additionally, there are routines for writing the tree out to an output file. 00154 * 00155 */ 00156 class XML_Node { 00157 public: 00158 00159 //! Default constructor for XML_Node, representing a tree structure 00160 /*! 00161 * Constructor for an XML_Node, which is a node in a tree-like structure 00162 * representing an XML file. 00163 * 00164 * @param cnm Name of the node. 00165 * The default name of the node is "--" 00166 */ 00167 XML_Node(const char * cnm = 0); 00168 00169 00170 //! Default constructor for XML_Node, representing a tree structure 00171 /*! 00172 * Constructor for an XML_Node, which is a node in a tree-like structure 00173 * representing an XML file. 00174 * 00175 * @param nm Name of the node. 00176 * The default name of the node is "--" 00177 * 00178 * @param p pointer to the root for this node in the tree. 00179 * The default is 0 indicating this is the top of the tree. 00180 */ 00181 XML_Node(const std::string nm, XML_Node * const p); 00182 00183 //! Copy constructor 00184 /*! 00185 * @param right Object to be copied 00186 */ 00187 XML_Node(const XML_Node &right); 00188 00189 //! Assignment operator for XML trees 00190 /*! 00191 * @param right XML tree to copy 00192 */ 00193 XML_Node& operator=(const XML_Node &right); 00194 00195 //! Destructor for the object 00196 virtual ~XML_Node(); 00197 00198 //! Add a child node to the current node containing a comment 00199 /*! 00200 * Child node will have the name, comment. 00201 * 00202 * @param comment Content of the comment 00203 */ 00204 void addComment(const std::string &comment); 00205 00206 //! Add a child node to the current node 00207 /*! 00208 * This will add an XML_Node as a child to the current node. 00209 * Note, this actually adds the node. Therefore, the current node is changed. 00210 * There is no copy made of the child node. 00211 * 00212 * @param node Reference to a child XML_Node object 00213 * 00214 * @return Returns a reference to the added child node 00215 */ 00216 XML_Node& addChild(XML_Node& node); 00217 00218 //! Add a child node to the current node with a specified name 00219 /*! 00220 * This will add an XML_Node as a child to the current node. 00221 * The node will be blank except for the specified name. 00222 * 00223 * @param sname Name of the new child 00224 * 00225 * @return Returns a reference to the added node 00226 */ 00227 XML_Node& addChild(const std::string &sname); 00228 00229 //! Add a child node to the current xml node, and at the 00230 //! same time add a value to the child 00231 /*! 00232 * Resulting XML string: 00233 * <name> value </name> 00234 * 00235 * @param name Name of the child XML_Node object 00236 * @param value Value of the XML_Node - string 00237 * @return Returns a reference to the created child XML_Node object 00238 */ 00239 XML_Node& addChild(const std::string &name, const std::string &value); 00240 00241 //! Add a child node to the current xml node, and at the 00242 //! same time add a formatted value to the child 00243 /*! 00244 * This version supplies a formatting string (printf format) 00245 * to the output of the value. 00246 * 00247 * Resulting XML string: 00248 * <name> value </name> 00249 * 00250 * @param name Name of the child XML_Node object 00251 * @param value Value of the XML_Node - double. 00252 * @param fmt Format of the output for value 00253 * 00254 * @return Returns a reference to the created child XML_Node object 00255 */ 00256 XML_Node& addChild(const std::string &name, const doublereal value, 00257 const std::string fmt="%g"); 00258 00259 //! Remove a child from this node's list of children 00260 /*! 00261 * This function removes an XML_Node from the children of this node. 00262 * 00263 * @param node Pointer to the node to be removed. Note, this node 00264 * isn't modified in any way. 00265 */ 00266 void removeChild(const XML_Node * const node); 00267 00268 //! Modify the value for the current node 00269 /*! 00270 * This functions fills in the m_value field of the current node 00271 * 00272 * @param val string Value that the node will be assigned 00273 */ 00274 void addValue(const std::string &val); 00275 00276 //! Modify the value for the current node 00277 /*! 00278 * This functions fills in the m_value field of the current node 00279 * with a formatted double value 00280 * 00281 * @param val double Value that the node will be assigned 00282 * @param fmt Format of the printf string conversion of the double. 00283 * Default is "%g". Must be less than 63 chars 00284 */ 00285 void addValue(const doublereal val, const std::string fmt="%g"); 00286 00287 //! Return the value of an XML node as a string 00288 /*! 00289 * This is a simple accessor routine 00290 */ 00291 std::string value() const; 00292 00293 //! Overloaded parenthesis operator returns the value of the Node 00294 /*! 00295 * @return Returns the value of the node as a string. 00296 */ 00297 std::string operator()() const; 00298 00299 //! Return the value of an XML child node as a string 00300 /*! 00301 * @param cname Name of the child node to the current 00302 * node, for which you want the value 00303 */ 00304 std::string value(const std::string &cname) const; 00305 00306 //! The Overloaded parenthesis operator with one augment 00307 //! returns the value of an XML child node as a string 00308 /*! 00309 * @param cname Name of the child node to the current 00310 * node, for which you want the value 00311 */ 00312 std::string operator()(std::string cname) const; 00313 00314 //! Return the value of an XML node as a single double 00315 /*! 00316 * This accesses the value string, and then tries to 00317 * interpret it as a single double value. 00318 */ 00319 doublereal fp_value() const; 00320 00321 //! Return the value of an XML node as a single int 00322 /*! 00323 * This accesses the value string, and then tries to 00324 * interpret it as a single int value. 00325 */ 00326 integer int_value() const; 00327 00328 //! Add or modify an attribute of the current node 00329 /*! 00330 * This functions fills in the m_value field of the current node 00331 * with a string value 00332 * 00333 * @param attrib String name for the attribute to be assigned 00334 * @param value String value that the attribute will have 00335 */ 00336 void addAttribute(const std::string & attrib, const std::string & value); 00337 00338 //! Add or modify an attribute to the double, value 00339 /*! 00340 * This functions fills in the attribute field, named attrib, 00341 * with the double value, value. A formatting string is used. 00342 * 00343 * @param attrib String name for the attribute to be assigned 00344 * @param value double Value that the node will be assigned 00345 * @param fmt Format of the printf string conversion of the double. 00346 * Default is "%g". 00347 */ 00348 void addAttribute(const std::string & attrib, const doublereal value, 00349 const std::string fmt="%g"); 00350 00351 //! The operator[] is overloaded to provide a lookup capability 00352 //! on attributes for the current XML element. 00353 /*! 00354 * For example 00355 * xmlNode["id"] 00356 * will return the value of the attribute "id" for the current 00357 * XML element. It will return the blank std::string if there isn't 00358 * an attribute with that name. 00359 * 00360 * @param attr attribute string to look up 00361 * 00362 * @return Returns a string representing the value of the attribute 00363 * within the XML node. If there is no attribute 00364 * with the given name, it returns the null string. 00365 */ 00366 std::string operator[](const std::string & attr) const; 00367 00368 //! Function returns the value of an attribute 00369 /*! 00370 * This function searches the attibutes vector for the parameter 00371 * std::string attribute. If a match is found, the attribute value 00372 * is returned as a string. If no match is found, the empty string 00373 * is returned. 00374 * 00375 * @param attr Std::String containing the attribute to be searched for. 00376 * 00377 * @return Returns If a match is found, the attribute value 00378 * is returned as a string. If no match is found, the empty string 00379 * is returned. 00380 */ 00381 std::string attrib(const std::string & attr) const; 00382 00383 //! Clear the current node and everything under it 00384 /*! 00385 * The value, attributes and children are all zeroed. The name and the 00386 * parent information is kept. 00387 */ 00388 void clear(); 00389 00390 private: 00391 //! Returns a changeable value of the attributes map for the current node 00392 /*! 00393 * Note this is a simple accessor routine. And, it is a private function. 00394 * It's used in some internal copy and assignment routines 00395 */ 00396 std::map<std::string,std::string>& attribs(); 00397 00398 public: 00399 00400 //! Set the line number 00401 /*! 00402 * @param n the member data m_linenum is set to n 00403 */ 00404 void setLineNumber(const int n); 00405 00406 //! Return the line number 00407 /*! 00408 * @return returns the member data m_linenum 00409 */ 00410 int lineNumber() const; 00411 00412 00413 //! Returns a pointer to the parent node of the current node 00414 XML_Node* parent() const; 00415 00416 //! Sets the pointer for the parent node of the current node 00417 /*! 00418 * @param p Pointer to the parent node 00419 * 00420 * @return Returns the pointer p 00421 */ 00422 XML_Node* setParent(XML_Node * const p); 00423 00424 //! Tests whether the current node has a child node with a particular name 00425 /*! 00426 * @param ch Name of the child node to test 00427 * 00428 * @return Returns true if the child node exists, false otherwise. 00429 */ 00430 bool hasChild(const std::string ch) const; 00431 00432 //! Tests whether the current node has an attribute with a particular name 00433 /*! 00434 * @param a Name of the attribute to test 00435 * 00436 * @return Returns true if the attribute exists, false otherwise. 00437 */ 00438 bool hasAttrib(std::string a) const; 00439 00440 //! Returns the name of the XML node 00441 /*! 00442 * The name is the XML node is the XML node name 00443 */ 00444 std::string name() const { return m_name; } 00445 00446 //! Sets the name of the XML node 00447 /*! 00448 * @param name The name of the XML node 00449 */ 00450 void setName(std::string name) { 00451 m_name = name; 00452 } 00453 00454 //! Return the id attribute, if present 00455 /*! 00456 * Returns the id attribute if present. If not 00457 * it return the empty string 00458 */ 00459 std::string id() const; 00460 00461 //! Return a changeable reference to the n'th child of the current node 00462 /*! 00463 * @param n Number of the child to return 00464 */ 00465 XML_Node& child(const int n) const ; 00466 00467 //! Return an unchangeable reference to the vector of children of the current node 00468 /*! 00469 * Each of the individual XML_Node child pointers, however, 00470 * is to a changeable xml node object. 00471 * 00472 */ 00473 const std::vector<XML_Node*>& children() const; 00474 00475 //! return the number of children 00476 /*! 00477 * 00478 */ 00479 int nChildren() const; 00480 00481 //! Require that the current xml node have an attribute named 00482 //! by the first argument, a, and that this attribute have the 00483 //! the string value listed in the second argument, v. 00484 /*! 00485 * @param a attribute name 00486 * @param v required value of the attribute 00487 * 00488 * If the condition is not true, an exception is thrown 00489 */ 00490 void _require(const std::string &a, const std::string &v) const; 00491 00492 //! This routine carries out a recursive search for an XML node based 00493 //! on both the xml element name and the attribute ID. 00494 /*! 00495 * If exact matches are found for both fields, the pointer 00496 * to the matching XML Node is returned. 00497 * 00498 * The ID attribute may be defaulted by setting it to "". 00499 * In this case the pointer to the first xml element matching the name 00500 * only is returned. 00501 * 00502 * @param nameTarget Name of the XML Node that is being searched for 00503 * @param idTarget "id" attribute of the XML Node that the routine 00504 * looks for 00505 * 00506 * @return Returns the pointer to the XML node that fits the criteria 00507 * 00508 * @internal 00509 * This algorithm does a lateral search of first generation children 00510 * first before diving deeper into each tree branch. 00511 */ 00512 XML_Node* findNameID(const std::string &nameTarget, 00513 const std::string &idTarget) const; 00514 00515 //! This routine carries out a recursive search for an XML node based 00516 //! on the xml element attribute ID. 00517 /*! 00518 * If exact match is found, the pointer 00519 * to the matching XML Node is returned. If not, 0 is returned. 00520 * 00521 * The ID attribute may be defaulted by setting it to "". 00522 * In this case the pointer to the first xml element matching the name 00523 * only is returned. 00524 * 00525 * @param id "id" attribute of the XML Node that the routine 00526 * looks for 00527 * @param depth Depth of the search. 00528 * 00529 * @return Returns the pointer to the XML node that fits the criteria 00530 * 00531 * @internal 00532 * This algorithm does a lateral search of first generation children 00533 * first before diving deeper into each tree branch. 00534 */ 00535 XML_Node* findID(const std::string& id, const int depth=100) const; 00536 00537 00538 //! This routine carries out a recursive search for an XML node based 00539 //! on an attribute of each XML node 00540 /*! 00541 * If exact match is found with respect to the attribute name and 00542 * value of the attribute, the pointer 00543 * to the matching XML Node is returned. If not, 0 is returned. 00544 * 00545 * 00546 * @param attr Attribute of the XML Node that the routine 00547 * looks for 00548 * @param val Value of the attribute 00549 * 00550 * @return Returns the pointer to the XML node that fits the criteria 00551 * 00552 */ 00553 XML_Node* findByAttr(const std::string& attr, const std::string& val) const; 00554 00555 //! This routine carries out a recursive search for an XML node based 00556 //! on the name of the node. 00557 /*! 00558 * If exact match is found with respect to XML_Node name, the pointer 00559 * to the matching XML Node is returned. If not, 0 is returned. 00560 * This is the const version of the routine. 00561 * 00562 * @param nm Name of the XML node 00563 * 00564 * @return Returns the pointer to the XML node that fits the criteria 00565 */ 00566 const XML_Node* findByName(const std::string& nm) const; 00567 00568 //! This routine carries out a recursive search for an XML node based 00569 //! on the name of the node. 00570 /*! 00571 * If exact match is found with respect to XML_Node name, the pointer 00572 * to the matching XML Node is returned. If not, 0 is returned. 00573 * This is the non-const version of the routine. 00574 * 00575 * @param nm Name of the XML node 00576 * 00577 * @return Returns the pointer to the XML node that fits the criteria 00578 */ 00579 XML_Node* findByName(const std::string& nm); 00580 00581 //! Get a vector of pointers to XML_Node containing all of the children 00582 //! of the current node which matches the input name 00583 /*! 00584 * @param name Name of the XML_Node children to search on 00585 * 00586 * @param children output vector of pointers to XML_Node children 00587 * with the matching name 00588 */ 00589 void getChildren(const std::string &name, std::vector<XML_Node*>& children) const; 00590 00591 //! Return a changeable reference to a child of the current node, 00592 //! named by the argument 00593 /*! 00594 * @param loc Name of the child to return 00595 */ 00596 XML_Node& child(const std::string &loc) const; 00597 00598 //! Write the header to the xml file to the specified ostream 00599 /*! 00600 * @param s ostream to write the output to 00601 */ 00602 void writeHeader(std::ostream& s); 00603 00604 00605 //! Write an XML subtree to an output stream. 00606 /*! 00607 * This is a 00608 * wrapper around the static routine write_int(). All this 00609 * does is add an endl on to the output stream. write_int() is 00610 * fine, but the last endl wasn't being written. 00611 * It also checks for the special name "--". If found and we 00612 * are at the root of the xml tree, then the block 00613 * is skipped and the children are processed. "--" is used 00614 * to denote the top of the tree. 00615 * 00616 * @param s ostream to write to 00617 * @param level Indentation level to work from 00618 */ 00619 void write(std::ostream& s, const int level = 0) const; 00620 00621 //! Return the root of the current XML_Node tree 00622 /*! 00623 * Returns a reference to the root of the current 00624 * XML tree 00625 */ 00626 XML_Node& root() const; 00627 00628 //! Set the root XML_Node value within the current node 00629 /*! 00630 * @param root Value of the root XML_Node. 00631 */ 00632 void setRoot(const XML_Node& root); 00633 00634 //! Main routine to create an tree-like representation of an XML file 00635 /*! 00636 * Given an input stream, this routine will read matched XML tags 00637 * representing the ctml file until an EOF is read from the file. 00638 * This routine is called by the root XML_Node object. 00639 * 00640 * @param f Input stream containing the ascii input file 00641 */ 00642 void build(std::istream& f); 00643 00644 //! Copy all of the information in the current XML_Node tree 00645 //! into the destination XML_Node tree, doing a union operation as 00646 //! we go 00647 /*! 00648 * Note this is a const function becuase the current XML_Node and 00649 * its children isn't altered by this operation. 00650 * copyUnion() doesn't duplicate existing entries in the 00651 * destination XML_Node tree. 00652 * 00653 * @param node_dest This is the XML node to receive the information 00654 * 00655 */ 00656 void copyUnion(XML_Node * const node_dest) const; 00657 00658 //! Copy all of the information in the current XML_Node tree 00659 //! into the destination XML_Node tree, doing a complete copy 00660 //! as we go. 00661 /*! 00662 * Note this is a const function because the current XML_Node and 00663 * its children isn't altered by this operation. 00664 * 00665 * @param node_dest This is the XML node to receive the information 00666 */ 00667 void copy(XML_Node * const node_dest) const; 00668 00669 //! Set the lock for this node and all of its children 00670 void lock(); 00671 00672 //! Unset the lock for this node and all of its children 00673 void unlock(); 00674 00675 private: 00676 00677 00678 //! Write an XML subtree to an output stream. 00679 /*! 00680 * This is the 00681 * main recursive routine. It doesn't put a final endl 00682 * on. This is fixed up in the public method. 00683 * 00684 * 00685 * @param s ostream to write to 00686 * @param level Indentation level to work from 00687 */ 00688 void write_int(std::ostream& s, int level = 0) const; 00689 00690 protected: 00691 00692 //! XML node name of the node. 00693 /*! 00694 * For example, if we were in the XML_Node where 00695 * @verbatim 00696 * <phase dim="3" id="gas"> 00697 * </phase> 00698 * @endverbatim 00699 * Then, this string would be equal to "phase". "dim" and "id" 00700 * are attributes of the XML_Node. 00701 */ 00702 std::string m_name; 00703 00704 //! Value of the xml node 00705 /*! 00706 * This is the string contents of the XML node. For 00707 * example. The xml node named eps: 00708 * 00709 * <eps> 00710 * valueString 00711 * </eps> 00712 * 00713 * has a m_value string containing "valueString". 00714 */ 00715 std::string m_value; 00716 00717 //! Map containing an index between the node name and the 00718 //! pointer to the node 00719 /*! 00720 * m_childindex[node.name()] = XML_Node *pointer 00721 * 00722 * This object helps to speed up searches 00723 */ 00724 std::map<std::string, XML_Node*> m_childindex; 00725 00726 //! Storage of attributes for a node 00727 /*! 00728 * m_attribs[attribName] = attribValue 00729 */ 00730 std::map<std::string, std::string> m_attribs; 00731 00732 //! Pointer to the parent XML_Node for the current node 00733 /*! 00734 * Note, the top node has a parent value of 0 00735 */ 00736 XML_Node* m_parent; 00737 00738 //! Pointer to the root XML_Node for the current node 00739 /*! 00740 * Note, the top node has a root value equal to itself 00741 */ 00742 XML_Node* m_root; 00743 00744 //! Lock for this node 00745 /*! 00746 * Currently, unimplemented functionality. If locked, 00747 * it means you can't delete this node. 00748 */ 00749 bool m_locked; 00750 00751 //! Vector of pointers to child nodes 00752 std::vector<XML_Node*> m_children; 00753 00754 //! Number of children of this node 00755 int m_nchildren; 00756 00757 //! True if the current node is a comment node 00758 bool m_iscomment; 00759 00760 //! the member data m_linenum 00761 /*! 00762 * Currently, unimplemented functionality 00763 */ 00764 int m_linenum; 00765 }; 00766 00767 //! Search an XML_Node tree for a named phase XML_Node 00768 /*! 00769 * Search for a phase Node matching a name. 00770 * 00771 * @param root Starting XML_Node* pointer for the search 00772 * @param phaseName Name of the phase to search for 00773 * 00774 * @return Returns the XML_Node pointer if the phase is found. 00775 * If the phase is not found, it returns 0 00776 */ 00777 XML_Node * findXMLPhase(XML_Node* root, const std::string &phaseName); 00778 00779 } 00780 00781 #endif 00782