KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xerces > xpointer > ElementSchemePointer


1 /*
2  * Copyright 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 package org.apache.xerces.xpointer;
17
18 import java.util.Hashtable JavaDoc;
19
20 import org.apache.xerces.impl.XMLErrorReporter;
21 import org.apache.xerces.util.SymbolTable;
22 import org.apache.xerces.util.XMLChar;
23 import org.apache.xerces.xni.Augmentations;
24 import org.apache.xerces.xni.QName;
25 import org.apache.xerces.xni.XMLAttributes;
26 import org.apache.xerces.xni.XNIException;
27 import org.apache.xerces.xni.parser.XMLErrorHandler;
28
29 /**
30  * <p>
31  * Implements the XPointerPart interface for element() scheme specific processing.
32  * </p>
33  *
34  * @xerces.internal
35  *
36  * @version $Id: ElementSchemePointer.java,v 1.1 2005/06/17 22:00:20 nddelima Exp $
37  *
38  */

39 class ElementSchemePointer implements XPointerPart {
40
41     // Fields
42

43     // The Scheme Name i.e element
44
private String JavaDoc fSchemeName;
45
46     // The scheme Data
47
private String JavaDoc fSchemeData;
48
49     // The scheme Data & child sequence
50
private String JavaDoc fShortHandPointerName;
51
52     // Should we attempt to resolve the ChildSequence from the
53
// current element position. If a ShortHand Pointer is present
54
// attempt to resolve relative to the short hand pointer.
55
private boolean fIsResolveElement = false;
56
57     // Has the element been found
58
private boolean fIsElementFound = false;
59     
60     // Was only an empty element found
61
private boolean fWasOnlyEmptyElementFound = false;
62     
63     // If a shorthand pointer is present and resolved
64
boolean fIsShortHand = false;
65
66     // The depth at which the element was found
67
int fFoundDepth = 0;
68
69     // The XPointer element child sequence
70
private int fChildSequence[];
71
72     // The current child position
73
private int fCurrentChildPosition = 1;
74
75     // The current child depth
76
private int fCurrentChildDepth = 0;
77
78     // The current element's child sequence
79
private int fCurrentChildSequence[];;
80
81     // Stores if the Fragment was resolved by the pointer
82
private boolean fIsFragmentResolved = false;
83
84     // Stores if the Fragment was resolved by the pointer
85
private ShortHandPointer fShortHandPointer;
86
87     // The XPointer Error reporter
88
protected XMLErrorReporter fErrorReporter;
89
90     // The XPointer Error Handler
91
protected XMLErrorHandler fErrorHandler;
92
93     //
94
private SymbolTable fSymbolTable;
95
96     // ************************************************************************
97
// Constructors
98
// ************************************************************************
99
public ElementSchemePointer() {
100     }
101
102     public ElementSchemePointer(SymbolTable symbolTable) {
103         fSymbolTable = symbolTable;
104     }
105
106     public ElementSchemePointer(SymbolTable symbolTable,
107             XMLErrorReporter errorReporter) {
108         fSymbolTable = symbolTable;
109         fErrorReporter = errorReporter;
110     }
111
112     // ************************************************************************
113
// XPointerPart implementation
114
// ************************************************************************
115

116     /**
117      * Parses the XPointer expression and tokenizes it into Strings
118      * delimited by whitespace.
119      *
120      * @see org.apache.xerces.xpointer.XPointerProcessor#parseXPointer(java.lang.String)
121      */

122     public void parseXPointer(String JavaDoc xpointer) throws XNIException {
123
124         //
125
init();
126
127         // tokens
128
final Tokens tokens = new Tokens(fSymbolTable);
129
130         // scanner
131
Scanner scanner = new Scanner(fSymbolTable) {
132             protected void addToken(Tokens tokens, int token)
133                     throws XNIException {
134                 if (token == Tokens.XPTRTOKEN_ELEM_CHILD
135                         || token == Tokens.XPTRTOKEN_ELEM_NCNAME) {
136                     super.addToken(tokens, token);
137                     return;
138                 }
139                 reportError("InvalidElementSchemeToken", new Object JavaDoc[] { tokens
140                         .getTokenString(token) });
141             }
142         };
143
144         // scan the element() XPointer expression
145
int length = xpointer.length();
146         boolean success = scanner.scanExpr(fSymbolTable, tokens, xpointer, 0,
147                 length);
148
149         if (!success) {
150             reportError("InvalidElementSchemeXPointer",
151                     new Object JavaDoc[] { xpointer });
152         }
153
154         // Initialize a temp arrays to the size of token count which should
155
// be atleast twice the size of child sequence, to hold the ChildSequence.
156
int tmpChildSequence[] = new int[tokens.getTokenCount() / 2 + 1];
157
158         // the element depth
159
int i = 0;
160
161         // Traverse the scanned tokens
162
while (tokens.hasMore()) {
163             int token = tokens.nextToken();
164
165             switch (token) {
166             case Tokens.XPTRTOKEN_ELEM_NCNAME: {
167                 // Note: Only a single ShortHand pointer can be present
168

169                 // The shortHand name
170
token = tokens.nextToken();
171                 fShortHandPointerName = tokens.getTokenString(token);
172
173                 // Create a new ShortHandPointer
174
fShortHandPointer = new ShortHandPointer(fSymbolTable);
175                 fShortHandPointer.setSchemeName(fShortHandPointerName);
176
177                 break;
178             }
179             case Tokens.XPTRTOKEN_ELEM_CHILD: {
180                 tmpChildSequence[i] = tokens.nextToken();
181                 i++;
182
183                 break;
184             }
185             default:
186                 reportError("InvalidElementSchemeXPointer",
187                         new Object JavaDoc[] { xpointer });
188             }
189         }
190
191         // Initialize the arrays to the number of elements in the ChildSequence.
192
fChildSequence = new int[i];
193         fCurrentChildSequence = new int[i];
194         System.arraycopy(tmpChildSequence, 0, fChildSequence, 0, i);
195
196     }
197
198     /**
199      * Returns the scheme name i.e element
200      * @see org.apache.xerces.xpointer.XPointerPart#getSchemeName()
201      */

202     public String JavaDoc getSchemeName() {
203         return fSchemeName;
204     }
205
206     /**
207      * Returns the scheme data
208      *
209      * @see org.apache.xerces.xpointer.XPointerPart#getSchemeData()
210      */

211     public String JavaDoc getSchemeData() {
212         return fSchemeData;
213     }
214
215     /**
216      * Sets the scheme name
217      *
218      * @see org.apache.xerces.xpointer.XPointerPart#setSchemeName(java.lang.String)
219      */

220     public void setSchemeName(String JavaDoc schemeName) {
221         fSchemeName = schemeName;
222
223     }
224
225     /**
226      * Sets the scheme data
227      *
228      * @see org.apache.xerces.xpointer.XPointerPart#setSchemeData(java.lang.String)
229      */

230     public void setSchemeData(String JavaDoc schemeData) {
231         fSchemeData = schemeData;
232     }
233
234     /**
235      * Responsible for resolving the element() scheme XPointer. If a ShortHand
236      * Pointer is present and it is successfully resolved and if a child
237      * sequence is present, the child sequence is resolved relative to it.
238      *
239      * @see org.apache.xerces.xpointer.XPointerProcessor#resolveXPointer(org.apache.xerces.xni.QName, org.apache.xerces.xni.XMLAttributes, org.apache.xerces.xni.Augmentations, int event)
240      */

241     public boolean resolveXPointer(QName element, XMLAttributes attributes,
242             Augmentations augs, int event) throws XNIException {
243
244         boolean isShortHandPointerResolved = false;
245
246         // if a ChildSequence exisits, resolve child elements
247

248         // if an element name exists
249
if (fShortHandPointerName != null) {
250             // resolve ShortHand Pointer
251
isShortHandPointerResolved = fShortHandPointer.resolveXPointer(
252                     element, attributes, augs, event);
253             if (isShortHandPointerResolved) {
254                 fIsResolveElement = true;
255                 fIsShortHand = true;
256             } else {
257                 fIsResolveElement = false;
258             }
259         } else {
260             fIsResolveElement = true;
261         }
262
263         // Added here to skip the ShortHand pointer corresponding to
264
// an element if one exisits and start searching from its child
265
if (fChildSequence.length > 0) {
266             fIsFragmentResolved = matchChildSequence(element, event);
267         } else if (isShortHandPointerResolved && fChildSequence.length <= 0) {
268             // if only a resolved shorthand pointer exists
269
fIsFragmentResolved = isShortHandPointerResolved;
270         } else {
271             fIsFragmentResolved = false;
272         }
273
274         return fIsFragmentResolved;
275     }
276
277     /**
278      * Matches the current element position in the document tree with the
279      * element position specified in the element XPointer scheme.
280      *
281      * @param event
282      * @return boolean - true if the current element position in the document
283      * tree matches theelement position specified in the element XPointer
284      * scheme.
285      */

286     protected boolean matchChildSequence(QName element, int event)
287             throws XNIException {
288         
289         // need to resize fCurrentChildSequence
290
if (fCurrentChildDepth >= fCurrentChildSequence.length) {
291             int tmpCurrentChildSequence[] = new int[fCurrentChildSequence.length];
292             System.arraycopy(fCurrentChildSequence, 0, tmpCurrentChildSequence,
293                     0, fCurrentChildSequence.length);
294
295             // Increase the size by a factor of 2 (?)
296
fCurrentChildSequence = new int[fCurrentChildDepth * 2];
297             System.arraycopy(tmpCurrentChildSequence, 0, fCurrentChildSequence,
298                     0, tmpCurrentChildSequence.length);
299         }
300
301         //
302
if (fIsResolveElement) {
303             // start
304
if (event == XPointerPart.EVENT_ELEMENT_START) {
305                 fCurrentChildSequence[fCurrentChildDepth] = fCurrentChildPosition;
306                 fCurrentChildDepth++;
307
308                 // reset the current child position
309
fCurrentChildPosition = 1;
310
311                 //if (!fSchemeNameFound) {
312
if ((fCurrentChildDepth <= fFoundDepth) || (fFoundDepth == 0)) {
313                     if (checkMatch()) {
314                         fIsElementFound = true;
315                         fFoundDepth = fCurrentChildDepth;
316                     } else {
317                         fIsElementFound = false;
318                         fFoundDepth = 0;
319                     }
320                 }
321
322             } else if (event == XPointerPart.EVENT_ELEMENT_END) {
323                 if (fCurrentChildDepth == fFoundDepth) {
324                     fIsElementFound = true;
325                 } else if (((fCurrentChildDepth < fFoundDepth) && (fFoundDepth != 0))
326                         || ((fCurrentChildDepth > fFoundDepth) // or empty element found
327
&& (fFoundDepth == 0))) {
328                     fIsElementFound = false;
329                 }
330
331                 // reset array position of last child
332
fCurrentChildSequence[fCurrentChildDepth] = 0;
333
334                 fCurrentChildDepth--;
335                 fCurrentChildPosition = fCurrentChildSequence[fCurrentChildDepth] + 1;
336                 
337             } else if (event == XPointerPart.EVENT_ELEMENT_EMPTY) {
338
339                 fCurrentChildSequence[fCurrentChildDepth] = fCurrentChildPosition;
340                 fCurrentChildPosition++;
341
342                 // Donot check for empty elements if the empty element is
343
// a child of a found parent element
344
//if (!fIsElementFound) {
345
if (checkMatch()) {
346                         fIsElementFound = true;
347                         fWasOnlyEmptyElementFound = true;
348                     } else {
349                         fIsElementFound = false;
350                     }
351                 //}
352

353             }
354         }
355
356         return fIsElementFound;
357     }
358
359     /**
360      * Matches the current position of the element being visited by checking
361      * its position and previous elements against the element XPointer expression.
362      * If a match is found it return true else false.
363      *
364      * @return boolean
365      */

366     protected boolean checkMatch() {
367         // If the number of elements in the ChildSequence is greater than the
368
// current child depth, there is not point in checking further
369
if (!fIsShortHand) {
370             // If a shorthand pointer is not present traverse the children
371
// and compare
372
if (fChildSequence.length <= fCurrentChildDepth + 1) {
373
374                 for (int i = 0; i < fChildSequence.length; i++) {
375                     if (fChildSequence[i] != fCurrentChildSequence[i]) {
376                         return false;
377                     }
378                 }
379             } else {
380                 return false;
381             }
382         } else {
383             // If a shorthand pointer is present traverse the children
384
// ignoring the first element of the CurrenChildSequence which
385
// contains the ShortHand pointer element and compare
386
if (fChildSequence.length <= fCurrentChildDepth + 1) {
387
388                 for (int i = 0; i < fChildSequence.length; i++) {
389                     // ensure fCurrentChildSequence is large enough
390
if (fCurrentChildSequence.length < i + 2) {
391                         return false;
392                     }
393
394                     // ignore the first element of fCurrentChildSequence
395
if (fChildSequence[i] != fCurrentChildSequence[i + 1]) {
396                         return false;
397                     }
398                 }
399             } else {
400                 return false;
401             }
402
403         }
404
405         return true;
406     }
407
408     /**
409      * Returns true if the node matches or is a child of a matching element()
410      * scheme XPointer.
411      *
412      * @see org.apache.xerces.xpointer.XPointerProcessor#isFragmentResolved()
413      */

414     public boolean isFragmentResolved() throws XNIException {
415         // Return true if the Fragment was resolved and the current Node depth
416
// is greater than or equal to the depth at which the element was found
417
return fIsFragmentResolved ;
418     }
419
420     /**
421      * Returns true if the XPointer expression resolves to a non-element child
422      * of the current resource fragment.
423      *
424      * @see org.apache.xerces.xpointer.XPointerPart#isChildFragmentResolved()
425      *
426      */

427     public boolean isChildFragmentResolved() {
428         // if only a shorthand pointer was present
429
if (fIsShortHand && fShortHandPointer != null && fChildSequence.length <= 0) {
430             return fShortHandPointer.isChildFragmentResolved();
431         } else {
432             return fWasOnlyEmptyElementFound ? !fWasOnlyEmptyElementFound
433                     : (fIsFragmentResolved && (fCurrentChildDepth >= fFoundDepth));
434         }
435     }
436     
437     /**
438      * Reports an XPointer error
439      */

440     protected void reportError(String JavaDoc key, Object JavaDoc[] arguments)
441             throws XNIException {
442         /*fErrorReporter.reportError(XPointerMessageFormatter.XPOINTER_DOMAIN,
443          key, arguments, XMLErrorReporter.SEVERITY_ERROR);
444          */

445         throw new XNIException((fErrorReporter
446                 .getMessageFormatter(XPointerMessageFormatter.XPOINTER_DOMAIN))
447                 .formatMessage(fErrorReporter.getLocale(), key, arguments));
448     }
449
450     /**
451      * Initializes error handling objects
452      */

453     protected void initErrorReporter() {
454         if (fErrorReporter == null) {
455             fErrorReporter = new XMLErrorReporter();
456         }
457         if (fErrorHandler == null) {
458             fErrorHandler = new XPointerErrorHandler();
459         }
460         fErrorReporter.putMessageFormatter(
461                 XPointerMessageFormatter.XPOINTER_DOMAIN,
462                 new XPointerMessageFormatter());
463     }
464
465     /**
466      * Initializes the element scheme processor
467      */

468     protected void init() {
469         fSchemeName = null;
470         fSchemeData = null;
471         fShortHandPointerName = null;
472         fIsResolveElement = false;
473         fIsElementFound = false;
474         fWasOnlyEmptyElementFound = false;
475         fFoundDepth = 0;
476         fCurrentChildPosition = 1;
477         fCurrentChildDepth = 0;
478         fIsFragmentResolved = false;
479         fShortHandPointer = null;
480         
481         initErrorReporter();
482     }
483
484     // ************************************************************************
485
// element() Scheme expression scanner
486
// ************************************************************************
487

488     /**
489      * List of XPointer Framework tokens.
490      *
491      * @xerces.internal
492      *
493      * @author Neil Delima, IBM
494      * @version $Id: ElementSchemePointer.java,v 1.1 2005/06/17 22:00:20 nddelima Exp $
495      *
496      */

497     private final class Tokens {
498
499         /**
500          * XPointer element() scheme
501          * [1] ElementSchemeData ::= (NCName ChildSequence?) | ChildSequence
502          * [2] ChildSequence ::= ('/' [1-9] [0-9]*)+
503          */

504         private static final int XPTRTOKEN_ELEM_NCNAME = 0;
505
506         private static final int XPTRTOKEN_ELEM_CHILD = 1;
507
508         // Token names
509
private final String JavaDoc[] fgTokenNames = { "XPTRTOKEN_ELEM_NCNAME",
510                 "XPTRTOKEN_ELEM_CHILD" };
511
512         // Token count
513
private static final int INITIAL_TOKEN_COUNT = 1 << 8;
514
515         private int[] fTokens = new int[INITIAL_TOKEN_COUNT];
516
517         private int fTokenCount = 0;
518
519         // Current token position
520
private int fCurrentTokenIndex;
521
522         private SymbolTable fSymbolTable;
523
524         private Hashtable JavaDoc fTokenNames = new Hashtable JavaDoc();
525
526         /**
527          * Constructor
528          *
529          * @param symbolTable SymbolTable
530          */

531         private Tokens(SymbolTable symbolTable) {
532             fSymbolTable = symbolTable;
533
534             fTokenNames.put(new Integer JavaDoc(XPTRTOKEN_ELEM_NCNAME),
535                     "XPTRTOKEN_ELEM_NCNAME");
536             fTokenNames.put(new Integer JavaDoc(XPTRTOKEN_ELEM_CHILD),
537                     "XPTRTOKEN_ELEM_CHILD");
538         }
539
540         /*
541          * Returns the token String
542          * @param token The index of the token
543          * @return String The token string
544          */

545         private String JavaDoc getTokenString(int token) {
546             return (String JavaDoc) fTokenNames.get(new Integer JavaDoc(token));
547         }
548
549         /**
550          * Returns the token String
551          * @param token The index of the token
552          * @return String The token string
553          */

554         private Integer JavaDoc getToken(int token) {
555             return (Integer JavaDoc) fTokenNames.get(new Integer JavaDoc(token));
556         }
557
558         /**
559          * Add the specified string as a token
560          *
561          * @param token The token string
562          */

563         private void addToken(String JavaDoc tokenStr) {
564             Integer JavaDoc tokenInt = (Integer JavaDoc) fTokenNames.get(tokenStr);
565             if (tokenInt == null) {
566                 tokenInt = new Integer JavaDoc(fTokenNames.size());
567                 fTokenNames.put(tokenInt, tokenStr);
568             }
569             addToken(tokenInt.intValue());
570         }
571
572         /**
573          * Add the specified int token
574          *
575          * @param token The int specifying the token
576          */

577         private void addToken(int token) {
578             try {
579                 fTokens[fTokenCount] = token;
580             } catch (ArrayIndexOutOfBoundsException JavaDoc ex) {
581                 int[] oldList = fTokens;
582                 fTokens = new int[fTokenCount << 1];
583                 System.arraycopy(oldList, 0, fTokens, 0, fTokenCount);
584                 fTokens[fTokenCount] = token;
585             }
586             fTokenCount++;
587         }
588
589         /**
590          * Resets the current position to the head of the token list.
591          */

592         private void rewind() {
593             fCurrentTokenIndex = 0;
594         }
595
596         /**
597          * Returns true if the {@link #getNextToken()} method
598          * returns a valid token.
599          */

600         private boolean hasMore() {
601             return fCurrentTokenIndex < fTokenCount;
602         }
603
604         /**
605          * Obtains the token at the current position, then advance
606          * the current position by one.
607          *
608          * If there's no such next token, this method throws
609          * <tt>new XNIException("InvalidXPointerExpression");</tt>.
610          */

611         private int nextToken() throws XNIException {
612             if (fCurrentTokenIndex == fTokenCount)
613                 reportError("XPointerElementSchemeProcessingError", null);
614             return fTokens[fCurrentTokenIndex++];
615         }
616
617         /**
618          * Obtains the token at the current position, without advancing
619          * the current position.
620          *
621          * If there's no such next token, this method throws
622          * <tt>new XNIException("InvalidXPointerExpression");</tt>.
623          */

624         private int peekToken() throws XNIException {
625             if (fCurrentTokenIndex == fTokenCount)
626                 reportError("XPointerElementSchemeProcessingError", null);
627             return fTokens[fCurrentTokenIndex];
628         }
629
630         /**
631          * Obtains the token at the current position as a String.
632          *
633          * If there's no current token or if the current token
634          * is not a string token, this method throws
635          * If there's no such next token, this method throws
636          * <tt>new XNIException("InvalidXPointerExpression");</tt>.
637          */

638         private String JavaDoc nextTokenAsString() throws XNIException {
639             String JavaDoc s = getTokenString(nextToken());
640             if (s == null)
641                 reportError("XPointerElementSchemeProcessingError", null);
642             return s;
643         }
644
645         /**
646          * Returns the number of tokens.
647          *
648          */

649         private int getTokenCount() {
650             return fTokenCount;
651         }
652     }
653
654     /**
655      *
656      * The XPointer expression scanner. Scans the XPointer framework expression.
657      *
658      * @xerces.internal
659      *
660      * @version $Id: ElementSchemePointer.java,v 1.1 2005/06/17 22:00:20 nddelima Exp $
661      */

662     private class Scanner {
663
664         /**
665          * 7-bit ASCII subset
666          *
667          * 0 1 2 3 4 5 6 7 8 9 A B C D E F
668          * 0, 0, 0, 0, 0, 0, 0, 0, 0, HT, LF, 0, 0, CR, 0, 0, // 0
669          * 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1
670          * SP, !, ", #, $, %, &, ', (, ), *, +, ,, -, ., /, // 2
671          * 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, :, ;, <, =, >, ?, // 3
672          * @, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, // 4
673          * P, Q, R, S, T, U, V, W, X, Y, Z, [, \, ], ^, _, // 5
674          * `, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, // 6
675          * p, q, r, s, t, u, v, w, x, y, z, {, |, }, ~, DEL // 7
676          */

677         private static final byte CHARTYPE_INVALID = 0, // invalid XML characters, control characters and 7F
678
CHARTYPE_OTHER = 1, // A valid XML character (possibly invalid NCNameChar) that does not fall in one of the other categories
679
CHARTYPE_MINUS = 2, // '-' (0x2D)
680
CHARTYPE_PERIOD = 3, // '.' (0x2E)
681
CHARTYPE_SLASH = 4, // '/' (0x2F)
682
CHARTYPE_DIGIT = 5, // '0'-'9' (0x30 to 0x39)
683
CHARTYPE_LETTER = 6, // 'A'-'Z' or 'a'-'z' (0x41 to 0x5A and 0x61 to 0x7A)
684
CHARTYPE_UNDERSCORE = 7, // '_' (0x5F)
685
CHARTYPE_NONASCII = 8; // Non-ASCII Unicode codepoint (>= 0x80)
686

687         private final byte[] fASCIICharMap = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
688                 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
689                 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 4, 5, 5, 5, 5, 5,
690                 5, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 6, 6, 6,
691                 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 1, 1, 1, 1,
692                 7, 1, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
693                 6, 6, 6, 6, 6, 6, 6, 1, 1, 1, 1, 1 };
694
695         /**
696          * Symbol literals
697          */

698
699         //
700
// Data
701
//
702
/** Symbol table. */
703         private SymbolTable fSymbolTable;
704
705         //
706
// Constructors
707
//
708

709         /**
710          * Constructs an XPath expression scanner.
711          *
712          * @param symbolTable SymbolTable
713          */

714         private Scanner(SymbolTable symbolTable) {
715             // save pool and tokens
716
fSymbolTable = symbolTable;
717
718         } // <init>(SymbolTable)
719

720         /**
721          * Scans the XPointer Expression
722          *
723          */

724         private boolean scanExpr(SymbolTable symbolTable, Tokens tokens,
725                 String JavaDoc data, int currentOffset, int endOffset)
726                 throws XNIException {
727
728             int ch;
729             int nameOffset;
730             String JavaDoc nameHandle = null;
731
732             while (true) {
733                 if (currentOffset == endOffset) {
734                     break;
735                 }
736
737                 ch = data.charAt(currentOffset);
738                 byte chartype = (ch >= 0x80) ? CHARTYPE_NONASCII
739                         : fASCIICharMap[ch];
740
741                 //
742
// [1] ElementSchemeData ::= (NCName ChildSequence?) | ChildSequence
743
// [2] ChildSequence ::= ('/' [1-9] [0-9]*)+
744
//
745

746                 switch (chartype) {
747
748                 case CHARTYPE_SLASH:
749                     // if last character is '/', break and report an error
750
if (++currentOffset == endOffset) {
751                         return false;
752                     }
753
754                     addToken(tokens, Tokens.XPTRTOKEN_ELEM_CHILD);
755                     ch = data.charAt(currentOffset);
756
757                     // ChildSequence ::= ('/' [1-9] [0-9]*)+
758
int child = 0;
759                     while (ch >= '0' && ch <= '9') {
760                         child = (child * 10) + (ch - '0');
761                         if (++currentOffset == endOffset) {
762                             break;
763                         }
764                         ch = data.charAt(currentOffset);
765                     }
766
767                     // An invalid child sequence character
768
if (child == 0) {
769                         reportError("InvalidChildSequenceCharacter",
770                                 new Object JavaDoc[] { new Character JavaDoc((char) ch) });
771                         return false;
772                     }
773
774                     tokens.addToken(child);
775
776                     break;
777
778                 case CHARTYPE_DIGIT:
779                 case CHARTYPE_LETTER:
780                 case CHARTYPE_MINUS:
781                 case CHARTYPE_NONASCII:
782                 case CHARTYPE_OTHER:
783                 case CHARTYPE_PERIOD:
784                 case CHARTYPE_UNDERSCORE:
785                     // Scan the ShortHand Pointer NCName
786
nameOffset = currentOffset;
787                     currentOffset = scanNCName(data, endOffset, currentOffset);
788
789                     if (currentOffset == nameOffset) {
790                         //return false;
791
reportError("InvalidNCNameInElementSchemeData",
792                                 new Object JavaDoc[] { data });
793                         return false;
794                     }
795
796                     if (currentOffset < endOffset) {
797                         ch = data.charAt(currentOffset);
798                     } else {
799                         ch = -1;
800                     }
801
802                     nameHandle = symbolTable.addSymbol(data.substring(
803                             nameOffset, currentOffset));
804                     addToken(tokens, Tokens.XPTRTOKEN_ELEM_NCNAME);
805                     tokens.addToken(nameHandle);
806
807                     break;
808                 }
809             }
810             return true;
811         }
812
813         /**
814          * Scans a NCName.
815          * From Namespaces in XML
816          * [5] NCName ::= (Letter | '_') (NCNameChar)*
817          * [6] NCNameChar ::= Letter | Digit | '.' | '-' | '_' | CombiningChar | Extender
818          *
819          * @param data A String containing the XPointer expression
820          * @param endOffset The int XPointer expression length
821          * @param currentOffset An int representing the current position of the XPointer expression pointer
822          */

823         private int scanNCName(String JavaDoc data, int endOffset, int currentOffset) {
824             int ch = data.charAt(currentOffset);
825             if (ch >= 0x80) {
826                 if (!XMLChar.isNameStart(ch)) {
827                     return currentOffset;
828                 }
829             } else {
830                 byte chartype = fASCIICharMap[ch];
831                 if (chartype != CHARTYPE_LETTER
832                         && chartype != CHARTYPE_UNDERSCORE) {
833                     return currentOffset;
834                 }
835             }
836             while (++currentOffset < endOffset) {
837                 ch = data.charAt(currentOffset);
838                 if (ch >= 0x80) {
839                     if (!XMLChar.isName(ch)) {
840                         break;
841                     }
842                 } else {
843                     byte chartype = fASCIICharMap[ch];
844                     if (chartype != CHARTYPE_LETTER
845                             && chartype != CHARTYPE_DIGIT
846                             && chartype != CHARTYPE_PERIOD
847                             && chartype != CHARTYPE_MINUS
848                             && chartype != CHARTYPE_UNDERSCORE) {
849                         break;
850                     }
851                 }
852             }
853             return currentOffset;
854         }
855
856         //
857
// Protected methods
858
//
859

860         /**
861          * This method adds the specified token to the token list. By
862          * default, this method allows all tokens. However, subclasses
863          * of the XPathExprScanner can override this method in order
864          * to disallow certain tokens from being used in the scanned
865          * XPath expression. This is a convenient way of allowing only
866          * a subset of XPath.
867          */

868         protected void addToken(Tokens tokens, int token) throws XNIException {
869             tokens.addToken(token);
870         } // addToken(int)
871

872     } // class Scanner
873

874 }
Popular Tags