KickJava   Java API By Example, From Geeks To Geeks.

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


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 import java.util.Vector JavaDoc;
20
21 import org.apache.xerces.impl.Constants;
22 import org.apache.xerces.impl.XMLErrorReporter;
23 import org.apache.xerces.util.SymbolTable;
24 import org.apache.xerces.util.XMLChar;
25 import org.apache.xerces.util.XMLSymbols;
26 import org.apache.xerces.xinclude.XIncludeHandler;
27 import org.apache.xerces.xinclude.XIncludeNamespaceSupport;
28 import org.apache.xerces.xni.Augmentations;
29 import org.apache.xerces.xni.QName;
30 import org.apache.xerces.xni.XMLAttributes;
31 import org.apache.xerces.xni.XMLString;
32 import org.apache.xerces.xni.XNIException;
33 import org.apache.xerces.xni.parser.XMLConfigurationException;
34 import org.apache.xerces.xni.parser.XMLErrorHandler;
35
36 /**
37  * <p>
38  * This is a pipeline component which extends the XIncludeHandler to perform
39  * XPointer specific processing specified in the W3C XPointerFramework and
40  * element() Scheme Recommendations.
41  * </p>
42  *
43  * <p>
44  * This component analyzes each event in the pipeline, looking for an element
45  * that matches a PointerPart in the parent XInclude element's xpointer attribute
46  * value. If the match succeeds, all children are passed by this component.
47  * </p>
48  *
49  * <p>
50  * See the <a HREF="http://www.w3.org/TR/xptr-framework//">XPointer Framework Recommendation</a> for
51  * more information on the XPointer Framework and ShortHand Pointers.
52  * See the <a HREF="http://www.w3.org/TR/xptr-element/">XPointer element() Scheme Recommendation</a> for
53  * more information on the XPointer element() Scheme.
54  * </p>
55  *
56  * @xerces.internal
57  *
58  * @version $Id: XPointerHandler.java,v 1.1 2005/06/17 22:00:20 nddelima Exp $
59  */

