package client.net.sf.saxon.ce.value; import client.net.sf.saxon.ce.Configuration; import client.net.sf.saxon.ce.expr.StaticProperty; import client.net.sf.saxon.ce.om.Item; import client.net.sf.saxon.ce.om.SequenceIterator; import client.net.sf.saxon.ce.pattern.AnyNodeTest; import client.net.sf.saxon.ce.pattern.EmptySequenceTest; import client.net.sf.saxon.ce.pattern.NodeKindTest; import client.net.sf.saxon.ce.trans.XPathException; import client.net.sf.saxon.ce.type.AnyItemType; import client.net.sf.saxon.ce.type.BuiltInAtomicType; import client.net.sf.saxon.ce.type.ItemType; import java.util.HashMap; import java.util.Map; /** * SequenceType: a sequence type consists of a primary type, which indicates the type of item, * and a cardinality, which indicates the number of occurrences permitted. Where the primary type * is element or attribute, there may also be a content type, indicating the required type * annotation on the element or attribute content. */ public final class SequenceType { private ItemType primaryType; // the primary type of the item, e.g. "element", "comment", or "integer" private int cardinality; // the required cardinality private static Map pool = new HashMap(50); /** * A type that allows any sequence of items */ public static final SequenceType ANY_SEQUENCE = makeSequenceType(AnyItemType.getInstance(), StaticProperty.ALLOWS_ZERO_OR_MORE); /** * A type that allows exactly one item, of any kind */ public static final SequenceType SINGLE_ITEM = makeSequenceType(AnyItemType.getInstance(), StaticProperty.EXACTLY_ONE); /** * A type that allows zero or one items, of any kind */ public static final SequenceType OPTIONAL_ITEM = makeSequenceType(AnyItemType.getInstance(), StaticProperty.ALLOWS_ZERO_OR_ONE); /** * A type that allows exactly one atomic value */ public static final SequenceType SINGLE_ATOMIC = makeSequenceType(BuiltInAtomicType.ANY_ATOMIC, StaticProperty.EXACTLY_ONE); /** * A type that allows zero or one atomic values */ public static final SequenceType OPTIONAL_ATOMIC = makeSequenceType(BuiltInAtomicType.ANY_ATOMIC, StaticProperty.ALLOWS_ZERO_OR_ONE); /** * A type that allows zero or more atomic values */ public static final SequenceType ATOMIC_SEQUENCE = makeSequenceType(BuiltInAtomicType.ANY_ATOMIC, StaticProperty.ALLOWS_ZERO_OR_MORE); /** * A type that allows a single string */ public static final SequenceType SINGLE_STRING = makeSequenceType(BuiltInAtomicType.STRING, StaticProperty.EXACTLY_ONE); public static final SequenceType OPTIONAL_STRING = makeSequenceType(BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_ONE); public static final SequenceType STRING_SEQUENCE = makeSequenceType(BuiltInAtomicType.STRING, StaticProperty.ALLOWS_ZERO_OR_MORE); /** * A type that allows a single untyped atomic */ public static final SequenceType SINGLE_UNTYPED_ATOMIC = makeSequenceType(BuiltInAtomicType.UNTYPED_ATOMIC, StaticProperty.EXACTLY_ONE); /** * A type that allows a single optional integer */ public static final SequenceType OPTIONAL_INTEGER = makeSequenceType(BuiltInAtomicType.INTEGER, StaticProperty.ALLOWS_ZERO_OR_ONE); public static final SequenceType SINGLE_INTEGER = makeSequenceType(BuiltInAtomicType.INTEGER, StaticProperty.EXACTLY_ONE); public static final SequenceType INTEGER_SEQUENCE = makeSequenceType(BuiltInAtomicType.INTEGER, StaticProperty.ALLOWS_ZERO_OR_MORE); /** * A type that allows an optional numeric value */ public static final SequenceType OPTIONAL_NUMERIC = makeSequenceType(BuiltInAtomicType.NUMERIC, StaticProperty.ALLOWS_ZERO_OR_ONE); /** * A type that allows zero or one nodes */ public static final SequenceType OPTIONAL_NODE = makeSequenceType(AnyNodeTest.getInstance(), StaticProperty.ALLOWS_ZERO_OR_ONE); public static final SequenceType SINGLE_NODE = makeSequenceType(AnyNodeTest.getInstance(), StaticProperty.EXACTLY_ONE); public static final SequenceType NODE_SEQUENCE = makeSequenceType(AnyNodeTest.getInstance(), StaticProperty.ALLOWS_ZERO_OR_MORE); public static final SequenceType OPTIONAL_DOCUMENT = makeSequenceType(NodeKindTest.DOCUMENT, StaticProperty.ALLOWS_ZERO_OR_ONE); public static final SequenceType SINGLE_ELEMENT = makeSequenceType(NodeKindTest.ELEMENT, StaticProperty.EXACTLY_ONE); public static final SequenceType ELEMENT_SEQUENCE = makeSequenceType(NodeKindTest.ELEMENT, StaticProperty.ALLOWS_ZERO_OR_MORE); /** * A type that allows a sequence of zero or more numeric values */ public static final SequenceType NUMERIC_SEQUENCE = makeSequenceType(BuiltInAtomicType.NUMERIC, StaticProperty.ALLOWS_ZERO_OR_MORE); public static final SequenceType OPTIONAL_BOOLEAN = makeSequenceType(BuiltInAtomicType.BOOLEAN, StaticProperty.ALLOWS_ZERO_OR_ONE); public static final SequenceType SINGLE_BOOLEAN = makeSequenceType(BuiltInAtomicType.BOOLEAN, StaticProperty.EXACTLY_ONE); public static final SequenceType OPTIONAL_DATE = makeSequenceType(BuiltInAtomicType.DATE, StaticProperty.ALLOWS_ZERO_OR_ONE); public static final SequenceType SINGLE_DATE = makeSequenceType(BuiltInAtomicType.DATE, StaticProperty.EXACTLY_ONE); public static final SequenceType OPTIONAL_DATE_TIME = makeSequenceType(BuiltInAtomicType.DATE_TIME, StaticProperty.ALLOWS_ZERO_OR_ONE); public static final SequenceType SINGLE_DATE_TIME = makeSequenceType(BuiltInAtomicType.DATE_TIME, StaticProperty.EXACTLY_ONE); public static final SequenceType OPTIONAL_TIME = makeSequenceType(BuiltInAtomicType.TIME, StaticProperty.ALLOWS_ZERO_OR_ONE); public static final SequenceType SINGLE_TIME = makeSequenceType(BuiltInAtomicType.TIME, StaticProperty.EXACTLY_ONE); public static final SequenceType OPTIONAL_DURATION = makeSequenceType(BuiltInAtomicType.DURATION, StaticProperty.ALLOWS_ZERO_OR_ONE); public static final SequenceType OPTIONAL_DAY_TIME_DURATION = makeSequenceType(BuiltInAtomicType.DAY_TIME_DURATION, StaticProperty.ALLOWS_ZERO_OR_ONE); public static final SequenceType SINGLE_DAY_TIME_DURATION = makeSequenceType(BuiltInAtomicType.DAY_TIME_DURATION, StaticProperty.EXACTLY_ONE); public static final SequenceType OPTIONAL_ANY_URI = makeSequenceType(BuiltInAtomicType.ANY_URI, StaticProperty.ALLOWS_ZERO_OR_ONE); public static final SequenceType SINGLE_ANY_URI = makeSequenceType(BuiltInAtomicType.ANY_URI, StaticProperty.EXACTLY_ONE); public static final SequenceType OPTIONAL_QNAME = makeSequenceType(BuiltInAtomicType.QNAME, StaticProperty.ALLOWS_ZERO_OR_ONE); public static final SequenceType OPTIONAL_DECIMAL = makeSequenceType(BuiltInAtomicType.DECIMAL, StaticProperty.ALLOWS_ZERO_OR_ONE); public static final SequenceType SINGLE_QNAME = makeSequenceType(BuiltInAtomicType.QNAME, StaticProperty.EXACTLY_ONE); public static final SequenceType SINGLE_DOUBLE = makeSequenceType(BuiltInAtomicType.DOUBLE, StaticProperty.EXACTLY_ONE); /** * A type that only permits the empty sequence */ public static final SequenceType EMPTY_SEQUENCE = makeSequenceType(EmptySequenceTest.getInstance(), StaticProperty.EMPTY); /** * Construct an instance of SequenceType. This is a private constructor: all external * clients use the factory method makeSequenceType(), to allow object pooling. * * @param primaryType The item type * @param cardinality The required cardinality */ private SequenceType(ItemType primaryType, int cardinality) { this.primaryType = primaryType; if (primaryType instanceof EmptySequenceTest) { this.cardinality = StaticProperty.EMPTY; } else { this.cardinality = cardinality; } } /** * Construct an instance of SequenceType. This is a factory method: it maintains a * pool of SequenceType objects to reduce the amount of object creation. * * @param primaryType The item type * @param cardinality The required cardinality */ public static SequenceType makeSequenceType(ItemType primaryType, int cardinality) { if (!(primaryType instanceof BuiltInAtomicType)) { return new SequenceType(primaryType, cardinality); } // For each ItemType, there is an array of 8 SequenceTypes, one for each possible // cardinality (including impossible cardinalities, such as "0 or many"). The pool // is a static HashMap that obtains this array, given an ItemType. The array contains null // entries for cardinalities that have not been requested. SequenceType[] array = (SequenceType[]) pool.get(primaryType); if (array == null) { array = new SequenceType[8]; pool.put(primaryType, array); } int code = StaticProperty.getCardinalityCode(cardinality); if (array[code] == null) { SequenceType s = new SequenceType(primaryType, cardinality); array[code] = s; return s; } else { return array[code]; } } /** * Get the "primary" part of this required type. E.g. for type element(*, xs:date) the "primary type" is element() * * @return The item type code of the primary type */ public ItemType getPrimaryType() { return primaryType; } /** * Get the cardinality component of this SequenceType. This is one of the constants Cardinality.EXACTLY_ONE, * Cardinality.ONE_OR_MORE, etc * * @return the required cardinality * @see client.net.sf.saxon.ce.value.Cardinality */ public int getCardinality() { return cardinality; } /** * Determine whether a given value is a valid instance of this SequenceType * * @param value the value to be tested * @return true if the value is a valid instance of this type */ public boolean matches(Value value, Configuration config) throws XPathException { int length = value.getLength(); if (length > 1 && !Cardinality.allowsMany(cardinality)) { return false; } if (length == 0 && !Cardinality.allowsZero(cardinality)) { return false; } SequenceIterator iter = value.iterate(); while (true) { Item item = iter.next(); if (item == null) { return true; } if (!primaryType.matchesItem(item, false, config)) { return false; } } } /** * Return a string representation of this SequenceType * * @return the string representation as an instance of the XPath * SequenceType construct */ public String toString() { String s = primaryType.toString(); if (cardinality == StaticProperty.ALLOWS_ONE_OR_MORE) { s = s + '+'; } else if (cardinality == StaticProperty.ALLOWS_ZERO_OR_MORE) { s = s + '*'; } else if (cardinality == StaticProperty.ALLOWS_ZERO_OR_ONE) { s = s + '?'; } return s; } /** * Returns a hash code value for the object. */ public int hashCode() { return primaryType.hashCode() ^ cardinality; } /** * Indicates whether some other object is "equal to" this one. */ public boolean equals(Object obj) { return obj instanceof SequenceType && this.primaryType.equals(((SequenceType) obj).primaryType) && this.cardinality == ((SequenceType) obj).cardinality; } } // This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. // If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. // This Source Code Form is “Incompatible With Secondary Licenses”, as defined by the Mozilla Public License, v. 2.0.