001: package net.sf.saxon.expr;
002:
003: import net.sf.saxon.om.Item;
004: import net.sf.saxon.om.NodeInfo;
005: import net.sf.saxon.om.SequenceIterator;
006: import net.sf.saxon.om.SingletonIterator;
007: import net.sf.saxon.pattern.AnyNodeTest;
008: import net.sf.saxon.trans.StaticError;
009: import net.sf.saxon.trans.XPathException;
010: import net.sf.saxon.type.AtomicType;
011: import net.sf.saxon.type.ItemType;
012: import net.sf.saxon.type.TypeHierarchy;
013:
014: /**
015: * A node set expression that will always return zero or one nodes
016: */
017:
018: public abstract class SingleNodeExpression extends ComputedExpression {
019:
020: /**
021: * Type-check the expression.
022: */
023:
024: public Expression typeCheck(StaticContext env,
025: ItemType contextItemType) throws XPathException {
026: if (contextItemType == null) {
027: StaticError err = new StaticError(
028: "Cannot select a node here: the context item is undefined");
029: err.setErrorCode("XPDY0002");
030: err.setIsTypeError(true);
031: err.setLocator(this );
032: throw err;
033: }
034: if (contextItemType instanceof AtomicType) {
035: StaticError err = new StaticError(
036: "Cannot select a node here: the context item is an atomic value");
037: err.setErrorCode("XPTY0020");
038: err.setIsTypeError(true);
039: err.setLocator(this );
040: throw err;
041: }
042: return this ;
043: }
044:
045: /**
046: * Perform optimisation of an expression and its subexpressions.
047: * <p/>
048: * <p>This method is called after all references to functions and variables have been resolved
049: * to the declaration of the function or variable, and after all type checking has been done.</p>
050: *
051: * @param opt the optimizer in use. This provides access to supporting functions; it also allows
052: * different optimization strategies to be used in different circumstances.
053: * @param env the static context of the expression
054: * @param contextItemType the static type of "." at the point where this expression is invoked.
055: * The parameter is set to null if it is known statically that the context item will be undefined.
056: * If the type of the context item is not known statically, the argument is set to
057: * {@link net.sf.saxon.type.Type#ITEM_TYPE}
058: * @return the original expression, rewritten if appropriate to optimize execution
059: * @throws net.sf.saxon.trans.StaticError if an error is discovered during this phase
060: * (typically a type error)
061: */
062:
063: public Expression optimize(Optimizer opt, StaticContext env,
064: ItemType contextItemType) throws XPathException {
065: // repeat the check: in XSLT insufficient information is available the first time
066: return typeCheck(env, contextItemType);
067: }
068:
069: /**
070: * Specify that the expression returns a singleton
071: */
072:
073: public int computeCardinality() {
074: return StaticProperty.ALLOWS_ZERO_OR_ONE;
075: }
076:
077: /**
078: * Determine the data type of the items returned by this expression
079: * @return Type.NODE
080: * @param th
081: */
082:
083: public ItemType getItemType(TypeHierarchy th) {
084: return AnyNodeTest.getInstance();
085: }
086:
087: /**
088: * Determine which aspects of the context the expression depends on. The result is
089: * a bitwise-or'ed value composed from constants such as StaticProperty.VARIABLES and
090: * StaticProperty.CURRENT_NODE
091: */
092:
093: public int getIntrinsicDependencies() {
094: return StaticProperty.DEPENDS_ON_CONTEXT_ITEM;
095: }
096:
097: public int computeSpecialProperties() {
098: return StaticProperty.ORDERED_NODESET
099: | StaticProperty.CONTEXT_DOCUMENT_NODESET
100: | StaticProperty.SINGLE_DOCUMENT_NODESET
101: | StaticProperty.NON_CREATIVE;
102: }
103:
104: /**
105: * Get the single node to which this expression refers. Returns null if the node-set is empty
106: */
107:
108: public abstract NodeInfo getNode(XPathContext context)
109: throws XPathException;
110:
111: /**
112: * Evaluate the expression in a given context to return an iterator
113: * @param context the evaluation context
114: */
115:
116: public SequenceIterator iterate(XPathContext context)
117: throws XPathException {
118: return SingletonIterator.makeIterator(getNode(context));
119: }
120:
121: public Item evaluateItem(XPathContext context)
122: throws XPathException {
123: return getNode(context);
124: }
125:
126: public boolean effectiveBooleanValue(XPathContext context)
127: throws XPathException {
128: return getNode(context) != null;
129: }
130:
131: }
132:
133: //
134: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
135: // you may not use this file except in compliance with the License. You may obtain a copy of the
136: // License at http://www.mozilla.org/MPL/
137: //
138: // Software distributed under the License is distributed on an "AS IS" basis,
139: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
140: // See the License for the specific language governing rights and limitations under the License.
141: //
142: // The Original Code is: all this file.
143: //
144: // The Initial Developer of the Original Code is Michael H. Kay.
145: //
146: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
147: //
148: // Contributor(s): none.
149: //
|