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
2 changed files with 268 additions and 30 deletions
|
|
@ -62,8 +62,10 @@ namespace Cantera {
|
||||||
class XML_NoChild : public XML_Error {
|
class XML_NoChild : public XML_Error {
|
||||||
public:
|
public:
|
||||||
XML_NoChild(string parent, string child) {
|
XML_NoChild(string parent, string child) {
|
||||||
m_msg += "Node " + parent + " has no child named "
|
m_msg += " The XML Node, \"" + parent +
|
||||||
+ child + ".\n";
|
"\", does not contain a required\n" +
|
||||||
|
" XML child node named \""
|
||||||
|
+ child + "\".\n";
|
||||||
setError("XML_NoChild",m_msg);
|
setError("XML_NoChild",m_msg);
|
||||||
}
|
}
|
||||||
virtual ~XML_NoChild() {}
|
virtual ~XML_NoChild() {}
|
||||||
|
|
@ -110,13 +112,84 @@ namespace Cantera {
|
||||||
if (j == i) return "";
|
if (j == i) return "";
|
||||||
else return aline.substr(j+1, i - j - 1);
|
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) {
|
map<string, string>& attribs) {
|
||||||
int iloc;
|
string::size_type iloc;
|
||||||
string attr, val;
|
string attr, val;
|
||||||
string s = strip(line);
|
string s = strip(tag);
|
||||||
iloc = s.find(' ');
|
iloc = s.find(' ');
|
||||||
if (iloc > 0) {
|
if (iloc > 0) {
|
||||||
name = s.substr(0, iloc);
|
name = s.substr(0, iloc);
|
||||||
|
|
@ -125,18 +198,20 @@ namespace Cantera {
|
||||||
// get attributes
|
// get attributes
|
||||||
while (1) {
|
while (1) {
|
||||||
iloc = s.find('=');
|
iloc = s.find('=');
|
||||||
if (iloc < 0) break;
|
if (iloc == string::npos) break;
|
||||||
attr = strip(s.substr(0,iloc));
|
attr = strip(s.substr(0,iloc));
|
||||||
if (attr == "") break;
|
if (attr == "") break;
|
||||||
s = strip(s.substr(iloc+1,s.size()));
|
s = strip(s.substr(iloc+1,s.size()));
|
||||||
iloc = s.find(' ');
|
//iloc = s.find(' ');
|
||||||
if (iloc < 0) iloc = s.size();
|
//if (iloc < 0) iloc = s.size();
|
||||||
val = inquotes(s.substr(0,iloc));
|
iloc = findQuotedString(s, val);
|
||||||
attribs[attr] = val;
|
attribs[attr] = val;
|
||||||
if (iloc < int(s.size()))
|
if (iloc != string::npos) {
|
||||||
s = strip(s.substr(iloc+1,s.size()));
|
if (iloc < s.size())
|
||||||
else
|
s = strip(s.substr(iloc,s.size()));
|
||||||
break;
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -177,6 +252,12 @@ namespace Cantera {
|
||||||
return tag;
|
return tag;
|
||||||
}
|
}
|
||||||
else {
|
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);
|
parseTag(tag, name, attribs);
|
||||||
return name;
|
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,
|
void XML_Node::getChildren(string nm,
|
||||||
vector<XML_Node*>& children) const {
|
vector<XML_Node*>& children) const {
|
||||||
|
|
@ -403,6 +546,15 @@ namespace Cantera {
|
||||||
int iloc;
|
int iloc;
|
||||||
string cname;
|
string cname;
|
||||||
map<string,XML_Node*>::const_iterator i;
|
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) {
|
while (1) {
|
||||||
iloc = loc.find('/');
|
iloc = loc.find('/');
|
||||||
if (iloc >= 0) {
|
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;
|
if (m_name == "") return;
|
||||||
|
|
||||||
m_level = level;
|
m_level = level;
|
||||||
string indent(level,' ');
|
string indent(level, ' ');
|
||||||
if (m_iscomment) {
|
if (m_iscomment) {
|
||||||
s << endl << indent << "<!-- " << m_value << " -->";
|
s << endl << indent << "<!-- " << m_value << " -->";
|
||||||
return;
|
return;
|
||||||
|
|
@ -447,11 +604,11 @@ namespace Cantera {
|
||||||
|
|
||||||
if (m_value != "") {
|
if (m_value != "") {
|
||||||
string vv = m_value;
|
string vv = m_value;
|
||||||
int ieol = vv.find('\n');
|
string::size_type ieol = vv.find('\n');
|
||||||
if (ieol >= 0) {
|
if (ieol != string::npos) {
|
||||||
while (1 > 0) {
|
while (1 > 0) {
|
||||||
ieol = vv.find('\n');
|
ieol = vv.find('\n');
|
||||||
if (ieol >= 0) {
|
if (ieol != string::npos) {
|
||||||
s << endl << indent << vv.substr(0,ieol);
|
s << endl << indent << vv.substr(0,ieol);
|
||||||
vv = vv.substr(ieol+1,vv.size());
|
vv = vv.substr(ieol+1,vv.size());
|
||||||
}
|
}
|
||||||
|
|
@ -461,28 +618,57 @@ namespace Cantera {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
s << m_value;
|
s << m_value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < m_nchildren; i++) {
|
for (i = 0; i < m_nchildren; i++) {
|
||||||
s << endl;
|
s << endl;
|
||||||
m_children[i]->write(s,level + 2);
|
m_children[i]->write_int(s,level + 2);
|
||||||
}
|
}
|
||||||
if (m_nchildren > 0) s << endl << indent;
|
if (m_nchildren > 0) s << endl << indent;
|
||||||
s << "</" << m_name << ">";
|
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() {
|
XML_Node* XML_Node::getRef() {
|
||||||
if (!hasAttrib("idRef")) return this;
|
if (!hasAttrib("idRef")) return this;
|
||||||
XML_Node& node = *this;
|
XML_Node& node = *this;
|
||||||
return find_XML(node["src"], &root(), node["idRef"]);
|
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,
|
XML_Node* find_XML(string src, XML_Node* root, string id, string loc,
|
||||||
string name) {
|
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;
|
string file, id2;
|
||||||
split(src, file, id2);
|
split(src, file, id2);
|
||||||
src = file;
|
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);
|
void getchr(char& ch);
|
||||||
string strip(const string& aline);
|
string strip(const string& aline);
|
||||||
string inquotes(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);
|
void parseTag(string line, string& name, map<string, string>& attribs);
|
||||||
string readTag(map<string, string>& attribs);
|
string readTag(map<string, string>& attribs);
|
||||||
string readValue();
|
string readValue();
|
||||||
|
|
@ -71,15 +74,27 @@ namespace Cantera {
|
||||||
}
|
}
|
||||||
string operator()() const { return m_value; }
|
string operator()() const { return m_value; }
|
||||||
string operator()(string loc) const { return value(loc); }
|
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 {
|
string operator[](string attr) const {
|
||||||
return attrib(attr);
|
return attrib(attr);
|
||||||
//if (hasAttrib(attr)) {return m_attribs[attr]; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
string attrib(string attr) const {
|
string attrib(string attr) const {
|
||||||
map<string,string>::const_iterator i = m_attribs.find(attr);
|
map<string,string>::const_iterator i = m_attribs.find(attr);
|
||||||
if (i != m_attribs.end()) return i->second;
|
if (i != m_attribs.end()) return i->second;
|
||||||
else return "";
|
else return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
map<string,string>& attribs() { return m_attribs; }
|
map<string,string>& attribs() { return m_attribs; }
|
||||||
XML_Node* parent() { return m_parent; }
|
XML_Node* parent() { return m_parent; }
|
||||||
XML_Node* setParent(XML_Node* p) { m_parent = p; return p; }
|
XML_Node* setParent(XML_Node* p) { m_parent = p; return p; }
|
||||||
|
|
@ -97,6 +112,7 @@ namespace Cantera {
|
||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
string name() { return m_name; }
|
string name() { return m_name; }
|
||||||
string id() {
|
string id() {
|
||||||
if (hasAttrib("id")) return attrib("id");
|
if (hasAttrib("id")) return attrib("id");
|
||||||
|
|
@ -105,7 +121,7 @@ namespace Cantera {
|
||||||
int number() { return m_n; }
|
int number() { return m_n; }
|
||||||
|
|
||||||
XML_Node& child(int n) const { return *m_children[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; }
|
int nChildren() const { return m_nchildren; }
|
||||||
|
|
||||||
void build(istream& f);
|
void build(istream& f);
|
||||||
|
|
@ -119,10 +135,14 @@ namespace Cantera {
|
||||||
XML_Node* getRef();
|
XML_Node* getRef();
|
||||||
XML_Node& root() { return *m_root; }
|
XML_Node& root() { return *m_root; }
|
||||||
void setRoot(XML_Node& root) { m_root = &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:
|
protected:
|
||||||
|
|
||||||
vector<string> m_tags;
|
|
||||||
string m_name;
|
string m_name;
|
||||||
string m_value;
|
string m_value;
|
||||||
int m_level;
|
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,
|
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
|
#endif
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue