cantera/Cantera/src/base/xml.h
2009-01-06 21:30:08 +00:00

756 lines
24 KiB
C++
Executable file

/**
* @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 <string>
#include <vector>
#include <iostream>
//@{
#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<std::string, std::string>& 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<std::string, std::string>& 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:
* \<name\> value \</name\>
*
* @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:
* \<name\> value \</name\>
*
* @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<std::string,std::string>& 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<XML_Node*>& 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<XML_Node*>& 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
* <phase dim="3" id="gas">
* </phase>
* @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:
*
* \<eps\>
* valueString
* \</eps\>
*
* 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<std::string, XML_Node*> m_childindex;
//! Storage of attributes for a node
/*!
* m_attribs[attribName] = attribValue
*/
std::map<std::string, std::string> 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<XML_Node*> 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