001: package net.sf.saxon.pattern;
002:
003: import net.sf.saxon.expr.Expression;
004: import net.sf.saxon.expr.StaticContext;
005: import net.sf.saxon.expr.XPathContext;
006: import net.sf.saxon.expr.PromotionOffer;
007: import net.sf.saxon.om.DocumentInfo;
008: import net.sf.saxon.om.NodeInfo;
009: import net.sf.saxon.trans.XPathException;
010: import net.sf.saxon.type.ItemType;
011: import net.sf.saxon.type.Type;
012: import net.sf.saxon.value.AtomicValue;
013:
014: import java.util.StringTokenizer;
015: import java.util.Iterator;
016:
017: /**
018: * An IDPattern is a pattern of the form id("literal") or id($variable)
019: */
020:
021: public final class IDPattern extends Pattern {
022:
023: private Expression idExpression;
024:
025: /**
026: * Create an id pattern.
027: * @param id Either a StringValue or a VariableReference
028: */
029: public IDPattern(Expression id) {
030: idExpression = id;
031: }
032:
033: /**
034: * Type-check the pattern.
035: * Default implementation does nothing. This is only needed for patterns that contain
036: * variable references or function calls.
037: * @return the optimised Pattern
038: */
039:
040: public Pattern analyze(StaticContext env, ItemType contextItemType)
041: throws XPathException {
042: idExpression = idExpression.typeCheck(env, contextItemType);
043: return this ;
044: }
045:
046: /**
047: * Get the dependencies of the pattern. The only possible dependency for a pattern is
048: * on local variables. This is analyzed in those patterns where local variables may appear.
049: */
050:
051: public int getDependencies() {
052: return idExpression.getDependencies();
053: }
054:
055: /**
056: * Iterate over the subexpressions within this pattern
057: */
058:
059: public Iterator iterateSubExpressions() {
060: return idExpression.iterateSubExpressions();
061: }
062:
063: /**
064: * Offer promotion for subexpressions within this pattern. The offer will be accepted if the subexpression
065: * is not dependent on the factors (e.g. the context item) identified in the PromotionOffer.
066: * By default the offer is not accepted - this is appropriate in the case of simple expressions
067: * such as constant values and variable references where promotion would give no performance
068: * advantage. This method is always called at compile time.
069: * <p/>
070: * <p>Unlike the corresponding method on {@link net.sf.saxon.expr.Expression}, this method does not return anything:
071: * it can make internal changes to the pattern, but cannot return a different pattern. Only certain
072: * kinds of promotion are applicable within a pattern: specifically, promotions affecting local
073: * variable references within the pattern.
074: *
075: * @param offer details of the offer, for example the offer to move
076: * expressions that don't depend on the context to an outer level in
077: * the containing expression
078: * @throws net.sf.saxon.trans.XPathException
079: * if any error is detected
080: */
081:
082: public void promote(PromotionOffer offer) throws XPathException {
083: idExpression = idExpression.promote(offer);
084: }
085:
086: /**
087: * Determine whether this Pattern matches the given Node
088: * @param e The NodeInfo representing the Element or other node to be tested against the Pattern
089: * @return true if the node matches the Pattern, false otherwise
090: */
091:
092: public boolean matches(NodeInfo e, XPathContext context)
093: throws XPathException {
094: if (e.getNodeKind() != Type.ELEMENT) {
095: return false;
096: }
097: DocumentInfo doc = e.getDocumentRoot();
098: if (doc == null) {
099: return false;
100: }
101: AtomicValue idValue = (AtomicValue) idExpression
102: .evaluateItem(context);
103: if (idValue == null) {
104: return false;
105: }
106: String ids = idValue.getStringValue();
107: if (ids.indexOf(' ') < 0 && ids.indexOf(0x09) < 0
108: && ids.indexOf(0x0a) < 0 && ids.indexOf(0x0c) < 0) {
109: NodeInfo element = doc.selectID(ids);
110: if (element == null)
111: return false;
112: return (element.isSameNodeInfo(e));
113: } else {
114: StringTokenizer tokenizer = new StringTokenizer(ids);
115: while (tokenizer.hasMoreElements()) {
116: String id = (String) tokenizer.nextElement();
117: NodeInfo element = doc.selectID(id);
118: if (element != null && e.isSameNodeInfo(element)) {
119: return true;
120: }
121: }
122: return false;
123: }
124:
125: }
126:
127: /**
128: * Determine the type of nodes to which this pattern applies.
129: * @return Type.ELEMENT
130: */
131:
132: public int getNodeKind() {
133: return Type.ELEMENT;
134: }
135:
136: /**
137: * Get a NodeTest that all the nodes matching this pattern must satisfy
138: */
139:
140: public NodeTest getNodeTest() {
141: return NodeKindTest.ELEMENT;
142: }
143:
144: }
145:
146: //
147: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
148: // you may not use this file except in compliance with the License. You may obtain a copy of the
149: // License at http://www.mozilla.org/MPL/
150: //
151: // Software distributed under the License is distributed on an "AS IS" basis,
152: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
153: // See the License for the specific language governing rights and limitations under the License.
154: //
155: // The Original Code is: all this file.
156: //
157: // The Initial Developer of the Original Code is Michael H. Kay.
158: //
159: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
160: //
161: // Contributor(s): none.
162: //
|