KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xerces > impl > xpath > XPath


1 /*
2  * Copyright 2000-2002,2004,2005 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.apache.xerces.impl.xpath;
18
19 import java.util.Vector JavaDoc;
20
21 import org.apache.xerces.util.SymbolTable;
22 import org.apache.xerces.util.XMLSymbols;
23 import org.apache.xerces.util.XMLChar;
24 import org.apache.xerces.xni.NamespaceContext;
25 import org.apache.xerces.xni.QName;
26
27 /**
28  * Bare minimum XPath parser.
29  *
30  * @xerces.internal
31  *
32  * @author Andy Clark, IBM
33  * @version $Id: XPath.java,v 1.18 2005/03/07 23:28:41 mrglavas Exp $
34  */

35 public class XPath {
36
37     //
38
// Constants
39
//
40

41     private static final boolean DEBUG_ALL = false;
42
43     private static final boolean DEBUG_XPATH_PARSE = DEBUG_ALL || false;
44
45     private static final boolean DEBUG_ANY = DEBUG_XPATH_PARSE;
46
47     //
48
// Data
49
//
50

51     /** Expression. */
52     protected String JavaDoc fExpression;
53
54     /** Symbol table. */
55     protected SymbolTable fSymbolTable;
56
57     /** Location paths. */
58     protected LocationPath[] fLocationPaths;
59
60     //
61
// Constructors
62
//
63

64     /** Constructs an XPath object from the specified expression. */
65     public XPath(String JavaDoc xpath, SymbolTable symbolTable,
66                  NamespaceContext context)
67         throws XPathException {
68         fExpression = xpath;
69         fSymbolTable = symbolTable;
70         parseExpression(context);
71     } // <init>(String,SymbolTable,NamespaceContext)
72

73     //
74
// Public methods
75
//
76

77     /**
78      * Returns a representation of all location paths for this XPath.
79      * XPath = locationPath ( '|' locationPath)
80      */

81     public LocationPath[] getLocationPaths() {
82         LocationPath[] ret=new LocationPath[fLocationPaths.length];
83         for (int i=0;i<fLocationPaths.length;i++){
84             ret[i]=(LocationPath)fLocationPaths[i].clone();
85         }
86         return ret;
87     } // getLocationPath(LocationPath)
88

89     /** Returns a representation of the first location path for this XPath. */
90     public LocationPath getLocationPath() {
91         return (LocationPath)fLocationPaths[0].clone();
92     } // getLocationPath(LocationPath)
93

94     //
95
// Object methods
96
//
97

98     /** Returns a string representation of this object. */
99     public String JavaDoc toString() {
100         StringBuffer JavaDoc buf=new StringBuffer JavaDoc();
101         for (int i=0;i<fLocationPaths.length;i++){
102             if (i>0){
103                 buf.append("|");
104             }
105             buf.append(fLocationPaths[i].toString());
106         }
107         return buf.toString();
108     } // toString():String
109

110     //
111
// Private methods
112
//
113

114     /**
115      * Used by the {@link #parseExpression(NamespaceContext)} method
116      * to verify the assumption.
117      *
118      * If <tt>b</tt> is false, this method throws XPathException
119      * to report the error.
120      */

121     private static void check( boolean b ) throws XPathException {
122         if(!b) throw new XPathException("c-general-xpath");
123     }
124     
125     /**
126      * Used by the {@link #parseExpression(NamespaceContext)} method
127      * to build a {@link LocationPath} object from the accumulated
128      * {@link Step}s.
129      */

130     private LocationPath buildLocationPath( Vector JavaDoc stepsVector ) throws XPathException {
131         int size = stepsVector.size();
132         check(size!=0);
133         Step[] steps = new Step[size];
134         stepsVector.copyInto(steps);
135         stepsVector.removeAllElements();
136         
137         return new LocationPath(steps);
138     }
139     
140     /**
141      * This method is implemented by using the XPathExprScanner and
142      * examining the list of tokens that it returns.
143      */

144     private void parseExpression(final NamespaceContext context)
145         throws XPathException {
146
147         // tokens
148
final XPath.Tokens xtokens = new XPath.Tokens(fSymbolTable);
149
150         // scanner
151
XPath.Scanner scanner = new XPath.Scanner(fSymbolTable) {
152             protected void addToken(XPath.Tokens tokens, int token)
153                 throws XPathException {
154                 if (
155                     token == XPath.Tokens.EXPRTOKEN_ATSIGN ||
156                     token == XPath.Tokens.EXPRTOKEN_NAMETEST_QNAME ||
157                     token == XPath.Tokens.EXPRTOKEN_OPERATOR_SLASH ||
158                     token == XPath.Tokens.EXPRTOKEN_PERIOD ||
159                     token == XPath.Tokens.EXPRTOKEN_NAMETEST_ANY ||
160                     token == XPath.Tokens.EXPRTOKEN_NAMETEST_NAMESPACE ||
161                     token == XPath.Tokens.EXPRTOKEN_OPERATOR_DOUBLE_SLASH ||
162                     token == XPath.Tokens.EXPRTOKEN_OPERATOR_UNION
163                     //
164
) {
165                     super.addToken(tokens, token);
166                     return;
167                 }
168                 throw new XPathException("c-general-xpath");
169             }
170         };
171
172         int length = fExpression.length();
173         
174         boolean success = scanner.scanExpr(fSymbolTable,
175                                            xtokens, fExpression, 0, length);
176         if(!success)
177             throw new XPathException("c-general-xpath");
178         
179         //fTokens.dumpTokens();
180
Vector JavaDoc stepsVector = new Vector JavaDoc();
181         Vector JavaDoc locationPathsVector= new Vector JavaDoc();
182         
183         // true when the next token should be 'Step' (as defined in
184
// the production rule [3] of XML Schema P1 section 3.11.6
185
// if false, we are expecting either '|' or '/'.
186
//
187
// this is to make sure we can detect a token list like
188
// 'abc' '/' '/' 'def' 'ghi'
189
boolean expectingStep = true;
190
191         while(xtokens.hasMore()) {
192             final int token = xtokens.nextToken();
193
194             switch (token) {
195                 case XPath.Tokens.EXPRTOKEN_OPERATOR_UNION :{
196                     check(!expectingStep);
197                     locationPathsVector.addElement(buildLocationPath(stepsVector));
198                     expectingStep=true;
199                     break;
200                 }
201
202                 case XPath.Tokens.EXPRTOKEN_ATSIGN: {
203                     check(expectingStep);
204                     Step step = new Step(
205                             new Axis(Axis.ATTRIBUTE),
206                             parseNodeTest(xtokens.nextToken(),xtokens,context));
207                     stepsVector.addElement(step);
208                     expectingStep=false;
209                     break;
210                 }
211                 case XPath.Tokens.EXPRTOKEN_NAMETEST_ANY:
212                 case XPath.Tokens.EXPRTOKEN_NAMETEST_NAMESPACE:
213                 case XPath.Tokens.EXPRTOKEN_NAMETEST_QNAME: {
214                     check(expectingStep);
215                     Step step = new Step(
216                             new Axis(Axis.CHILD),
217                             parseNodeTest(token,xtokens,context));
218                     stepsVector.addElement(step);
219                     expectingStep=false;
220                     break;
221                 }
222
223                 case XPath.Tokens.EXPRTOKEN_PERIOD: {
224                     check(expectingStep);
225                     expectingStep=false;
226
227                     // unless this is the first step in this location path,
228
// there's really no reason to keep them in LocationPath.
229
// This amounts to shorten "a/././b/./c" to "a/b/c".
230
// Also, the matcher fails to work correctly if XPath
231
// has those redundant dots.
232
if (stepsVector.size()==0) {
233                         // build step
234
Axis axis = new Axis(Axis.SELF);
235                         NodeTest nodeTest = new NodeTest(NodeTest.NODE);
236                         Step step = new Step(axis, nodeTest);
237                         stepsVector.addElement(step);
238                         
239                         if( xtokens.hasMore()
240                          && xtokens.peekToken() == XPath.Tokens.EXPRTOKEN_OPERATOR_DOUBLE_SLASH){
241                             // consume '//'
242
xtokens.nextToken();
243                             
244                             // build step
245
axis = new Axis(Axis.DESCENDANT);
246                             nodeTest = new NodeTest(NodeTest.NODE);
247                             step = new Step(axis, nodeTest);
248                             stepsVector.addElement(step);
249                             expectingStep=true;
250                         }
251                     }
252                     break;
253                 }
254
255                 case XPath.Tokens.EXPRTOKEN_OPERATOR_DOUBLE_SLASH:{
256                     // this cannot appear in arbitrary position.
257
// it is only allowed right after '.' when
258
// '.' is the first token of a location path.
259
throw new XPathException("c-general-xpath");
260                 }
261                 case XPath.Tokens.EXPRTOKEN_OPERATOR_SLASH: {
262                     check(!expectingStep);
263                     expectingStep=true;
264                     break;
265                 }
266                 default:
267                     // we should have covered all the tokens that we can possibly see.
268
throw new InternalError JavaDoc();
269             }
270         }
271         
272         check(!expectingStep);
273
274         locationPathsVector.addElement(buildLocationPath(stepsVector));
275
276         // save location path
277
fLocationPaths=new LocationPath[locationPathsVector.size()];
278         locationPathsVector.copyInto(fLocationPaths);
279
280
281         if (DEBUG_XPATH_PARSE) {
282             System.out.println(">>> "+fLocationPaths);
283         }
284
285     } // parseExpression(SymbolTable,NamespaceContext)
286

287     /**
288      * Used by {@link #parseExpression} to parse a node test
289      * from the token list.
290      */

291     private NodeTest parseNodeTest( int typeToken, Tokens xtokens, NamespaceContext context )
292         throws XPathException {
293         switch(typeToken) {
294         case XPath.Tokens.EXPRTOKEN_NAMETEST_ANY:
295             return new NodeTest(NodeTest.WILDCARD);
296             
297         case XPath.Tokens.EXPRTOKEN_NAMETEST_NAMESPACE:
298         case XPath.Tokens.EXPRTOKEN_NAMETEST_QNAME:
299             // consume QName token
300
String JavaDoc prefix = xtokens.nextTokenAsString();
301             String JavaDoc uri = null;
302             if (context != null && prefix != XMLSymbols.EMPTY_STRING) {
303                 uri = context.getURI(prefix);
304             }
305             if (prefix != XMLSymbols.EMPTY_STRING && context != null && uri == null) {
306                 throw new XPathException("c-general-xpath-ns");
307             }
308     
309             if (typeToken==XPath.Tokens.EXPRTOKEN_NAMETEST_NAMESPACE)
310                 return new NodeTest(prefix,uri);
311     
312             String JavaDoc localpart = xtokens.nextTokenAsString();
313             String JavaDoc rawname = prefix != XMLSymbols.EMPTY_STRING
314             ? fSymbolTable.addSymbol(prefix+':'+localpart)
315             : localpart;
316     
317             return new NodeTest(new QName(prefix, localpart, rawname, uri));
318         
319         default:
320             // assertion error
321
throw new InternalError JavaDoc();
322         }
323     }
324     
325     
326     //
327
// Classes
328
//
329

330     // location path information
331

332     /**
333      * A location path representation for an XPath expression.
334      *
335      * @xerces.internal
336      *
337      * @author Andy Clark, IBM
338      */

339     public static class LocationPath
340         implements Cloneable JavaDoc {
341
342         //
343
// Data
344
//
345

346         /** List of steps. */
347         public Step[] steps;
348
349         //
350
// Constructors
351
//
352

353         /** Creates a location path from a series of steps. */
354         public LocationPath(Step[] steps) {
355             this.steps = steps;
356         } // <init>(Step[])
357

358         /** Copy constructor. */
359         protected LocationPath(LocationPath path) {
360             steps = new Step[path.steps.length];
361             for (int i = 0; i < steps.length; i++) {
362                 steps[i] = (Step)path.steps[i].clone();
363             }
364         } // <init>(LocationPath)
365

366         //
367
// Object methods
368
//
369

370         /** Returns a string representation of this object. */
371         public String JavaDoc toString() {
372             StringBuffer JavaDoc str = new StringBuffer JavaDoc();
373             for (int i = 0; i < steps.length; i++) {
374                 if (i > 0 && (steps[i-1].axis.type!=Axis.DESCENDANT
375                     && steps[i].axis.type!=Axis.DESCENDANT) ){
376                     str.append('/');
377                 }
378                 str.append(steps[i].toString());
379             }
380             // DEBUG: This code is just for debugging and should *not*
381
// be left in because it will mess up hashcodes of
382
// serialized versions of this object. -Ac
383
if (false) {
384                 str.append('[');
385                 String JavaDoc s = super.toString();
386                 str.append(s.substring(s.indexOf('@')));
387                 str.append(']');
388             }
389             return str.toString();
390         } // toString():String
391

392         /** Returns a clone of this object. */
393         public Object JavaDoc clone() {
394             return new LocationPath(this);
395         } // clone():Object
396

397     } // class locationPath
398

399     /**
400      * A location path step comprised of an axis and node test.
401      *
402      * @xerces.internal
403      *
404      * @author Andy Clark, IBM
405      */

406     public static class Step
407         implements Cloneable JavaDoc {
408
409         //
410
// Data
411
//
412

413         /** Axis. */
414         public Axis axis;
415
416         /** Node test. */
417         public NodeTest nodeTest;
418
419         //
420
// Constructors
421
//
422

423         /** Constructs a step from an axis and node test. */
424         public Step(Axis axis, NodeTest nodeTest) {
425             this.axis = axis;
426             this.nodeTest = nodeTest;
427         } // <init>(Axis,NodeTest)
428

429         /** Copy constructor. */
430         protected Step(Step step) {
431             axis = (Axis)step.axis.clone();
432             nodeTest = (NodeTest)step.nodeTest.clone();
433         } // <init>(Step)
434

435         //
436
// Object methods
437
//
438

439         /** Returns a string representation of this object. */
440         public String JavaDoc toString() {
441             if (axis.type == Axis.SELF) {
442                 return ".";
443             }
444             if (axis.type == Axis.ATTRIBUTE) {
445                 return "@" + nodeTest.toString();
446             }
447             if (axis.type == Axis.CHILD) {
448                 return nodeTest.toString();
449             }
450             if (axis.type == Axis.DESCENDANT) {
451                 return "//";
452             }
453             return "??? ("+axis.type+')';
454         } // toString():String
455

456         /** Returns a clone of this object. */
457         public Object JavaDoc clone() {
458             return new Step(this);
459         } // clone():Object
460

461     } // class Step
462

463     /**
464      * Axis.
465      *
466      * @xerces.internal
467      *
468      * @author Andy Clark, IBM
469      */

470     public static class Axis
471         implements Cloneable JavaDoc {
472
473         //
474
// Constants
475
//
476

477         /** Type: child. */
478         public static final short CHILD = 1;
479
480         /** Type: attribute. */
481         public static final short ATTRIBUTE = 2;
482
483         /** Type: self. */
484         public static final short SELF = 3;
485
486
487         /** Type: descendant. */
488         public static final short DESCENDANT = 4;
489         //
490
// Data
491
//
492

493         /** Axis type. */
494         public short type;
495
496         //
497
// Constructors
498
//
499

500         /** Constructs an axis with the specified type. */
501         public Axis(short type) {
502             this.type = type;
503         } // <init>(short)
504

505         /** Copy constructor. */
506         protected Axis(Axis axis) {
507             type = axis.type;
508         } // <init>(Axis)
509

510         //
511
// Object methods
512
//
513

514         /** Returns a string representation of this object. */
515         public String JavaDoc toString() {
516             switch (type) {
517                 case CHILD: return "child";
518                 case ATTRIBUTE: return "attribute";
519                 case SELF: return "self";
520                 case DESCENDANT: return "descendant";
521             }
522             return "???";
523         } // toString():String
524

525         /** Returns a clone of this object. */
526         public Object JavaDoc clone() {
527             return new Axis(this);
528         } // clone():Object
529

530     } // class Axis
531

532     /**
533      * Node test.
534      *
535      * @xerces.internal
536      *
537      * @author Andy Clark, IBM
538      */

539     public static class NodeTest
540         implements Cloneable JavaDoc {
541
542         //
543
// Constants
544
//
545

546         /** Type: qualified name. */
547         public static final short QNAME = 1;
548
549         /** Type: wildcard. */
550         public static final short WILDCARD = 2;
551
552         /** Type: node. */
553         public static final short NODE = 3;
554
555         /** Type: namespace */
556         public static final short NAMESPACE= 4;
557
558         //
559
// Data
560
//
561

562         /** Node test type. */
563         public short type;
564
565         /** Node qualified name. */
566         public final QName name = new QName();
567
568         //
569
// Constructors
570
//
571

572         /** Constructs a node test of type WILDCARD or NODE. */
573         public NodeTest(short type) {
574             this.type = type;
575         } // <init>(int)
576

577         /** Constructs a node test of type QName. */
578         public NodeTest(QName name) {
579             this.type = QNAME;
580             this.name.setValues(name);
581         } // <init>(QName)
582
/** Constructs a node test of type Namespace. */
583         public NodeTest(String JavaDoc prefix, String JavaDoc uri) {
584             this.type = NAMESPACE;
585             this.name.setValues(prefix, null, null, uri);
586         } // <init>(String,String)
587

588         /** Copy constructor. */
589         public NodeTest(NodeTest nodeTest) {
590             type = nodeTest.type;
591             name.setValues(nodeTest.name);
592         } // <init>(NodeTest)
593

594         //
595
// Object methods
596
//
597

598         /** Returns a string representation of this object. */
599         public String JavaDoc toString() {
600
601             switch (type) {
602                 case QNAME: {
603                     if (name.prefix.length() !=0) {
604                         if (name.uri != null) {
605                             return name.prefix+':'+name.localpart;
606                         }
607                         return "{"+name.uri+'}'+name.prefix+':'+name.localpart;
608                     }
609                     return name.localpart;
610                 }
611                 case NAMESPACE: {
612                     if (name.prefix.length() !=0) {
613                         if (name.uri != null) {
614                             return name.prefix+":*";
615                         }
616                         return "{"+name.uri+'}'+name.prefix+":*";
617                     }
618                     return "???:*";
619                 }
620                 case WILDCARD: {
621                     return "*";
622                 }
623                 case NODE: {
624                     return "node()";
625                 }
626             }
627             return "???";
628
629         } // toString():String
630

631         /** Returns a clone of this object. */
632         public Object JavaDoc clone() {
633             return new NodeTest(this);
634         } // clone():Object
635

636     } // class NodeTest
637

638     // xpath implementation
639

640     // NOTE: The XPath implementation classes are kept internal because
641
// this implementation is just a temporary hack until a better
642
// and/or more appropriate implementation can be written.
643
// keeping the code in separate source files would "muddy" the
644
// CVS directory when it's not needed. -Ac
645

646     /**
647      * List of tokens.
648      *
649      * @xerces.internal
650      *
651      * @author Glenn Marcy, IBM
652      * @author Andy Clark, IBM
653      *
654      * @version $Id: XPath.java,v 1.18 2005/03/07 23:28:41 mrglavas Exp $
655      */

656     private static final class Tokens {
657
658         static final boolean DUMP_TOKENS = false;
659
660         /**
661          * [28] ExprToken ::= '(' | ')' | '[' | ']' | '.' | '..' | '@' | ',' | '::'
662          * | NameTest | NodeType | Operator | FunctionName
663          * | AxisName | Literal | Number | VariableReference
664          */

665         public static final int
666             EXPRTOKEN_OPEN_PAREN = 0,
667             EXPRTOKEN_CLOSE_PAREN = 1,
668             EXPRTOKEN_OPEN_BRACKET = 2,
669             EXPRTOKEN_CLOSE_BRACKET = 3,
670             EXPRTOKEN_PERIOD = 4,
671             EXPRTOKEN_DOUBLE_PERIOD = 5,
672             EXPRTOKEN_ATSIGN = 6,
673             EXPRTOKEN_COMMA = 7,
674             EXPRTOKEN_DOUBLE_COLON = 8,
675             //
676
// [37] NameTest ::= '*' | NCName ':' '*' | QName
677
//
678
// followed by symbol handle of NCName or QName
679
//
680
EXPRTOKEN_NAMETEST_ANY = 9,
681             EXPRTOKEN_NAMETEST_NAMESPACE = 10,
682             EXPRTOKEN_NAMETEST_QNAME = 11,
683             //
684
// [38] NodeType ::= 'comment' | 'text' | 'processing-instruction' | 'node'
685
//
686
EXPRTOKEN_NODETYPE_COMMENT = 12,
687             EXPRTOKEN_NODETYPE_TEXT = 13,
688             EXPRTOKEN_NODETYPE_PI = 14,
689             EXPRTOKEN_NODETYPE_NODE = 15,
690             //
691
// [32] Operator ::= OperatorName
692
// | MultiplyOperator
693
// | '/' | '//' | '|' | '+' | '-' | '=' | '!=' | '<' | '<=' | '>' | '>='
694
// [33] OperatorName ::= 'and' | 'or' | 'mod' | 'div'
695
// [34] MultiplyOperator ::= '*'
696
//
697
EXPRTOKEN_OPERATOR_AND = 16,
698             EXPRTOKEN_OPERATOR_OR = 17,
699             EXPRTOKEN_OPERATOR_MOD = 18,
700             EXPRTOKEN_OPERATOR_DIV = 19,
701             EXPRTOKEN_OPERATOR_MULT = 20,
702             EXPRTOKEN_OPERATOR_SLASH = 21,
703             EXPRTOKEN_OPERATOR_DOUBLE_SLASH = 22,
704             EXPRTOKEN_OPERATOR_UNION = 23,
705             EXPRTOKEN_OPERATOR_PLUS = 24,
706             EXPRTOKEN_OPERATOR_MINUS = 25,
707             EXPRTOKEN_OPERATOR_EQUAL = 26,
708             EXPRTOKEN_OPERATOR_NOT_EQUAL = 27,
709             EXPRTOKEN_OPERATOR_LESS = 28,
710             EXPRTOKEN_OPERATOR_LESS_EQUAL = 29,
711             EXPRTOKEN_OPERATOR_GREATER = 30,
712             EXPRTOKEN_OPERATOR_GREATER_EQUAL = 31,
713
714             //EXPRTOKEN_FIRST_OPERATOR = EXPRTOKEN_OPERATOR_AND,
715
//EXPRTOKEN_LAST_OPERATOR = EXPRTOKEN_OPERATOR_GREATER_EQUAL,
716

717             //
718
// [35] FunctionName ::= QName - NodeType
719
//
720
// followed by symbol handle
721
//
722
EXPRTOKEN_FUNCTION_NAME = 32,
723             //
724
// [6] AxisName ::= 'ancestor' | 'ancestor-or-self'
725
// | 'attribute'
726
// | 'child'
727
// | 'descendant' | 'descendant-or-self'
728
// | 'following' | 'following-sibling'
729
// | 'namespace'
730
// | 'parent'
731
// | 'preceding' | 'preceding-sibling'
732
// | 'self'
733
//
734
EXPRTOKEN_AXISNAME_ANCESTOR = 33,
735             EXPRTOKEN_AXISNAME_ANCESTOR_OR_SELF = 34,
736             EXPRTOKEN_AXISNAME_ATTRIBUTE = 35,
737             EXPRTOKEN_AXISNAME_CHILD = 36,
738             EXPRTOKEN_AXISNAME_DESCENDANT = 37,
739             EXPRTOKEN_AXISNAME_DESCENDANT_OR_SELF = 38,
740             EXPRTOKEN_AXISNAME_FOLLOWING = 39,
741             EXPRTOKEN_AXISNAME_FOLLOWING_SIBLING = 40,
742             EXPRTOKEN_AXISNAME_NAMESPACE = 41,
743             EXPRTOKEN_AXISNAME_PARENT = 42,
744             EXPRTOKEN_AXISNAME_PRECEDING = 43,
745             EXPRTOKEN_AXISNAME_PRECEDING_SIBLING = 44,
746             EXPRTOKEN_AXISNAME_SELF = 45,
747             //
748
// [29] Literal ::= '"' [^"]* '"' | "'" [^']* "'"
749
//
750
// followed by symbol handle for literal
751
//
752
EXPRTOKEN_LITERAL = 46,
753             //
754
// [30] Number ::= Digits ('.' Digits?)? | '.' Digits
755
// [31] Digits ::= [0-9]+
756
//
757
// followed by number handle
758
//
759
EXPRTOKEN_NUMBER = 47,
760             //
761
// [36] VariableReference ::= '$' QName
762
//
763
// followed by symbol handle for QName
764
//
765
EXPRTOKEN_VARIABLE_REFERENCE = 48;
766
767         private static final String JavaDoc[] fgTokenNames = {
768             "EXPRTOKEN_OPEN_PAREN",
769             "EXPRTOKEN_CLOSE_PAREN",
770             "EXPRTOKEN_OPEN_BRACKET",
771             "EXPRTOKEN_CLOSE_BRACKET",
772             "EXPRTOKEN_PERIOD",
773             "EXPRTOKEN_DOUBLE_PERIOD",
774             "EXPRTOKEN_ATSIGN",
775             "EXPRTOKEN_COMMA",
776             "EXPRTOKEN_DOUBLE_COLON",
777             "EXPRTOKEN_NAMETEST_ANY",
778             "EXPRTOKEN_NAMETEST_NAMESPACE",
779             "EXPRTOKEN_NAMETEST_QNAME",
780             "EXPRTOKEN_NODETYPE_COMMENT",
781             "EXPRTOKEN_NODETYPE_TEXT",
782             "EXPRTOKEN_NODETYPE_PI",
783             "EXPRTOKEN_NODETYPE_NODE",
784             "EXPRTOKEN_OPERATOR_AND",
785             "EXPRTOKEN_OPERATOR_OR",
786             "EXPRTOKEN_OPERATOR_MOD",
787             "EXPRTOKEN_OPERATOR_DIV",
788             "EXPRTOKEN_OPERATOR_MULT",
789             "EXPRTOKEN_OPERATOR_SLASH",
790             "EXPRTOKEN_OPERATOR_DOUBLE_SLASH",
791             "EXPRTOKEN_OPERATOR_UNION",
792             "EXPRTOKEN_OPERATOR_PLUS",
793             "EXPRTOKEN_OPERATOR_MINUS",
794             "EXPRTOKEN_OPERATOR_EQUAL",
795             "EXPRTOKEN_OPERATOR_NOT_EQUAL",
796             "EXPRTOKEN_OPERATOR_LESS",
797             "EXPRTOKEN_OPERATOR_LESS_EQUAL",
798             "EXPRTOKEN_OPERATOR_GREATER",
799             "EXPRTOKEN_OPERATOR_GREATER_EQUAL",
800             "EXPRTOKEN_FUNCTION_NAME",
801             "EXPRTOKEN_AXISNAME_ANCESTOR",
802             "EXPRTOKEN_AXISNAME_ANCESTOR_OR_SELF",
803             "EXPRTOKEN_AXISNAME_ATTRIBUTE",
804             "EXPRTOKEN_AXISNAME_CHILD",
805             "EXPRTOKEN_AXISNAME_DESCENDANT",
806             "EXPRTOKEN_AXISNAME_DESCENDANT_OR_SELF",
807             "EXPRTOKEN_AXISNAME_FOLLOWING",
808             "EXPRTOKEN_AXISNAME_FOLLOWING_SIBLING",
809             "EXPRTOKEN_AXISNAME_NAMESPACE",
810             "EXPRTOKEN_AXISNAME_PARENT",
811             "EXPRTOKEN_AXISNAME_PRECEDING",
812             "EXPRTOKEN_AXISNAME_PRECEDING_SIBLING",
813             "EXPRTOKEN_AXISNAME_SELF",
814             "EXPRTOKEN_LITERAL",
815             "EXPRTOKEN_NUMBER",
816             "EXPRTOKEN_VARIABLE_REFERENCE"
817         };
818
819         /**
820          *
821          */

822         private static final int INITIAL_TOKEN_COUNT = 1 << 8;
823         private int[] fTokens = new int[INITIAL_TOKEN_COUNT];
824         private int fTokenCount = 0; // for writing
825

826         private SymbolTable fSymbolTable;
827
828         // REVISIT: Code something better here. -Ac
829
private java.util.Hashtable JavaDoc fSymbolMapping = new java.util.Hashtable JavaDoc();
830
831         // REVISIT: Code something better here. -Ac
832
private java.util.Hashtable JavaDoc fTokenNames = new java.util.Hashtable JavaDoc();
833
834         /**
835          * Current position in the token list.
836          */

837         private int fCurrentTokenIndex;
838         
839         //
840
// Constructors
841
//
842

843         public Tokens(SymbolTable symbolTable) {
844             fSymbolTable = symbolTable;
845             final String JavaDoc[] symbols = {
846                 "ancestor", "ancestor-or-self", "attribute",
847                 "child", "descendant", "descendant-or-self",
848                 "following", "following-sibling", "namespace",
849                 "parent", "preceding", "preceding-sibling",
850                 "self",
851             };
852             for (int i = 0; i < symbols.length; i++) {
853                 fSymbolMapping.put(fSymbolTable.addSymbol(symbols[i]), new Integer JavaDoc(i));
854             }
855             fTokenNames.put(new Integer JavaDoc(EXPRTOKEN_OPEN_PAREN), "EXPRTOKEN_OPEN_PAREN");
856             fTokenNames.put(new Integer JavaDoc(EXPRTOKEN_CLOSE_PAREN), "EXPRTOKEN_CLOSE_PAREN");
857             fTokenNames.put(new Integer JavaDoc(EXPRTOKEN_OPEN_BRACKET), "EXPRTOKEN_OPEN_BRACKET");
858             fTokenNames.put(new Integer JavaDoc(EXPRTOKEN_CLOSE_BRACKET), "EXPRTOKEN_CLOSE_BRACKET");
859             fTokenNames.put(new Integer JavaDoc(EXPRTOKEN_PERIOD), "EXPRTOKEN_PERIOD");
860             fTokenNames.put(new Integer JavaDoc(EXPRTOKEN_DOUBLE_PERIOD), "EXPRTOKEN_DOUBLE_PERIOD");
861             fTokenNames.put(new Integer JavaDoc(EXPRTOKEN_ATSIGN), "EXPRTOKEN_ATSIGN");
862             fTokenNames.put(new Integer JavaDoc(EXPRTOKEN_COMMA), "EXPRTOKEN_COMMA");
863             fTokenNames.put(new Integer JavaDoc(EXPRTOKEN_DOUBLE_COLON), "EXPRTOKEN_DOUBLE_COLON");
864             fTokenNames.put(new Integer JavaDoc(EXPRTOKEN_NAMETEST_ANY), "EXPRTOKEN_NAMETEST_ANY");
865             fTokenNames.put(new Integer JavaDoc(EXPRTOKEN_NAMETEST_NAMESPACE), "EXPRTOKEN_NAMETEST_NAMESPACE");
866             fTokenNames.put(new Integer JavaDoc(EXPRTOKEN_NAMETEST_QNAME), "EXPRTOKEN_NAMETEST_QNAME");
867             fTokenNames.put(new Integer JavaDoc(EXPRTOKEN_NODETYPE_COMMENT), "EXPRTOKEN_NODETYPE_COMMENT");
868             fTokenNames.put(new Integer JavaDoc(EXPRTOKEN_NODETYPE_TEXT), "EXPRTOKEN_NODETYPE_TEXT");
869             fTokenNames.put(new Integer JavaDoc(EXPRTOKEN_NODETYPE_PI), "EXPRTOKEN_NODETYPE_PI");
870             fTokenNames.put(new Integer JavaDoc(EXPRTOKEN_NODETYPE_NODE), "EXPRTOKEN_NODETYPE_NODE");
871             fTokenNames.put(new Integer JavaDoc(EXPRTOKEN_OPERATOR_AND), "EXPRTOKEN_OPERATOR_AND");
872             fTokenNames.put(new Integer JavaDoc(EXPRTOKEN_OPERATOR_OR), "EXPRTOKEN_OPERATOR_OR");
873             fTokenNames.put(new Integer JavaDoc(EXPRTOKEN_OPERATOR_MOD), "EXPRTOKEN_OPERATOR_MOD");
874             fTokenNames.put(new Integer JavaDoc(EXPRTOKEN_OPERATOR_DIV), "EXPRTOKEN_OPERATOR_DIV");
875             fTokenNames.put(new Integer JavaDoc(EXPRTOKEN_OPERATOR_MULT), "EXPRTOKEN_OPERATOR_MULT");
876             fTokenNames.put(new Integer JavaDoc(EXPRTOKEN_OPERATOR_SLASH), "EXPRTOKEN_OPERATOR_SLASH");
877             fTokenNames.put(new Integer JavaDoc(EXPRTOKEN_OPERATOR_DOUBLE_SLASH), "EXPRTOKEN_OPERATOR_DOUBLE_SLASH");
878             fTokenNames.put(new Integer JavaDoc(EXPRTOKEN_OPERATOR_UNION), "EXPRTOKEN_OPERATOR_UNION");
879             fTokenNames.put(new Integer JavaDoc(EXPRTOKEN_OPERATOR_PLUS), "EXPRTOKEN_OPERATOR_PLUS");
880             fTokenNames.put(new Integer JavaDoc(EXPRTOKEN_OPERATOR_MINUS), "EXPRTOKEN_OPERATOR_MINUS");
881             fTokenNames.put(new Integer JavaDoc(EXPRTOKEN_OPERATOR_EQUAL), "EXPRTOKEN_OPERATOR_EQUAL");
882             fTokenNames.put(new Integer JavaDoc(EXPRTOKEN_OPERATOR_NOT_EQUAL), "EXPRTOKEN_OPERATOR_NOT_EQUAL");
883             fTokenNames.put(new Integer JavaDoc(EXPRTOKEN_OPERATOR_LESS), "EXPRTOKEN_OPERATOR_LESS");
884             fTokenNames.put(new Integer JavaDoc(EXPRTOKEN_OPERATOR_LESS_EQUAL), "EXPRTOKEN_OPERATOR_LESS_EQUAL");
885             fTokenNames.put(new Integer JavaDoc(EXPRTOKEN_OPERATOR_GREATER), "EXPRTOKEN_OPERATOR_GREATER");
886             fTokenNames.put(new Integer JavaDoc(EXPRTOKEN_OPERATOR_GREATER_EQUAL), "EXPRTOKEN_OPERATOR_GREATER_EQUAL");
887             fTokenNames.put(new Integer JavaDoc(EXPRTOKEN_FUNCTION_NAME), "EXPRTOKEN_FUNCTION_NAME");
888             fTokenNames.put(new Integer JavaDoc(EXPRTOKEN_AXISNAME_ANCESTOR), "EXPRTOKEN_AXISNAME_ANCESTOR");
889             fTokenNames.put(new Integer JavaDoc(EXPRTOKEN_AXISNAME_ANCESTOR_OR_SELF), "EXPRTOKEN_AXISNAME_ANCESTOR_OR_SELF");
890             fTokenNames.put(new Integer JavaDoc(EXPRTOKEN_AXISNAME_ATTRIBUTE), "EXPRTOKEN_AXISNAME_ATTRIBUTE");
891             fTokenNames.put(new Integer JavaDoc(EXPRTOKEN_AXISNAME_CHILD), "EXPRTOKEN_AXISNAME_CHILD");
892             fTokenNames.put(new Integer JavaDoc(EXPRTOKEN_AXISNAME_DESCENDANT), "EXPRTOKEN_AXISNAME_DESCENDANT");
893             fTokenNames.put(new Integer JavaDoc(EXPRTOKEN_AXISNAME_DESCENDANT_OR_SELF), "EXPRTOKEN_AXISNAME_DESCENDANT_OR_SELF");
894             fTokenNames.put(new Integer JavaDoc(EXPRTOKEN_AXISNAME_FOLLOWING), "EXPRTOKEN_AXISNAME_FOLLOWING");
895             fTokenNames.put(new Integer JavaDoc(EXPRTOKEN_AXISNAME_FOLLOWING_SIBLING), "EXPRTOKEN_AXISNAME_FOLLOWING_SIBLING");
896             fTokenNames.put(new Integer JavaDoc(EXPRTOKEN_AXISNAME_NAMESPACE), "EXPRTOKEN_AXISNAME_NAMESPACE");
897             fTokenNames.put(new Integer JavaDoc(EXPRTOKEN_AXISNAME_PARENT), "EXPRTOKEN_AXISNAME_PARENT");
898             fTokenNames.put(new Integer JavaDoc(EXPRTOKEN_AXISNAME_PRECEDING), "EXPRTOKEN_AXISNAME_PRECEDING");
899             fTokenNames.put(new Integer JavaDoc(EXPRTOKEN_AXISNAME_PRECEDING_SIBLING), "EXPRTOKEN_AXISNAME_PRECEDING_SIBLING");
900             fTokenNames.put(new Integer JavaDoc(EXPRTOKEN_AXISNAME_SELF), "EXPRTOKEN_AXISNAME_SELF");
901             fTokenNames.put(new Integer JavaDoc(EXPRTOKEN_LITERAL), "EXPRTOKEN_LITERAL");
902             fTokenNames.put(new Integer JavaDoc(EXPRTOKEN_NUMBER), "EXPRTOKEN_NUMBER");
903             fTokenNames.put(new Integer JavaDoc(EXPRTOKEN_VARIABLE_REFERENCE), "EXPRTOKEN_VARIABLE_REFERENCE");
904         }
905
906         //
907
// Public methods
908
//
909

910 // public String getTokenName(int token) {
911
// if (token < 0 || token >= fgTokenNames.length)
912
// return null;
913
// return fgTokenNames[token];
914
// }
915
//
916
public String JavaDoc getTokenString(int token) {
917             return (String JavaDoc)fTokenNames.get(new Integer JavaDoc(token));
918         }
919
920         public void addToken(String JavaDoc tokenStr) {
921             Integer JavaDoc tokenInt = (Integer JavaDoc)fTokenNames.get(tokenStr);
922             if (tokenInt == null) {
923                 tokenInt = new Integer JavaDoc(fTokenNames.size());
924                 fTokenNames.put(tokenInt, tokenStr);
925             }
926             addToken(tokenInt.intValue());
927         }
928
929         public void addToken(int token) {
930             try {
931                 fTokens[fTokenCount] = token;
932             } catch (ArrayIndexOutOfBoundsException JavaDoc ex) {
933                 int[] oldList = fTokens;
934                 fTokens = new int[fTokenCount << 1];
935                 System.arraycopy(oldList, 0, fTokens, 0, fTokenCount);
936                 fTokens[fTokenCount] = token;
937             }
938             fTokenCount++;
939         }
940 // public int getTokenCount() {
941
// return fTokenCount;
942
// }
943
// public int getToken(int tokenIndex) {
944
// return fTokens[tokenIndex];
945
// }
946

947         /**
948          * Resets the current position to the head of the token list.
949          */

950         public void rewind() {
951             fCurrentTokenIndex=0;
952         }
953         /**
954          * Returns true if the {@link #getNextToken()} method
955          * returns a valid token.
956          */

957         public boolean hasMore() {
958             return fCurrentTokenIndex<fTokenCount;
959         }
960         /**
961          * Obtains the token at the current position, then advance
962          * the current position by one.
963          *
964          * If there's no such next token, this method throws
965          * <tt>new XPathException("c-general-xpath");</tt>.
966          */

967         public int nextToken() throws XPathException {
968             if( fCurrentTokenIndex==fTokenCount )
969                 throw new XPathException("c-general-xpath");
970             return fTokens[fCurrentTokenIndex++];
971         }
972         /**
973          * Obtains the token at the current position, without advancing
974          * the current position.
975          *
976          * If there's no such next token, this method throws
977          * <tt>new XPathException("c-general-xpath");</tt>.
978          */

979         public int peekToken() throws XPathException {
980             if( fCurrentTokenIndex==fTokenCount )
981                 throw new XPathException("c-general-xpath");
982             return fTokens[fCurrentTokenIndex];
983         }
984         /**
985          * Obtains the token at the current position as a String.
986          *
987          * If there's no current token or if the current token
988          * is not a string token, this method throws
989          * <tt>new XPathException("c-general-xpath");</tt>.
990          */

991         public String JavaDoc nextTokenAsString() throws XPathException {
992             String JavaDoc s = getTokenString(nextToken());
993             if(s==null) throw new XPathException("c-general-xpath");
994             return s;
995         }
996         
997         public void dumpTokens() {
998             //if (DUMP_TOKENS) {
999
for (int i = 0; i < fTokenCount; i++) {
1000                    switch (fTokens[i]) {
1001                    case EXPRTOKEN_OPEN_PAREN:
1002                        System.out.print("<OPEN_PAREN/>");
1003                        break;
1004                    case EXPRTOKEN_CLOSE_PAREN:
1005                        System.out.print("<CLOSE_PAREN/>");
1006                        break;
1007                    case EXPRTOKEN_OPEN_BRACKET:
1008                        System.out.print("<OPEN_BRACKET/>");
1009                        break;
1010                    case EXPRTOKEN_CLOSE_BRACKET:
1011                        System.out.print("<CLOSE_BRACKET/>");
1012                        break;
1013                    case EXPRTOKEN_PERIOD:
1014                        System.out.print("<PERIOD/>");
1015                        break;
1016                    case EXPRTOKEN_DOUBLE_PERIOD:
1017                        System.out.print("<DOUBLE_PERIOD/>");
1018                        break;
1019                    case EXPRTOKEN_ATSIGN:
1020                        System.out.print("<ATSIGN/>");
1021                        break;
1022                    case EXPRTOKEN_COMMA:
1023                        System.out.print("<COMMA/>");
1024                        break;
1025                    case EXPRTOKEN_DOUBLE_COLON:
1026                        System.out.print("<DOUBLE_COLON/>");
1027                        break;
1028                    case EXPRTOKEN_NAMETEST_ANY:
1029                        System.out.print("<NAMETEST_ANY/>");
1030                        break;
1031                    case EXPRTOKEN_NAMETEST_NAMESPACE:
1032                        System.out.print("<NAMETEST_NAMESPACE");
1033                        System.out.print(" prefix=\"" + getTokenString(fTokens[++i]) + "\"");
1034                        System.out.print("/>");
1035                        break;
1036                    case EXPRTOKEN_NAMETEST_QNAME:
1037                        System.out.print("<NAMETEST_QNAME");
1038                        if (fTokens[++i] != -1)
1039                            System.out.print(" prefix=\"" + getTokenString(fTokens[i]) + "\"");
1040                        System.out.print(" localpart=\"" + getTokenString(fTokens[++i]) + "\"");
1041                        System.out.print("/>");
1042                        break;
1043                    case EXPRTOKEN_NODETYPE_COMMENT:
1044                        System.out.print("<NODETYPE_COMMENT/>");
1045                        break;
1046                    case EXPRTOKEN_NODETYPE_TEXT:
1047                        System.out.print("<NODETYPE_TEXT/>");
1048                        break;
1049                    case EXPRTOKEN_NODETYPE_PI:
1050                        System.out.print("<NODETYPE_PI/>");
1051                        break;
1052                    case EXPRTOKEN_NODETYPE_NODE:
1053                        System.out.print("<NODETYPE_NODE/>");
1054                        break;
1055                    case EXPRTOKEN_OPERATOR_AND:
1056                        System.out.print("<OPERATOR_AND/>");
1057                        break;
1058                    case EXPRTOKEN_OPERATOR_OR:
1059                        System.out.print("<OPERATOR_OR/>");
1060                        break;
1061                    case EXPRTOKEN_OPERATOR_MOD:
1062                        System.out.print("<OPERATOR_MOD/>");
1063                        break;
1064                    case EXPRTOKEN_OPERATOR_DIV:
1065                        System.out.print("<OPERATOR_DIV/>");
1066                        break;
1067                    case EXPRTOKEN_OPERATOR_MULT:
1068                        System.out.print("<OPERATOR_MULT/>");
1069                        break;
1070                    case EXPRTOKEN_OPERATOR_SLASH:
1071                        System.out.print("<OPERATOR_SLASH/>");
1072                        if (i + 1 < fTokenCount) {
1073                            System.out.println();
1074                            System.out.print(" ");
1075                        }
1076                        break;
1077                    case EXPRTOKEN_OPERATOR_DOUBLE_SLASH:
1078                        System.out.print("<OPERATOR_DOUBLE_SLASH/>");
1079                        break;
1080                    case EXPRTOKEN_OPERATOR_UNION:
1081                        System.out.print("<OPERATOR_UNION/>");
1082                        break;
1083                    case EXPRTOKEN_OPERATOR_PLUS:
1084                        System.out.print("<OPERATOR_PLUS/>");
1085                        break;
1086                    case EXPRTOKEN_OPERATOR_MINUS:
1087                        System.out.print("<OPERATOR_MINUS/>");
1088                        break;
1089                    case EXPRTOKEN_OPERATOR_EQUAL:
1090                        System.out.print("<OPERATOR_EQUAL/>");
1091                        break;
1092                    case EXPRTOKEN_OPERATOR_NOT_EQUAL:
1093                        System.out.print("<OPERATOR_NOT_EQUAL/>");
1094                        break;
1095                    case EXPRTOKEN_OPERATOR_LESS:
1096                        System.out.print("<OPERATOR_LESS/>");
1097                        break;
1098                    case EXPRTOKEN_OPERATOR_LESS_EQUAL:
1099                        System.out.print("<OPERATOR_LESS_EQUAL/>");
1100                        break;
1101                    case EXPRTOKEN_OPERATOR_GREATER:
1102                        System.out.print("<OPERATOR_GREATER/>");
1103                        break;
1104                    case EXPRTOKEN_OPERATOR_GREATER_EQUAL:
1105                        System.out.print("<OPERATOR_GREATER_EQUAL/>");
1106                        break;
1107                    case EXPRTOKEN_FUNCTION_NAME:
1108                        System.out.print("<FUNCTION_NAME");
1109                        if (fTokens[++i] != -1)
1110                            System.out.print(" prefix=\"" + getTokenString(fTokens[i]) + "\"");
1111                        System.out.print(" localpart=\"" + getTokenString(fTokens[++i]) + "\"");
1112                        System.out.print("/>");
1113                        break;
1114                    case EXPRTOKEN_AXISNAME_ANCESTOR:
1115                        System.out.print("<AXISNAME_ANCESTOR/>");
1116                        break;
1117                    case EXPRTOKEN_AXISNAME_ANCESTOR_OR_SELF:
1118                        System.out.print("<AXISNAME_ANCESTOR_OR_SELF/>");
1119                        break;
1120                    case EXPRTOKEN_AXISNAME_ATTRIBUTE:
1121                        System.out.print("<AXISNAME_ATTRIBUTE/>");
1122                        break;
1123                    case EXPRTOKEN_AXISNAME_CHILD:
1124                        System.out.print("<AXISNAME_CHILD/>");
1125                        break;
1126                    case EXPRTOKEN_AXISNAME_DESCENDANT:
1127                        System.out.print("<AXISNAME_DESCENDANT/>");
1128                        break;
1129                    case EXPRTOKEN_AXISNAME_DESCENDANT_OR_SELF:
1130                        System.out.print("<AXISNAME_DESCENDANT_OR_SELF/>");
1131                        break;
1132                    case EXPRTOKEN_AXISNAME_FOLLOWING:
1133                        System.out.print("<AXISNAME_FOLLOWING/>");
1134                        break;
1135                    case EXPRTOKEN_AXISNAME_FOLLOWING_SIBLING:
1136                        System.out.print("<AXISNAME_FOLLOWING_SIBLING/>");
1137                        break;
1138                    case EXPRTOKEN_AXISNAME_NAMESPACE:
1139                        System.out.print("<AXISNAME_NAMESPACE/>");
1140                        break;
1141                    case EXPRTOKEN_AXISNAME_PARENT:
1142                        System.out.print("<AXISNAME_PARENT/>");
1143                        break;
1144                    case EXPRTOKEN_AXISNAME_PRECEDING:
1145                        System.out.print("<AXISNAME_PRECEDING/>");
1146                        break;
1147                    case EXPRTOKEN_AXISNAME_PRECEDING_SIBLING:
1148                        System.out.print("<AXISNAME_PRECEDING_SIBLING/>");
1149                        break;
1150                    case EXPRTOKEN_AXISNAME_SELF:
1151                        System.out.print("<AXISNAME_SELF/>");
1152                        break;
1153                    case EXPRTOKEN_LITERAL:
1154                        System.out.print("<LITERAL");
1155                        System.out.print(" value=\"" + getTokenString(fTokens[++i]) + "\"");
1156                        System.out.print("/>");
1157                        break;
1158                    case EXPRTOKEN_NUMBER:
1159                        System.out.print("<NUMBER");
1160                        System.out.print(" whole=\"" + getTokenString(fTokens[++i]) + "\"");
1161                        System.out.print(" part=\"" + getTokenString(fTokens[++i]) + "\"");
1162                        System.out.print("/>");
1163                        break;
1164                    case EXPRTOKEN_VARIABLE_REFERENCE:
1165                        System.out.print("<VARIABLE_REFERENCE");
1166                        if (fTokens[++i] != -1)
1167                            System.out.print(" prefix=\"" + getTokenString(fTokens[i]) + "\"");
1168                        System.out.print(" localpart=\"" + getTokenString(fTokens[++i]) + "\"");
1169                        System.out.print("/>");
1170                        break;
1171                    default:
1172                        System.out.println("<???/>");
1173                    }
1174                }
1175                System.out.println();
1176            //}
1177
}
1178
1179    } // class Tokens
1180

1181    /**
1182     * @xerces.internal
1183     *
1184     * @author Glenn Marcy, IBM
1185     * @author Andy Clark, IBM
1186     *
1187     * @version $Id: XPath.java,v 1.18 2005/03/07 23:28:41 mrglavas Exp $
1188     */

1189    private static class Scanner {
1190
1191        /**
1192         * 7-bit ASCII subset
1193         *
1194         * 0 1 2 3 4 5 6 7 8 9 A B C D E F
1195         * 0, 0, 0, 0, 0, 0, 0, 0, 0, HT, LF, 0, 0, CR, 0, 0, // 0
1196         * 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1
1197         * SP, !, ", #, $, %, &, ', (, ), *, +, ,, -, ., /, // 2
1198         * 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, :, ;, <, =, >, ?, // 3
1199         * @, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, // 4
1200         * P, Q, R, S, T, U, V, W, X, Y, Z, [, \, ], ^, _, // 5
1201         * `, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, // 6
1202         * p, q, r, s, t, u, v, w, x, y, z, {, |, }, ~, DEL // 7
1203         */

1204        private static final byte
1205            CHARTYPE_INVALID = 0, // invalid XML character
1206
CHARTYPE_OTHER = 1, // not special - one of "#%&;?\^`{}~" or DEL
1207
CHARTYPE_WHITESPACE = 2, // one of "\t\n\r " (0x09, 0x0A, 0x0D, 0x20)
1208
CHARTYPE_EXCLAMATION = 3, // '!' (0x21)
1209
CHARTYPE_QUOTE = 4, // '\"' or '\'' (0x22 and 0x27)
1210
CHARTYPE_DOLLAR = 5, // '$' (0x24)
1211
CHARTYPE_OPEN_PAREN = 6, // '(' (0x28)
1212
CHARTYPE_CLOSE_PAREN = 7, // ')' (0x29)
1213
CHARTYPE_STAR = 8, // '*' (0x2A)
1214
CHARTYPE_PLUS = 9, // '+' (0x2B)
1215
CHARTYPE_COMMA = 10, // ',' (0x2C)
1216
CHARTYPE_MINUS = 11, // '-' (0x2D)
1217
CHARTYPE_PERIOD = 12, // '.' (0x2E)
1218
CHARTYPE_SLASH = 13, // '/' (0x2F)
1219
CHARTYPE_DIGIT = 14, // '0'-'9' (0x30 to 0x39)
1220
CHARTYPE_COLON = 15, // ':' (0x3A)
1221
CHARTYPE_LESS = 16, // '<' (0x3C)
1222
CHARTYPE_EQUAL = 17, // '=' (0x3D)
1223
CHARTYPE_GREATER = 18, // '>' (0x3E)
1224
CHARTYPE_ATSIGN = 19, // '@' (0x40)
1225
CHARTYPE_LETTER = 20, // 'A'-'Z' or 'a'-'z' (0x41 to 0x5A and 0x61 to 0x7A)
1226
CHARTYPE_OPEN_BRACKET = 21, // '[' (0x5B)
1227
CHARTYPE_CLOSE_BRACKET = 22, // ']' (0x5D)
1228
CHARTYPE_UNDERSCORE = 23, // '_' (0x5F)
1229
CHARTYPE_UNION = 24, // '|' (0x7C)
1230
CHARTYPE_NONASCII = 25; // Non-ASCII Unicode codepoint (>= 0x80)
1231

1232        private static final byte[] fASCIICharMap = {
1233            0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 2, 0, 0,
1234            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1235            2, 3, 4, 1, 5, 1, 1, 4, 6, 7, 8, 9, 10, 11, 12, 13,
1236           14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 1, 16, 17, 18, 1,
1237           19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1238           20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 1, 22, 1, 23,
1239            1, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1240           20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 1, 24, 1, 1, 1
1241        };
1242
1243        /**
1244         * Symbol literals
1245         */

1246
1247        //
1248
// Data
1249
//
1250

1251        /** Symbol table. */
1252        private SymbolTable fSymbolTable;
1253
1254        // symbols
1255

1256        private static final String JavaDoc fAndSymbol = "and".intern();
1257        private static final String JavaDoc fOrSymbol = "or".intern();
1258        private static final String JavaDoc fModSymbol = "mod".intern();
1259        private static final String JavaDoc fDivSymbol = "div".intern();
1260
1261        private static final String JavaDoc fCommentSymbol = "comment".intern();
1262        private static final String JavaDoc fTextSymbol = "text".intern();
1263        private static final String JavaDoc fPISymbol = "processing-instruction".intern();
1264        private static final String JavaDoc fNodeSymbol = "node".intern();
1265
1266        private static final String JavaDoc fAncestorSymbol = "ancestor".intern();
1267        private static final String JavaDoc fAncestorOrSelfSymbol = "ancestor-or-self".intern();
1268        private static final String JavaDoc fAttributeSymbol = "attribute".intern();
1269        private static final String JavaDoc fChildSymbol = "child".intern();
1270        private static final String JavaDoc fDescendantSymbol = "descendant".intern();
1271        private static final String JavaDoc fDescendantOrSelfSymbol = "descendant-or-self".intern();
1272        private static final String JavaDoc fFollowingSymbol = "following".intern();
1273        private static final String JavaDoc fFollowingSiblingSymbol = "following-sibling".intern();
1274        private static final String JavaDoc fNamespaceSymbol = "namespace".intern();
1275        private static final String JavaDoc fParentSymbol = "parent".intern();
1276        private static final String JavaDoc fPrecedingSymbol = "preceding".intern();
1277        private static final String JavaDoc fPrecedingSiblingSymbol = "preceding-sibling".intern();
1278        private static final String JavaDoc fSelfSymbol = "self".intern();
1279
1280        //
1281
// Constructors
1282
//
1283

1284        /** Constructs an XPath expression scanner. */
1285        public Scanner(SymbolTable symbolTable) {
1286
1287            // save pool and tokens
1288
fSymbolTable = symbolTable;
1289
1290        } // <init>(SymbolTable)
1291

1292        /**
1293         *
1294         */

1295        public boolean scanExpr(SymbolTable symbolTable,
1296                                XPath.Tokens tokens, String JavaDoc data,
1297                                int currentOffset, int endOffset)
1298            throws XPathException {
1299
1300            int nameOffset;
1301            String JavaDoc nameHandle, prefixHandle;
1302            boolean starIsMultiplyOperator = false;
1303            int ch;
1304
1305            while (true) {
1306                if (currentOffset == endOffset) {
1307                    break;
1308                }
1309                ch = data.charAt(currentOffset);
1310                //
1311
// [39] ExprWhitespace ::= S
1312
//
1313
while (ch == ' ' || ch == 0x0A || ch == 0x09 || ch == 0x0D) {
1314                    if (++currentOffset == endOffset) {
1315                        break;
1316                    }
1317                    ch = data.charAt(currentOffset);
1318                }
1319                if (currentOffset == endOffset) {
1320                    break;
1321                }
1322                //
1323
// [28] ExprToken ::= '(' | ')' | '[' | ']' | '.' | '..' | '@' | ',' | '::'
1324
// | NameTest | NodeType | Operator | FunctionName
1325
// | AxisName | Literal | Number | VariableReference
1326
//
1327
byte chartype = (ch >= 0x80) ? CHARTYPE_NONASCII : fASCIICharMap[ch];
1328                switch (chartype) {
1329                case CHARTYPE_OPEN_PAREN: // '('
1330
addToken(tokens, XPath.Tokens.EXPRTOKEN_OPEN_PAREN);
1331                    starIsMultiplyOperator = false;
1332                    if (++currentOffset == endOffset) {
1333                        break;
1334                    }
1335                    break;
1336                case CHARTYPE_CLOSE_PAREN: // ')'
1337
addToken(tokens, XPath.Tokens.EXPRTOKEN_CLOSE_PAREN);
1338                    starIsMultiplyOperator = true;
1339                    if (++currentOffset == endOffset) {
1340                        break;
1341                    }
1342                    break;
1343                case CHARTYPE_OPEN_BRACKET: // '['
1344
addToken(tokens, XPath.Tokens.EXPRTOKEN_OPEN_BRACKET);
1345                    starIsMultiplyOperator = false;
1346                    if (++currentOffset == endOffset) {
1347                        break;
1348                    }
1349                    break;
1350                case CHARTYPE_CLOSE_BRACKET: // ']'
1351
addToken(tokens, XPath.Tokens.EXPRTOKEN_CLOSE_BRACKET);
1352                    starIsMultiplyOperator = true;
1353                    if (++currentOffset == endOffset) {
1354                        break;
1355                    }
1356                    break;
1357                //
1358
// [30] Number ::= Digits ('.' Digits?)? | '.' Digits
1359
// ^^^^^^^^^^
1360
//
1361
case CHARTYPE_PERIOD: // '.', '..' or '.' Digits
1362
if (currentOffset + 1 == endOffset) {
1363                        addToken(tokens, XPath.Tokens.EXPRTOKEN_PERIOD);
1364                        starIsMultiplyOperator = true;
1365                        currentOffset++;
1366                        break;
1367                    }
1368                    ch = data.charAt(currentOffset + 1);
1369                    if (ch == '.') { // '..'
1370
addToken(tokens, XPath.Tokens.EXPRTOKEN_DOUBLE_PERIOD);
1371                        starIsMultiplyOperator = true;
1372                        currentOffset += 2;
1373                    } else if (ch >= '0' && ch <= '9') {
1374                        addToken(tokens, XPath.Tokens.EXPRTOKEN_NUMBER);
1375                        starIsMultiplyOperator = true;
1376                        currentOffset = scanNumber(tokens, data, endOffset, currentOffset/*, encoding*/);
1377                    } else if (ch == '/') {
1378                        addToken(tokens, XPath.Tokens.EXPRTOKEN_PERIOD);
1379                        starIsMultiplyOperator = true;
1380                        currentOffset++;
1381                    } else if (ch == '|') {
1382                        addToken(tokens, XPath.Tokens.EXPRTOKEN_PERIOD);
1383                        starIsMultiplyOperator = true;
1384                        currentOffset++;
1385                        break;
1386                    } else if (ch == ' ' || ch == 0x0A || ch == 0x09 || ch == 0x0D) {
1387                        // this is legal if the next token is non-existent or |
1388
do {
1389                            if (++currentOffset == endOffset) {
1390                                break;
1391                            }
1392                            ch = data.charAt(currentOffset);
1393                        } while (ch == ' ' || ch == 0x0A || ch == 0x09 || ch == 0x0D);
1394                        if (currentOffset == endOffset || ch == '|') {
1395                            addToken(tokens, XPath.Tokens.EXPRTOKEN_PERIOD);
1396                            starIsMultiplyOperator = true;
1397                            break;
1398                        }
1399                        throw new XPathException ("c-general-xpath");
1400                    } else { // '.'
1401
throw new XPathException ("c-general-xpath");
1402                    }
1403                    if (currentOffset == endOffset) {
1404                        break;
1405                    }
1406                    break;
1407                case CHARTYPE_ATSIGN: // '@'
1408
addToken(tokens, XPath.Tokens.EXPRTOKEN_ATSIGN);
1409                    starIsMultiplyOperator = false;
1410                    if (++currentOffset == endOffset) {
1411                        break;
1412                    }
1413                    break;
1414                case CHARTYPE_COMMA: // ','
1415
addToken(tokens, XPath.Tokens.EXPRTOKEN_COMMA);
1416                    starIsMultiplyOperator = false;
1417                    if (++currentOffset == endOffset) {
1418                        break;
1419                    }
1420                    break;
1421                case CHARTYPE_COLON: // '::'
1422
if (++currentOffset == endOffset) {
1423                // System.out.println("abort 1a");
1424
return false; // REVISIT
1425
}
1426                    ch = data.charAt(currentOffset);
1427                    if (ch != ':') {
1428                // System.out.println("abort 1b");
1429
return false; // REVISIT
1430
}
1431                    addToken(tokens, XPath.Tokens.EXPRTOKEN_DOUBLE_COLON);
1432                    starIsMultiplyOperator = false;
1433                    if (++currentOffset == endOffset) {
1434                        break;
1435                    }
1436                    break;
1437                case CHARTYPE_SLASH: // '/' and '//'
1438
if (++currentOffset == endOffset) {
1439                        addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_SLASH);
1440                        starIsMultiplyOperator = false;
1441                        break;
1442                    }
1443                    ch = data.charAt(currentOffset);
1444                    if (ch == '/') { // '//'
1445
addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_DOUBLE_SLASH);
1446                        starIsMultiplyOperator = false;
1447                        if (++currentOffset == endOffset) {
1448                            break;
1449                        }
1450                    } else {
1451                        addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_SLASH);
1452                        starIsMultiplyOperator = false;
1453                    }
1454                    break;
1455                case CHARTYPE_UNION: // '|'
1456
addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_UNION);
1457                    starIsMultiplyOperator = false;
1458                    if (++currentOffset == endOffset) {
1459                        break;
1460                    }
1461                    break;
1462                case CHARTYPE_PLUS: // '+'
1463
addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_PLUS);
1464                    starIsMultiplyOperator = false;
1465                    if (++currentOffset == endOffset) {
1466                        break;
1467                    }
1468                    break;
1469                case CHARTYPE_MINUS: // '-'
1470
addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_MINUS);
1471                    starIsMultiplyOperator = false;
1472                    if (++currentOffset == endOffset) {
1473                        break;
1474                    }
1475                    break;
1476                case CHARTYPE_EQUAL: // '='
1477
addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_EQUAL);
1478                    starIsMultiplyOperator = false;
1479                    if (++currentOffset == endOffset) {
1480                        break;
1481                    }
1482                    break;
1483                case CHARTYPE_EXCLAMATION: // '!='
1484
if (++currentOffset == endOffset) {
1485                // System.out.println("abort 2a");
1486
return false; // REVISIT
1487
}
1488                    ch = data.charAt(currentOffset);
1489                    if (ch != '=') {
1490                // System.out.println("abort 2b");
1491
return false; // REVISIT
1492
}
1493                    addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_NOT_EQUAL);
1494                    starIsMultiplyOperator = false;
1495                    if (++currentOffset == endOffset) {
1496                        break;
1497                    }
1498                    break;
1499                case CHARTYPE_LESS: // '<' and '<='
1500
if (++currentOffset == endOffset) {
1501                        addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_LESS);
1502                        starIsMultiplyOperator = false;
1503                        break;
1504                    }
1505                    ch = data.charAt(currentOffset);
1506                    if (ch == '=') { // '<='
1507
addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_LESS_EQUAL);
1508                        starIsMultiplyOperator = false;
1509                        if (++currentOffset == endOffset) {
1510                            break;
1511                        }
1512                    } else {
1513                        addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_LESS);
1514                        starIsMultiplyOperator = false;
1515                    }
1516                    break;
1517                case CHARTYPE_GREATER: // '>' and '>='
1518
if (++currentOffset == endOffset) {
1519                        addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_GREATER);
1520                        starIsMultiplyOperator = false;
1521                        break;
1522                    }
1523                    ch = data.charAt(currentOffset);
1524                    if (ch == '=') { // '>='
1525
addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_GREATER_EQUAL);
1526                        starIsMultiplyOperator = false;
1527                        if (++currentOffset == endOffset) {
1528                            break;
1529                        }
1530                    } else {
1531                        addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_GREATER);
1532                        starIsMultiplyOperator = false;
1533                    }
1534                    break;
1535                //
1536
// [29] Literal ::= '"' [^"]* '"' | "'" [^']* "'"
1537
//
1538
case CHARTYPE_QUOTE: // '\"' or '\''
1539
int qchar = ch;
1540                    if (++currentOffset == endOffset) {
1541                // System.out.println("abort 2c");
1542
return false; // REVISIT
1543
}
1544                    ch = data.charAt(currentOffset);
1545                    int litOffset = currentOffset;
1546                    while (ch != qchar) {
1547                        if (++currentOffset == endOffset) {
1548                // System.out.println("abort 2d");
1549
return false; // REVISIT
1550
}
1551                        ch = data.charAt(currentOffset);
1552                    }
1553                    int litLength = currentOffset - litOffset;
1554                    addToken(tokens, XPath.Tokens.EXPRTOKEN_LITERAL);
1555                    starIsMultiplyOperator = true;
1556                    tokens.addToken(symbolTable.addSymbol(data.substring(litOffset, litOffset + litLength)));
1557                    if (++currentOffset == endOffset) {
1558                        break;
1559                    }
1560                    break;
1561                //
1562
// [30] Number ::= Digits ('.' Digits?)? | '.' Digits
1563
// [31] Digits ::= [0-9]+
1564
//
1565
case CHARTYPE_DIGIT:
1566                    addToken(tokens, XPath.Tokens.EXPRTOKEN_NUMBER);
1567                    starIsMultiplyOperator = true;
1568                    currentOffset = scanNumber(tokens, data, endOffset, currentOffset/*, encoding*/);
1569                    break;
1570                //
1571
// [36] VariableReference ::= '$' QName
1572
//
1573
case CHARTYPE_DOLLAR:
1574                    if (++currentOffset == endOffset) {
1575                // System.out.println("abort 3a");
1576
return false; // REVISIT
1577
}
1578                    nameOffset = currentOffset;
1579                    currentOffset = scanNCName(data, endOffset, currentOffset);
1580                    if (currentOffset == nameOffset) {
1581                // System.out.println("abort 3b");
1582
return false; // REVISIT
1583
}
1584                    if (currentOffset < endOffset) {
1585                        ch = data.charAt(currentOffset);
1586                    }
1587                    else {
1588                        ch = -1;
1589                    }
1590                    nameHandle = symbolTable.addSymbol(data.substring(nameOffset, currentOffset));
1591                    if (ch != ':') {
1592                        prefixHandle = XMLSymbols.EMPTY_STRING;
1593                    } else {
1594                        prefixHandle = nameHandle;
1595                        if (++currentOffset == endOffset) {
1596                // System.out.println("abort 4a");
1597
return false; // REVISIT
1598
}
1599                        nameOffset = currentOffset;
1600                        currentOffset = scanNCName(data, endOffset, currentOffset);
1601                        if (currentOffset == nameOffset) {
1602                // System.out.println("abort 4b");
1603
return false; // REVISIT
1604
}
1605                        if (currentOffset < endOffset) {
1606                            ch = data.charAt(currentOffset);
1607                        }
1608                        else {
1609                            ch = -1;
1610                        }
1611                        nameHandle = symbolTable.addSymbol(data.substring(nameOffset, currentOffset));
1612                    }
1613                    addToken(tokens, XPath.Tokens.EXPRTOKEN_VARIABLE_REFERENCE);
1614                    starIsMultiplyOperator = true;
1615                    tokens.addToken(prefixHandle);
1616                    tokens.addToken(nameHandle);
1617                    break;
1618                //
1619
// [37] NameTest ::= '*' | NCName ':' '*' | QName
1620
// [34] MultiplyOperator ::= '*'
1621
//
1622
case CHARTYPE_STAR: // '*'
1623
//
1624
// 3.7 Lexical Structure
1625
//
1626
// If there is a preceding token and the preceding token is not one of @, ::, (, [, , or
1627
// an Operator, then a * must be recognized as a MultiplyOperator.
1628
//
1629
// Otherwise, the token must not be recognized as a MultiplyOperator.
1630
//
1631
if (starIsMultiplyOperator) {
1632                        addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_MULT);
1633                        starIsMultiplyOperator = false;
1634                    } else {
1635                        addToken(tokens, XPath.Tokens.EXPRTOKEN_NAMETEST_ANY);
1636                        starIsMultiplyOperator = true;
1637                    }
1638                    if (++currentOffset == endOffset) {
1639                        break;
1640                    }
1641                    break;
1642                //
1643
// NCName, QName and non-terminals
1644
//
1645
case CHARTYPE_NONASCII: // possibly a valid non-ascii 'Letter' (BaseChar | Ideographic)
1646
case CHARTYPE_LETTER:
1647                case CHARTYPE_UNDERSCORE:
1648                    //
1649
// 3.7 Lexical Structure
1650
//
1651
// If there is a preceding token and the preceding token is not one of @, ::, (, [, , or
1652
// an Operator, then an NCName must be recognized as an OperatorName.
1653
//
1654
// If the character following an NCName (possibly after intervening ExprWhitespace) is (,
1655
// then the token must be recognized as a NodeType or a FunctionName.
1656
//
1657
// If the two characters following an NCName (possibly after intervening ExprWhitespace)
1658
// are ::, then the token must be recognized as an AxisName.
1659
//
1660
// Otherwise, the token must not be recognized as an OperatorName, a NodeType, a
1661
// FunctionName, or an AxisName.
1662
//
1663
// [33] OperatorName ::= 'and' | 'or' | 'mod' | 'div'
1664
// [38] NodeType ::= 'comment' | 'text' | 'processing-instruction' | 'node'
1665
// [35] FunctionName ::= QName - NodeType
1666
// [6] AxisName ::= (see above)
1667
//
1668
// [37] NameTest ::= '*' | NCName ':' '*' | QName
1669
// [5] NCName ::= (Letter | '_') (NCNameChar)*
1670
// [?] NCNameChar ::= Letter | Digit | '.' | '-' | '_' (ascii subset of 'NCNameChar')
1671
// [?] QName ::= (NCName ':')? NCName
1672
// [?] Letter ::= [A-Za-z] (ascii subset of 'Letter')
1673
// [?] Digit ::= [0-9] (ascii subset of 'Digit')
1674
//
1675
nameOffset = currentOffset;
1676                    currentOffset = scanNCName(data, endOffset, currentOffset);
1677                    if (currentOffset == nameOffset) {
1678                // System.out.println("abort 4c");
1679
return false; // REVISIT
1680
}
1681                    if (currentOffset < endOffset) {
1682                        ch = data.charAt(currentOffset);
1683                    }
1684                    else {
1685                        ch = -1;
1686                    }
1687                    nameHandle = symbolTable.addSymbol(data.substring(nameOffset, currentOffset));
1688                    boolean isNameTestNCName = false;
1689                    boolean isAxisName = false;
1690                    prefixHandle = XMLSymbols.EMPTY_STRING;
1691                    if (ch == ':') {
1692                        if (++currentOffset == endOffset) {
1693                // System.out.println("abort 5");
1694
return false; // REVISIT
1695
}
1696                        ch = data.charAt(currentOffset);
1697                        if (ch == '*') {
1698                            if (++currentOffset < endOffset) {
1699                                ch = data.charAt(currentOffset);
1700                            }
1701                            isNameTestNCName = true;
1702                        } else if (ch == ':') {
1703                            if (++currentOffset < endOffset) {
1704                                ch = data.charAt(currentOffset);
1705                            }
1706                            isAxisName = true;
1707                        } else {
1708                            prefixHandle = nameHandle;
1709                            nameOffset = currentOffset;
1710                            currentOffset = scanNCName(data, endOffset, currentOffset);
1711                            if (currentOffset == nameOffset) {
1712                // System.out.println("abort 5b");
1713
return false; // REVISIT
1714
}
1715                            if (currentOffset < endOffset) {
1716                                ch = data.charAt(currentOffset);
1717                            }
1718                            else {
1719                                ch = -1;
1720                            }
1721                            nameHandle = symbolTable.addSymbol(data.substring(nameOffset, currentOffset));
1722                        }
1723                    }
1724                    //
1725
// [39] ExprWhitespace ::= S
1726
//
1727
while (ch == ' ' || ch == 0x0A || ch == 0x09 || ch == 0x0D) {
1728                        if (++currentOffset == endOffset) {
1729                            break;
1730                        }
1731                        ch = data.charAt(currentOffset);
1732                    }
1733                    //
1734
// If there is a preceding token and the preceding token is not one of @, ::, (, [, , or
1735
// an Operator, then an NCName must be recognized as an OperatorName.
1736
//
1737
if (starIsMultiplyOperator) {
1738                        if (nameHandle == fAndSymbol) {
1739                            addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_AND);
1740                            starIsMultiplyOperator = false;
1741                        } else if (nameHandle == fOrSymbol) {
1742                            addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_OR);
1743                            starIsMultiplyOperator = false;
1744                        } else if (nameHandle == fModSymbol) {
1745                            addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_MOD);
1746                            starIsMultiplyOperator = false;
1747                        } else if (nameHandle == fDivSymbol) {
1748                            addToken(tokens, XPath.Tokens.EXPRTOKEN_OPERATOR_DIV);
1749                            starIsMultiplyOperator = false;
1750                        } else {
1751                // System.out.println("abort 6");
1752
return false; // REVISIT
1753
}
1754                        if (isNameTestNCName) {
1755                // System.out.println("abort 7");
1756
return false; // REVISIT - NCName:* where an OperatorName is required
1757
} else if (isAxisName) {
1758                // System.out.println("abort 8");
1759
return false; // REVISIT - AxisName:: where an OperatorName is required
1760
}
1761                        break;
1762                    }
1763                    //
1764
// If the character following an NCName (possibly after intervening ExprWhitespace) is (,
1765
// then the token must be recognized as a NodeType or a FunctionName.
1766
//
1767
if (ch == '(' && !isNameTestNCName && !isAxisName) {
1768                        if (nameHandle == fCommentSymbol) {
1769                            addToken(tokens, XPath.Tokens.EXPRTOKEN_NODETYPE_COMMENT);
1770                        } else if (nameHandle == fTextSymbol) {
1771                            addToken(tokens, XPath.Tokens.EXPRTOKEN_NODETYPE_TEXT);
1772                        } else if (nameHandle == fPISymbol) {
1773                            addToken(tokens, XPath.Tokens.EXPRTOKEN_NODETYPE_PI);
1774                        } else if (nameHandle == fNodeSymbol) {
1775                            addToken(tokens, XPath.Tokens.EXPRTOKEN_NODETYPE_NODE);
1776                        } else {
1777                            addToken(tokens, XPath.Tokens.EXPRTOKEN_FUNCTION_NAME);
1778                            tokens.addToken(prefixHandle);
1779                            tokens.addToken(nameHandle);
1780                        }
1781                        addToken(tokens, XPath.Tokens.EXPRTOKEN_OPEN_PAREN);
1782                        starIsMultiplyOperator = false;
1783                        if (++currentOffset == endOffset) {
1784                            break;
1785                        }
1786                        break;
1787                    }
1788                    //
1789
// If the two characters following an NCName (possibly after intervening ExprWhitespace)
1790
// are ::, then the token must be recognized as an AxisName.
1791
//
1792
if (isAxisName ||
1793                        (ch == ':' && currentOffset + 1 < endOffset &&
1794                         data.charAt(currentOffset + 1) == ':')) {
1795                        if (nameHandle == fAncestorSymbol) {
1796                            addToken(tokens, XPath.Tokens.EXPRTOKEN_AXISNAME_ANCESTOR);
1797                        } else if (nameHandle == fAncestorOrSelfSymbol) {
1798                            addToken(tokens, XPath.Tokens.EXPRTOKEN_AXISNAME_ANCESTOR_OR_SELF);
1799                        } else if (nameHandle == fAttributeSymbol) {
1800                            addToken(tokens, XPath.Tokens.EXPRTOKEN_AXISNAME_ATTRIBUTE);
1801                        } else if (nameHandle == fChildSymbol) {
1802                            addToken(tokens, XPath.Tokens.EXPRTOKEN_AXISNAME_CHILD);
1803                        } else if (nameHandle == fDescendantSymbol) {
1804                            addToken(tokens, XPath.Tokens.EXPRTOKEN_AXISNAME_DESCENDANT);
1805                        } else if (nameHandle == fDescendantOrSelfSymbol) {
1806                            addToken(tokens, XPath.Tokens.EXPRTOKEN_AXISNAME_DESCENDANT_OR_SELF);
1807                        } else if (nameHandle == fFollowingSymbol) {
1808                            addToken(tokens, XPath.Tokens.EXPRTOKEN_AXISNAME_FOLLOWING);
1809                        } else if (nameHandle == fFollowingSiblingSymbol) {
1810                            addToken(tokens, XPath.Tokens.EXPRTOKEN_AXISNAME_FOLLOWING_SIBLING);
1811                        } else if (nameHandle == fNamespaceSymbol) {
1812                            addToken(tokens, XPath.Tokens.EXPRTOKEN_AXISNAME_NAMESPACE);
1813                        } else if (nameHandle == fParentSymbol) {
1814                            addToken(tokens, XPath.Tokens.EXPRTOKEN_AXISNAME_PARENT);
1815                        } else if (nameHandle == fPrecedingSymbol) {
1816                            addToken(tokens, XPath.Tokens.EXPRTOKEN_AXISNAME_PRECEDING);
1817                        } else if (nameHandle == fPrecedingSiblingSymbol) {
1818                            addToken(tokens, XPath.Tokens.EXPRTOKEN_AXISNAME_PRECEDING_SIBLING);
1819                        } else if (nameHandle == fSelfSymbol) {
1820                            addToken(tokens, XPath.Tokens.EXPRTOKEN_AXISNAME_SELF);
1821                        } else {
1822                // System.out.println("abort 9");
1823
return false; // REVISIT
1824
}
1825                        if (isNameTestNCName) {
1826                // System.out.println("abort 10");
1827
return false; // REVISIT - "NCName:* ::" where "AxisName ::" is required
1828
}
1829                        addToken(tokens, XPath.Tokens.EXPRTOKEN_DOUBLE_COLON);
1830                        starIsMultiplyOperator = false;
1831                        if (!isAxisName) {
1832                            currentOffset++;
1833                            if (++currentOffset == endOffset) {
1834                                break;
1835                            }
1836                        }
1837                        break;
1838                    }
1839                    //
1840
// Otherwise, the token must not be recognized as an OperatorName, a NodeType, a
1841
// FunctionName, or an AxisName.
1842
//
1843
if (isNameTestNCName) {
1844                        addToken(tokens, XPath.Tokens.EXPRTOKEN_NAMETEST_NAMESPACE);
1845                        starIsMultiplyOperator = true;
1846                        tokens.addToken(nameHandle);
1847                    } else {
1848                        addToken(tokens, XPath.Tokens.EXPRTOKEN_NAMETEST_QNAME);
1849                        starIsMultiplyOperator = true;
1850                        tokens.addToken(prefixHandle);
1851                        tokens.addToken(nameHandle);
1852                    }
1853                    break;
1854                }
1855            }
1856            if (XPath.Tokens.DUMP_TOKENS) {
1857                tokens.dumpTokens();
1858            }
1859            return true;
1860        }
1861        //
1862
// [5] NCName ::= (Letter | '_') (NCNameChar)*
1863
// [6] NCNameChar ::= Letter | Digit | '.' | '-' | '_' | CombiningChar | Extender
1864
//
1865
int scanNCName(String JavaDoc data, int endOffset, int currentOffset) {
1866            int ch = data.charAt(currentOffset);
1867            if (ch >= 0x80) {
1868                if (!XMLChar.isNameStart(ch))
1869                /*** // REVISIT: Make sure this is a negation. ***
1870                if ((XMLCharacterProperties.fgCharFlags[ch] &
1871                     XMLCharacterProperties.E_InitialNameCharFlag) == 0)
1872                /***/

1873                {
1874                    return currentOffset;
1875                }
1876            }
1877            else {
1878                byte chartype = fASCIICharMap[ch];
1879                if (chartype != CHARTYPE_LETTER && chartype != CHARTYPE_UNDERSCORE) {
1880                    return currentOffset;
1881                }
1882            }
1883            while (++currentOffset < endOffset) {
1884                ch = data.charAt(currentOffset);
1885                if (ch >= 0x80) {
1886                    if (!XMLChar.isName(ch))
1887                    /*** // REVISIT: Make sure this is a negation. ***
1888                    if ((XMLCharacterProperties.fgCharFlags[ch] &
1889                         XMLCharacterProperties.E_NameCharFlag) == 0)
1890                    /***/

1891                    {
1892                        break;
1893                    }
1894                }
1895                else {
1896                    byte chartype = fASCIICharMap[ch];
1897                    if (chartype != CHARTYPE_LETTER && chartype != CHARTYPE_DIGIT &&
1898                        chartype != CHARTYPE_PERIOD && chartype != CHARTYPE_MINUS &&
1899                        chartype != CHARTYPE_UNDERSCORE)
1900                    {
1901                        break;
1902                    }
1903                }
1904            }
1905            return currentOffset;
1906        }
1907        //
1908
// [30] Number ::= Digits ('.' Digits?)? | '.' Digits
1909
// [31] Digits ::= [0-9]+
1910
//
1911
private int scanNumber(XPath.Tokens tokens, String JavaDoc/*byte[]*/ data, int endOffset, int currentOffset/*, EncodingSupport encoding*/) {
1912            int ch = data.charAt(currentOffset);
1913            int whole = 0;
1914            int part = 0;
1915            while (ch >= '0' && ch <= '9') {
1916                whole = (whole * 10) + (ch - '0');
1917                if (++currentOffset == endOffset) {
1918                    break;
1919                }
1920                ch = data.charAt(currentOffset);
1921            }
1922            if (ch == '.') {
1923                if (++currentOffset < endOffset) {
1924                    /** int start = currentOffset; **/
1925                    ch = data.charAt(currentOffset);
1926                    while (ch >= '0' && ch <= '9') {
1927                        part = (part * 10) + (ch - '0');
1928                        if (++currentOffset == endOffset) {
1929                            break;
1930                        }
1931                        ch = data.charAt(currentOffset);
1932                    }
1933                    if (part != 0) {
1934                        /***
1935                        part = tokens.addSymbol(data, start, currentOffset - start, encoding);
1936                        /***/

1937                        throw new RuntimeException JavaDoc("find a solution!");
1938                        //part = fStringPool.addSymbol(data.substring(start, currentOffset));
1939
/***/
1940                    }
1941                }
1942            }
1943            tokens.addToken(whole);
1944            tokens.addToken(part);
1945            return currentOffset;
1946        }
1947
1948        //
1949
// Protected methods
1950
//
1951