60 public final class XPointerHandler extends XIncludeHandler implements
61         XPointerProcessor {
62
63     // Fields
64
// A Vector of XPointerParts
65
protected Vector JavaDoc fXPointerParts = null;
66
67     // The current XPointerPart
68
protected XPointerPart fXPointerPart = null;
69
70     // Has the fXPointerPart resolved successfully
71
protected boolean fFoundMatchingPtrPart = false;
72
73     // The XPointer Error reporter
74
protected XMLErrorReporter fXPointerErrorReporter;
75
76     // The XPointer Error Handler
77
protected XMLErrorHandler fErrorHandler;
78
79     // XPointerFramework symbol table
80
protected SymbolTable fSymbolTable = null;
81
82     // Supported schemes
83
private final String JavaDoc ELEMENT_SCHEME_NAME = "element";
84
85    // Has the XPointer resolved the subresource
86
protected boolean fIsXPointerResolved = false;
87     
88     // Fixup xml:base and xml:lang attributes
89
protected boolean fFixupBase = false;
90     protected boolean fFixupLang = false;
91     
92     // ************************************************************************
93
// Constructors
94
// ************************************************************************
95

96     /**
97      *
98      */

99     public XPointerHandler() {
100         super();
101
102         fXPointerParts = new Vector JavaDoc();
103         fSymbolTable = new SymbolTable();
104     }
105
106     public XPointerHandler(SymbolTable symbolTable,
107             XMLErrorHandler errorHandler, XMLErrorReporter errorReporter) {
108         super();
109
110         fXPointerParts = new Vector JavaDoc();
111         fSymbolTable = symbolTable;
112         fErrorHandler = errorHandler;
113         fXPointerErrorReporter = errorReporter;
114         //fErrorReporter = errorReporter; // The XInclude ErrorReporter
115
}
116     
117     // ************************************************************************
118
// Implementation of the XPointerProcessor interface.
119
// ************************************************************************
120

121     /**
122      * Parses the XPointer framework expression and delegates scheme specific parsing.
123      *
124      * @see org.apache.xerces.xpointer.XPointerProcessor#parseXPointer(java.lang.String)
125      */

126     public void parseXPointer(String JavaDoc xpointer) throws XNIException {
127
128         // Initialize
129
init();
130
131         // tokens
132
final Tokens tokens = new Tokens(fSymbolTable);
133
134         // scanner
135
Scanner scanner = new Scanner(fSymbolTable) {
136             protected void addToken(Tokens tokens, int token)
137                     throws XNIException {
138                 if (token == Tokens.XPTRTOKEN_OPEN_PAREN
139                         || token == Tokens.XPTRTOKEN_CLOSE_PAREN
140                         || token == Tokens.XPTRTOKEN_SCHEMENAME
141                         || token == Tokens.XPTRTOKEN_SCHEMEDATA
142                         || token == Tokens.XPTRTOKEN_SHORTHAND) {
143                     super.addToken(tokens, token);
144                     return;
145                 }
146                 reportError("InvalidXPointerToken", new Object JavaDoc[] { tokens
147                         .getTokenString(token) });
148             }
149         };
150
151         // scan the XPointer expression
152
int length = xpointer.length();
153         boolean success = scanner.scanExpr(fSymbolTable, tokens, xpointer, 0,
154                 length);
155
156         if (!success)
157             reportError("InvalidXPointerExpression", new Object JavaDoc[] { xpointer });
158
159         while (tokens.hasMore()) {
160             int token = tokens.nextToken();
161
162             switch (token) {
163             case Tokens.XPTRTOKEN_SHORTHAND: {
164
165                 // The shortHand name
166
token = tokens.nextToken();
167                 String JavaDoc shortHandPointerName = tokens.getTokenString(token);
168
169                 if (shortHandPointerName == null) {
170                     reportError("InvalidXPointerExpression",
171                             new Object JavaDoc[] { xpointer });
172                 }
173
174                 XPointerPart shortHandPointer = new ShortHandPointer(
175                         fSymbolTable);
176                 shortHandPointer.setSchemeName(shortHandPointerName);
177                 fXPointerParts.add(shortHandPointer);
178                 break;
179             }
180             case Tokens.XPTRTOKEN_SCHEMENAME: {
181
182                 // Retreive the local name and prefix to form the scheme name
183
token = tokens.nextToken();
184                 String JavaDoc prefix = tokens.getTokenString(token);
185                 token = tokens.nextToken();
186                 String JavaDoc localName = tokens.getTokenString(token);
187
188                 String JavaDoc schemeName = prefix + localName;
189
190                 // The next character should be an open parenthesis
191
int openParenCount = 0;
192                 int closeParenCount = 0;
193
194                 token = tokens.nextToken();
195                 String JavaDoc openParen = tokens.getTokenString(token);
196                 if (openParen != "XPTRTOKEN_OPEN_PAREN") {
197
198                     // can not have more than one ShortHand Pointer
199
if (token == Tokens.XPTRTOKEN_SHORTHAND) {
200                         reportError("MultipleShortHandPointers",
201                                 new Object JavaDoc[] { xpointer });
202                     } else {
203                         reportError("InvalidXPointerExpression",
204                                 new Object JavaDoc[] { xpointer });
205                     }
206                 }
207                 openParenCount++;
208
209                 // followed by zero or more ( and the schemeData
210
String JavaDoc schemeData = null;
211                 while (tokens.hasMore()) {
212                     token = tokens.nextToken();
213                     schemeData = tokens.getTokenString(token);
214                     if (schemeData != "XPTRTOKEN_OPEN_PAREN") {
215                         break;
216                     }
217                     openParenCount++;
218                 }
219                 token = tokens.nextToken();
220                 schemeData = tokens.getTokenString(token);
221
222                 // followed by the same number of )
223
token = tokens.nextToken();
224                 String JavaDoc closeParen = tokens.getTokenString(token);
225                 if (closeParen != "XPTRTOKEN_CLOSE_PAREN") {
226                     reportError("SchemeDataNotFollowedByCloseParenthesis",
227                             new Object JavaDoc[] { xpointer });
228                 }
229                 closeParenCount++;
230
231                 while (tokens.hasMore()) {
232                     if (tokens.getTokenString(tokens.peekToken()) != "XPTRTOKEN_OPEN_PAREN") {
233                         break;
234                     }
235                     closeParenCount++;
236                 }
237
238                 // check if the number of open parenthesis are equal to the number of close parenthesis
239
if (openParenCount != closeParenCount) {
240                     reportError("UnbalancedParenthesisInXPointerExpression",
241                             new Object JavaDoc[] { xpointer,
242                                     new Integer JavaDoc(openParenCount),
243                                     new Integer JavaDoc(closeParenCount) });
244                 }
245
246                 // Perform scheme specific parsing of the pointer part
247
if (schemeName.equals(ELEMENT_SCHEME_NAME)) {
248                     XPointerPart elementSchemePointer = new ElementSchemePointer(
249                             fSymbolTable, fErrorReporter);
250                     elementSchemePointer.setSchemeName(schemeName);
251                     elementSchemePointer.setSchemeData(schemeData);
252
253                     // If an exception occurs while parsing the element() scheme expression
254
// ignore it and move on to the next pointer part
255
try {
256                         elementSchemePointer.parseXPointer(schemeData);
257                         fXPointerParts.add(elementSchemePointer);
258                     } catch (XNIException e) {
259                         // Re-throw the XPointer element() scheme syntax error.
260
throw new XNIException (e);
261                     }
262
263                 } else {
264                     // ????
265
reportWarning("SchemeUnsupported",
266                             new Object JavaDoc[] { schemeName });
267                 }
268
269                 break;
270             }
271             default:
272                 reportError("InvalidXPointerExpression",
273                         new Object JavaDoc[] { xpointer });
274             }
275         }
276
277     }
278
279     /**
280      *
281      * @see org.apache.xerces.xpointer.XPointerProcessor#resolveXPointer(org.apache.xerces.xni.QName, org.apache.xerces.xni.XMLAttributes, org.apache.xerces.xni.Augmentations, int event)
282      */

283     public boolean resolveXPointer(QName element, XMLAttributes attributes,
284             Augmentations augs, int event) throws XNIException {
285         boolean resolved = false;
286         
287         // The result of the first pointer part whose evaluation identifies
288
// one or more subresources is reported by the XPointer processor as the
289
// result of the pointer as a whole, and evaluation stops.
290
// In our implementation, typically the first xpointer scheme that
291
// matches an element is the document is considered.
292
// If the pointer part resolved then use it, else search for the fragment
293
// using next pointer part from lef-right.
294
if (!fFoundMatchingPtrPart) {
295
296             // for each element, attempt to resolve it against each pointer part
297
// in the XPointer expression until a matching element is found.
298
for (int i = 0; i < fXPointerParts.size(); i++) {
299
300                 fXPointerPart = (XPointerPart) fXPointerParts.get(i);
301
302                 if (fXPointerPart.resolveXPointer(element, attributes, augs,
303                         event)) {
304                     fFoundMatchingPtrPart = true;
305                     resolved = true;
306                 }
307             }
308         } else {
309             if (fXPointerPart.resolveXPointer(element, attributes, augs, event)) {
310                 resolved = true;
311             }
312         }
313
314         if (!fIsXPointerResolved) {
315             fIsXPointerResolved = resolved;
316         }
317
318         return resolved;
319     }
320
321     /**
322      * Returns true if the Node fragment is resolved.
323      *
324      * @see org.apache.xerces.xpointer.XPointerProcessor#isFragmentResolved()
325      */

326     public boolean isFragmentResolved() throws XNIException {
327         boolean resolved = (fXPointerPart != null) ? fXPointerPart.isFragmentResolved()
328                 : false;
329         
330         if (!fIsXPointerResolved) {
331             fIsXPointerResolved = resolved;
332         }
333         
334         return resolved;
335     }
336
337     /**
338      * Returns true if the XPointer expression resolves to a non-element child
339      * of the current resource fragment.
340      *
341      * @see org.apache.xerces.xpointer.XPointerPart#isChildFragmentResolved()
342      *
343      */

344     public boolean isChildFragmentResolved() throws XNIException {
345         boolean resolved = (fXPointerPart != null) ? fXPointerPart
346                 .isChildFragmentResolved() : false;
347         return resolved;
348     }
349
350     /**
351      * Returns true if the XPointer successfully found a sub-resource .
352      *
353      * @see org.apache.xerces.xpointer.XPointerProcessor#isFragmentResolved()
354      */

355     public boolean isXPointerResolved() throws XNIException {
356         return fIsXPointerResolved;
357     }
358     
359     /**
360      * Returns the pointer part used to resolve the document fragment.
361      *
362      * @return String - The pointer part used to resolve the document fragment.
363      */

364     public XPointerPart getXPointerPart() {
365         return fXPointerPart;
366     }
367
368     /**
369      * Reports XPointer Errors
370      *
371      */

372     private void reportError(String JavaDoc key, Object JavaDoc[] arguments)
373             throws XNIException {
374         /*
375         fXPointerErrorReporter.reportError(
376                 XPointerMessageFormatter.XPOINTER_DOMAIN, key, arguments,
377                 XMLErrorReporter.SEVERITY_ERROR);
378         */

379         throw new XNIException((fErrorReporter
380                 .getMessageFormatter(XPointerMessageFormatter.XPOINTER_DOMAIN))
381                 .formatMessage(fErrorReporter.getLocale(), key, arguments));
382     }
383
384     /**
385      * Reports XPointer Warnings
386      *
387      */

388     private void reportWarning(String JavaDoc key, Object JavaDoc[] arguments)
389             throws XNIException {
390         fXPointerErrorReporter.reportError(
391                 XPointerMessageFormatter.XPOINTER_DOMAIN, key, arguments,
392                 XMLErrorReporter.SEVERITY_WARNING);
393     }
394
395     /**
396      * Initializes error handling objects
397      *
398      */

399     protected void initErrorReporter() {
400         if (fXPointerErrorReporter == null) {
401             fXPointerErrorReporter = new XMLErrorReporter();
402         }
403         if (fErrorHandler == null) {
404             fErrorHandler = new XPointerErrorHandler();
405         }
406         /*
407          fXPointerErrorReporter.setProperty(Constants.XERCES_PROPERTY_PREFIX
408          + Constants.ERROR_HANDLER_PROPERTY, fErrorHandler);
409          */

410         fXPointerErrorReporter.putMessageFormatter(
411                 XPointerMessageFormatter.XPOINTER_DOMAIN,
412                 new XPointerMessageFormatter());
413     }
414
415     /**
416      * Initializes the XPointer Processor;
417      */

418     protected void init() {
419         fXPointerParts.clear();
420         fXPointerPart = null;
421         fFoundMatchingPtrPart = false;
422         fIsXPointerResolved = false;
423         //fFixupBase = false;
424
//fFixupLang = false;
425

426         initErrorReporter();
427     }
428
429     /**
430      * Returns a Vector of XPointerPart objects
431      *
432      * @return A Vector of XPointerPart objects.
433      */

434     public Vector JavaDoc getPointerParts() {
435         return fXPointerParts;
436     }
437
438     /**
439      * List of XPointer Framework tokens.
440      *
441      * @xerces.internal
442      *
443      */

444     private final class Tokens {
445
446         /**
447          * XPointer Framework tokens
448          * [1] Pointer ::= Shorthand | SchemeBased
449          * [2] Shorthand ::= NCName
450          * [3] SchemeBased ::= PointerPart (S? PointerPart)*
451          * [4] PointerPart ::= SchemeName '(' SchemeData ')'
452          * [5] SchemeName ::= QName
453          * [6] SchemeData ::= EscapedData*
454          * [7] EscapedData ::= NormalChar | '^(' | '^)' | '^^' | '(' SchemeData ')'
455          * [8] NormalChar ::= UnicodeChar - [()^]
456          * [9] UnicodeChar ::= [#x0-#x10FFFF]
457          *
458          */

459         private static final int XPTRTOKEN_OPEN_PAREN = 0,
460                 XPTRTOKEN_CLOSE_PAREN = 1, XPTRTOKEN_SHORTHAND = 2,
461                 XPTRTOKEN_SCHEMENAME = 3, XPTRTOKEN_SCHEMEDATA = 4;
462
463         // Token names
464
private final String JavaDoc[] fgTokenNames = { "XPTRTOKEN_OPEN_PAREN",
465                 "XPTRTOKEN_CLOSE_PAREN", "XPTRTOKEN_SHORTHAND",
466                 "XPTRTOKEN_SCHEMENAME", "XPTRTOKEN_SCHEMEDATA" };
467
468         // Token count
469
private static final int INITIAL_TOKEN_COUNT = 1 << 8;
470
471         private int[] fTokens = new int[INITIAL_TOKEN_COUNT];
472
473         private int fTokenCount = 0;
474
475         // Current token position
476
private int fCurrentTokenIndex;
477
478         private SymbolTable fSymbolTable;
479
480         private Hashtable JavaDoc fTokenNames = new Hashtable JavaDoc();
481
482         /**
483          * Constructor
484          *
485          * @param symbolTable SymbolTable
486          */

487         private Tokens(SymbolTable symbolTable) {
488             fSymbolTable = symbolTable;
489
490             fTokenNames.put(new Integer JavaDoc(XPTRTOKEN_OPEN_PAREN),
491                     "XPTRTOKEN_OPEN_PAREN");
492             fTokenNames.put(new Integer JavaDoc(XPTRTOKEN_CLOSE_PAREN),
493                     "XPTRTOKEN_CLOSE_PAREN");
494             fTokenNames.put(new Integer JavaDoc(XPTRTOKEN_SHORTHAND),
495                     "XPTRTOKEN_SHORTHAND");
496             fTokenNames.put(new Integer JavaDoc(XPTRTOKEN_SCHEMENAME),
497                     "XPTRTOKEN_SCHEMENAME");
498             fTokenNames.put(new Integer JavaDoc(XPTRTOKEN_SCHEMEDATA),
499                     "XPTRTOKEN_SCHEMEDATA");
500         }
501
502         /**
503          * Returns the token String
504          * @param token The index of the token
505          * @return String The token string
506          */

507         private String JavaDoc getTokenString(int token) {
508             return (String JavaDoc) fTokenNames.get(new Integer JavaDoc(token));
509         }
510
511         /**
512          * Add the specified string as a token
513          *
514          * @param token The token string
515          */

516         private void addToken(String JavaDoc tokenStr) {
517             Integer JavaDoc tokenInt = (Integer JavaDoc) fTokenNames.get(tokenStr);
518             if (tokenInt == null) {
519                 tokenInt = new Integer JavaDoc(fTokenNames.size());
520                 fTokenNames.put(tokenInt, tokenStr);
521             }
522             addToken(tokenInt.intValue());
523         }
524
525         /**
526          * Add the specified int token
527          *
528          * @param token The int specifying the token
529          */

530         private void addToken(int token) {
531             try {
532                 fTokens[fTokenCount] = token;
533             } catch (ArrayIndexOutOfBoundsException JavaDoc ex) {
534                 int[] oldList = fTokens;
535                 fTokens = new int[fTokenCount << 1];
536                 System.arraycopy(oldList, 0, fTokens, 0, fTokenCount);
537                 fTokens[fTokenCount] = token;
538             }
539             fTokenCount++;
540         }
541
542         /**
543          * Resets the current position to the head of the token list.
544          */

545         private void rewind() {
546             fCurrentTokenIndex = 0;
547         }
548
549         /**
550          * Returns true if the {@link #getNextToken()} method
551          * returns a valid token.
552          */

553         private boolean hasMore() {
554             return fCurrentTokenIndex < fTokenCount;
555         }
556
557         /**
558          * Obtains the token at the current position, then advance
559          * the current position by one.
560          *
561          * throws If there's no such next token, this method throws
562          * <tt>new XNIException("XPointerProcessingError");</tt>.
563          */

564         private int nextToken() throws XNIException {
565             if (fCurrentTokenIndex == fTokenCount) {
566                 reportError("XPointerProcessingError", null);
567             }
568             return fTokens[fCurrentTokenIndex++];
569         }
570
571         /**
572          * Obtains the token at the current position, without advancing
573          * the current position.
574          *
575          * If there's no such next token, this method throws
576          * <tt>new XNIException("XPointerProcessingError");</tt>.
577          */

578         private int peekToken() throws XNIException {
579             if (fCurrentTokenIndex == fTokenCount) {
580                 reportError("XPointerProcessingError", null);
581             }
582             return fTokens[fCurrentTokenIndex];
583         }
584
585         /**
586          * Obtains the token at the current position as a String.
587          *
588          * If there's no current token or if the current token
589          * is not a string token, this method throws
590          * If there's no such next token, this method throws
591          * <tt>new XNIException("XPointerProcessingError");</tt>.
592          */

593         private String JavaDoc nextTokenAsString() throws XNIException {
594             String JavaDoc tokenStrint = getTokenString(nextToken());
595             if (tokenStrint == null) {
596                 reportError("XPointerProcessingError", null);
597             }
598             return tokenStrint;
599         }
600     }
601
602     /**
603      *
604      * The XPointer expression scanner. Scans the XPointer framework expression.
605      *
606      * @xerces.internal
607      *
608      */

609     private class Scanner {
610
611         /**
612          * 7-bit ASCII subset
613          *
614          * 0 1 2 3 4 5 6 7 8 9 A B C D E F
615          * 0, 0, 0, 0, 0, 0, 0, 0, 0, HT, LF, 0, 0, CR, 0, 0, // 0
616          * 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1
617          * SP, !, ", #, $, %, &, ', (, ), *, +, ,, -, ., /, // 2
618          * 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, :, ;, <, =, >, ?, // 3
619          * @, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, // 4
620          * P, Q, R, S, T, U, V, W, X, Y, Z, [, \, ], ^, _, // 5
621          * `, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, // 6
622          * p, q, r, s, t, u, v, w, x, y, z, {, |, }, ~, DEL // 7
623          */

624         private static final byte CHARTYPE_INVALID = 0, // invalid XML character
625
CHARTYPE_OTHER = 1, // not special - one of "#%&;?\`{}~" or DEL
626
CHARTYPE_WHITESPACE = 2, // one of "\t\n\r " (0x09, 0x0A, 0x0D, 0x20)
627
CHARTYPE_CARRET = 3, // ^
628
CHARTYPE_OPEN_PAREN = 4, // '(' (0x28)
629
CHARTYPE_CLOSE_PAREN = 5, // ')' (0x29)
630
CHARTYPE_MINUS = 6, // '-' (0x2D)
631
CHARTYPE_PERIOD = 7, // '.' (0x2E)
632
CHARTYPE_SLASH = 8, // '/' (0x2F)
633
CHARTYPE_DIGIT = 9, // '0'-'9' (0x30 to 0x39)
634
CHARTYPE_COLON = 10, // ':' (0x3A)
635
CHARTYPE_EQUAL = 11, // '=' (0x3D)
636
CHARTYPE_LETTER = 12, // 'A'-'Z' or 'a'-'z' (0x41 to 0x5A and 0x61 to 0x7A)
637
CHARTYPE_UNDERSCORE = 13, // '_' (0x5F)
638
CHARTYPE_NONASCII = 14; // Non-ASCII Unicode codepoint (>= 0x80)
639

640         private final byte[] fASCIICharMap = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2,
641                 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
642                 2, 1, 1, 1, 1, 1, 1, 1, 4, 5, 1, 1, 1, 6, 7, 8, 9, 9, 9, 9, 9,
643                 9, 9, 9, 9, 9, 10, 1, 1, 11, 1, 1, 1, 12, 12, 12, 12, 12, 12,
644                 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
645                 12, 12, 12, 12, 1, 1, 1, 3, 13, 1, 12, 12, 12, 12, 12, 12, 12,
646                 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
647                 12, 12, 12, 1, 1, 1, 1, 1 };
648
649         //
650
// Data
651
//
652
/** Symbol table. */
653         private SymbolTable fSymbolTable;
654
655         /**
656          * Constructs an XPointer Framework expression scanner.
657          *
658          * @param symbolTable SymbolTable
659          */

660         private Scanner(SymbolTable symbolTable) {
661             // save pool and tokens
662
fSymbolTable = symbolTable;
663
664         } // <init>(SymbolTable)
665

666         /**
667          * Scans the XPointer Expression
668          *
669          */

670         private boolean scanExpr(SymbolTable symbolTable, Tokens tokens,
671                 String JavaDoc data, int currentOffset, int endOffset)
672                 throws XNIException {
673
674             int ch;
675             int openParen = 0;
676             int closeParen = 0;
677             int nameOffset, dataOffset;
678             boolean isQName = false;
679             String JavaDoc name = null;
680             String JavaDoc prefix = null;
681             String JavaDoc schemeData = null;
682             StringBuffer JavaDoc schemeDataBuff = new StringBuffer JavaDoc();
683
684             while (true) {
685
686                 if (currentOffset == endOffset) {
687                     break;
688                 }
689                 ch = data.charAt(currentOffset);
690
691                 //
692
while (ch == ' ' || ch == 0x0A || ch == 0x09 || ch == 0x0D) {
693                     if (++currentOffset == endOffset) {
694                         break;
695                     }
696                     ch = data.charAt(currentOffset);
697                 }
698                 if (currentOffset == endOffset) {
699                     break;
700                 }
701
702                 //
703
// [1] Pointer ::= Shorthand | SchemeBased
704
// [2] Shorthand ::= NCName
705
// [3] SchemeBased ::= PointerPart (S? PointerPart)*
706
// [4] PointerPart ::= SchemeName '(' SchemeData ')'
707
// [5] SchemeName ::= QName
708
// [6] SchemeData ::= EscapedData*
709
// [7] EscapedData ::= NormalChar | '^(' | '^)' | '^^' | '(' SchemeData ')'
710
// [8] NormalChar ::= UnicodeChar - [()^]
711
// [9] UnicodeChar ::= [#x0-#x10FFFF]
712
// [?] QName ::= (NCName ':')? NCName
713
// [?] NCName ::= (Letter | '_') (NCNameChar)*
714
// [?] NCNameChar ::= Letter | Digit | '.' | '-' | '_' (ascii subset of 'NCNameChar')
715
// [?] Letter ::= [A-Za-z] (ascii subset of 'Letter')
716
// [?] Digit ::= [0-9] (ascii subset of 'Digit')
717
//
718
byte chartype = (ch >= 0x80) ? CHARTYPE_NONASCII
719                         : fASCIICharMap[ch];
720
721                 switch (chartype) {
722
723                 case CHARTYPE_OPEN_PAREN: // '('
724
addToken(tokens, Tokens.XPTRTOKEN_OPEN_PAREN);
725                     openParen++;
726                     ++currentOffset;
727                     break;
728
729                 case CHARTYPE_CLOSE_PAREN: // ')'
730
addToken(tokens, Tokens.XPTRTOKEN_CLOSE_PAREN);
731                     closeParen++;
732                     ++currentOffset;
733                     break;
734
735                 case CHARTYPE_CARRET:
736                 case CHARTYPE_COLON:
737                 case CHARTYPE_DIGIT:
738                 case CHARTYPE_EQUAL:
739                 case CHARTYPE_LETTER:
740                 case CHARTYPE_MINUS:
741                 case CHARTYPE_NONASCII:
742                 case CHARTYPE_OTHER:
743                 case CHARTYPE_PERIOD:
744                 case CHARTYPE_SLASH:
745                 case CHARTYPE_UNDERSCORE:
746                 case CHARTYPE_WHITESPACE:
747                     // Scanning SchemeName | Shorthand
748
if (openParen == 0) {
749                         nameOffset = currentOffset;
750                         currentOffset = scanNCName(data, endOffset,
751                                 currentOffset);
752
753                         if (currentOffset == nameOffset) {
754                             reportError("InvalidShortHandPointer",
755                                     new Object JavaDoc[] { data });
756                             return false;
757                         }
758
759                         if (currentOffset < endOffset) {
760                             ch = data.charAt(currentOffset);
761                         } else {
762                             ch = -1;
763                         }
764
765                         name = symbolTable.addSymbol(data.substring(nameOffset,
766                                 currentOffset));
767                         prefix = XMLSymbols.EMPTY_STRING;
768
769                         // The name is a QName => a SchemeName
770
if (ch == ':') {
771                             if (++currentOffset == endOffset) {
772                                 return false;
773                             }
774
775                             ch = data.charAt(currentOffset);
776                             prefix = name;
777                             nameOffset = currentOffset;
778                             currentOffset = scanNCName(data, endOffset,
779                                     currentOffset);
780
781                             if (currentOffset == nameOffset) {
782                                 return false;
783                             }
784
785                             if (currentOffset < endOffset) {
786                                 ch = data.charAt(currentOffset);
787                             } else {
788                                 ch = -1;
789                             }
790
791                             isQName = true;
792                             name = symbolTable.addSymbol(data.substring(
793                                     nameOffset, currentOffset));
794                         }
795
796                         // REVISIT:
797
if (currentOffset != endOffset) {
798                             addToken(tokens, Tokens.XPTRTOKEN_SCHEMENAME);
799                             tokens.addToken(prefix);
800                             tokens.addToken(name);
801                             isQName = false;
802                         } else if (currentOffset == endOffset) {
803                             // NCName => Shorthand
804
addToken(tokens, Tokens.XPTRTOKEN_SHORTHAND);
805                             tokens.addToken(name);
806                             isQName = false;
807                         }
808
809                         // reset open/close paren for the next pointer part
810
closeParen = 0;
811
812                         break;
813
814                     } else if (openParen > 0 && closeParen == 0 && name != null) {
815                         // Scanning SchemeData
816
dataOffset = currentOffset;
817                         currentOffset = scanData(data, schemeDataBuff,
818                                 endOffset, currentOffset);
819
820                         if (currentOffset == dataOffset) {
821                             reportError("InvalidSchemeDataInXPointer",
822                                     new Object JavaDoc[] { data });
823                             return false;
824                         }
825
826                         if (currentOffset < endOffset) {
827                             ch = data.charAt(currentOffset);
828                         } else {
829                             ch = -1;
830                         }
831
832                         schemeData = symbolTable.addSymbol(schemeDataBuff
833                                 .toString());
834                         addToken(tokens, Tokens.XPTRTOKEN_SCHEMEDATA);
835                         tokens.addToken(schemeData);
836
837                         // reset open/close paren for the next pointer part
838
openParen = 0;
839                         schemeDataBuff.delete(0, schemeDataBuff.length());
840
841                     } else {
842                         // ex. schemeName()
843
// Should we throw an exception with a more suitable message instead??
844
return false;
845                     }
846                 }
847             } // end while
848
return true;
849         }
850
851         /**
852          * Scans a NCName.
853          * From Namespaces in XML
854          * [5] NCName ::= (Letter | '_') (NCNameChar)*
855          * [6] NCNameChar ::= Letter | Digit | '.' | '-' | '_' | CombiningChar | Extender
856          *
857          * @param data A String containing the XPointer expression
858          * @param endOffset The int XPointer expression length
859          * @param currentOffset An int representing the current position of the XPointer expression pointer
860          */

861         private int scanNCName(String JavaDoc data, int endOffset, int currentOffset) {
862             int ch = data.charAt(currentOffset);
863             if (ch >= 0x80) {
864                 if (!XMLChar.isNameStart(ch)) {
865                     return currentOffset;
866                 }
867             } else {
868                 byte chartype = fASCIICharMap[ch];
869                 if (chartype != CHARTYPE_LETTER
870                         && chartype != CHARTYPE_UNDERSCORE) {
871                     return currentOffset;
872                 }
873             }
874
875             //while (currentOffset++ < endOffset) {
876
while (++currentOffset < endOffset) {
877                 ch = data.charAt(currentOffset);
878                 if (ch >= 0x80) {
879                     if (!XMLChar.isName(ch)) {
880                         break;
881                     }
882                 } else {
883                     byte chartype = fASCIICharMap[ch];
884                     if (chartype != CHARTYPE_LETTER
885                             && chartype != CHARTYPE_DIGIT
886                             && chartype != CHARTYPE_PERIOD
887                             && chartype != CHARTYPE_MINUS
888                             && chartype != CHARTYPE_UNDERSCORE) {
889                         break;
890                     }
891                 }
892             }
893             return currentOffset;
894         }
895
896         /**
897          * Scans the SchemeData.
898          * [6] SchemeData ::= EscapedData*
899          * [7] EscapedData ::= NormalChar | '^(' | '^)' | '^^' | '(' SchemeData ')'
900          * [8] NormalChar ::= UnicodeChar - [()^]
901          * [9] UnicodeChar ::= [#x0-#x10FFFF]
902          *
903          */

904         private int scanData(String JavaDoc data, StringBuffer JavaDoc schemeData,
905                 int endOffset, int currentOffset) {
906             while (true) {
907
908                 if (currentOffset == endOffset) {
909                     break;
910                 }
911
912                 int ch = data.charAt(currentOffset);
913                 byte chartype = (ch >= 0x80) ? CHARTYPE_NONASCII
914                         : fASCIICharMap[ch];
915
916                 if (chartype == CHARTYPE_OPEN_PAREN) {
917                     schemeData.append(ch);
918                     //schemeData.append(Tokens.XPTRTOKEN_OPEN_PAREN);
919
currentOffset = scanData(data, schemeData, endOffset,
920                             ++currentOffset);
921                     if (currentOffset == endOffset) {
922                         return currentOffset;
923                     }
924
925                     ch = data.charAt(currentOffset);
926                     chartype = (ch >= 0x80) ? CHARTYPE_NONASCII
927                             : fASCIICharMap[ch];
928
929                     if (chartype != CHARTYPE_CLOSE_PAREN) {
930                         return endOffset;
931                     }
932                     schemeData.append((char) ch);
933                     ++currentOffset;//
934

935                 } else if (chartype == CHARTYPE_CLOSE_PAREN) {
936                     return currentOffset;
937                     
938                 } else if (chartype == CHARTYPE_CARRET) {
939                     ch = data.charAt(++currentOffset);
940                     chartype = (ch >= 0x80) ? CHARTYPE_NONASCII
941                             : fASCIICharMap[ch];
942
943                     if (chartype != CHARTYPE_CARRET
944                             && chartype != CHARTYPE_OPEN_PAREN
945                             && chartype != CHARTYPE_CLOSE_PAREN) {
946                         break;
947                     }
948                     schemeData.append((char) ch);
949                     ++currentOffset;
950
951                 } else {
952                     schemeData.append((char) ch);
953                     ++currentOffset;//
954
}
955             }
956
957             return currentOffset;
958         }
959
960         //
961
// Protected methods
962
//
963

964         /**
965          * This method adds the specified token to the token list. By
966          * default, this method allows all tokens. However, subclasses
967          * of the XPathExprScanner can override this method in order
968          * to disallow certain tokens from being used in the scanned
969          * XPath expression. This is a convenient way of allowing only
970          * a subset of XPath.
971          */

972         protected void addToken(Tokens tokens, int token) throws XNIException {
973             tokens.addToken(token);
974         } // addToken(int)
975

976     } // class Scanner
977

