XMLEntity.cc

Go to the documentation of this file.
00001 /*
00002  *  Copyright (C) 2000-2002  The Exult Team
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017  */
00018 
00019 #ifdef HAVE_CONFIG_H
00020 #  include <config.h>
00021 #endif
00022 
00023 #ifndef ALPHA_LINUX_CXX
00024 #  include <cassert>
00025 #endif
00026 #include "common_types.h"
00027 #include "XMLEntity.h"
00028 #include <iostream>
00029 
00030 using std::string;
00031 using std::vector;
00032 using std::ostream;
00033 using std::endl;
00034 
00035 static  string  encode_entity(const string &s);
00036 static  string  close_tag(const string &s);
00037 
00038 XMLnode::~XMLnode()
00039 {
00040   for(std::vector<XMLnode *>::iterator i=nodelist.begin(); i!=nodelist.end(); ++i)
00041     delete *i;
00042 }
00043 
00044 const string  &XMLnode::reference(const string &h,bool &exists)
00045 {
00046   if(h.find('/')==string::npos)
00047   {
00048     // Must refer to me.
00049     if(id==h)
00050     {
00051       exists = true;
00052       return content;
00053     }
00054   }
00055   else
00056   {
00057     // Otherwise we want to split the string at the first /
00058     // then locate the branch to walk, and pass the rest
00059     // down.
00060 
00061     string k;
00062     k=h.substr(h.find('/')+1);
00063     string k2=k.substr(0,k.find('/'));
00064     for(std::vector<XMLnode*>::iterator it=nodelist.begin();
00065       it!=nodelist.end();++it)
00066     {
00067       if((*it)->id==k2)
00068         return (*it)->reference(k,exists);
00069     }
00070   }
00071   
00072   exists = false;
00073   return c_empty_string;
00074 }
00075 
00076 
00077 const XMLnode *XMLnode::subtree(const string &h) const
00078 {
00079   if(h.find('/') == string::npos)
00080   {
00081     // Must refer to me.
00082     if(id == h)
00083       return this;
00084   }
00085   else
00086   {
00087     // Otherwise we want to split the string at the first /
00088     // then locate the branch to walk, and pass the rest
00089     // down.
00090 
00091     string k;
00092     k=h.substr(h.find('/')+1);
00093     string k2=k.substr(0,k.find('/'));
00094     for(std::vector<XMLnode*>::const_iterator it=nodelist.begin();
00095       it!=nodelist.end();++it)
00096     {
00097       if((*it)->id==k2)
00098         return (*it)->subtree(k);
00099     }
00100   }
00101 
00102   return 0;
00103 }
00104 
00105 
00106 string  XMLnode::dump(int depth)
00107 {
00108   string s(depth,' ');
00109 
00110   s+="<";
00111   s+=id;
00112   s+=">\n";
00113   if(id[id.length()-1]!='/')
00114   {
00115     for(std::vector<XMLnode*>::const_iterator it=nodelist.begin();
00116       it!=nodelist.end();
00117       ++it)
00118     {
00119       s += (**it).dump(depth+1);
00120     }
00121 
00122     if(content.length())
00123     {
00124       s += string(depth,' ');
00125       s += encode_entity(content);
00126     }
00127     if(id[0]=='?')
00128     {
00129       return s;
00130     }
00131     if(content.length())
00132       s += "\n";
00133 
00134     if(!no_close)
00135     {
00136     s += string(depth,' ');
00137     
00138       s += "</";
00139       s += close_tag(id);
00140       s += ">\n";
00141     }
00142   }
00143   
00144   return s;
00145 }
00146 
00147 /* Output's a 'nicer' dump of the xmltree, one <tag> value </tag> per line
00148   the indent characters are specified by indentstr */
00149 void XMLnode::dump(ostream &o, const string &indentstr, const unsigned int depth) const
00150 {
00151   // indent
00152   for(unsigned int i=0; i<depth; i++)
00153     o << indentstr;
00154   
00155   // open tag
00156   o << '<' << id << '>';
00157   
00158   // if this tag has a closing tag...
00159   if(id[id.length()-1]!='/')
00160   {
00161     // if we've got some subnodes, terminate this line...
00162     if(nodelist.size())
00163     {
00164       o << endl;
00165     
00166       // ... then walk through them outputting them all ...
00167       for(std::vector<XMLnode *>::const_iterator it=nodelist.begin(); it!=nodelist.end(); ++it)
00168         (*it)->dump(o, indentstr, depth+1);
00169     }
00170     // ... else, if we have content in this output it.
00171     else if(content.length())
00172       o << ' ' << encode_entity(content) << ' ';
00173     
00174     // not a clue... it's in XMLnode::dump() so there must be a reason...
00175     if(id[0]=='?')
00176       return;
00177     
00178     // append a closing tag if there is one.
00179     if(!no_close)
00180     {
00181       // if we've got subnodes, we need to reindent
00182       if(nodelist.size())
00183       for(unsigned int i=0; i<depth; i++)
00184         o << indentstr;
00185       
00186       o << "</" << close_tag(id) << '>';
00187     }
00188   }
00189   o << endl;
00190 }
00191 
00192 // This function does not make sense here. It should be in XMLEntity
00193 void  XMLnode::xmlassign(const string &key, const string &value)
00194 {
00195   if(key.find('/')==string::npos)
00196   {
00197     // Must refer to me.
00198     if(id==key)
00199       content = value;
00200     else
00201       CERR("Walking the XML tree failed to create a final node.");
00202     return;
00203   }
00204   string k;
00205   k=key.substr(key.find('/')+1);
00206   string k2=k.substr(0,k.find('/'));
00207   for(std::vector<XMLnode*>::iterator it=nodelist.begin();it!=nodelist.end();++it)
00208   {
00209     if((*it)->id==k2)
00210     {
00211       (**it).xmlassign(k,value);
00212       return;
00213     }
00214   }
00215   
00216   // No match, so create a new node and do recursion
00217   XMLnode *t = new XMLnode(k2);
00218   nodelist.push_back(t);
00219   (*t).xmlassign(k,value);
00220 }
00221 
00222 
00223 void  XMLnode::listkeys(const string &key,vector<string> &vs, bool longformat) const
00224 {
00225   string s(key);
00226   s+="/";
00227 
00228   for(std::vector<XMLnode*>::const_iterator it=nodelist.begin();
00229     it!=nodelist.end(); ++it)
00230   {
00231     if(!longformat)
00232       vs.push_back((*it)->id);
00233     else
00234       vs.push_back(s + (*it)->id);
00235   }
00236 }
00237 
00238 static  string  encode_entity(const string &s)
00239 {
00240   string  ret;
00241 
00242   for(string::const_iterator it=s.begin();it!=s.end();++it)
00243   {
00244     switch(*it)
00245     {
00246       case '<':
00247         ret+="&lt;";
00248         break;
00249       case '>':
00250         ret+="&gt;";
00251         break;
00252       case '"':
00253         ret+="&quot;";
00254         break;
00255       case '\'':
00256         ret+="&apos;";
00257         break;
00258       case '&':
00259         ret+="&amp;";
00260         break;
00261       default:
00262         ret += *it;
00263     }
00264   }
00265   return ret;
00266 }
00267 
00268 static  string  decode_entity(const string &s, std::size_t &pos)
00269 {
00270   std::size_t     old_pos = pos;
00271   string::size_type entity_name_len = s.find_first_of("; \t\r\n", pos) -pos -1;
00272   
00273   /* Call me paranoid... but I don't think having an end-of-line or similar
00274     inside a &...; expression is 'good', valid though it may be. */
00275   assert(s[pos+entity_name_len+1]==';');
00276   
00277   string        entity_name = s.substr(pos+1, entity_name_len);
00278   
00279   pos += entity_name_len + 2;
00280   
00281   // std::cout << "DECODE: " << entity_name << endl;
00282   
00283   if     (entity_name == "amp")  return string("&");
00284   else if(entity_name == "apos") return string("'");
00285   else if(entity_name == "quot") return string("\"");
00286   else if(entity_name == "lt")   return string("<");
00287   else if(entity_name == "gt")   return string(">");
00288   
00289   return s.substr(old_pos, entity_name_len+2);
00290 }
00291 
00292 static  string  close_tag(const string &s)
00293 {
00294   if(s.find(" ")==string::npos)
00295     return s;
00296   
00297   return s.substr(0,s.find(" "));
00298 }
00299 
00300 
00301 static  void  trim(string &s)
00302 {
00303   // Clean off leading whitespace
00304   while(s.length()&&s[0]<=32)
00305   {
00306     s=s.substr(1);
00307   }
00308   // Clean off trailing whitespace
00309   while(s.length()&&s[s.length()-1]<=32)
00310   {
00311     s.erase(s.length()-1);
00312   }
00313 }
00314 
00315 void  XMLnode::xmlparse(const string &s,std::size_t &pos)
00316 {
00317   bool  intag = true;
00318 
00319   id = "";
00320   while(pos<s.length())
00321   {
00322     switch(s[pos])
00323     {
00324       case '<':
00325       {
00326         // New tag?
00327         if(s[pos+1]=='/')
00328         {
00329           // No. Close tag.
00330           while(s[pos]!='>')
00331             pos++;
00332           ++pos;
00333           trim(content);
00334           return;
00335         }
00336         XMLnode *t = new XMLnode;
00337         ++pos;
00338         t->xmlparse(s,pos);
00339         nodelist.push_back(t);
00340         break;
00341       }
00342       case '>':
00343         // End of tag
00344         if(s[pos-1]=='/')
00345         {
00346           if(s[pos-2]=='<')
00347           {
00348             ++pos;
00349             return; // An empty tag
00350           }
00351           else
00352           {
00353             ++pos;
00354             no_close=true;
00355             return;
00356           }
00357         }
00358         else if((id[0]=='!') && (id[1]=='-') && (id[2]=='-'))
00359         {
00360           ++pos;
00361           no_close=true;
00362           return;
00363         }
00364         ++pos;
00365         intag = false;
00366         if(s[pos]<32)
00367           ++pos;
00368         break;
00369       case '&':
00370         content+=decode_entity(s,pos);
00371         break;
00372       default:
00373         if(intag)
00374           id += s[pos++];
00375         else
00376           content += s[pos++];
00377     }
00378   }
00379   trim(content);
00380 }
00381 
00382 /* Returns a list of key->value pairs that are found under the provided 'basekey'.
00383   Ignores comments (<!-- ... --> and doesn't return them.
00384   Returns true if search is 'finished' */
00385 bool XMLnode::searchpairs(KeyTypeList &ktl, const string &basekey, const string currkey, const unsigned int pos)
00386 {
00387   /* If our 'current key' is longer then the key we're serching for
00388     we've obviously gone too deep in this branch, and we won't find
00389     it here. */
00390   if((currkey.size()<=basekey.size()) && (id[0]!='!'))
00391   {
00392     /* If we've found it, return every key->value pair under this key,
00393       then return true, since we've found the key we were looking for. */
00394     if(basekey==currkey+id)
00395     {
00396       for(std::vector<XMLnode *>::iterator i=nodelist.begin(); i!=nodelist.end(); ++i)
00397         if((*i)->id[0]!='!')
00398           (*i)->selectpairs(ktl, "");
00399       return true;
00400     }
00401     /* Else, keep searching for the key under it's subnodes */
00402     else
00403       for(std::vector<XMLnode *>::iterator i=nodelist.begin(); i!=nodelist.end(); ++i)
00404         if((*i)->searchpairs(ktl, basekey, currkey + id + '/', pos)==true)
00405           return true;
00406   }
00407   return false;
00408 }
00409 
00410 /* Just adds every key->value pair under the this node to the ktl */
00411 void XMLnode::selectpairs(KeyTypeList &ktl, const std::string currkey)
00412 {
00413   ktl.push_back(KeyType(currkey + id, content));
00414   
00415   for(std::vector<XMLnode *>::iterator i=nodelist.begin(); i!=nodelist.end(); ++i)
00416     (*i)->selectpairs(ktl, currkey + id + '/');
00417 }
00418 
00419 
00420 
00421 
00422 

Generated on Mon Jul 9 14:42:44 2007 for ExultEngine by  doxygen 1.5.1