1952        /**
1953         * This method adds the specified token to the token list. By
1954         * default, this method allows all tokens. However, subclasses
1955         * of the XPathExprScanner can override this method in order
1956         * to disallow certain tokens from being used in the scanned
1957         * XPath expression. This is a convenient way of allowing only
1958         * a subset of XPath.
1959         */

1960        protected void addToken(XPath.Tokens tokens, int token)
1961            throws XPathException {
1962            tokens.addToken(token);
1963        } // addToken(int)
1964

1965    } // class Scanner
1966

1967    //
1968
// MAIN
1969
//
1970

1971    /** Main program entry. */
1972    public static void main(String JavaDoc[] argv) throws Exception JavaDoc {
1973
1974        for (int i = 0; i < argv.length; i++) {
1975            final String JavaDoc expression = argv[i];
1976            System.out.println("# XPath expression: \""+expression+'"');
1977            try {
1978                SymbolTable symbolTable = new SymbolTable();
1979                XPath xpath = new XPath(expression, symbolTable, null);
1980                System.out.println("expanded xpath: \""+xpath.toString()+'"');
1981            }
1982            catch (XPathException e) {
1983                System.out.println("error: "+e.getMessage());
1984            }
1985        }
1986
1987    } // main(String[])
1988

1989} // class XPath
1990
Popular Tags