* The arithmetic operation method
- * {@link #operation(IAnyAtomicItem, IAnyAtomicItem)} must be implemented by
- * extending classes to provide the evaluation logic.
+ * {@link #operation(IAnyAtomicItem, IAnyAtomicItem, DynamicContext)} must be
+ * implemented by extending classes to provide the evaluation logic.
*/
public abstract class AbstractBasicArithmeticExpression
extends AbstractArithmeticExpression
- * Based on XPath 3.1
- * op:numeric-add.
+ * Based on XPath 3.1 op:numeric-add.
*
* @param addend1
* the first addend
@@ -883,8 +948,8 @@ public static INumericItem opNumericAdd(@NonNull INumericItem addend1, @NonNull
}
/**
- * Determine the difference by subtracting the provided subtrahend value from the provided minuend
- * value.
+ * Determine the difference by subtracting the provided subtrahend value from
+ * the provided minuend value.
*
* Based on XPath 3.1 op:numeric-subtract.
@@ -893,7 +958,8 @@ public static INumericItem opNumericAdd(@NonNull INumericItem addend1, @NonNull
* the value to subtract from
* @param subtrahend
* the value to subtract
- * @return a new value resulting from subtracting the subtrahend from the minuend
+ * @return a new value resulting from subtracting the subtrahend from the
+ * minuend
*/
@NonNull
public static INumericItem opNumericSubtract(
@@ -916,7 +982,8 @@ public static INumericItem opNumericSubtract(
* the value to multiply
* @param multiplier
* the value to multiply by
- * @return a new value resulting from multiplying the multiplicand by the multiplier
+ * @return a new value resulting from multiplying the multiplicand by the
+ * multiplier
*/
@NonNull
public static INumericItem opNumericMultiply(
@@ -930,8 +997,8 @@ public static INumericItem opNumericMultiply(
}
/**
- * Based on XPath 3.1
- * op:numeric-divide.
+ * Based on XPath 3.1 op:numeric-divide.
*
* @param dividend
* the number to be divided
@@ -939,8 +1006,8 @@ public static INumericItem opNumericMultiply(
* the number to divide by
* @return the quotient
* @throws ArithmeticFunctionException
- * with the code {@link ArithmeticFunctionException#DIVISION_BY_ZERO} if the divisor is
- * zero
+ * with the code {@link ArithmeticFunctionException#DIVISION_BY_ZERO}
+ * if the divisor is zero
*/
@NonNull
public static IDecimalItem opNumericDivide(@NonNull INumericItem dividend, @NonNull INumericItem divisor) {
@@ -969,8 +1036,8 @@ public static IIntegerItem opNumericIntegerDivide(
}
/**
- * Based on XPath 3.1
- * op:numeric-mod.
+ * Based on XPath 3.1 op:numeric-mod.
*
* @param dividend
* the number to be divided
@@ -1009,14 +1076,15 @@ public static INumericItem opNumericUnaryMinus(@NonNull INumericItem item) {
}
/**
- * Based on XPath 3.1
- * op:numeric-equal.
+ * Based on XPath 3.1 op:numeric-equal.
*
* @param arg1
* the first number to check for equality
* @param arg2
* the second number to check for equality
- * @return {@code true} if the numbers are numerically equal or {@code false} otherwise
+ * @return {@code true} if the numbers are numerically equal or {@code false}
+ * otherwise
*/
@NonNull
public static IBooleanItem opNumericEqual(@Nullable INumericItem arg1, @Nullable INumericItem arg2) {
@@ -1039,8 +1107,8 @@ public static IBooleanItem opNumericEqual(@Nullable INumericItem arg1, @Nullable
* the first number to check
* @param arg2
* the second number to check
- * @return {@code true} if the first number is greater than or equal to the second, or {@code false}
- * otherwise
+ * @return {@code true} if the first number is greater than or equal to the
+ * second, or {@code false} otherwise
*/
@NonNull
public static IBooleanItem opNumericGreaterThan(@Nullable INumericItem arg1, @Nullable INumericItem arg2) {
@@ -1065,8 +1133,8 @@ public static IBooleanItem opNumericGreaterThan(@Nullable INumericItem arg1, @Nu
* the first number to check
* @param arg2
* the second number to check
- * @return {@code true} if the first number is less than or equal to the second, or {@code false}
- * otherwise
+ * @return {@code true} if the first number is less than or equal to the second,
+ * or {@code false} otherwise
*/
@NonNull
public static IBooleanItem opNumericLessThan(@Nullable INumericItem arg1, @Nullable INumericItem arg2) {
@@ -1084,14 +1152,15 @@ public static IBooleanItem opNumericLessThan(@Nullable INumericItem arg1, @Nulla
}
/**
- * Based on XPath 3.1
- * op:boolean-equal.
+ * Based on XPath 3.1 op:boolean-equal.
*
* @param arg1
* the first boolean to check
* @param arg2
* the second boolean to check
- * @return {@code true} if the first boolean is equal to the second, or {@code false} otherwise
+ * @return {@code true} if the first boolean is equal to the second, or
+ * {@code false} otherwise
*/
@NonNull
public static IBooleanItem opBooleanEqual(@Nullable IBooleanItem arg1, @Nullable IBooleanItem arg2) {
@@ -1109,8 +1178,8 @@ public static IBooleanItem opBooleanEqual(@Nullable IBooleanItem arg1, @Nullable
* the first boolean to check
* @param arg2
* the second boolean to check
- * @return {@code true} if the first argument is {@link IBooleanItem#TRUE} and the second is
- * {@link IBooleanItem#FALSE}, or {@code false} otherwise
+ * @return {@code true} if the first argument is {@link IBooleanItem#TRUE} and
+ * the second is {@link IBooleanItem#FALSE}, or {@code false} otherwise
*/
@NonNull
public static IBooleanItem opBooleanGreaterThan(@Nullable IBooleanItem arg1, @Nullable IBooleanItem arg2) {
@@ -1128,8 +1197,8 @@ public static IBooleanItem opBooleanGreaterThan(@Nullable IBooleanItem arg1, @Nu
* the first boolean to check
* @param arg2
* the second boolean to check
- * @return {@code true} if the first argument is {@link IBooleanItem#FALSE} and the second is
- * {@link IBooleanItem#TRUE}, or {@code false} otherwise
+ * @return {@code true} if the first argument is {@link IBooleanItem#FALSE} and
+ * the second is {@link IBooleanItem#TRUE}, or {@code false} otherwise
*/
@NonNull
public static IBooleanItem opBooleanLessThan(@Nullable IBooleanItem arg1, @Nullable IBooleanItem arg2) {
@@ -1140,14 +1209,15 @@ public static IBooleanItem opBooleanLessThan(@Nullable IBooleanItem arg1, @Nulla
}
/**
- * Based on XPath 3.1
- * op:same-key.
+ * Based on XPath 3.1 op:same-key.
*
* @param k1
* the first key to compare
* @param k2
* the second key to compare
- * @return {@code true} if the compared keys are the same, or {@code false} otherwise
+ * @return {@code true} if the compared keys are the same, or {@code false}
+ * otherwise
*/
public static boolean opSameKey(@NonNull IAnyAtomicItem k1, @NonNull IAnyAtomicItem k2) {
boolean retval;
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractDecimalMapKey.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractDecimalMapKey.java
new file mode 100644
index 000000000..47abd6a2f
--- /dev/null
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractDecimalMapKey.java
@@ -0,0 +1,29 @@
+/*
+ * SPDX-FileCopyrightText: none
+ * SPDX-License-Identifier: CC0-1.0
+ */
+
+package gov.nist.secauto.metaschema.core.metapath.impl;
+
+import gov.nist.secauto.metaschema.core.metapath.item.function.IDecimalMapKey;
+import gov.nist.secauto.metaschema.core.metapath.item.function.IMapKey;
+
+/**
+ * An implementation of a {@link IMapKey} that uses a string-based value.
+ */
+public abstract class AbstractDecimalMapKey
+ extends AbstractMapKey
+ implements IDecimalMapKey {
+
+ @Override
+ public int hashCode() {
+ return asDecimal().hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return this == obj
+ // TODO: implement fn:codepoint-equal per spec
+ || obj instanceof IDecimalMapKey && asDecimal().equals(((IDecimalMapKey) obj).asDecimal());
+ }
+}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractMapKey.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractMapKey.java
new file mode 100644
index 000000000..48fe859f8
--- /dev/null
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractMapKey.java
@@ -0,0 +1,15 @@
+/*
+ * SPDX-FileCopyrightText: none
+ * SPDX-License-Identifier: CC0-1.0
+ */
+
+package gov.nist.secauto.metaschema.core.metapath.impl;
+
+import gov.nist.secauto.metaschema.core.metapath.item.function.IMapKey;
+
+public abstract class AbstractMapKey implements IMapKey {
+ @Override
+ public String toString() {
+ return getKey().toSignature();
+ }
+}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractOpaqueMapKey.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractOpaqueMapKey.java
new file mode 100644
index 000000000..c5aa6fed5
--- /dev/null
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractOpaqueMapKey.java
@@ -0,0 +1,23 @@
+/*
+ * SPDX-FileCopyrightText: none
+ * SPDX-License-Identifier: CC0-1.0
+ */
+
+package gov.nist.secauto.metaschema.core.metapath.impl;
+
+import gov.nist.secauto.metaschema.core.metapath.item.function.IOpaqueMapKey;
+
+public abstract class AbstractOpaqueMapKey
+ extends AbstractMapKey
+ implements IOpaqueMapKey {
+ @Override
+ public int hashCode() {
+ return getKey().hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return this == obj
+ || obj instanceof IOpaqueMapKey && getKey().deepEquals(((IOpaqueMapKey) obj).getKey());
+ }
+}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractStringMapKey.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractStringMapKey.java
index 86b895874..92a990b3f 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractStringMapKey.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractStringMapKey.java
@@ -6,22 +6,24 @@
package gov.nist.secauto.metaschema.core.metapath.impl;
import gov.nist.secauto.metaschema.core.metapath.item.function.IMapKey;
+import gov.nist.secauto.metaschema.core.metapath.item.function.IStringMapKey;
/**
* An implementation of a {@link IMapKey} that uses a string-based value.
*/
public abstract class AbstractStringMapKey
- implements IMapKey {
+ extends AbstractMapKey
+ implements IStringMapKey {
@Override
public int hashCode() {
- return getKey().asStringItem().hashCode();
+ return asString().hashCode();
}
@Override
public boolean equals(Object obj) {
- return this == obj ||
- obj instanceof IMapKey
- && getKey().asStringItem().equals(((AbstractStringMapKey) obj).getKey().asStringItem());
+ return this == obj
+ // TODO: implement fn:codepoint-equal per spec
+ || obj instanceof IStringMapKey && getKey().asString().equals(((IStringMapKey) obj).getKey().asString());
}
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractTemporalMapKey.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractTemporalMapKey.java
new file mode 100644
index 000000000..0edf61765
--- /dev/null
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractTemporalMapKey.java
@@ -0,0 +1,45 @@
+/*
+ * SPDX-FileCopyrightText: none
+ * SPDX-License-Identifier: CC0-1.0
+ */
+
+package gov.nist.secauto.metaschema.core.metapath.impl;
+
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.ITemporalItem;
+import gov.nist.secauto.metaschema.core.metapath.item.function.ITemporalMapKey;
+
+import java.time.ZoneOffset;
+
+import edu.umd.cs.findbugs.annotations.NonNull;
+
+public abstract class AbstractTemporalMapKey
+ extends AbstractMapKey
+ implements ITemporalMapKey {
+ @Override
+ public int hashCode() {
+ ITemporalItem temporal = asTemporalItem();
+ int hash = 7;
+ hash = 31 * hash + temporal.getYear();
+ hash = 31 * hash + temporal.getDay();
+ hash = 31 * hash + temporal.getHour();
+ hash = 31 * hash + temporal.getYear();
+ hash = 31 * hash + temporal.getMinute();
+ hash = 31 * hash + temporal.getSecond();
+ hash = 31 * hash + temporal.getNano();
+
+ ZoneOffset offset = temporal.getZoneOffset();
+ return 31 * hash + (offset == null ? 0 : offset.hashCode());
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return this == obj
+ || obj instanceof ITemporalMapKey && equalsInternal((ITemporalMapKey) obj);
+ }
+
+ private boolean equalsInternal(@NonNull ITemporalMapKey other) {
+ ITemporalItem focus = asTemporalItem();
+ ITemporalItem that = other.asTemporalItem();
+ return focus.hasTimezone() == that.hasTimezone() && focus.deepEquals(that);
+ }
+}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractUntypedAtomicItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractUntypedAtomicItem.java
index 1bf43d499..90bf7cbc2 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractUntypedAtomicItem.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractUntypedAtomicItem.java
@@ -42,5 +42,10 @@ private final class MapKey
public IUntypedAtomicItem getKey() {
return AbstractUntypedAtomicItem.this;
}
+
+ @Override
+ public String asString() {
+ return getKey().asString();
+ }
}
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IDateTimeItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IDateTimeItem.java
index b54836a2b..994f1f80f 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IDateTimeItem.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IDateTimeItem.java
@@ -105,7 +105,7 @@ static IDateTimeItem valueOf(@NonNull ZonedDateTime value, boolean hasTimeZone)
@NonNull
static IDateTimeItem valueOf(@NonNull LocalDateTime value) {
- return valueOf(new AmbiguousDateTime(value.atZone(ZoneOffset.UTC), false));
+ return valueOf(new AmbiguousDateTime(ObjectUtils.notNull(value.atZone(ZoneOffset.UTC)), false));
}
/**
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IDayTimeDurationItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IDayTimeDurationItem.java
index 3e2990337..0d59ebf9a 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IDayTimeDurationItem.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IDayTimeDurationItem.java
@@ -19,7 +19,8 @@
import edu.umd.cs.findbugs.annotations.NonNull;
/**
- * An atomic Metapath item containing a duration data value in days, hours, and seconds.
+ * An atomic Metapath item containing a duration data value in days, hours, and
+ * seconds.
*/
public interface IDayTimeDurationItem extends IDurationItem {
/**
@@ -38,13 +39,15 @@ default IAtomicOrUnionType
- * This interface supports both day-time and year-month duration formats following the ISO 8601
- * standard. Examples of valid durations include:
+ * This interface supports both day-time and year-month duration formats
+ * following the ISO 8601 standard. Examples of valid durations include:
*
- * This interface provides functionality for handling time values with and without time zone
- * information, supporting parsing, casting, and comparison operations. It works in conjunction with
- * {@link AmbiguousTime} to properly handle time zone ambiguity.
+ * This interface provides functionality for handling time values with and
+ * without time zone information, supporting parsing, casting, and comparison
+ * operations. It works in conjunction with {@link AmbiguousTime} to properly
+ * handle time zone ambiguity.
*/
public interface ITimeItem extends ITemporalItem {
/**
@@ -69,15 +70,15 @@ static ITimeItem valueOf(@NonNull String value) {
/**
* Construct a new time item using the provided {@code value}.
*
- * This method handles recording if an explicit timezone was provided using the {@code hasTimeZone}
- * parameter. The {@link AmbiguousTime#hasTimeZone()} method can be called to determine if timezone
- * information is present.
+ * This method handles recording if an explicit timezone was provided using the
+ * {@code hasTimeZone} parameter. The {@link AmbiguousTime#hasTimeZone()} method
+ * can be called to determine if timezone information is present.
*
* @param value
* a time, without time zone information
* @param hasTimeZone
- * {@code true} if the date/time is intended to have an associated time zone or
- * {@code false} otherwise
+ * {@code true} if the date/time is intended to have an associated time
+ * zone or {@code false} otherwise
* @return the new item
* @see AmbiguousTime for more details on timezone handling
*/
@@ -92,8 +93,8 @@ static ITimeItem valueOf(@NonNull OffsetTime value, boolean hasTimeZone) {
* Construct a new time item using the provided {@code value}.
*
* This method handles recording if an explicit timezone was provided using the
- * {@link AmbiguousTime}. The {@link AmbiguousTime#hasTimeZone()} method can be called to determine
- * if timezone information is present.
+ * {@link AmbiguousTime}. The {@link AmbiguousTime#hasTimeZone()} method can be
+ * called to determine if timezone information is present.
*
* @param value
* a time, without time zone information
@@ -170,18 +171,20 @@ default ZoneOffset getZoneOffset() {
OffsetTime asOffsetTime();
/**
- * Adjusts an xs:dateTime value to a specific timezone, or to no timezone at all.
+ * Adjusts an xs:dateTime value to a specific timezone, or to no timezone at
+ * all.
*
* This method does one of the following things based on the arguments.
*
*
- *
*