| /* |
| * reserved comment block |
| * DO NOT REMOVE OR ALTER! |
| */ |
| /* |
| * Copyright 2005 The Apache Software Foundation. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package com.sun.org.apache.xerces.internal.xpointer; |
| |
| import java.util.Hashtable; |
| |
| import com.sun.org.apache.xerces.internal.impl.XMLErrorReporter; |
| import com.sun.org.apache.xerces.internal.util.SymbolTable; |
| import com.sun.org.apache.xerces.internal.util.XMLChar; |
| import com.sun.org.apache.xerces.internal.xni.Augmentations; |
| import com.sun.org.apache.xerces.internal.xni.QName; |
| import com.sun.org.apache.xerces.internal.xni.XMLAttributes; |
| import com.sun.org.apache.xerces.internal.xni.XNIException; |
| import com.sun.org.apache.xerces.internal.xni.parser.XMLErrorHandler; |
| |
| /** |
| * <p> |
| * Implements the XPointerPart interface for element() scheme specific processing. |
| * </p> |
| * |
| * @xerces.internal |
| * |
| * @version $Id: ElementSchemePointer.java,v 1.4 2009/06/11 23:51:50 joehw Exp $ |
| * |
| */ |
| class ElementSchemePointer implements XPointerPart { |
| |
| // Fields |
| |
| // The Scheme Name i.e element |
| private String fSchemeName; |
| |
| // The scheme Data |
| private String fSchemeData; |
| |
| // The scheme Data & child sequence |
| private String fShortHandPointerName; |
| |
| // Should we attempt to resolve the ChildSequence from the |
| // current element position. If a ShortHand Pointer is present |
| // attempt to resolve relative to the short hand pointer. |
| private boolean fIsResolveElement = false; |
| |
| // Has the element been found |
| private boolean fIsElementFound = false; |
| |
| // Was only an empty element found |
| private boolean fWasOnlyEmptyElementFound = false; |
| |
| // If a shorthand pointer is present and resolved |
| boolean fIsShortHand = false; |
| |
| // The depth at which the element was found |
| int fFoundDepth = 0; |
| |
| // The XPointer element child sequence |
| private int fChildSequence[]; |
| |
| // The current child position |
| private int fCurrentChildPosition = 1; |
| |
| // The current child depth |
| private int fCurrentChildDepth = 0; |
| |
| // The current element's child sequence |
| private int fCurrentChildSequence[];; |
| |
| // Stores if the Fragment was resolved by the pointer |
| private boolean fIsFragmentResolved = false; |
| |
| // Stores if the Fragment was resolved by the pointer |
| private ShortHandPointer fShortHandPointer; |
| |
| // The XPointer Error reporter |
| protected XMLErrorReporter fErrorReporter; |
| |
| // The XPointer Error Handler |
| protected XMLErrorHandler fErrorHandler; |
| |
| // |
| private SymbolTable fSymbolTable; |
| |
| // ************************************************************************ |
| // Constructors |
| // ************************************************************************ |
| public ElementSchemePointer() { |
| } |
| |
| public ElementSchemePointer(SymbolTable symbolTable) { |
| fSymbolTable = symbolTable; |
| } |
| |
| public ElementSchemePointer(SymbolTable symbolTable, |
| XMLErrorReporter errorReporter) { |
| fSymbolTable = symbolTable; |
| fErrorReporter = errorReporter; |
| } |
| |
| // ************************************************************************ |
| // XPointerPart implementation |
| // ************************************************************************ |
| |
| /** |
| * Parses the XPointer expression and tokenizes it into Strings |
| * delimited by whitespace. |
| * |
| * @see com.sun.org.apache.xerces.internal.xpointer.XPointerProcessor#parseXPointer(java.lang.String) |
| */ |
| public void parseXPointer(String xpointer) throws XNIException { |
| |
| // |
| init(); |
| |
| // tokens |
| final Tokens tokens = new Tokens(fSymbolTable); |
| |
| // scanner |
| Scanner scanner = new Scanner(fSymbolTable) { |
| protected void addToken(Tokens tokens, int token) |
| throws XNIException { |
| if (token == Tokens.XPTRTOKEN_ELEM_CHILD |
| || token == Tokens.XPTRTOKEN_ELEM_NCNAME) { |
| super.addToken(tokens, token); |
| return; |
| } |
| reportError("InvalidElementSchemeToken", new Object[] { tokens |
| .getTokenString(token) }); |
| } |
| }; |
| |
| // scan the element() XPointer expression |
| int length = xpointer.length(); |
| boolean success = scanner.scanExpr(fSymbolTable, tokens, xpointer, 0, |
| length); |
| |
| if (!success) { |
| reportError("InvalidElementSchemeXPointer", |
| new Object[] { xpointer }); |
| } |
| |
| // Initialize a temp arrays to the size of token count which should |
| // be atleast twice the size of child sequence, to hold the ChildSequence. |
| int tmpChildSequence[] = new int[tokens.getTokenCount() / 2 + 1]; |
| |
| // the element depth |
| int i = 0; |
| |
| // Traverse the scanned tokens |
| while (tokens.hasMore()) { |
| int token = tokens.nextToken(); |
| |
| switch (token) { |
| case Tokens.XPTRTOKEN_ELEM_NCNAME: { |
| // Note: Only a single ShortHand pointer can be present |
| |
| // The shortHand name |
| token = tokens.nextToken(); |
| fShortHandPointerName = tokens.getTokenString(token); |
| |
| // Create a new ShortHandPointer |
| fShortHandPointer = new ShortHandPointer(fSymbolTable); |
| fShortHandPointer.setSchemeName(fShortHandPointerName); |
| |
| break; |
| } |
| case Tokens.XPTRTOKEN_ELEM_CHILD: { |
| tmpChildSequence[i] = tokens.nextToken(); |
| i++; |
| |
| break; |
| } |
| default: |
| reportError("InvalidElementSchemeXPointer", |
| new Object[] { xpointer }); |
| } |
| } |
| |
| // Initialize the arrays to the number of elements in the ChildSequence. |
| fChildSequence = new int[i]; |
| fCurrentChildSequence = new int[i]; |
| System.arraycopy(tmpChildSequence, 0, fChildSequence, 0, i); |
| |
| } |
| |
| /** |
| * Returns the scheme name i.e element |
| * @see com.sun.org.apache.xerces.internal.xpointer.XPointerPart#getSchemeName() |
| */ |
| public String getSchemeName() { |
| return fSchemeName; |
| } |
| |
| /** |
| * Returns the scheme data |
| * |
| * @see com.sun.org.apache.xerces.internal.xpointer.XPointerPart#getSchemeData() |
| */ |
| public String getSchemeData() { |
| return fSchemeData; |
| } |
| |
| /** |
| * Sets the scheme name |
| * |
| * @see com.sun.org.apache.xerces.internal.xpointer.XPointerPart#setSchemeName(java.lang.String) |
| */ |
| public void setSchemeName(String schemeName) { |
| fSchemeName = schemeName; |
| |
| } |
| |
| /** |
| * Sets the scheme data |
| * |
| * @see com.sun.org.apache.xerces.internal.xpointer.XPointerPart#setSchemeData(java.lang.String) |
| */ |
| public void setSchemeData(String schemeData) { |
| fSchemeData = schemeData; |
| } |
| |
| /** |
| * Responsible for resolving the element() scheme XPointer. If a ShortHand |
| * Pointer is present and it is successfully resolved and if a child |
| * sequence is present, the child sequence is resolved relative to it. |
| * |
| * @see com.sun.org.apache.xerces.internal.xpointer.XPointerProcessor#resolveXPointer(com.sun.org.apache.xerces.internal.xni.QName, com.sun.org.apache.xerces.internal.xni.XMLAttributes, com.sun.org.apache.xerces.internal.xni.Augmentations, int event) |
| */ |
| public boolean resolveXPointer(QName element, XMLAttributes attributes, |
| Augmentations augs, int event) throws XNIException { |
| |
| boolean isShortHandPointerResolved = false; |
| |
| // if a ChildSequence exisits, resolve child elements |
| |
| // if an element name exists |
| if (fShortHandPointerName != null) { |
| // resolve ShortHand Pointer |
| isShortHandPointerResolved = fShortHandPointer.resolveXPointer( |
| element, attributes, augs, event); |
| if (isShortHandPointerResolved) { |
| fIsResolveElement = true; |
| fIsShortHand = true; |
| } else { |
| fIsResolveElement = false; |
| } |
| } else { |
| fIsResolveElement = true; |
| } |
| |
| // Added here to skip the ShortHand pointer corresponding to |
| // an element if one exisits and start searching from its child |
| if (fChildSequence.length > 0) { |
| fIsFragmentResolved = matchChildSequence(element, event); |
| } else if (isShortHandPointerResolved && fChildSequence.length <= 0) { |
| // if only a resolved shorthand pointer exists |
| fIsFragmentResolved = isShortHandPointerResolved; |
| } else { |
| fIsFragmentResolved = false; |
| } |
| |
| return fIsFragmentResolved; |
| } |
| |
| /** |
| * Matches the current element position in the document tree with the |
| * element position specified in the element XPointer scheme. |
| * |
| * @param event |
| * @return boolean - true if the current element position in the document |
| * tree matches theelement position specified in the element XPointer |
| * scheme. |
| */ |
| protected boolean matchChildSequence(QName element, int event) |
| throws XNIException { |
| |
| // need to resize fCurrentChildSequence |
| if (fCurrentChildDepth >= fCurrentChildSequence.length) { |
| int tmpCurrentChildSequence[] = new int[fCurrentChildSequence.length]; |
| System.arraycopy(fCurrentChildSequence, 0, tmpCurrentChildSequence, |
| 0, fCurrentChildSequence.length); |
| |
| // Increase the size by a factor of 2 (?) |
| fCurrentChildSequence = new int[fCurrentChildDepth * 2]; |
| System.arraycopy(tmpCurrentChildSequence, 0, fCurrentChildSequence, |
| 0, tmpCurrentChildSequence.length); |
| } |
| |
| // |
| if (fIsResolveElement) { |
| // start |
| fWasOnlyEmptyElementFound = false; |
| if (event == XPointerPart.EVENT_ELEMENT_START) { |
| fCurrentChildSequence[fCurrentChildDepth] = fCurrentChildPosition; |
| fCurrentChildDepth++; |
| |
| // reset the current child position |
| fCurrentChildPosition = 1; |
| |
| //if (!fSchemeNameFound) { |
| if ((fCurrentChildDepth <= fFoundDepth) || (fFoundDepth == 0)) { |
| if (checkMatch()) { |
| fIsElementFound = true; |
| fFoundDepth = fCurrentChildDepth; |
| } else { |
| fIsElementFound = false; |
| fFoundDepth = 0; |
| } |
| } |
| |
| } else if (event == XPointerPart.EVENT_ELEMENT_END) { |
| if (fCurrentChildDepth == fFoundDepth) { |
| fIsElementFound = true; |
| } else if (((fCurrentChildDepth < fFoundDepth) && (fFoundDepth != 0)) |
| || ((fCurrentChildDepth > fFoundDepth) // or empty element found |
| && (fFoundDepth == 0))) { |
| fIsElementFound = false; |
| } |
| |
| // reset array position of last child |
| fCurrentChildSequence[fCurrentChildDepth] = 0; |
| |
| fCurrentChildDepth--; |
| fCurrentChildPosition = fCurrentChildSequence[fCurrentChildDepth] + 1; |
| |
| } else if (event == XPointerPart.EVENT_ELEMENT_EMPTY) { |
| |
| fCurrentChildSequence[fCurrentChildDepth] = fCurrentChildPosition; |
| fCurrentChildPosition++; |
| |
| // Donot check for empty elements if the empty element is |
| // a child of a found parent element |
| //if (!fIsElementFound) { |
| if (checkMatch()) { |
| fIsElementFound = true; |
| fWasOnlyEmptyElementFound = true; |
| } else { |
| fIsElementFound = false; |
| } |
| //} |
| |
| } |
| } |
| |
| return fIsElementFound; |
| } |
| |
| /** |
| * Matches the current position of the element being visited by checking |
| * its position and previous elements against the element XPointer expression. |
| * If a match is found it return true else false. |
| * |
| * @return boolean |
| */ |
| protected boolean checkMatch() { |
| // If the number of elements in the ChildSequence is greater than the |
| // current child depth, there is not point in checking further |
| if (!fIsShortHand) { |
| // If a shorthand pointer is not present traverse the children |
| // and compare |
| if (fChildSequence.length <= fCurrentChildDepth + 1) { |
| |
| for (int i = 0; i < fChildSequence.length; i++) { |
| if (fChildSequence[i] != fCurrentChildSequence[i]) { |
| return false; |
| } |
| } |
| } else { |
| return false; |
| } |
| } else { |
| // If a shorthand pointer is present traverse the children |
| // ignoring the first element of the CurrenChildSequence which |
| // contains the ShortHand pointer element and compare |
| if (fChildSequence.length <= fCurrentChildDepth + 1) { |
| |
| for (int i = 0; i < fChildSequence.length; i++) { |
| // ensure fCurrentChildSequence is large enough |
| if (fCurrentChildSequence.length < i + 2) { |
| return false; |
| } |
| |
| // ignore the first element of fCurrentChildSequence |
| if (fChildSequence[i] != fCurrentChildSequence[i + 1]) { |
| return false; |
| } |
| } |
| } else { |
| return false; |
| } |
| |
| } |
| |
| return true; |
| } |
| |
| /** |
| * Returns true if the node matches or is a child of a matching element() |
| * scheme XPointer. |
| * |
| * @see com.sun.org.apache.xerces.internal.xpointer.XPointerProcessor#isFragmentResolved() |
| */ |
| public boolean isFragmentResolved() throws XNIException { |
| // Return true if the Fragment was resolved and the current Node depth |
| // is greater than or equal to the depth at which the element was found |
| return fIsFragmentResolved ; |
| } |
| |
| /** |
| * Returns true if the XPointer expression resolves to a non-element child |
| * of the current resource fragment. |
| * |
| * @see com.sun.org.apache.xerces.internal.xpointer.XPointerPart#isChildFragmentResolved() |
| * |
| */ |
| public boolean isChildFragmentResolved() { |
| // if only a shorthand pointer was present |
| if (fIsShortHand && fShortHandPointer != null && fChildSequence.length <= 0) { |
| return fShortHandPointer.isChildFragmentResolved(); |
| } else { |
| return fWasOnlyEmptyElementFound ? !fWasOnlyEmptyElementFound |
| : (fIsFragmentResolved && (fCurrentChildDepth >= fFoundDepth)); |
| } |
| } |
| |
| /** |
| * Reports an XPointer error |
| */ |
| protected void reportError(String key, Object[] arguments) |
| throws XNIException { |
| /*fErrorReporter.reportError(XPointerMessageFormatter.XPOINTER_DOMAIN, |
| key, arguments, XMLErrorReporter.SEVERITY_ERROR); |
| */ |
| throw new XNIException((fErrorReporter |
| .getMessageFormatter(XPointerMessageFormatter.XPOINTER_DOMAIN)) |
| .formatMessage(fErrorReporter.getLocale(), key, arguments)); |
| } |
| |
| /** |
| * Initializes error handling objects |
| */ |
| protected void initErrorReporter() { |
| if (fErrorReporter == null) { |
| fErrorReporter = new XMLErrorReporter(); |
| } |
| if (fErrorHandler == null) { |
| fErrorHandler = new XPointerErrorHandler(); |
| } |
| fErrorReporter.putMessageFormatter( |
| XPointerMessageFormatter.XPOINTER_DOMAIN, |
| new XPointerMessageFormatter()); |
| } |
| |
| /** |
| * Initializes the element scheme processor |
| */ |
| protected void init() { |
| fSchemeName = null; |
| fSchemeData = null; |
| fShortHandPointerName = null; |
| fIsResolveElement = false; |
| fIsElementFound = false; |
| fWasOnlyEmptyElementFound = false; |
| fFoundDepth = 0; |
| fCurrentChildPosition = 1; |
| fCurrentChildDepth = 0; |
| fIsFragmentResolved = false; |
| fShortHandPointer = null; |
| |
| initErrorReporter(); |
| } |
| |
| // ************************************************************************ |
| // element() Scheme expression scanner |
| // ************************************************************************ |
| |
| /** |
| * List of XPointer Framework tokens. |
| * |
| * @xerces.internal |
| * |
| * @author Neil Delima, IBM |
| * @version $Id: ElementSchemePointer.java,v 1.4 2009/06/11 23:51:50 joehw Exp $ |
| * |
| */ |
| private final class Tokens { |
| |
| /** |
| * XPointer element() scheme |
| * [1] ElementSchemeData ::= (NCName ChildSequence?) | ChildSequence |
| * [2] ChildSequence ::= ('/' [1-9] [0-9]*)+ |
| */ |
| private static final int XPTRTOKEN_ELEM_NCNAME = 0; |
| |
| private static final int XPTRTOKEN_ELEM_CHILD = 1; |
| |
| // Token names |
| private final String[] fgTokenNames = { "XPTRTOKEN_ELEM_NCNAME", |
| "XPTRTOKEN_ELEM_CHILD" }; |
| |
| // Token count |
| private static final int INITIAL_TOKEN_COUNT = 1 << 8; |
| |
| private int[] fTokens = new int[INITIAL_TOKEN_COUNT]; |
| |
| private int fTokenCount = 0; |
| |
| // Current token position |
| private int fCurrentTokenIndex; |
| |
| private SymbolTable fSymbolTable; |
| |
| private Hashtable fTokenNames = new Hashtable(); |
| |
| /** |
| * Constructor |
| * |
| * @param symbolTable SymbolTable |
| */ |
| private Tokens(SymbolTable symbolTable) { |
| fSymbolTable = symbolTable; |
| |
| fTokenNames.put(new Integer(XPTRTOKEN_ELEM_NCNAME), |
| "XPTRTOKEN_ELEM_NCNAME"); |
| fTokenNames.put(new Integer(XPTRTOKEN_ELEM_CHILD), |
| "XPTRTOKEN_ELEM_CHILD"); |
| } |
| |
| /* |
| * Returns the token String |
| * @param token The index of the token |
| * @return String The token string |
| */ |
| private String getTokenString(int token) { |
| return (String) fTokenNames.get(new Integer(token)); |
| } |
| |
| /** |
| * Returns the token String |
| * @param token The index of the token |
| * @return String The token string |
| */ |
| private Integer getToken(int token) { |
| return (Integer) fTokenNames.get(new Integer(token)); |
| } |
| |
| /** |
| * Add the specified string as a token |
| * |
| * @param token The token string |
| */ |
| private void addToken(String tokenStr) { |
| Integer tokenInt = (Integer) fTokenNames.get(tokenStr); |
| if (tokenInt == null) { |
| tokenInt = new Integer(fTokenNames.size()); |
| fTokenNames.put(tokenInt, tokenStr); |
| } |
| addToken(tokenInt.intValue()); |
| } |
| |
| /** |
| * Add the specified int token |
| * |
| * @param token The int specifying the token |
| */ |
| private void addToken(int token) { |
| try { |
| fTokens[fTokenCount] = token; |
| } catch (ArrayIndexOutOfBoundsException ex) { |
| int[] oldList = fTokens; |
| fTokens = new int[fTokenCount << 1]; |
| System.arraycopy(oldList, 0, fTokens, 0, fTokenCount); |
| fTokens[fTokenCount] = token; |
| } |
| fTokenCount++; |
| } |
| |
| /** |
| * Resets the current position to the head of the token list. |
| */ |
| private void rewind() { |
| fCurrentTokenIndex = 0; |
| } |
| |
| /** |
| * Returns true if the {@link #getNextToken()} method |
| * returns a valid token. |
| */ |
| private boolean hasMore() { |
| return fCurrentTokenIndex < fTokenCount; |
| } |
| |
| /** |
| * Obtains the token at the current position, then advance |
| * the current position by one. |
| * |
| * If there's no such next token, this method throws |
| * <tt>new XNIException("InvalidXPointerExpression");</tt>. |
| */ |
| private int nextToken() throws XNIException { |
| if (fCurrentTokenIndex == fTokenCount) |
| reportError("XPointerElementSchemeProcessingError", null); |
| return fTokens[fCurrentTokenIndex++]; |
| } |
| |
| /** |
| * Obtains the token at the current position, without advancing |
| * the current position. |
| * |
| * If there's no such next token, this method throws |
| * <tt>new XNIException("InvalidXPointerExpression");</tt>. |
| */ |
| private int peekToken() throws XNIException { |
| if (fCurrentTokenIndex == fTokenCount) |
| reportError("XPointerElementSchemeProcessingError", null); |
| return fTokens[fCurrentTokenIndex]; |
| } |
| |
| /** |
| * Obtains the token at the current position as a String. |
| * |
| * If there's no current token or if the current token |
| * is not a string token, this method throws |
| * If there's no such next token, this method throws |
| * <tt>new XNIException("InvalidXPointerExpression");</tt>. |
| */ |
| private String nextTokenAsString() throws XNIException { |
| String s = getTokenString(nextToken()); |
| if (s == null) |
| reportError("XPointerElementSchemeProcessingError", null); |
| return s; |
| } |
| |
| /** |
| * Returns the number of tokens. |
| * |
| */ |
| private int getTokenCount() { |
| return fTokenCount; |
| } |
| } |
| |
| /** |
| * |
| * The XPointer expression scanner. Scans the XPointer framework expression. |
| * |
| * @xerces.internal |
| * |
| * @version $Id: ElementSchemePointer.java,v 1.4 2009/06/11 23:51:50 joehw Exp $ |
| */ |
| private class Scanner { |
| |
| /** |
| * 7-bit ASCII subset |
| * |
| * 0 1 2 3 4 5 6 7 8 9 A B C D E F |
| * 0, 0, 0, 0, 0, 0, 0, 0, 0, HT, LF, 0, 0, CR, 0, 0, // 0 |
| * 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 |
| * SP, !, ", #, $, %, &, ', (, ), *, +, ,, -, ., /, // 2 |
| * 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, :, ;, <, =, >, ?, // 3 |
| * @, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, // 4 |
| * P, Q, R, S, T, U, V, W, X, Y, Z, [, \, ], ^, _, // 5 |
| * `, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, // 6 |
| * p, q, r, s, t, u, v, w, x, y, z, {, |, }, ~, DEL // 7 |
| */ |
| private static final byte CHARTYPE_INVALID = 0, // invalid XML characters, control characters and 7F |
| CHARTYPE_OTHER = 1, // A valid XML character (possibly invalid NCNameChar) that does not fall in one of the other categories |
| CHARTYPE_MINUS = 2, // '-' (0x2D) |
| CHARTYPE_PERIOD = 3, // '.' (0x2E) |
| CHARTYPE_SLASH = 4, // '/' (0x2F) |
| CHARTYPE_DIGIT = 5, // '0'-'9' (0x30 to 0x39) |
| CHARTYPE_LETTER = 6, // 'A'-'Z' or 'a'-'z' (0x41 to 0x5A and 0x61 to 0x7A) |
| CHARTYPE_UNDERSCORE = 7, // '_' (0x5F) |
| CHARTYPE_NONASCII = 8; // Non-ASCII Unicode codepoint (>= 0x80) |
| |
| private final byte[] fASCIICharMap = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, |
| 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 4, 5, 5, 5, 5, 5, |
| 5, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 6, 6, 6, |
| 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 1, 1, 1, 1, |
| 7, 1, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, |
| 6, 6, 6, 6, 6, 6, 6, 1, 1, 1, 1, 1 }; |
| |
| /** |
| * Symbol literals |
| */ |
| |
| // |
| // Data |
| // |
| /** Symbol table. */ |
| private SymbolTable fSymbolTable; |
| |
| // |
| // Constructors |
| // |
| |
| /** |
| * Constructs an XPath expression scanner. |
| * |
| * @param symbolTable SymbolTable |
| */ |
| private Scanner(SymbolTable symbolTable) { |
| // save pool and tokens |
| fSymbolTable = symbolTable; |
| |
| } // <init>(SymbolTable) |
| |
| /** |
| * Scans the XPointer Expression |
| * |
| */ |
| private boolean scanExpr(SymbolTable symbolTable, Tokens tokens, |
| String data, int currentOffset, int endOffset) |
| throws XNIException { |
| |
| int ch; |
| int nameOffset; |
| String nameHandle = null; |
| |
| while (true) { |
| if (currentOffset == endOffset) { |
| break; |
| } |
| |
| ch = data.charAt(currentOffset); |
| byte chartype = (ch >= 0x80) ? CHARTYPE_NONASCII |
| : fASCIICharMap[ch]; |
| |
| // |
| // [1] ElementSchemeData ::= (NCName ChildSequence?) | ChildSequence |
| // [2] ChildSequence ::= ('/' [1-9] [0-9]*)+ |
| // |
| |
| switch (chartype) { |
| |
| case CHARTYPE_SLASH: |
| // if last character is '/', break and report an error |
| if (++currentOffset == endOffset) { |
| return false; |
| } |
| |
| addToken(tokens, Tokens.XPTRTOKEN_ELEM_CHILD); |
| ch = data.charAt(currentOffset); |
| |
| // ChildSequence ::= ('/' [1-9] [0-9]*)+ |
| int child = 0; |
| while (ch >= '0' && ch <= '9') { |
| child = (child * 10) + (ch - '0'); |
| if (++currentOffset == endOffset) { |
| break; |
| } |
| ch = data.charAt(currentOffset); |
| } |
| |
| // An invalid child sequence character |
| if (child == 0) { |
| reportError("InvalidChildSequenceCharacter", |
| new Object[] { new Character((char) ch) }); |
| return false; |
| } |
| |
| tokens.addToken(child); |
| |
| break; |
| |
| case CHARTYPE_DIGIT: |
| case CHARTYPE_LETTER: |
| case CHARTYPE_MINUS: |
| case CHARTYPE_NONASCII: |
| case CHARTYPE_OTHER: |
| case CHARTYPE_PERIOD: |
| case CHARTYPE_UNDERSCORE: |
| // Scan the ShortHand Pointer NCName |
| nameOffset = currentOffset; |
| currentOffset = scanNCName(data, endOffset, currentOffset); |
| |
| if (currentOffset == nameOffset) { |
| //return false; |
| reportError("InvalidNCNameInElementSchemeData", |
| new Object[] { data }); |
| return false; |
| } |
| |
| if (currentOffset < endOffset) { |
| ch = data.charAt(currentOffset); |
| } else { |
| ch = -1; |
| } |
| |
| nameHandle = symbolTable.addSymbol(data.substring( |
| nameOffset, currentOffset)); |
| addToken(tokens, Tokens.XPTRTOKEN_ELEM_NCNAME); |
| tokens.addToken(nameHandle); |
| |
| break; |
| } |
| } |
| return true; |
| } |
| |
| /** |
| * Scans a NCName. |
| * From Namespaces in XML |
| * [5] NCName ::= (Letter | '_') (NCNameChar)* |
| * [6] NCNameChar ::= Letter | Digit | '.' | '-' | '_' | CombiningChar | Extender |
| * |
| * @param data A String containing the XPointer expression |
| * @param endOffset The int XPointer expression length |
| * @param currentOffset An int representing the current position of the XPointer expression pointer |
| */ |
| private int scanNCName(String data, int endOffset, int currentOffset) { |
| int ch = data.charAt(currentOffset); |
| if (ch >= 0x80) { |
| if (!XMLChar.isNameStart(ch)) { |
| return currentOffset; |
| } |
| } else { |
| byte chartype = fASCIICharMap[ch]; |
| if (chartype != CHARTYPE_LETTER |
| && chartype != CHARTYPE_UNDERSCORE) { |
| return currentOffset; |
| } |
| } |
| while (++currentOffset < endOffset) { |
| ch = data.charAt(currentOffset); |
| if (ch >= 0x80) { |
| if (!XMLChar.isName(ch)) { |
| break; |
| } |
| } else { |
| byte chartype = fASCIICharMap[ch]; |
| if (chartype != CHARTYPE_LETTER |
| && chartype != CHARTYPE_DIGIT |
| && chartype != CHARTYPE_PERIOD |
| && chartype != CHARTYPE_MINUS |
| && chartype != CHARTYPE_UNDERSCORE) { |
| break; |
| } |
| } |
| } |
| return currentOffset; |
| } |
| |
| // |
| // Protected methods |
| // |
| |
| /** |
| * This method adds the specified token to the token list. By |
| * default, this method allows all tokens. However, subclasses |
| * of the XPathExprScanner can override this method in order |
| * to disallow certain tokens from being used in the scanned |
| * XPath expression. This is a convenient way of allowing only |
| * a subset of XPath. |
| */ |
| protected void addToken(Tokens tokens, int token) throws XNIException { |
| tokens.addToken(token); |
| } // addToken(int) |
| |
| } // class Scanner |
| |
| } |