978     // ************************************************************************
979
// Overridden XMLDocumentHandler methods
980
// ************************************************************************
981
/**
982      * If the comment is a child of a matched element, then pass else return.
983      *
984      * @param text The text in the comment.
985      * @param augs Additional information that may include infoset augmentations
986      *
987      * @exception XNIException
988      * Thrown by application to signal an error.
989      */

990     public void comment(XMLString text, Augmentations augs) throws XNIException {
991         if (!isChildFragmentResolved()) {
992             return;
993         }
994         super.comment(text, augs);
995     }
996
997     /**
998      * A processing instruction. Processing instructions consist of a
999      * target name and, optionally, text data. The data is only meaningful
1000     * to the application.
1001     * <p>
1002     * Typically, a processing instruction's data will contain a series
1003     * of pseudo-attributes. These pseudo-attributes follow the form of
1004     * element attributes but are <strong>not</strong> parsed or presented
1005     * to the application as anything other than text. The application is
1006     * responsible for parsing the data.
1007     *
1008     * @param target The target.
1009     * @param data The data or null if none specified.
1010     * @param augs Additional information that may include infoset augmentations
1011     *
1012     * @exception XNIException
1013     * Thrown by handler to signal an error.
1014     */

1015    public void processingInstruction(String JavaDoc target, XMLString data,
1016            Augmentations augs) throws XNIException {
1017        if (!isChildFragmentResolved()) {
1018            return;
1019        }
1020        super.processingInstruction(target, data, augs);
1021    }
1022
1023    /**
1024     * The start of an element.
1025     *
1026     * @param element The name of the element.
1027     * @param attributes The element attributes.
1028     * @param augs Additional information that may include infoset augmentations
1029     *
1030     * @exception XNIException
1031     * Thrown by handler to signal an error.
1032     */

