private List<AtomicMatchKey> getComparisonKey(List<AtomicValue> key, XPathContext keyContext) throws XPathException { List<AtomicMatchKey> ckey = new ArrayList<>(key.size()); for (AtomicValue aKey : key) { AtomicMatchKey comparisonKey; if (aKey.isNaN()) { comparisonKey = AtomicMatchKey.NaN_MATCH_KEY; } else { comparisonKey = aKey.getXPathComparable(false, collator, keyContext.getImplicitTimezone()); } ckey.add(comparisonKey); } return ckey; }
/** * Compare two AtomicValue objects according to the rules for their data type. UntypedAtomic * values are compared as if they were strings; if different semantics are wanted, the conversion * must be done by the caller. * * @param a the first object to be compared. It is intended that this should be an instance * of AtomicValue, though this restriction is not enforced. If it is a StringValue, the * collator is used to compare the values, otherwise the value must implement the java.util.Comparable * interface. * @param b the second object to be compared. This must be comparable with the first object: for * example, if one is a string, they must both be strings. * @return <0 if a<b, 0 if a=b, >0 if a>b * @throws ClassCastException if the objects are not comparable */ public int compareAtomicValues(AtomicValue a, AtomicValue b) throws NoDynamicContextException { if (a == null) { return b == null ? 0 : -1; } else if (b == null) { return +1; } return ((CalendarValue) a).compareTo((CalendarValue) b, context.getImplicitTimezone()); }
private List<AtomicMatchKey> getComparisonKey(List<AtomicValue> key, XPathContext keyContext) throws XPathException { List<AtomicMatchKey> ckey = new ArrayList<>(key.size()); for (AtomicValue aKey : key) { AtomicMatchKey comparisonKey; if (aKey.isNaN()) { comparisonKey = AtomicMatchKey.NaN_MATCH_KEY; } else { comparisonKey = aKey.getXPathComparable(false, collator, keyContext.getImplicitTimezone()); } ckey.add(comparisonKey); } return ckey; }
/** * Compare two AtomicValue objects according to the rules for their data type. UntypedAtomic * values are compared as if they were strings; if different semantics are wanted, the conversion * must be done by the caller. * * @param a the first object to be compared. It is intended that this should be an instance * of AtomicValue, though this restriction is not enforced. If it is a StringValue, the * collator is used to compare the values, otherwise the value must implement the java.util.Comparable * interface. * @param b the second object to be compared. This must be comparable with the first object: for * example, if one is a string, they must both be strings. * @return <0 if a<b, 0 if a=b, >0 if a>b * @throws ClassCastException if the objects are not comparable */ public int compareAtomicValues(AtomicValue a, AtomicValue b) throws NoDynamicContextException { if (a == null) { return b == null ? 0 : -1; } else if (b == null) { return +1; } return ((CalendarValue) a).compareTo((CalendarValue) b, context.getImplicitTimezone()); }
/** * Method retained only because it is used in a test case */ public AtomicMatchKey getComparisonKey(XPathContext context) { try { return getXPathComparable(false, CodepointCollator.getInstance(), context.getImplicitTimezone()); } catch (NoDynamicContextException e) { return null; } }
/** * Method retained only because it is used in a test case */ public AtomicMatchKey getComparisonKey(XPathContext context) { try { return getXPathComparable(false, CodepointCollator.getInstance(), context.getImplicitTimezone()); } catch (NoDynamicContextException e) { return null; } }
/** * Get an object value that implements the XPath equality and ordering comparison semantics for this value. * If the ordered parameter is set to true, the result will be a Comparable and will support a compareTo() * method with the semantics of the XPath lt/gt operator, provided that the other operand is also obtained * using the getXPathComparable() method. In all cases the result will support equals() and hashCode() methods * that support the semantics of the XPath eq operator, again provided that the other operand is also obtained * using the getXPathComparable() method. A context argument is supplied for use in cases where the comparison * semantics are context-sensitive, for example where they depend on the implicit timezone or the default * collation. * * @param ordered true if an ordered comparison is required. In this case the result is null if the * type is unordered; in other cases the returned value will be a Comparable. * @param collator collation used for strings * @param context the XPath dynamic evaluation context, used in cases where the comparison is context * sensitive @return an Object whose equals() and hashCode() methods implement the XPath comparison semantics * with respect to this atomic value. If ordered is specified, the result will either be null if * no ordering is defined, or will be a Comparable */ public Object getXPathComparable(boolean ordered, StringCollator collator, XPathContext context) throws NoDynamicContextException { if (ordered && !(this instanceof Comparable)) { return null; } return (hasTimezone() ? this : adjustTimezone(context.getImplicitTimezone())); }
/** * Get the next item in the sequence. <BR> * * @return the next item, or null if there are no more items. * @throws net.sf.saxon.trans.XPathException * if an error occurs retrieving the next item */ public AtomicValue next() throws XPathException { int implicitTimezone = context.getImplicitTimezone(); while (true) { AtomicValue nextBase = base.next(); if (nextBase == null) { return null; } AtomicMatchKey key; if (nextBase.isNaN()) { key = AtomicMatchKey.NaN_MATCH_KEY; } else { key = nextBase.getXPathComparable(false, collator, implicitTimezone); } if (lookup.add(key)) { // returns true if newly added (if not, keep looking) return nextBase; } } }
/** * Build the index for a particular document for a named key * * * @param keySet The set of key definitions with this name * @param doc The source document in question * @param context The dynamic context * @throws XPathException if a dynamic error is encountered */ public void buildIndex(KeyDefinitionSet keySet, TreeInfo doc, XPathContext context) throws XPathException { List<KeyDefinition> definitions = keySet.getKeyDefinitions(); // There may be multiple xsl:key definitions with the same name. Index them all. for (int k = 0; k < definitions.size(); k++) { constructIndex(doc, definitions.get(k), context, k == 0); } this.rules = context.getConfiguration().getConversionRules(); this.implicitTimezone = context.getImplicitTimezone(); this.collation = definitions.get(0).getCollation(); }
/** * Build the index for a particular document for a named key * * * @param keySet The set of key definitions with this name * @param doc The source document in question * @param context The dynamic context * @throws XPathException if a dynamic error is encountered */ public void buildIndex(KeyDefinitionSet keySet, TreeInfo doc, XPathContext context) throws XPathException { List<KeyDefinition> definitions = keySet.getKeyDefinitions(); // There may be multiple xsl:key definitions with the same name. Index them all. for (int k = 0; k < definitions.size(); k++) { constructIndex(doc, definitions.get(k), context, k == 0); } this.rules = context.getConfiguration().getConversionRules(); this.implicitTimezone = context.getImplicitTimezone(); this.collation = definitions.get(0).getCollation(); }
/** * Compare two AtomicValue objects for equality according to the rules for their data type. UntypedAtomic * values are compared as if they were strings; if different semantics are wanted, the conversion * must be done by the caller. * * @param a the first object to be compared. If it is a StringValue, the * collator is used to compare the values, otherwise the value must implement the equals() method. * @param b the second object to be compared. This must be comparable with the first object: for * example, if one is a string, they must both be strings. * @return true if the values are equal, false if not * @throws ClassCastException if the objects are not comparable */ public boolean comparesEqual(AtomicValue a, AtomicValue b) throws NoDynamicContextException { // System.err.println("Comparing " + a.getClass() + ": " + a + " with " + b.getClass() + ": " + b); if (a instanceof StringValue && b instanceof StringValue) { return collator.comparesEqual(a.getStringValue(), b.getStringValue()); } else if (a instanceof CalendarValue && b instanceof CalendarValue) { return ((CalendarValue) a).compareTo((CalendarValue) b, context.getImplicitTimezone()) == 0; } else { int implicitTimezone = context.getImplicitTimezone(); Object ac = a.getXPathComparable(false, collator, implicitTimezone); Object bc = b.getXPathComparable(false, collator, implicitTimezone); return ac.equals(bc); } }
/** * Compare two AtomicValue objects for equality according to the rules for their data type. UntypedAtomic * values are compared as if they were strings; if different semantics are wanted, the conversion * must be done by the caller. * * @param a the first object to be compared. If it is a StringValue, the * collator is used to compare the values, otherwise the value must implement the equals() method. * @param b the second object to be compared. This must be comparable with the first object: for * example, if one is a string, they must both be strings. * @return true if the values are equal, false if not * @throws ClassCastException if the objects are not comparable */ public boolean comparesEqual(AtomicValue a, AtomicValue b) throws NoDynamicContextException { // System.err.println("Comparing " + a.getClass() + ": " + a + " with " + b.getClass() + ": " + b); if (a instanceof StringValue && b instanceof StringValue) { return collator.comparesEqual(a.getStringValue(), b.getStringValue()); } else if (a instanceof CalendarValue && b instanceof CalendarValue) { return ((CalendarValue) a).compareTo((CalendarValue) b, context.getImplicitTimezone()) == 0; } else { int implicitTimezone = context.getImplicitTimezone(); Object ac = a.getXPathComparable(false, collator, implicitTimezone); Object bc = b.getXPathComparable(false, collator, implicitTimezone); return ac.equals(bc); } }
public int hashCode() { int h = 0x77557755 ^ groupingValues.length; for (int i = 0; i < groupingValues.length; i++) { GenericAtomicComparer comparer = comparers[i]; int implicitTimezone = comparer.getContext().getImplicitTimezone(); try { SequenceIterator atoms = groupingValues[i].iterate(); while (true) { AtomicValue val = (AtomicValue) atoms.next(); if (val == null) { break; } h ^= i + val.getXPathComparable(false, comparer.getCollator(), implicitTimezone).hashCode(); } } catch (XPathException e) { // ignore any errors } } return h; }
public int hashCode() { int h = 0x77557755 ^ groupingValues.length; for (int i = 0; i < groupingValues.length; i++) { GenericAtomicComparer comparer = comparers[i]; int implicitTimezone = comparer.getContext().getImplicitTimezone(); try { SequenceIterator atoms = groupingValues[i].iterate(); while (true) { AtomicValue val = (AtomicValue) atoms.next(); if (val == null) { break; } h ^= i + val.getXPathComparable(false, comparer.getCollator(), implicitTimezone).hashCode(); } } catch (XPathException e) { // ignore any errors } } return h; }
/** * Evaluate the expression * * @param context the dynamic evaluation context * @param arguments the values of the arguments, supplied as Sequences * @return the result of the evaluation, in the form of a Sequence * @throws net.sf.saxon.trans.XPathException * if a dynamic error occurs during the evaluation of the expression */ public ZeroOrOne<CalendarValue> call(XPathContext context, Sequence[] arguments) throws XPathException { CalendarValue in = (CalendarValue) arguments[0].head(); if (in == null) { return ZeroOrOne.empty(); } else { return new ZeroOrOne<>(in.adjustTimezone(context.getImplicitTimezone())); } } }
/** * Evaluate the expression * * @param context the dynamic evaluation context * @param arguments the values of the arguments, supplied as Sequences * @return the result of the evaluation, in the form of a Sequence * @throws net.sf.saxon.trans.XPathException * if a dynamic error occurs during the evaluation of the expression */ public ZeroOrOne<CalendarValue> call(XPathContext context, Sequence[] arguments) throws XPathException { CalendarValue in = (CalendarValue) arguments[0].head(); if (in == null) { return ZeroOrOne.empty(); } else { return new ZeroOrOne<>(in.adjustTimezone(context.getImplicitTimezone())); } } }
/** * Normalize the date and time to be in timezone Z. * * @param cc used to supply the implicit timezone, used when the value has * no explicit timezone * @return in general, a new DateTimeValue in timezone Z, representing the same instant in time. * Returns the original DateTimeValue if this is already in timezone Z. * @throws NoDynamicContextException if the implicit timezone is needed and is not available */ public DateTimeValue normalize(XPathContext cc) throws NoDynamicContextException { if (hasTimezone()) { return (DateTimeValue)adjustTimezone(0); } else { DateTimeValue dt = (DateTimeValue)copyAsSubType(null); dt.setTimezoneInMinutes(cc.getImplicitTimezone()); return (DateTimeValue)dt.adjustTimezone(0); } }
/** * Normalize the date and time to be in timezone Z. * * @param cc used to supply the implicit timezone, used when the value has * no explicit timezone * @return in general, a new DateTimeValue in timezone Z, representing the same instant in time. * Returns the original DateTimeValue if this is already in timezone Z. * @throws NoDynamicContextException if the implicit timezone is needed and is not available */ public DateTimeValue normalize(XPathContext cc) throws NoDynamicContextException { if (hasTimezone()) { return (DateTimeValue)adjustTimezone(0); } else { DateTimeValue dt = (DateTimeValue)copyAsSubType(null); dt.setTimezoneInMinutes(cc.getImplicitTimezone()); return (DateTimeValue)dt.adjustTimezone(0); } }
/** * Compare two AtomicValue objects for equality according to the rules for their data type. UntypedAtomic * values are compared as if they were strings; if different semantics are wanted, the conversion * must be done by the caller. * * @param a the first object to be compared. If it is a StringValue, the * collator is used to compare the values, otherwise the value must implement the equals() method. * @param b the second object to be compared. This must be comparable with the first object: for * example, if one is a string, they must both be strings. * @return true if the values are equal, false if not * @throws ClassCastException if the objects are not comparable */ public boolean comparesEqual (AtomicValue a, AtomicValue b) throws NoDynamicContextException { // System.err.println("Comparing " + a.getClass() + ": " + a + " with " + b.getClass() + ": " + b); if (a instanceof StringValue && b instanceof StringValue) { return getStringCollator().comparesEqual(a.getStringValue(), b.getStringValue()); } else if (a instanceof CalendarValue && b instanceof CalendarValue) { return ((CalendarValue) a).compareTo((CalendarValue) b, getContext().getImplicitTimezone()) == 0; } else if (a.isNaN() && b.isNaN()) { return true; } else { int implicitTimezone = getContext().getImplicitTimezone(); Object ac = a.getXPathComparable(false, getStringCollator(), implicitTimezone); Object bc = b.getXPathComparable(false, getStringCollator(), implicitTimezone); return ac.equals(bc); } }
/** * Determine the difference between two points in time, as a duration * * @param other the other point in time * @param context the dynamic context, used to obtain timezone information. May be set to null * only if both values contain an explicit timezone, or if neither does so. * @return the duration as an xs:dayTimeDuration * @throws net.sf.saxon.trans.XPathException * for example if one value is a date and the other is a time */ public DayTimeDurationValue subtract(/*@NotNull*/ CalendarValue other, /*@Nullable*/ XPathContext context) throws XPathException { DateTimeValue dt1 = toDateTime(); DateTimeValue dt2 = other.toDateTime(); if (dt1.getTimezoneInMinutes() != dt2.getTimezoneInMinutes()) { int tz = CalendarValue.NO_TIMEZONE; if (context == null || (tz = context.getImplicitTimezone()) == CalendarValue.MISSING_TIMEZONE) { throw new NoDynamicContextException("Implicit timezone required"); } dt1 = dt1.adjustToUTC(tz); dt2 = dt2.adjustToUTC(tz); } BigDecimal d1 = dt1.toJulianInstant(); BigDecimal d2 = dt2.toJulianInstant(); BigDecimal difference = d1.subtract(d2); return DayTimeDurationValue.fromSeconds(difference); }