/** * @file xml.h * Classes providing support for XML data files. These classes * implement only those aspects of XML required to read, write, and * manipulate CTML data files. */ /* * $Revision$ * $Date$ */ // Copyright 2001 California Institute of Technology #ifndef CT_XML_H #define CT_XML_H #include "ctexceptions.h" #include "ct_defs.h" #include "global.h" #include #include #include //@{ #define XML_INDENT 4 //@} namespace Cantera { //! Class XML_Reader reads an XML file into an XML_Node object. /*! * * Class XML_Reader is designed for internal use. */ class XML_Reader { public: //! Sole Constructor for the XML_Reader class /*! * @param input Reference to the istream object containing * the XML file */ XML_Reader(std::istream& input); //! Read a single character from the input stream //! and return it /*! * All low level reads occur through this function. * The function also keeps track of the line numbers. * * @param ch Character to be returned. */ void getchr(char& ch); //! Returns string 'aline' stripped of leading and trailing white //! space. /*! * White space is defined by the ISO C function isspace(), and * includes tabs, spaces, \\n. \\r, \\v, and \\f. * * @param aline Input line to be stripped * * @return Returns a string stripped of leading and trailing white * space. * * @todo why is this a class method? */ std::string strip(const std::string& aline) const; //! Looks for a substring within 'aline' enclosed in double //! quotes, and returns this substring (without the quotes) if //! found. If not, an empty string is returned. /*! * * @param aline This is the input string to be searched * * @todo why is this a class method? */ std::string inquotes(const std::string& aline) const; //! Searches a string for the first occurrence of a valid //! quoted string. /*! * Quotes can start with either a single * quote or a double quote, but must also end with the same * type. Quotes may be commented out by preceding with a * backslash character, '\\'. * * @param aline This is the input string to be searched * @param rstring Return value of the string that is found. * The quotes are stripped from the string. * * @return Returns the integer position just after * the quoted string. */ int findQuotedString(const std::string& aline, std::string &rstring) const; //! parseTag parses XML tags, i.e., the XML elements that are //! inbetween angle brackets. /*! * @param tag Tag to be parsed - input * * @param name Output string containing name * of the XML * @param attribs map of attribute name and * attribute value - output */ void parseTag(std::string tag, std::string& name, std::map& attribs) const; //! Reads an XML tag into a string /*! * This function advances the input streams pointer * * @param attribs map of attribute name and * attribute value - output * * @return Output string containing name * of the XML */ std::string readTag(std::map& attribs); //! Return the value portion of an XML element /*! * This function advances the input streams pointer */ std::string readValue(); protected: //! Input Stream containing the XML file std::istream& m_s; public: //! Line count int m_line; }; ////////////////////////// XML_Node ///////////////////////////////// //! Class XML_Node is a tree-based representation of the contents of an XML file /*! * Class XML_Node is a tree-based representation of the contents of an XML file. * * There are routines for adding to the tree. * * There are routines for querying and searching the tree. * * Additionally, there are routines for writing the tree out to an output file. * */ class XML_Node { public: //! Default constructor for XML_Node, representing a tree structure /*! * Constructor for an XML_Node, which is a node in a tree-like structure * representing an XML file. * * @param nm Name of the node. * The default name of the node is "--" * * @param p pointer to the root for this node in the tree. * The default is 0 indicating this is the top of the tree. */ XML_Node(const std::string nm = "--", XML_Node * const p = 0); //! Copy constructor /*! * @param right Object to be copied */ XML_Node(const XML_Node &right); //! Assignment operator for XML trees /*! * @param right XML tree to copy */ XML_Node& operator=(const XML_Node &right); //! Destructor for the object virtual ~XML_Node(); //! Add a child node to the current node containing a comment /*! * Child node will have the name, comment. * * @param comment Content of the comment */ void addComment(const std::string &comment); //! Add a child node to the current node /*! * This will add an XML_Node as a child to the current node. * Note, this actually adds the node. Therefore, the current node is changed. * There is no copy made of the child node. * * @param node Reference to a child XML_Node object * * @return Returns a reference to the added child node */ XML_Node& addChild(XML_Node& node); //! Add a child node to the current node with a specified name /*! * This will add an XML_Node as a child to the current node. * The node will be blank except for the specified name. * * @param sname Name of the new child * * @return Returns a reference to the added node */ XML_Node& addChild(const std::string &sname); //! Add a child node to the current xml node, and at the //! same time add a value to the child /*! * Resulting XML string: * \ value \ * * @param name Name of the child XML_Node object * @param value Value of the XML_Node - string * @return Returns a reference to the created child XML_Node object */ XML_Node& addChild(const std::string &name, const std::string &value); //! Add a child node to the current xml node, and at the //! same time add a formatted value to the child /*! * This version supplies a formatting string (printf format) * to the output of the value. * * Resulting XML string: * \ value \ * * @param name Name of the child XML_Node object * @param value Value of the XML_Node - double. * @param fmt Format of the output for value * * @return Returns a reference to the created child XML_Node object */ XML_Node& addChild(const std::string &name, const doublereal value, const std::string fmt="%g"); //! Remove a child from this node's list of children /*! * This function removes an XML_Node from the children of this node. * * @param node Pointer to the node to be removed. Note, this node * isn't modified in any way. */ void removeChild(const XML_Node * const node); //! Modify the value for the current node /*! * This functions fills in the m_value field of the current node * * @param val string Value that the node will be assigned */ void addValue(const std::string &val); //! Modify the value for the current node /*! * This functions fills in the m_value field of the current node * with a formatted double value * * @param val double Value that the node will be assigned * @param fmt Format of the printf string conversion of the double. * Default is "%g". Must be less than 63 chars */ void addValue(const doublereal val, const std::string fmt="%g"); //! Return the value of an XML node as a string /*! * This is a simple accessor routine */ std::string value() const; //! Overloaded parenthesis operator returns the value of the Node /*! * @return Returns the value of the node as a string. */ std::string operator()() const; //! Return the value of an XML child node as a string /*! * @param cname Name of the child node to the current * node, for which you want the value */ std::string value(const std::string &cname) const; //! Overloaded parenthesis operator with one augment //! returns the value of an XML child node as a string /*! * @param cname Name of the child node to the current * node, for which you want the value */ std::string operator()(std::string cname) const; //! Return the value of an XML node as a single double /*! * This accesses the value string, and then tries to * interpret it as a single double value. */ doublereal fp_value() const; //! Return the value of an XML node as a single int /*! * This accesses the value string, and then tries to * interpret it as a single int value. */ integer int_value() const; //! Add or modify an attribute of the current node /*! * This functions fills in the m_value field of the current node * with a string value * * @param attrib String name for the attribute to be assigned * @param value String value that the attribute will have */ void addAttribute(const std::string & attrib, const std::string & value); //! Add or modify an attribute to the double, value /*! * This functions fills in the attribute field, named attrib, * with the double value, value. A formatting string is used. * * @param attrib String name for the attribute to be assigned * @param value double Value that the node will be assigned * @param fmt Format of the printf string conversion of the double. * Default is "%g". */ void addAttribute(const std::string & attrib, const doublereal value, const std::string fmt="%g"); //! The operator[] is overloaded to provide a lookup capability //! on attributes for the current XML element. /*! * For example * xmlNode["id"] * will return the value of the attribute "id" for the current * XML element. It will return the blank std::string if there isn't * an attribute with that name. * * @param attr attribute string to look up * * @return Returns a string representing the value of the attribute * within the XML node. If there is no attribute * with the given name, it returns the null string. */ std::string operator[](const std::string & attr) const; //! Function returns the value of an attribute /*! * This function searches the attibutes vector for the parameter * std::string attribute. If a match is found, the attribute value * is returned as a string. If no match is found, the empty string * is returned. * * @param attr Std::String containing the attribute to be searched for. * * @return Returns If a match is found, the attribute value * is returned as a string. If no match is found, the empty string * is returned. */ std::string attrib(const std::string & attr) const; private: //! Returns a changeable value of the attributes map for the current node /*! * Note this is a simple accessor routine. And, it is a private function. * It's used in some internal copy and assignment routines */ std::map& attribs(); public: //! Set the line number /*! * @param n the member data m_linenum is set to n */ void setLineNumber(const int n); //! Return the line number /*! * @return returns the member data m_linenum */ int lineNumber() const; //! Returns a pointer to the parent node of the current node XML_Node* parent() const; //! Sets the pointer for the parent node of the current node /*! * @param p Pointer to the parent node * * @return Returns the pointer p */ XML_Node* setParent(XML_Node * const p); //! Tests whether the current node has a child node with a particular name /*! * @param ch Name of the child node to test * * @return Returns true if the child node exists, false otherwise. */ bool hasChild(const std::string ch) const; //! Tests whether the current node has an attribute with a particular name /*! * @param a Name of the attribute to test * * @return Returns true if the attribute exists, false otherwise. */ bool hasAttrib(std::string a) const; //! Returns the name of the XML node /*! * The name is the XML node is the XML node name */ std::string name() const { return m_name; } //! Return the id attribute, if present /*! * Returns the id attribute if present. If not * it return the empty string */ std::string id() const; //! Return a changeable reference to the n'th child of the current node /*! * @param n Number of the child to return */ XML_Node& child(const int n) const ; //! Return an unchangeable reference to the vector of children of the current node /*! * Each of the individual XML_Node child pointers, however, * is to a changeable xml node object. * */ const std::vector& children() const; //! return the number of children /*! * */ int nChildren() 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. /*! * @param a attribute name * @param v required value of the attribute * * If the condition is not true, an exception is thrown */ void _require(const std::string &a, const std::string &v) const; //! This routine carries out a recursive search for an XML node based //! on both the xml element name and the attribute ID. /*! * If exact matches are found for both fields, the pointer * to the matching XML Node is returned. * * The ID attribute may be defaulted by setting it to "". * In this case the pointer to the first xml element matching the name * only is returned. * * @param nameTarget Name of the XML Node that is being searched for * @param idTarget "id" attribute of the XML Node that the routine * looks for * * @return Returns the pointer to the XML node that fits the criteria * * @internal * This algorithm does a lateral search of first generation children * first before diving deeper into each tree branch. */ 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 the xml element attribute ID. /*! * If exact match is found, the pointer * to the matching XML Node is returned. If not, 0 is returned. * * The ID attribute may be defaulted by setting it to "". * In this case the pointer to the first xml element matching the name * only is returned. * * @param id "id" attribute of the XML Node that the routine * looks for * @param depth Depth of the search. * * @return Returns the pointer to the XML node that fits the criteria * * @internal * This algorithm does a lateral search of first generation children * first before diving deeper into each tree branch. */ 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 an attribute of each XML node /*! * If exact match is found with respect to the attribute name and * value of the attribute, the pointer * to the matching XML Node is returned. If not, 0 is returned. * * * @param attr Attribute of the XML Node that the routine * looks for * @param val Value of the attribute * * @return Returns the pointer to the XML node that fits the criteria * */ XML_Node* findByAttr(const std::string& attr, const std::string& val) const; //! This routine carries out a recursive search for an XML node based //! on the name of the node. /*! * If exact match is found with respect to XML_Node name, the pointer * to the matching XML Node is returned. If not, 0 is returned. * This is the const version of the routine. * * @param nm Name of the XML node * * @return Returns the pointer to the XML node that fits the criteria */ const XML_Node* findByName(const std::string& nm) const; //! This routine carries out a recursive search for an XML node based //! on the name of the node. /*! * If exact match is found with respect to XML_Node name, the pointer * to the matching XML Node is returned. If not, 0 is returned. * This is the non-const version of the routine. * * @param nm Name of the XML node * * @return Returns the pointer to the XML node that fits the criteria */ XML_Node* findByName(const std::string& nm); //! Get a vector of pointers to XML_Node containing all of the children //! of the current node which matches the input name /*! * @param name Name of the XML_Node children to search on * * @param children output vector of pointers to XML_Node children * with the matching name */ void getChildren(const std::string &name, std::vector& children) const; //! Return a changeable reference to a child of the current node, //! named by the argument /*! * @param loc Name of the child to return */ XML_Node& child(const std::string &loc) const; //! Write the header to the xml file to the specified ostream /*! * @param s ostream to write the output to */ void writeHeader(std::ostream& s); //! Write an XML subtree to an output stream. /*! * This is a * wrapper around the static routine write_int(). All this * does is add an endl on to the output stream. write_int() is * fine, but the last endl wasn't being written. * It also checks for the special name "--". If found and we * are at the root of the xml tree, then the block * is skipped and the children are processed. "--" is used * to denote the top of the tree. * * @param s ostream to write to * @param level Indentation level to work from */ void write(std::ostream& s, const int level = 0) const; //! Return the root of the current XML_Node tree /*! * Returns a reference to the root of the current * XML tree */ XML_Node& root() const; //! Set the root XML_Node value within the current node /*! * @param root Value of the root XML_Node. */ void setRoot(const XML_Node& root); //! Main routine to create an tree-like representation of an XML file /*! * Given an input stream, this routine will read matched XML tags * representing the ctml file until an EOF is read from the file. * This routine is called by the root XML_Node object. * * @param f Input stream containing the ascii input file */ void build(std::istream& f); //! Copy all of the information in the current XML_Node tree //! into the destination XML_Node tree, doing a union operation as //! we go /*! * Note this is a const function becuase the current XML_Node and * its children isn't altered by this operation. * copyUnion() doesn't duplicate existing entries in the * destination XML_Node tree. * * @param node_dest This is the XML node to receive the information * */ 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, doing a complete copy //! as we go. /*! * Note this is a const function becuase the current XML_Node and * its children isn't altered by this operation. * * @param node_dest This is the XML node to receive the information */ void copy(XML_Node * const node_dest) const; //! Set the lock for this node and all of its children void lock(); //! Unset the lock for this node and all of its children void unlock(); private: //! Write an XML subtree to an output stream. /*! * This is the * main recursive routine. It doesn't put a final endl * on. This is fixed up in the public method. * * * @param s ostream to write to * @param level Indentation level to work from */ void write_int(std::ostream& s, int level = 0) const; protected: //! XML node name of the node. /*! * For example, if we were in the XML_Node where * @verbatim * * * @endverbatim * Then, this string would be equal to "phase". "dim" and "id" * are attributes of the XML_Node. */ std::string m_name; //! Value of the xml node /*! * This is the string contents of the XML node. For * example. The xml node named eps: * * \ * valueString * \ * * has a m_value string containing "valueString". */ std::string m_value; //! Map containing an index between the node name and the //! pointer to the node /*! * m_childindex[node.name()] = XML_Node *pointer * * This object helps to speed up searches */ std::map m_childindex; //! Storage of attributes for a node /*! * m_attribs[attribName] = attribValue */ std::map m_attribs; //! Pointer to the parent XML_Node for the current node /*! * Note, the top node has a parent value of 0 */ XML_Node* m_parent; //! Pointer to the root XML_Node for the current node /*! * Note, the top node has a root value equal to itself */ XML_Node* m_root; //! Lock for this node /*! * Currently, unimplemented functionality. If locked, * it means you can't delete this node. */ bool m_locked; //! Vector of pointers to child nodes std::vector m_children; //! Number of children of this node int m_nchildren; //! True if the current node is a comment node bool m_iscomment; //! the member data m_linenum /*! * Currently, unimplemented functionality */ int m_linenum; }; //! Search an XML_Node tree for a named phase XML_Node /*! * Search for a phase Node matching a name. * * @param root Starting XML_Node* pointer for the search * @param phaseName Name of the phase to search for * * @return Returns the XML_Node pointer if the phase is found. * If the phase is not found, it returns 0 */ XML_Node * findXMLPhase(XML_Node* root, const std::string &phaseName); } #endif