/** * @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. */ /* $Author$ * $Revision$ * $Date$ */ // Copyright 2001 California Institute of Technology #ifndef CT_XML_H #define CT_XML_H #include #include #include #include "ctexceptions.h" #include "ct_defs.h" #include "stringUtils.h" #include #include "global.h" #define XML_INDENT 4 namespace Cantera { /** * Class XML_Reader is designed for internal use. * This function reads an XML file into an XML_Node object. */ 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); //! Input Stream containing the XML file std::istream& m_s; //! Line count int m_line; //! 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); /// 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. /// @todo why is this a class method? std::string inquotes(const std::string& aline); /** * 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, '\\'. */ int findQuotedString(const std::string& aline, std::string &rstring); void parseTag(std::string line, std::string& name, std::map& attribs); std::string readTag(std::map& attribs); std::string readValue(); }; ////////////////////////// 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. * * * * */ 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, 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 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"); //! 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 double 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; void writeHeader(std::ostream& s); std::string value() const { return m_value; } std::string value(std::string loc) const { return child(loc).value(); } void setLineNumber(int n) {m_linenum = n;} int lineNumber() const {return m_linenum;} doublereal fp_value() const { return std::atof(m_value.c_str()); } integer int_value() const { return std::atoi(m_value.c_str()); } std::string operator()() const { return m_value; } std::string operator()(std::string loc) const { return value(loc); } std::map& attribs() { return m_attribs; } XML_Node* parent() const { return m_parent; } XML_Node* setParent(XML_Node* p) { m_parent = p; return 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 { return (m_childindex.find(ch) != m_childindex.end()); } //! 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 { return (m_attribs.find(a) != m_attribs.end()); } //! 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; XML_Node& child(int n) const { return *m_children[n]; } std::vector& children() { return m_children; } const std::vector& children() const { return m_children; } int nChildren() const { return m_nchildren; } void build(std::istream& f); void _require(std::string a, std::string v) const; /** * This routine carries out a 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. * @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; XML_Node* findID(const std::string& id, int depth=100) const; XML_Node* findByAttr(const std::string& attr, const std::string& val); const XML_Node* findByName(const std::string& nm) const; XML_Node* findByName(const std::string& nm); void getChildren(std::string name, std::vector& children) const; XML_Node& child(std::string loc) const; void write(std::ostream& s, int level = 0) const; XML_Node& root() const { return *m_root; } void setRoot(XML_Node& root) { m_root = &root; } void copyUnion(XML_Node *node_dest) const; void copy(XML_Node *node_dest) const; void lock() {m_locked = true;} void unlock() {m_locked = false; } private: 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 * * * 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; std::map m_childindex; std::map m_attribs; XML_Node* m_parent; XML_Node* m_root; bool m_locked; std::vector m_children; //! Number of children of this node int m_nchildren; bool m_iscomment; int m_linenum; }; XML_Node * findXMLPhase(XML_Node* root, const std::string &id); } #endif