1033    public void startElement(QName element, XMLAttributes attributes,
1034            Augmentations augs) throws XNIException {
1035        if (!resolveXPointer(element, attributes, augs,
1036                XPointerPart.EVENT_ELEMENT_START)) {
1037
1038            // xml:base and xml:lang processing
1039
if (fFixupBase) {
1040                processXMLBaseAttributes(attributes);
1041            }
1042            if (fFixupLang) {
1043                processXMLLangAttributes(attributes);
1044            }
1045
1046            // set the context invalid if the element till an element from the result infoset is included
1047
fNamespaceContext.setContextInvalid();
1048
1049            return;
1050        }
1051        super.startElement(element, attributes, augs);
1052    }
1053
1054    /**
1055     * An empty element.
1056     *
1057     * @param element The name of the element.
1058     * @param attributes The element attributes.
1059     * @param augs Additional information that may include infoset augmentations
1060     *
1061     * @exception XNIException
1062     * Thrown by handler to signal an error.
1063     */

1064    public void emptyElement(QName element, XMLAttributes attributes,
1065            Augmentations augs) throws XNIException {
1066        if (!resolveXPointer(element, attributes, augs,
1067                XPointerPart.EVENT_ELEMENT_EMPTY)) {
1068            // xml:base and xml:lang processing
1069
if (fFixupBase) {
1070                processXMLBaseAttributes(attributes);
1071            }
1072            if (fFixupLang) {
1073                processXMLLangAttributes(attributes);
1074            }
1075            // no need to restore restoreBaseURI() for xml:base and xml:lang processing
1076

1077            // set the context invalid if the element till an element from the result infoset is included
1078
fNamespaceContext.setContextInvalid();
1079            return;
1080        }
1081        super.emptyElement(element, attributes, augs);
1082    }
1083
1084    /**
1085     * Character content.
1086     *
1087     * @param text The content.
1088     * @param augs Additional information that may include infoset augmentations
1089     *
1090     * @exception XNIException
1091     * Thrown by handler to signal an error.
1092     */

