mirror of
https://github.com/Cantera/cantera.git
synced 2025-02-25 18:55:29 -06:00
Fixed several serious errors and added a couple of routines.
1) the read operation would hash any quoted string with a space character in it. 2) changed children() to return a reference rather than the complete object 3) write() would leave off the final endl character. This has been fixed. Additions: copy() copyUnion(): union of two trees; this routine may be problematic findXMLPhase(): phase lookup. Notes: find_XML() still contains a memory leak.
This commit is contained in:
parent
712176ae08
commit
9227cd87fb
@ -62,8 +62,10 @@ namespace Cantera {
|
||||
class XML_NoChild : public XML_Error {
|
||||
public:
|
||||
XML_NoChild(string parent, string child) {
|
||||
m_msg += "Node " + parent + " has no child named "
|
||||
+ child + ".\n";
|
||||
m_msg += " The XML Node, \"" + parent +
|
||||
"\", does not contain a required\n" +
|
||||
" XML child node named \""
|
||||
+ child + "\".\n";
|
||||
setError("XML_NoChild",m_msg);
|
||||
}
|
||||
virtual ~XML_NoChild() {}
|
||||
@ -110,13 +112,84 @@ namespace Cantera {
|
||||
if (j == i) return "";
|
||||
else return aline.substr(j+1, i - j - 1);
|
||||
}
|
||||
|
||||
|
||||
void XML_Reader::parseTag(string line, string& name,
|
||||
/**
|
||||
* Find the first position of a character, q, in string s,
|
||||
* which is not immediately preceded by the backslash character
|
||||
* '\'
|
||||
*/
|
||||
static string::size_type findUnbackslashed(string s, const char q,
|
||||
string::size_type istart = 0) {
|
||||
string::size_type iloc, icurrent, len;
|
||||
icurrent = istart;
|
||||
len = s.size();
|
||||
while (1) {
|
||||
iloc = s.find(q, icurrent);
|
||||
if (iloc == string::npos || iloc == 0) {
|
||||
return iloc;
|
||||
}
|
||||
char cm1 = s[iloc-1];
|
||||
if (cm1 == '\\') {
|
||||
if (iloc >= (len -1)) return string::npos;
|
||||
icurrent = iloc + 1;
|
||||
} else {
|
||||
return iloc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 XML_Reader::findQuotedString(const string& s, string &rstring) {
|
||||
const char q1 = '\'';
|
||||
const char q2 = '"';
|
||||
rstring = "";
|
||||
char qtype = ' ';
|
||||
string::size_type iloc1, iloc2, ilocStart;
|
||||
iloc1 = findUnbackslashed(s, q1);
|
||||
iloc2 = findUnbackslashed(s, q2);
|
||||
if (iloc2 != string::npos) {
|
||||
ilocStart = iloc2;
|
||||
qtype = q2;
|
||||
}
|
||||
if (iloc1 != string::npos) {
|
||||
if (iloc1 < ilocStart) {
|
||||
ilocStart = iloc1;
|
||||
qtype = q1;
|
||||
}
|
||||
}
|
||||
if (qtype == ' ') return 0;
|
||||
|
||||
iloc1 = findUnbackslashed(s, qtype, ilocStart+1);
|
||||
|
||||
if (iloc1 == string::npos) {
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* Define the return string by the two endpoints.
|
||||
* Strip the surrounding quotes as well
|
||||
*/
|
||||
rstring = s.substr(ilocStart + 1, iloc1 - 1);
|
||||
/*
|
||||
* Return the first character position past the quotes
|
||||
*/
|
||||
return iloc1+1;
|
||||
}
|
||||
|
||||
/**
|
||||
* parseTag parses XML tags, i.e., the XML elements that are
|
||||
* inbetween angle brackets.
|
||||
*/
|
||||
void XML_Reader::parseTag(string tag, string& name,
|
||||
map<string, string>& attribs) {
|
||||
int iloc;
|
||||
string::size_type iloc;
|
||||
string attr, val;
|
||||
string s = strip(line);
|
||||
string s = strip(tag);
|
||||
iloc = s.find(' ');
|
||||
if (iloc > 0) {
|
||||
name = s.substr(0, iloc);
|
||||
@ -125,18 +198,20 @@ namespace Cantera {
|
||||
// get attributes
|
||||
while (1) {
|
||||
iloc = s.find('=');
|
||||
if (iloc < 0) break;
|
||||
if (iloc == string::npos) break;
|
||||
attr = strip(s.substr(0,iloc));
|
||||
if (attr == "") break;
|
||||
s = strip(s.substr(iloc+1,s.size()));
|
||||
iloc = s.find(' ');
|
||||
if (iloc < 0) iloc = s.size();
|
||||
val = inquotes(s.substr(0,iloc));
|
||||
//iloc = s.find(' ');
|
||||
//if (iloc < 0) iloc = s.size();
|
||||
iloc = findQuotedString(s, val);
|
||||
attribs[attr] = val;
|
||||
if (iloc < int(s.size()))
|
||||
s = strip(s.substr(iloc+1,s.size()));
|
||||
else
|
||||
break;
|
||||
if (iloc != string::npos) {
|
||||
if (iloc < s.size())
|
||||
s = strip(s.substr(iloc,s.size()));
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -177,6 +252,12 @@ namespace Cantera {
|
||||
return tag;
|
||||
}
|
||||
else {
|
||||
#ifdef DEBUG_HKM
|
||||
cout << "tag fed to parseTag = " << tag << endl;
|
||||
if (tag == "standardConc model=\"molar volume\" /") {
|
||||
cout << "we are here" << endl;
|
||||
}
|
||||
#endif
|
||||
parseTag(tag, name, attribs);
|
||||
return name;
|
||||
}
|
||||
@ -388,6 +469,68 @@ namespace Cantera {
|
||||
}
|
||||
}
|
||||
|
||||
void XML_Node::copyUnion(XML_Node *node_dest) {
|
||||
XML_Node *sc, *dc;
|
||||
int ndc, idc;
|
||||
node_dest->addValue(m_value);
|
||||
if (m_name == "") return;
|
||||
map<string,string>::const_iterator b = m_attribs.begin();
|
||||
for (; b != m_attribs.end(); ++b) {
|
||||
if (! node_dest->hasAttrib(b->first)) {
|
||||
node_dest->addAttribute(b->first, b->second);
|
||||
}
|
||||
}
|
||||
vector<XML_Node*> &vsc = node_dest->children();
|
||||
for (int n = 0; n < m_nchildren; n++) {
|
||||
sc = m_children[n];
|
||||
ndc = node_dest->nChildren();
|
||||
dc = 0;
|
||||
if (! sc->m_iscomment) {
|
||||
for (idc = 0; idc < ndc; idc++) {
|
||||
XML_Node *dcc = vsc[idc];
|
||||
if (dcc->name() == sc->name()) {
|
||||
if (sc->hasAttrib("id")) {
|
||||
if (sc->attrib("id") != dcc->attrib("id")) break;
|
||||
}
|
||||
if (sc->hasAttrib("name")) {
|
||||
if (sc->attrib("name") != dcc->attrib("name")) break;
|
||||
}
|
||||
if (sc->hasAttrib("model")) {
|
||||
if (sc->attrib("model") != dcc->attrib("model")) break;
|
||||
}
|
||||
if (sc->hasAttrib("title")) {
|
||||
if (sc->attrib("title") != dcc->attrib("title")) break;
|
||||
}
|
||||
dc = vsc[idc];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!dc) {
|
||||
(void) node_dest->addChild(sc->name());
|
||||
dc = vsc[ndc];
|
||||
}
|
||||
sc->copyUnion(dc);
|
||||
}
|
||||
}
|
||||
|
||||
void XML_Node::copy(XML_Node *node_dest) {
|
||||
XML_Node *sc, *dc;
|
||||
int ndc;
|
||||
node_dest->addValue(m_value);
|
||||
if (m_name == "") return;
|
||||
map<string,string>::const_iterator b = m_attribs.begin();
|
||||
for (; b != m_attribs.end(); ++b) {
|
||||
node_dest->addAttribute(b->first, b->second);
|
||||
}
|
||||
vector<XML_Node*> &vsc = node_dest->children();
|
||||
for (int n = 0; n < m_nchildren; n++) {
|
||||
sc = m_children[n];
|
||||
ndc = node_dest->nChildren();
|
||||
(void) node_dest->addChild(sc->name());
|
||||
dc = vsc[ndc];
|
||||
sc->copy(dc);
|
||||
}
|
||||
}
|
||||
|
||||
void XML_Node::getChildren(string nm,
|
||||
vector<XML_Node*>& children) const {
|
||||
@ -403,6 +546,15 @@ namespace Cantera {
|
||||
int iloc;
|
||||
string cname;
|
||||
map<string,XML_Node*>::const_iterator i;
|
||||
#ifdef DEBUG_HKM
|
||||
if (loc == "elementArray") {
|
||||
i = m_childindex.begin();
|
||||
for ( ; i != m_childindex.end(); i++) {
|
||||
XML_Node*ccc = i->second;
|
||||
cout << i->first << " " << ccc->name() << endl;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
while (1) {
|
||||
iloc = loc.find('/');
|
||||
if (iloc >= 0) {
|
||||
@ -423,12 +575,17 @@ namespace Cantera {
|
||||
}
|
||||
}
|
||||
|
||||
void XML_Node::write(ostream& s, int level) {
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
void XML_Node::write_int(ostream& s, int level) {
|
||||
|
||||
if (m_name == "") return;
|
||||
|
||||
m_level = level;
|
||||
string indent(level,' ');
|
||||
string indent(level, ' ');
|
||||
if (m_iscomment) {
|
||||
s << endl << indent << "<!-- " << m_value << " -->";
|
||||
return;
|
||||
@ -447,11 +604,11 @@ namespace Cantera {
|
||||
|
||||
if (m_value != "") {
|
||||
string vv = m_value;
|
||||
int ieol = vv.find('\n');
|
||||
if (ieol >= 0) {
|
||||
string::size_type ieol = vv.find('\n');
|
||||
if (ieol != string::npos) {
|
||||
while (1 > 0) {
|
||||
ieol = vv.find('\n');
|
||||
if (ieol >= 0) {
|
||||
if (ieol != string::npos) {
|
||||
s << endl << indent << vv.substr(0,ieol);
|
||||
vv = vv.substr(ieol+1,vv.size());
|
||||
}
|
||||
@ -461,28 +618,57 @@ namespace Cantera {
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
s << m_value;
|
||||
else {
|
||||
s << m_value;
|
||||
}
|
||||
}
|
||||
int i;
|
||||
for (i = 0; i < m_nchildren; i++) {
|
||||
s << endl;
|
||||
m_children[i]->write(s,level + 2);
|
||||
m_children[i]->write_int(s,level + 2);
|
||||
}
|
||||
if (m_nchildren > 0) s << endl << indent;
|
||||
s << "</" << m_name << ">";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 beeing written.
|
||||
*/
|
||||
void XML_Node::write(ostream& s, int level) {
|
||||
write_int(s, level);
|
||||
s << endl;
|
||||
}
|
||||
|
||||
XML_Node* XML_Node::getRef() {
|
||||
if (!hasAttrib("idRef")) return this;
|
||||
XML_Node& node = *this;
|
||||
return find_XML(node["src"], &root(), node["idRef"]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find a particular XML element by a fairly complicated hierarchal
|
||||
* search objective.
|
||||
*
|
||||
* HKM -Note: Right now this routine contains a memory leak.
|
||||
* A "new" operation is conditionally carried out and
|
||||
* the pointer may or may not be returned to the calling
|
||||
* program. Therefore, it can't be deleted in the
|
||||
* calling program. This
|
||||
* eventually needs to be fixed by extracting the xml
|
||||
* malloc and build operation from the search operation.
|
||||
*/
|
||||
XML_Node* find_XML(string src, XML_Node* root, string id, string loc,
|
||||
string name) {
|
||||
|
||||
#ifdef DEBUG_HKM
|
||||
cout << "find_XML src = " << src << endl;
|
||||
cout << "find_XML id = " << id << endl;
|
||||
cout << "find_XML loc = " << loc << endl;
|
||||
cout << "find_XML name = " << name << endl;
|
||||
#endif
|
||||
string file, id2;
|
||||
split(src, file, id2);
|
||||
src = file;
|
||||
@ -538,6 +724,38 @@ namespace Cantera {
|
||||
}
|
||||
}
|
||||
|
||||
XML_Node* findXMLPhase(XML_Node *root, string idtarget) {
|
||||
XML_Node *scResult = 0;
|
||||
XML_Node *sc;
|
||||
if (!root) return 0;
|
||||
string idattrib;
|
||||
string rname = root->name();
|
||||
if (rname == "phase") {
|
||||
if (idtarget == "") return root;
|
||||
idattrib = root->id();
|
||||
if (idtarget == idattrib) return root;
|
||||
else return 0;
|
||||
}
|
||||
|
||||
vector<XML_Node*> &vsc = root->children();
|
||||
for (int n = 0; n < root->nChildren(); n++) {
|
||||
sc = vsc[n];
|
||||
if (sc->name() == "phase") {
|
||||
if (idtarget == "") return sc;
|
||||
idattrib = sc->id();
|
||||
if (idtarget == idattrib) return sc;
|
||||
}
|
||||
}
|
||||
for (int n = 0; n < root->nChildren(); n++) {
|
||||
sc = vsc[n];
|
||||
if (sc->name() != "phase") {
|
||||
scResult = findXMLPhase(sc, idtarget);
|
||||
if (scResult) return scResult;
|
||||
}
|
||||
}
|
||||
return scResult;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -37,6 +37,9 @@ namespace Cantera {
|
||||
void getchr(char& ch);
|
||||
string strip(const string& aline);
|
||||
string inquotes(const string& aline);
|
||||
|
||||
int findQuotedString(const string& aline, string &rstring);
|
||||
|
||||
void parseTag(string line, string& name, map<string, string>& attribs);
|
||||
string readTag(map<string, string>& attribs);
|
||||
string readValue();
|
||||
@ -71,15 +74,27 @@ namespace Cantera {
|
||||
}
|
||||
string operator()() const { return m_value; }
|
||||
string operator()(string loc) const { return value(loc); }
|
||||
|
||||
/**
|
||||
* 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 string if there isn't
|
||||
* an attribute with that name.
|
||||
*/
|
||||
string operator[](string attr) const {
|
||||
return attrib(attr);
|
||||
//if (hasAttrib(attr)) {return m_attribs[attr]; }
|
||||
}
|
||||
|
||||
string attrib(string attr) const {
|
||||
map<string,string>::const_iterator i = m_attribs.find(attr);
|
||||
if (i != m_attribs.end()) return i->second;
|
||||
else return "";
|
||||
}
|
||||
|
||||
map<string,string>& attribs() { return m_attribs; }
|
||||
XML_Node* parent() { return m_parent; }
|
||||
XML_Node* setParent(XML_Node* p) { m_parent = p; return p; }
|
||||
@ -97,6 +112,7 @@ namespace Cantera {
|
||||
//}
|
||||
}
|
||||
|
||||
|
||||
string name() { return m_name; }
|
||||
string id() {
|
||||
if (hasAttrib("id")) return attrib("id");
|
||||
@ -105,7 +121,7 @@ namespace Cantera {
|
||||
int number() { return m_n; }
|
||||
|
||||
XML_Node& child(int n) const { return *m_children[n]; }
|
||||
vector<XML_Node*> children() { return m_children; }
|
||||
vector<XML_Node*> &children() { return m_children; }
|
||||
int nChildren() const { return m_nchildren; }
|
||||
|
||||
void build(istream& f);
|
||||
@ -119,10 +135,14 @@ namespace Cantera {
|
||||
XML_Node* getRef();
|
||||
XML_Node& root() { return *m_root; }
|
||||
void setRoot(XML_Node& root) { m_root = &root; }
|
||||
void copyUnion(XML_Node *node_dest);
|
||||
void copy(XML_Node *node_dest);
|
||||
|
||||
private:
|
||||
void write_int(ostream& s, int level = 0);
|
||||
|
||||
protected:
|
||||
|
||||
vector<string> m_tags;
|
||||
string m_name;
|
||||
string m_value;
|
||||
int m_level;
|
||||
@ -228,11 +248,11 @@ namespace Cantera {
|
||||
}
|
||||
};
|
||||
|
||||
//inline XML_getByID(string file, string id) {
|
||||
|
||||
|
||||
XML_Node* find_XML(string src, XML_Node* root=0,
|
||||
string id="", string loc="", string name="");
|
||||
|
||||
string id="", string loc="", string name="");
|
||||
|
||||
XML_Node* findXMLPhase(XML_Node* root, string id);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user