Save This Page
Home » xmlbeans-2.4.0-src » org.apache.xmlbeans.impl.common » [javadoc | source]
    1   /*   Copyright 2004 The Apache Software Foundation
    2    *
    3    *   Licensed under the Apache License, Version 2.0 (the "License");
    4    *   you may not use this file except in compliance with the License.
    5    *   You may obtain a copy of the License at
    6    *
    7    *       http://www.apache.org/licenses/LICENSE-2.0
    8    *
    9    *   Unless required by applicable law or agreed to in writing, software
   10    *   distributed under the License is distributed on an "AS IS" BASIS,
   11    *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   12    *   See the License for the specific language governing permissions and
   13    *  limitations under the License.
   14    */
   15   
   16   package org.apache.xmlbeans.impl.common;
   17   
   18   import javax.xml.namespace.QName;
   19   
   20   import java.util.ArrayList;
   21   import java.util.List;
   22   import java.util.Map;
   23   import java.util.HashMap;
   24   import org.apache.xmlbeans.XmlError;
   25   import org.apache.xmlbeans.XmlException;
   26   import org.apache.xmlbeans.impl.common.XMLChar;
   27   
   28   
   29   public class XPath
   30   {
   31       public static class XPathCompileException extends XmlException
   32       {
   33           XPathCompileException ( XmlError err )
   34           {
   35               super( err.toString(), null, err );
   36           }
   37       }
   38   
   39       //
   40       //
   41       //
   42   
   43       public static class ExecutionContext
   44       {
   45           public ExecutionContext ( )
   46           {
   47               _stack = new ArrayList();
   48           }
   49   
   50           public static final int HIT     = 0x1;
   51           public static final int DESCEND = 0x2;
   52           public static final int ATTRS   = 0x4;
   53           
   54           public final void init ( XPath xpath )
   55           {
   56               if (_xpath != xpath)
   57               {
   58                   _xpath = xpath;
   59                   
   60                   _paths = new PathContext [ xpath._selector._paths.length ];
   61                   
   62                   for ( int i = 0 ; i < _paths.length ; i++ )
   63                       _paths[ i ] = new PathContext();
   64               }
   65   
   66               _stack.clear();
   67   
   68               for ( int i = 0 ; i < _paths.length ; i++ )
   69                   _paths[ i ].init( xpath._selector._paths[ i ] );
   70           }
   71   
   72           public final int start ( )
   73           {
   74               int result = 0;
   75               
   76               for ( int i = 0 ; i < _paths.length ; i++ )
   77                   result |= _paths[ i ].start();
   78   
   79               return result;
   80           }
   81           
   82           public final int element ( QName name )
   83           {
   84               assert name != null;
   85               
   86               _stack.add( name );
   87               
   88               int result = 0;
   89               
   90               for ( int i = 0 ; i < _paths.length ; i++ )
   91                   result |= _paths[ i ].element( name );
   92   
   93               return result;
   94           }
   95           
   96           public final boolean attr ( QName name )
   97           {
   98               boolean hit = false;
   99               
  100               for ( int i = 0 ; i < _paths.length ; i++ )
  101                   hit = hit | _paths[ i ].attr( name );
  102   
  103               return hit;
  104           }
  105   
  106           public final void end ( )
  107           {
  108               _stack.remove( _stack.size() - 1 );
  109               
  110               for ( int i = 0 ; i < _paths.length ; i++ )
  111                   _paths[ i ].end();
  112           }
  113           
  114           private final class PathContext
  115           {
  116               PathContext ( )
  117               {
  118                   _prev = new ArrayList();
  119               }
  120               
  121               void init ( Step steps )
  122               {
  123                   _curr = steps;
  124                   _prev.clear();
  125               }
  126   
  127               private QName top ( int i )
  128               {
  129                   return (QName) ExecutionContext.this._stack.get( _stack.size() - 1 - i );
  130               }
  131   
  132               // goes back to the begining of the sequence since last // wildcard
  133               private void backtrack ( )
  134               {
  135                   assert _curr != null;
  136                   
  137                   if (_curr._hasBacktrack)
  138                   {   // _backtrack seems to be a pointer to the step that follows a // wildcard
  139                       // ex: for .//b/c/d steps c and d should backtrack to b in case there isn't a match 
  140                       _curr = _curr._backtrack;
  141                       return;
  142                   }
  143   
  144                   assert !_curr._deep;
  145   
  146                   _curr = _curr._prev;
  147   
  148                   search: for ( ; !_curr._deep ; _curr = _curr._prev )
  149                   {
  150                       int t = 0;
  151                       
  152                       for ( Step s = _curr ; !s._deep ; s = s._prev )
  153                       {
  154                           if (!s.match( top( t++ )))
  155                               continue search;
  156                       }
  157   
  158                       break;
  159                   }
  160               }
  161               
  162               int start ( )
  163               {
  164                   assert _curr != null;
  165                   assert _curr._prev == null;
  166   
  167                   if (_curr._name != null)
  168                       return _curr._flags;
  169   
  170                   // If the steps consist on only a terminator, then the path can
  171                   // only be '.'.  In this case, we get a hit, but there is
  172                   // nothing else to match.  No need to backtrack.
  173   
  174                   _curr = null;
  175   
  176                   return HIT;
  177               }
  178               
  179               int element ( QName name )
  180               {
  181                   //System.out.println("  Path.element: " + name);
  182                   _prev.add( _curr );
  183   
  184                   if (_curr == null)
  185                       return 0;
  186   
  187                   assert _curr._name != null;
  188   
  189                   if (!_curr._attr && _curr.match( name ))
  190                   {
  191                       if ((_curr = _curr._next)._name != null)
  192                           return _curr._flags;
  193                       
  194                       backtrack();
  195                       
  196                       //System.out.println("    element - HIT " + _curr._flags);
  197                       return _curr == null ? HIT : HIT | _curr._flags;
  198                   }
  199   
  200                   for ( ; ; )
  201                   {
  202                       backtrack();
  203   
  204                       if (_curr == null)
  205                           return 0;
  206   
  207                       if (_curr.match( name ))
  208                       {
  209                           _curr = _curr._next;
  210                           break;
  211                       }
  212   
  213                       if (_curr._deep)
  214                           break;
  215                   }
  216                   
  217                   return _curr._flags;
  218               }
  219               
  220               boolean attr ( QName name )
  221               {
  222                   return _curr != null && _curr._attr && _curr.match( name );
  223               }
  224   
  225               void end ( )
  226               {
  227                   //System.out.println("  Path.end ");
  228                   _curr = (Step) _prev.remove( _prev.size() - 1 );
  229               }
  230               
  231               private Step _curr;
  232               private List _prev;
  233           }
  234   
  235           private XPath         _xpath;
  236           private ArrayList     _stack;
  237           private PathContext[] _paths;
  238       }
  239   
  240       //
  241       //
  242       //
  243   
  244       public static XPath compileXPath ( String xpath )
  245           throws XPathCompileException
  246       {
  247           return compileXPath( xpath, "$this", null );
  248       }
  249       
  250       public static XPath compileXPath ( String xpath, String currentNodeVar )
  251           throws XPathCompileException
  252       {
  253           return compileXPath( xpath, currentNodeVar, null );
  254       }
  255   
  256       public static XPath compileXPath ( String xpath, Map namespaces )
  257               throws XPathCompileException
  258       {
  259           return compileXPath( xpath, "$this", namespaces );
  260       }
  261       
  262       public static XPath compileXPath (
  263           String xpath, String currentNodeVar, Map namespaces )
  264               throws XPathCompileException
  265       {
  266           return
  267               new CompilationContext( namespaces, currentNodeVar ).
  268                   compile( xpath );
  269       }
  270   
  271       private static class CompilationContext
  272       {
  273           CompilationContext ( Map namespaces, String currentNodeVar )
  274           {
  275               assert
  276                   _currentNodeVar == null ||
  277                   _currentNodeVar.startsWith( "$" );
  278   
  279               if (currentNodeVar == null)
  280                   _currentNodeVar = "$this";
  281               else
  282                   _currentNodeVar = currentNodeVar;
  283   
  284               _namespaces = new HashMap();
  285               
  286               _externalNamespaces =
  287                   namespaces == null ? new HashMap() : namespaces;
  288           }
  289   
  290           XPath compile ( String expr ) throws XPathCompileException
  291           {
  292               _offset = 0;
  293               _line = 1;
  294               _column = 1;
  295               _expr = expr;
  296   
  297               return tokenizeXPath();
  298           }
  299           
  300           int currChar ( )
  301           {
  302               return currChar( 0 );
  303           }
  304           
  305           int currChar ( int offset )
  306           {
  307               return
  308                   _offset + offset >= _expr.length()
  309                       ? -1
  310                       : _expr.charAt( _offset + offset );
  311           }
  312           
  313           void advance ( )
  314           {
  315               if (_offset < _expr.length())
  316               {
  317                   char ch = _expr.charAt( _offset );
  318                   
  319                   _offset++;
  320                   _column++;
  321   
  322                   if (ch == '\r' || ch == '\n')
  323                   {
  324                       _line++;
  325                       _column = 1;
  326   
  327                       if (_offset + 1 < _expr.length())
  328                       {
  329                           char nextCh = _expr.charAt( _offset + 1 );
  330   
  331                           if ((nextCh == '\r' || nextCh == '\n') && ch != nextCh)
  332                               _offset++;
  333                       }
  334                   }
  335               }
  336           }
  337   
  338           void advance ( int count )
  339           {
  340               assert count >= 0;
  341               
  342               while ( count-- > 0 )
  343                   advance();
  344           }
  345                   
  346           boolean isWhitespace ( )
  347           {
  348               return isWhitespace( 0 );
  349           }
  350           
  351           boolean isWhitespace ( int offset )
  352           {
  353               int ch = currChar( offset );
  354               return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r';
  355           }
  356   
  357           boolean isNCNameStart ( )
  358           {
  359               return
  360                   currChar() == -1
  361                       ? false :
  362                       XMLChar.isNCNameStart( currChar() );
  363           }
  364           
  365           boolean isNCName ( )
  366           {
  367               return
  368                   currChar() == -1
  369                       ? false :
  370                       XMLChar.isNCName( currChar() );
  371           }
  372           
  373           boolean startsWith ( String s )
  374           {
  375               return startsWith( s, 0 );
  376           }
  377           
  378           boolean startsWith ( String s, int offset )
  379           {
  380               if (_offset + offset >= _expr.length())
  381                   return false;
  382               
  383               return _expr.startsWith( s, _offset + offset );
  384           }
  385   
  386           private XPathCompileException newError ( String msg )
  387           {
  388               XmlError err =
  389                   XmlError.forLocation(
  390                       msg, XmlError.SEVERITY_ERROR, null,
  391                       _line, _column, _offset );
  392                                        
  393               return new XPathCompileException( err );
  394           }
  395   
  396           String lookupPrefix ( String prefix ) throws XPathCompileException
  397           {
  398               if (_namespaces.containsKey( prefix ))
  399                   return (String) _namespaces.get( prefix );
  400               
  401               if (_externalNamespaces.containsKey( prefix ))
  402                   return (String) _externalNamespaces.get( prefix );
  403   
  404               if (prefix.equals( "xml" ))
  405                     return "http://www.w3.org/XML/1998/namespace";
  406               
  407               if (prefix.equals( "xs" ))
  408                     return "http://www.w3.org/2001/XMLSchema";
  409               
  410               if (prefix.equals( "xsi" ))
  411                     return "http://www.w3.org/2001/XMLSchema-instance";
  412               
  413               if (prefix.equals( "fn" ))
  414                     return "http://www.w3.org/2002/11/xquery-functions";
  415   
  416               if (prefix.equals( "xdt" ))
  417                     return "http://www.w3.org/2003/11/xpath-datatypes";
  418   
  419               if (prefix.equals( "local" ))
  420                     return "http://www.w3.org/2003/11/xquery-local-functions";
  421   
  422               throw newError( "Undefined prefix: " + prefix );
  423           }
  424   
  425           private boolean parseWhitespace ( ) throws XPathCompileException
  426           {
  427               boolean sawSpace = false;
  428               
  429               while ( isWhitespace() )
  430               {
  431                   advance();
  432                   sawSpace = true;
  433               }
  434   
  435               return sawSpace;
  436           }
  437           
  438           //
  439           // Tokenizing will consume whitespace followed by the tokens, separated
  440           // by whitespace.  The whitespace following the last token is not
  441           // consumed.
  442           //
  443           
  444           private boolean tokenize ( String s )
  445           {
  446               assert s.length() > 0;
  447               
  448               int offset = 0;
  449   
  450               while ( isWhitespace( offset ) )
  451                   offset++;
  452               
  453               if (!startsWith( s, offset ))
  454                   return false;
  455   
  456               offset += s.length();
  457   
  458               advance( offset );
  459   
  460               return true;
  461           }
  462   
  463           private boolean tokenize ( String s1, String s2 )
  464           {
  465               assert s1.length() > 0;
  466               assert s2.length() > 0;
  467               
  468               int offset = 0;
  469   
  470               while ( isWhitespace( offset ) )
  471                   offset++;
  472               
  473               if (!startsWith( s1, offset ))
  474                   return false;
  475   
  476               offset += s1.length();
  477   
  478               while ( isWhitespace( offset ) )
  479                   offset++;
  480               
  481               if (!startsWith( s2, offset ))
  482                   return false;
  483                   
  484               offset += s2.length();
  485   
  486               advance( offset );
  487   
  488               return true;
  489           }
  490   
  491           private boolean tokenize ( String s1, String s2, String s3)
  492           {
  493               assert s1.length() > 0;
  494               assert s2.length() > 0;
  495               assert s3.length() > 0;
  496   
  497               int offset = 0;
  498   
  499               while ( isWhitespace( offset ) )
  500                   offset++;
  501               
  502               if (!startsWith( s1, offset ))
  503                   return false;
  504   
  505               offset += s1.length();
  506   
  507               while ( isWhitespace( offset ) )
  508                   offset++;
  509               
  510               if (!startsWith( s2, offset ))
  511                   return false;
  512                   
  513               offset += s2.length();
  514   
  515               while ( isWhitespace( offset ) )
  516                   offset++;
  517               
  518               if (!startsWith( s3, offset ))
  519                   return false;
  520               
  521               offset += s3.length();
  522   
  523                while ( isWhitespace( offset ) )
  524                   offset++;
  525   
  526               advance( offset );
  527   
  528               return true;
  529           }
  530           private boolean tokenize ( String s1, String s2, String s3,String s4) {
  531               assert s1.length() > 0;
  532               assert s2.length() > 0;
  533               assert s3.length() > 0;
  534               assert s4.length() > 0;
  535   
  536               int offset = 0;
  537   
  538               while ( isWhitespace( offset ) )
  539                   offset++;
  540   
  541               if (!startsWith( s1, offset ))
  542                   return false;
  543   
  544               offset += s1.length();
  545   
  546               while ( isWhitespace( offset ) )
  547                   offset++;
  548   
  549               if (!startsWith( s2, offset ))
  550                   return false;
  551   
  552               offset += s2.length();
  553   
  554               while ( isWhitespace( offset ) )
  555                   offset++;
  556   
  557               if (!startsWith( s3, offset ))
  558                   return false;
  559   
  560               offset += s3.length();
  561   
  562                while ( isWhitespace( offset ) )
  563                   offset++;
  564   
  565               if (!startsWith( s4, offset ))
  566                   return false;
  567   
  568               offset += s4.length();
  569   
  570               advance( offset );
  571   
  572               return true;
  573           }
  574   
  575   
  576           private String tokenizeNCName ( ) throws XPathCompileException
  577           {
  578               parseWhitespace();
  579               
  580               if (!isNCNameStart())
  581                   throw newError( "Expected non-colonized name" );
  582   
  583               StringBuffer sb = new StringBuffer();
  584   
  585               sb.append( (char) currChar() );
  586   
  587               for ( advance() ; isNCName() ; advance() )
  588                   sb.append( (char) currChar() );
  589   
  590               return sb.toString();
  591           }
  592   
  593           private QName getAnyQName ( )
  594           {
  595               return new QName( "", "" );
  596           }
  597           
  598           private QName tokenizeQName ( ) throws XPathCompileException
  599           {
  600               if (tokenize( "*" ))
  601                   return getAnyQName();
  602               
  603               String ncName = tokenizeNCName();
  604   
  605               if (!tokenize( ":" ))
  606                   return new QName( lookupPrefix( "" ), ncName );
  607               
  608               return
  609                   new QName(
  610                       lookupPrefix( ncName ),
  611                       tokenize( "*" ) ? "" : tokenizeNCName() );
  612           }
  613           
  614           private String tokenizeQuotedUri ( ) throws XPathCompileException
  615           {
  616               char quote;
  617               
  618               if (tokenize( "\"" ))
  619                   quote = '"';
  620               else  if (tokenize( "'" ))
  621                   quote = '\'';
  622               else
  623                   throw newError( "Expected quote (\" or ')" );
  624   
  625               StringBuffer sb = new StringBuffer();
  626   
  627               for ( ; ; )
  628               {
  629                   if (currChar() == -1)
  630                       throw newError( "Path terminated in URI literal" );
  631                   
  632                   if (currChar() == quote)
  633                   {
  634                       advance();
  635                       
  636                       if (currChar() != quote)
  637                           break;
  638                   }
  639                   
  640                   sb.append( (char) currChar() );
  641                   
  642                   advance();
  643               }
  644   
  645               return sb.toString();
  646           }
  647   
  648           private Step addStep ( boolean deep, boolean attr, QName name, Step steps )
  649           {
  650               Step step = new Step( deep, attr, name );
  651   
  652               if (steps == null)
  653                   return step;
  654   
  655               Step s = steps;
  656               
  657               while ( steps._next != null )
  658                   steps = steps._next;
  659   
  660               steps._next = step;
  661               step._prev = steps;
  662   
  663               return s;
  664           }
  665   
  666           private Step tokenizeSteps ( ) throws XPathCompileException
  667           {
  668               if (tokenize( "/" ))
  669                   throw newError( "Absolute paths unsupported" );
  670   
  671               boolean deep;
  672   
  673               if (tokenize( "$", _currentNodeVar, "//" ) || tokenize( ".", "//" ))
  674                   deep = true;
  675               else if (tokenize( "$", _currentNodeVar, "/" ) || tokenize( ".", "/" ))
  676                   deep = false;
  677               else if (tokenize( "$", _currentNodeVar ) || tokenize( "." ))
  678                   return addStep( false, false, null, null );
  679               else
  680                   deep = false;
  681   
  682               Step steps = null;
  683   
  684               // Compile the steps removing /. and mergind //. with the next step
  685   
  686               boolean deepDot = false;
  687   
  688               for ( ; ; )
  689               {
  690                   if (tokenize( "attribute", "::" ) || tokenize( "@" ))
  691                   {
  692                       steps = addStep( deep, true, tokenizeQName(), steps );
  693                       break;
  694                   }
  695   
  696                   QName name;
  697                   
  698                   if (tokenize( "." ))
  699                       deepDot = deepDot || deep;
  700                   else
  701                   {
  702                       tokenize( "child", "::" );
  703                       if ((name = tokenizeQName()) != null)
  704                       {
  705                           steps = addStep( deep, false, name, steps );
  706                           deep = false; // only this step needs to be deep
  707                           // other folowing steps will be deep only if they are preceded by // wildcard
  708                       }
  709                   }
  710   
  711                   if (tokenize( "//" ))
  712                   {
  713                       deep = true;
  714                       deepDot = false;
  715                   }
  716                   else if (tokenize( "/" ))
  717                   {
  718                       if (deepDot)
  719                           deep = true;
  720                   }
  721                   else
  722                       break;
  723               }
  724   
  725               // If there was a //. at the end of th path, then we need to make
  726               // two paths, one with * at the end and another with @* at the end.
  727   
  728               if ((_lastDeepDot = deepDot))
  729               {
  730                   _lastDeepDot = true;
  731                   steps = addStep( true, false, getAnyQName(), steps );
  732               }
  733   
  734               // Add sentinal step (_name == null)
  735               
  736               return addStep( false, false, null, steps );
  737           }
  738   
  739           private void computeBacktrack ( Step steps )
  740               throws XPathCompileException
  741           {
  742               //
  743               // Compute static backtrack information
  744               //
  745               // Note that I use the fact that _hasBacktrack is initialized to
  746               // false and _backtrack to null in the following code.
  747               //
  748   
  749               Step s, t;
  750               
  751               for ( s = steps ; s != null ; s = t )
  752               {
  753                   // Compute the segment from [ s, t )
  754                   
  755                   for ( t = s._next ; t != null && !t._deep ; )
  756                       t = t._next;
  757   
  758                   // If the segment is NOT rooted at //, then the backtrack is
  759                   // null for the entire segment, including possible attr and/or
  760                   // sentinal
  761   
  762                   if (!s._deep)
  763                   {
  764                       for ( Step u = s ; u != t ; u = u._next )
  765                           u._hasBacktrack = true;
  766   
  767                       continue;
  768                   }
  769   
  770                   // Compute the sequence [ s, u ) of length n which contain no
  771                   // wild steps.
  772   
  773                   int n = 0;
  774                   Step u = s;
  775   
  776                   while ( u != t && u._name != null && !u.isWild() && !u._attr )
  777                   {
  778                       n++;
  779                       u = u._next;
  780                   }
  781   
  782                   // Now, apply KMP to [ s, u ) for fast backtracking
  783   
  784                   QName [] pattern = new QName [ n + 1 ];
  785                   int [] kmp = new int [ n + 1 ];
  786   
  787                   Step v = s;
  788                   
  789                   for ( int i = 0 ; i < n ; i++ )
  790                   {
  791                       pattern[ i ] = v._name;
  792                       v = v._next;
  793                   }
  794   
  795                   pattern[ n ] = getAnyQName();
  796   
  797                   int i = 0;
  798                   int j = kmp[ 0 ] = -1;
  799   
  800                   while ( i < n )
  801                   {
  802                       while ( j > -1 && !pattern[ i ].equals( pattern[ j ] ) )
  803                           j = kmp[ j ];
  804   
  805                       if (pattern[ ++i ].equals( pattern[ ++j ] ))
  806                           kmp[ i ] = kmp[ j ];
  807                       else
  808                           kmp[ i ] = j;
  809                   }
  810   
  811                   i = 0;
  812                   
  813                   for ( v = s ; v != u ; v = v._next )
  814                   {
  815                       v._hasBacktrack = true;
  816                       v._backtrack = s;
  817                       
  818                       for ( j = kmp[ i ] ; j > 0 ; j-- )
  819                           v._backtrack = v._backtrack._next;
  820                       
  821                       i++;
  822                   }
  823   
  824                   // Compute the success backtrack and stuff it into an attr and
  825                   // sentinal if they exist for this segment
  826                   
  827                   v = s;
  828   
  829                   if (n > 1)
  830                   {
  831                       for ( j = kmp[ n - 1 ] ; j > 0 ; j-- )
  832                           v = v._next;
  833                   }
  834   
  835                   if (u != t && u._attr)
  836                   {
  837                       u._hasBacktrack = true;
  838                       u._backtrack = v;
  839                       u = u._next;
  840                   }
  841   
  842                   if (u != t && u._name == null)
  843                   {
  844                       u._hasBacktrack = true;
  845                       u._backtrack = v;
  846                   }
  847   
  848                   // The first part of a deep segment always backtracks to itself
  849                   
  850                   assert s._deep;
  851   
  852                   s._hasBacktrack = true;
  853                   s._backtrack = s;
  854               }
  855           }
  856   
  857           private void tokenizePath ( ArrayList paths )
  858               throws XPathCompileException
  859           {
  860               _lastDeepDot = false;
  861               
  862               Step steps = tokenizeSteps();
  863               
  864               computeBacktrack( steps );
  865   
  866               paths.add( steps );
  867   
  868               // If the last path ended in //., that path will match all
  869               // elements, here I make a path which matches all attributes.
  870   
  871               if (_lastDeepDot)
  872               {
  873                   _sawDeepDot = true;
  874                   
  875                   Step s = null;
  876   
  877                   for ( Step t = steps ; t != null ; t = t._next )
  878                   {
  879                       if (t._next != null && t._next._next == null)
  880                           s = addStep( t._deep, true, t._name, s );
  881                       else
  882                           s = addStep( t._deep, t._attr, t._name, s );
  883                   }
  884   
  885                   computeBacktrack( s );
  886   
  887                   paths.add( s );
  888               }
  889           }
  890           
  891           private Selector tokenizeSelector ( ) throws XPathCompileException
  892           {
  893               ArrayList paths = new ArrayList();
  894   
  895               tokenizePath( paths );
  896   
  897               while ( tokenize( "|" ) )
  898                   tokenizePath( paths );
  899   
  900               return new Selector( (Step[]) paths.toArray( new Step [ 0 ] ) );
  901           }
  902   
  903           private XPath tokenizeXPath ( ) throws XPathCompileException
  904           {
  905               for ( ; ; )
  906               {
  907                   if (tokenize( "declare", "namespace" ))
  908                   {
  909                       if (!parseWhitespace())
  910                           throw newError( "Expected prefix after 'declare namespace'" );
  911   
  912                       String prefix = tokenizeNCName();
  913   
  914                       if (!tokenize( "=" ))
  915                           throw newError( "Expected '='" );
  916   
  917                       String uri = tokenizeQuotedUri();
  918                       
  919                       if (_namespaces.containsKey( prefix ))
  920                       {
  921                           throw newError(
  922                               "Redefinition of namespace prefix: " + prefix );
  923                       }
  924   
  925                       _namespaces.put( prefix, uri );
  926   
  927                       //return these to saxon:? Is it an error to pass external NS
  928                       //that conflicts? or should we just override it?
  929                       if (_externalNamespaces.containsKey( prefix ))
  930                       {
  931                           throw newError(
  932                               "Redefinition of namespace prefix: " + prefix );
  933                       }
  934                       _externalNamespaces.put( prefix, uri );
  935   
  936                       if (! tokenize( ";" ))
  937                       {
  938   //			            throw newError(
  939   //                            "Namespace declaration must end with ;" );
  940   			        }
  941   
  942                       _externalNamespaces.put(_NS_BOUNDARY,new Integer(_offset));
  943   
  944                       continue;
  945                   }
  946                   
  947                   if (tokenize( "declare","default", "element", "namespace" ))
  948                   {
  949                       String uri = tokenizeQuotedUri();
  950                       
  951                       if (_namespaces.containsKey( "" ))
  952                       {
  953                           throw newError(
  954                               "Redefinition of default element namespace" );
  955                       }
  956   
  957                       _namespaces.put( "", uri );
  958   
  959                       //return these to saxon:? Is it an error to pass external NS
  960                       //that conflicts? or should we just override it?
  961                       if (_externalNamespaces.containsKey( XPath._DEFAULT_ELT_NS ))
  962                       {
  963                            throw newError("Redefinition of default element namespace : ");
  964                       }
  965                       _externalNamespaces.put( XPath._DEFAULT_ELT_NS, uri );
  966   
  967                       if (! tokenize( ";" ))
  968                           throw newError("Default Namespace declaration must end with ;" );
  969                       //the boundary is the last ; in the prolog...
  970                       _externalNamespaces.put(_NS_BOUNDARY,new Integer(_offset));
  971   
  972                       continue;
  973                   }
  974                   
  975                   break;
  976               }
  977   
  978               // Add the default prefix mapping if it has not been redefined
  979               
  980               if (!_namespaces.containsKey( "" ))
  981                   _namespaces.put( "", "" );
  982   
  983               Selector selector = tokenizeSelector();
  984   
  985               parseWhitespace();
  986               
  987               if (currChar() != -1)
  988               {
  989                   throw newError(
  990                       "Unexpected char '" + (char) currChar() + "'" );
  991               }
  992   
  993               return new XPath( selector, _sawDeepDot );
  994           }
  995   
  996           //split of prolog decls that are not standard XPath syntax
  997           //but work in v1
  998           private void processNonXpathDecls(){
  999   
 1000           }
 1001   
 1002           private String _expr;
 1003   
 1004           private boolean _sawDeepDot;  // Saw one overall
 1005           private boolean _lastDeepDot;
 1006   
 1007           private String _currentNodeVar;
 1008           
 1009          // private Map _namespaces;
 1010           protected Map _namespaces;
 1011           private Map _externalNamespaces;
 1012           
 1013           private int _offset;
 1014           private int _line;
 1015           private int _column;
 1016       }
 1017   
 1018       private static final class Step
 1019       {
 1020           Step ( boolean deep, boolean attr, QName name )
 1021           {
 1022               _name = name;
 1023   
 1024               _deep = deep;
 1025               _attr = attr;
 1026   
 1027               int flags = 0;
 1028   
 1029               if (_deep || !_attr)
 1030                   flags |= ExecutionContext.DESCEND;
 1031   
 1032               if (_attr)
 1033                   flags |= ExecutionContext.ATTRS;
 1034   
 1035               _flags = flags;
 1036           }
 1037   
 1038           boolean isWild ( )
 1039           {
 1040               return _name.getLocalPart().length() == 0;
 1041           }
 1042   
 1043           boolean match ( QName name )
 1044           {
 1045               String local = _name.getLocalPart();
 1046               String nameLocal = name.getLocalPart();
 1047               String uri;
 1048               String nameUri;
 1049   
 1050               int localLength = local.length();
 1051               int uriLength;
 1052   
 1053               // match any name to _name when _name is empty ""@""
 1054               if (localLength==0)
 1055               {
 1056                   uri = _name.getNamespaceURI();
 1057                   uriLength = uri.length();
 1058   
 1059                   if (uriLength==0)
 1060                       return true;
 1061   
 1062                   return uri.equals(name.getNamespaceURI());
 1063               }
 1064   
 1065               if (localLength!=nameLocal.length())
 1066                   return false;
 1067   
 1068               uri = _name.getNamespaceURI();
 1069               nameUri = name.getNamespaceURI();
 1070   
 1071               if (uri.length()!=nameUri.length())
 1072                   return false;
 1073   
 1074               return local.equals(nameLocal) && uri.equals(nameUri);
 1075           }
 1076   
 1077           final boolean _attr;
 1078           final boolean _deep;
 1079   
 1080           int _flags;
 1081           
 1082           final QName _name;
 1083   
 1084           Step _next, _prev;
 1085   
 1086           boolean _hasBacktrack;
 1087           Step    _backtrack;
 1088       }
 1089   
 1090       private static final class Selector
 1091       {
 1092           Selector ( Step[] paths )
 1093           {
 1094               _paths = paths;
 1095           }
 1096   
 1097           final Step[] _paths;
 1098       }
 1099   
 1100       //
 1101       //
 1102       //
 1103       
 1104       private XPath ( Selector selector, boolean sawDeepDot )
 1105       {
 1106           _selector = selector;
 1107           _sawDeepDot = sawDeepDot;
 1108       }
 1109   
 1110       public boolean sawDeepDot ( )
 1111       {
 1112           return _sawDeepDot;
 1113       }
 1114   
 1115       public static final String _NS_BOUNDARY = "$xmlbeans!ns_boundary";
 1116       public static final String _DEFAULT_ELT_NS = "$xmlbeans!default_uri";
 1117       private final Selector _selector;
 1118       private final boolean  _sawDeepDot;
 1119   }

Save This Page
Home » xmlbeans-2.4.0-src » org.apache.xmlbeans.impl.common » [javadoc | source]