1093    public void characters(XMLString text, Augmentations augs)
1094            throws XNIException {
1095        if (!isChildFragmentResolved()) {
1096            return;
1097        }
1098        super.characters(text, augs);
1099    }
1100
1101    /**
1102     * Ignorable whitespace. For this method to be called, the document
1103     * source must have some way of determining that the text containing
1104     * only whitespace characters should be considered ignorable. For
1105     * example, the validator can determine if a length of whitespace
1106     * characters in the document are ignorable based on the element
1107     * content model.
1108     *
1109     * @param text The ignorable whitespace.
1110     * @param augs Additional information that may include infoset augmentations
1111     *
1112     * @exception XNIException
1113     * Thrown by handler to signal an error.
1114     */

1115    public void ignorableWhitespace(XMLString text, Augmentations augs)
1116            throws XNIException {
1117        if (!isChildFragmentResolved()) {
1118            return;
1119        }
1120        super.ignorableWhitespace(text, augs);
1121    }
1122
1123    /**
1124     * The end of an element.
1125     *
1126     * @param element The name of the element.
1127     * @param augs Additional information that may include infoset augmentations
1128     *
1129     * @exception XNIException
1130     * Thrown by handler to signal an error.
1131     */

1132    public void endElement(QName element, Augmentations augs)
1133            throws XNIException {
1134        if (!resolveXPointer(element, null, augs,
1135                XPointerPart.EVENT_ELEMENT_END)) {
1136
1137            // no need to restore restoreBaseURI() for xml:base and xml:lang processing
1138
return;
1139        }
1140        super.endElement(element, augs);
1141    }
1142
1143    /**
1144     * The start of a CDATA section.
1145     *
1146     * @param augs Additional information that may include infoset augmentations
1147     *
1148     * @exception XNIException
1149     * Thrown by handler to signal an error.
1150     */

