001: package net.sf.saxon.functions;
002:
003: import net.sf.saxon.expr.PositionIterator;
004: import net.sf.saxon.expr.TailExpression;
005: import net.sf.saxon.expr.XPathContext;
006: import net.sf.saxon.expr.Token;
007: import net.sf.saxon.om.SequenceIterator;
008: import net.sf.saxon.om.EmptyIterator;
009: import net.sf.saxon.trans.XPathException;
010: import net.sf.saxon.type.ItemType;
011: import net.sf.saxon.type.TypeHierarchy;
012: import net.sf.saxon.value.AtomicValue;
013: import net.sf.saxon.value.NumericValue;
014: import net.sf.saxon.value.IntegerValue;
015:
016: /**
017: * Implements the XPath 2.0 subsequence() function
018: */
019:
020: public class Subsequence extends SystemFunction {
021:
022: // Ideally, we would simply convert this at compile time to a filter expression.
023: // Unfortunately, this is not always possible, because a filter expression changes
024: // the focus for evaluating the filter expression, while this function does not.
025:
026: /**
027: * Determine the data type of the items in the sequence
028: * @return the type of the argument
029: * @param th
030: */
031:
032: public ItemType getItemType(TypeHierarchy th) {
033: return argument[0].getItemType(th);
034: }
035:
036: /**
037: * Get the static properties of this expression (other than its type). The result is
038: * bit-significant. These properties are used for optimizations. In general, if
039: * property bit is set, it is true, but if it is unset, the value is unknown.
040: */
041:
042: public int computeSpecialProperties() {
043: return argument[0].getSpecialProperties();
044: }
045:
046: /**
047: * Evaluate the function to return an iteration of selected nodes.
048: */
049:
050: public SequenceIterator iterate(XPathContext context)
051: throws XPathException {
052: SequenceIterator seq = argument[0].iterate(context);
053: AtomicValue startVal0 = (AtomicValue) argument[1]
054: .evaluateItem(context);
055: NumericValue startVal = (NumericValue) startVal0
056: .getPrimitiveValue();
057:
058: if (argument.length == 2) {
059: long lstart;
060: if (startVal instanceof IntegerValue) {
061: lstart = ((IntegerValue) startVal).longValue();
062: if (lstart <= 1) {
063: return seq;
064: }
065: } else {
066: startVal = startVal.round();
067: if (startVal.compareTo(IntegerValue.PLUS_ONE) <= 0) {
068: return seq;
069: } else if (startVal.compareTo(IntegerValue.MAX_LONG) > 0) {
070: return EmptyIterator.getInstance();
071: } else if (startVal.isNaN()) {
072: return EmptyIterator.getInstance();
073: } else {
074: lstart = startVal.longValue();
075: }
076: }
077:
078: if (lstart > Integer.MAX_VALUE) {
079: // we don't allow sequences longer than an this
080: return EmptyIterator.getInstance();
081: }
082:
083: return new TailExpression.TailIterator(seq, (int) lstart);
084:
085: } else {
086:
087: // There are three arguments
088:
089: AtomicValue lengthVal0 = (AtomicValue) argument[2]
090: .evaluateItem(context);
091: NumericValue lengthVal = (NumericValue) lengthVal0
092: .getPrimitiveValue();
093:
094: if (startVal instanceof IntegerValue
095: && lengthVal instanceof IntegerValue) {
096: long lstart = ((IntegerValue) startVal).longValue();
097: if (lstart > Integer.MAX_VALUE) {
098: return EmptyIterator.getInstance();
099: }
100: long llength = ((IntegerValue) lengthVal).longValue();
101: if (llength > Integer.MAX_VALUE) {
102: llength = Integer.MAX_VALUE;
103: }
104: if (llength < 1) {
105: return EmptyIterator.getInstance();
106: }
107: long lend = lstart + llength - 1;
108: if (lend < 1) {
109: return EmptyIterator.getInstance();
110: }
111: int start = (lstart < 1 ? 1 : (int) lstart);
112: return PositionIterator.make(seq, start, (int) lend);
113: } else {
114: if (startVal.isNaN()) {
115: return EmptyIterator.getInstance();
116: }
117: if (startVal.compareTo(IntegerValue.MAX_LONG) > 0) {
118: return EmptyIterator.getInstance();
119: }
120: startVal = startVal.round();
121:
122: if (lengthVal.isNaN()) {
123: return EmptyIterator.getInstance();
124: }
125: lengthVal = lengthVal.round();
126:
127: if (lengthVal.compareTo(IntegerValue.ZERO) <= 0) {
128: return EmptyIterator.getInstance();
129: }
130: NumericValue rend = startVal.arithmetic(Token.PLUS,
131: lengthVal, context).arithmetic(Token.MINUS,
132: IntegerValue.PLUS_ONE, context);
133: if (rend.compareTo(IntegerValue.ZERO) <= 0) {
134: return EmptyIterator.getInstance();
135: }
136:
137: long lstart;
138: if (startVal.compareTo(IntegerValue.PLUS_ONE) <= 0) {
139: lstart = 1;
140: } else {
141: lstart = startVal.longValue();
142: }
143: if (lstart > Integer.MAX_VALUE) {
144: return EmptyIterator.getInstance();
145: }
146:
147: long lend;
148: if (rend.compareTo(IntegerValue.MAX_LONG) >= 0) {
149: lend = Integer.MAX_VALUE;
150: } else {
151: lend = rend.longValue();
152: }
153: return PositionIterator.make(seq, (int) lstart,
154: (int) lend);
155:
156: }
157: }
158: }
159:
160: }
161:
162: //
163: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
164: // you may not use this file except in compliance with the License. You may obtain a copy of the
165: // License at http://www.mozilla.org/MPL/
166: //
167: // Software distributed under the License is distributed on an "AS IS" basis,
168: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
169: // See the License for the specific language governing rights and limitations under the License.
170: //
171: // The Original Code is: all this file.
172: //
173: // The Initial Developer of the Original Code is Michael H. Kay.
174: //
175: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
176: //
177: // Contributor(s): none.
178: //
|