Main Page   Namespace List   Class Hierarchy   Compound List   File List   Compound Members  

XPath.cpp

00001 #include "XPath.h"
00002 #include "XPathOps.h"
00003 
00004 using namespace std;
00005 using namespace judo;
00006 using namespace judo::XPath;
00007 
00008 char Query::getNextToken(string::size_type& cur)
00009 {
00010     if (cur == std::string::npos)
00011         return 0;
00012 
00013     std::list<char>::iterator it = find (_tokens.begin(), _tokens.end(),
00014             _query[cur]);;
00015 
00016     while (it == _tokens.end())
00017     {
00018         cur++;
00019         if (cur > _query.length())
00020         {
00021             cur = _query.length();
00022             return 0;
00023         }
00024         it = find(_tokens.begin(), _tokens.end(), _query[cur]);
00025     }
00026     return *it;
00027 }
00028 
00029 std::string Query::getNextIdentifier(string::size_type& pos)
00030 {
00031     string::size_type sp = pos;
00032     getNextToken(pos);
00033     return _query.substr(sp, pos - sp);
00034 }
00035 
00036 Op* Query::getOp(std::string::size_type& pos, char in_context)
00037 {
00038     Op* ret_op = NULL;
00039 
00040     do
00041     {
00042         Op* tmp_op = NULL;
00043         string::size_type pos_start = pos;
00044         char token = getNextToken(pos);
00045         // If we are in a context and get a token barf
00046         if (token == 0 && in_context)
00047             throw Invalid();
00048         string::size_type token_start = ++pos;
00049         string ident;
00050 
00051         if (pos_start != (token_start - 1))
00052         {
00053             pos = pos_start;
00054             ret_op = new NodeOp(getNextIdentifier(pos), false);
00055         }
00056         else
00057         {
00058         
00059             // Get rid of the whitespace
00060             switch(token)
00061             {
00062                 case '/':
00063                     if (_query[token_start] == '/')
00064                     {
00065                         pos++;
00066                         string temp_ident = getNextIdentifier(pos);
00067                         if (!temp_ident.empty())
00068                         {
00069                             ret_op = new AllOp(temp_ident);
00070                         }
00071                     }
00072                     else
00073                     {
00074                         string temp_ident = getNextIdentifier(pos);
00075                         if (!temp_ident.empty())
00076                         {
00077                             ret_op = new NodeOp(temp_ident,
00078                                     (pos_start == 0 ? true : false));
00079                         }
00080                     }
00081                     break;
00082                 case '@':
00083                     ret_op = new AttributeOp(getNextIdentifier(pos));
00084                     break;
00085                 case ']':
00086                     if (in_context == '[')
00087                     {
00088                         ret_op = _ops.back();
00089                         _ops.pop_back();
00090                         in_context = 0;
00091                     }
00092                     else
00093                     {
00094                         std::cerr << "Found ']' but not in context" << std::endl;
00095                         throw Invalid();
00096                     }
00097                     break;
00098                 case '\'':
00099                 case '\"':
00100                     pos = _query.find(token, token_start);
00101                     ret_op = new Op(Op::OP_LITERAL, _query.substr(token_start, pos - 
00102                                 token_start));
00103                     pos++;
00104                     break;
00105                 case ' ':
00106                     //ident = _query.substr(pos_start, pos - pos_start - 1);
00107                     ident = getNextIdentifier(pos);
00108                     if (ident == "and")
00109                     {
00110                         pos++;
00111                         tmp_op = getOp(pos, in_context);
00112                         if (!tmp_op)
00113                         {
00114                             std::cerr << "Invalid and operation" << std::endl;
00115                             throw Invalid();
00116                         }
00117                         ret_op = new AndOp(_ops.back(), tmp_op);
00118                         in_context = 0;
00119                         _ops.pop_back();
00120                     }
00121                     else if(ident == "or")
00122                     {
00123                         pos++;
00124                         tmp_op = getOp(pos, in_context);
00125                         ret_op = new OrOp(_ops.back(), tmp_op);
00126                         in_context = 0;
00127                         _ops.pop_back();
00128                     }
00129                     break;
00130                 case '[':
00131                     // See if we have a position op
00132                     if (getNextToken(pos) == ']')
00133                     {
00134                         if (pos == token_start)
00135                         {
00136                             std::cerr << "Nothing in the []" << std::endl;
00137                             throw Invalid();
00138                         }
00139                         
00140                         pos = token_start;
00141 
00142                         std::string temp_ident = getNextIdentifier(pos);
00143                         int val = atoi(temp_ident.c_str());
00144                         // small hack here... if you get something back
00145                         // assume it was a number
00146                         if (val > 0)
00147                         {
00148                             ret_op = new PositionOp(val);
00149                             pos++;
00150                         }
00151                         // otherwise assume it was a node op, and start a new
00152                         // context ("0" is not a number in this model)
00153                         else
00154                         {
00155                             pos = pos_start + 1;
00156                             ret_op = new ContextOp(getOp(pos, token));
00157                         }
00158                     }
00159                     else
00160                     {
00161                         pos = pos_start + 1;
00162                         ret_op = new ContextOp(getOp(pos, token));
00163                     }
00164                     break;
00165                 case '(':
00166                     //--------------------------------------------------------
00167                     // The function name would have been mistaken for a NodeOp.
00168                     // Pop it off the back and get the function name.
00169                     //--------------------------------------------------------
00170                     tmp_op = _ops.back();
00171                     _ops.pop_back();
00172                     ident = tmp_op->getValue();
00173                     delete tmp_op;
00174                     
00175                     if (!ident.empty())
00176                     {
00177                         int op_pos = _ops.size();
00178                         ret_op = new FunctionOp(ident);
00179 
00180                         getOp(pos, token);
00181 
00182                         OpList::iterator it = _ops.begin() + op_pos;
00183                         while( it != _ops.end())
00184                         {
00185                             static_cast<FunctionOp*>(ret_op)->addArg(*it);
00186                             it = _ops.erase(it);
00187                         }
00188                     }
00189                     else
00190                     {
00191                         std::cerr << "No function name specified!\n" <<
00192                             std::endl;
00193                         throw Invalid();
00194                     }
00195                     break;
00196                 case ')':
00197                     if (in_context == '(')
00198                     {
00199                         ret_op = NULL;
00200                         in_context = 0;
00201                     }
00202                     else
00203                     {
00204                         std::cerr << "Found ')' but not in context" << std::endl;
00205                         throw Invalid();
00206                     }
00207                     break;
00208                 case ',':
00209                     if (in_context != '(')
00210                     {
00211                         std::cerr << "Found ',' but not in a function" << std::endl;
00212                         throw Invalid();
00213                     }
00214                     break;
00215                 case '=':
00216                     while (!tmp_op)
00217                         tmp_op = getOp(pos);
00218                     
00219                     ret_op = new EqualOp(_ops.back(), tmp_op);
00220                     _ops.pop_back();
00221                     break;
00222                 case '!':
00223                     if (_query[token_start] != '=')
00224                     {
00225                         std::cerr << "Badly formed !=" << std::endl;
00226                         throw Invalid();
00227                     }
00228                     pos++;
00229                     while (!tmp_op)
00230                         tmp_op = getOp(pos);
00231                     
00232                     ret_op = new NotEqualOp(_ops.back(), tmp_op);
00233                     _ops.pop_back();
00234                     break;
00235                 default:
00236                     std::cerr << "Unhandled \"" << token << "\"" << std::endl;
00237                     ret_op = NULL;
00238                     break;
00239             };
00240         }
00241 
00242         if (in_context)
00243         {
00244             if (ret_op)
00245             {
00246                 _ops.push_back(ret_op);
00247             }
00248             ret_op = NULL;
00249         }
00250 
00251     } while (in_context);
00252 
00253     return ret_op;
00254 }
00255 
00256 bool Query::parseQuery()
00257 {
00258     Op* op = NULL;
00259     string::size_type pos = 0;
00260 
00261     while (pos < _query.length())
00262     {
00263         op = getOp(pos);
00264         if (op)
00265         {
00266             _ops.push_back(op);
00267         }
00268     }
00269 
00270     return true;
00271 }
00272     
00273 bool Query::check(const judo::Element& root)
00274 {
00275     judo::Element check_elem(root);
00276     Value* ctxt = execute(&check_elem);
00277     bool matched = ctxt->check();
00278     delete ctxt;
00279     return matched;
00280 }
00281 
00282 Value* Query::execute(judo::Element* root)
00283 {
00284     OpList::iterator it = _ops.begin();
00285 
00286     Value* ctxt = new Value(root);
00287     
00288     for (;it != _ops.end(); it++)
00289     {
00290         //(*it)->display();
00291         if (!(*it)->isValid(ctxt))
00292         {
00293             //(*it)->display();
00294             ctxt->setMatch(false);
00295             return ctxt;
00296         }
00297     }
00298 
00299     /* XXX DEBUG 
00300     Value::ElemList elems = ctxt.getList();
00301     for(Value::ElemList::iterator it = elems.begin(); it != elems.end(); 
00302             it++)
00303     {
00304         std::cout << "Ctxt Entry: " << (*it)->toString() << std::endl;
00305     }
00306     */
00307     ctxt->setMatch(true);
00308     return ctxt;
00309 }

Generated on Thu Jul 24 13:31:51 2003 for jabberoo by doxygen1.3-rc3