1151    public void startCDATA(Augmentations augs) throws XNIException {
1152        if (!isChildFragmentResolved()) {
1153            return;
1154        }
1155        super.startCDATA(augs);
1156    }
1157
1158    /**
1159     * The end of a CDATA section.
1160     *
1161     * @param augs Additional information that may include infoset augmentations
1162     *
1163     * @exception XNIException
1164     * Thrown by handler to signal an error.
1165     */

1166    public void endCDATA(Augmentations augs) throws XNIException {
1167        if (!isChildFragmentResolved()) {
1168            return;
1169        }
1170        super.endCDATA(augs);
1171    }
1172
1173    // ************************************************************************
1174
// Overridden XMLComponent methods
1175
// ************************************************************************
1176
/**
1177     * <p>
1178     * Sets the value of a property. This method is called by the component
1179     * manager any time after reset when a property changes value.
1180     * </p>
1181     * <strong>Note:</strong> Components should silently ignore properties
1182     * that do not affect the operation of the component.
1183     *
1184     * @param propertyId The property identifier.
1185     * @param value The value of the property.
1186     *
1187     * @throws XMLConfigurationException Thrown for configuration error.
1188     * In general, components should
1189     * only throw this exception if
1190     * it is <strong>really</strong>
1191     * a critical error.
1192     */

1193    public void setProperty(String JavaDoc propertyId, Object JavaDoc value)
1194            throws XMLConfigurationException {
1195
1196        // Error reporter
1197
if (propertyId == Constants.XERCES_PROPERTY_PREFIX
1198                + Constants.ERROR_REPORTER_PROPERTY) {
1199            if (value != null) {
1200                fXPointerErrorReporter = (XMLErrorReporter) value;
1201            } else {
1202                fXPointerErrorReporter = null;
1203            }
1204        }
1205
1206        // Error handler
1207
if (propertyId == Constants.XERCES_PROPERTY_PREFIX
1208                + Constants.ERROR_HANDLER_PROPERTY) {
1209            if (value != null) {
1210                fErrorHandler = (XMLErrorHandler) value;
1211            } else {
1212                fErrorHandler = null;
1213            }
1214        }
1215
1216        // xml:lang
1217
if (propertyId == Constants.XERCES_FEATURE_PREFIX
1218                + Constants.XINCLUDE_FIXUP_LANGUAGE_FEATURE) {
1219            if (value != null) {
1220                fFixupLang = ((Boolean JavaDoc)value).booleanValue();
1221            } else {
1222                fFixupLang = false;
1223            }
1224        }
1225        
1226        // xml:base
1227
if (propertyId == Constants.XERCES_FEATURE_PREFIX
1228                + Constants.XINCLUDE_FIXUP_BASE_URIS_FEATURE) {
1229            if (value != null) {
1230                fFixupBase = ((Boolean JavaDoc)value).booleanValue();
1231            } else {
1232                fFixupBase = false;
1233            }
1234        }
1235        
1236        //
1237
if (propertyId == Constants.XERCES_PROPERTY_PREFIX
1238                + Constants.NAMESPACE_CONTEXT_PROPERTY) {
1239            fNamespaceContext = (XIncludeNamespaceSupport) value;
1240        }
1241
1242        super.setProperty(propertyId, value);
1243    }
1244
1245}
Popular Tags