Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 23 additions & 28 deletions src/main/java/org/rumbledb/api/Item.java
Original file line number Diff line number Diff line change
Expand Up @@ -951,9 +951,13 @@ default void removeSequenceAt(int index) throws UnsupportedOperationException {
// endregion arrays

/**
* Returns the string value of the item, if it is an atomic item.
* XDM 3.1 string-value Accessor.
*
* @return the string value.
* For node items, this method corresponds to the {@code dm:string-value} accessor and
* returns the node's string value as defined by its node kind. For atomic items, it
* returns the lexical string value of the atomic item.
*
* @return the string value of the item.
*/
default String getStringValue() {
throw new UnsupportedOperationException("Operation not defined for type " + this.getDynamicType());
Expand Down Expand Up @@ -1462,6 +1466,8 @@ default void addParentToDescendants() {
* "The dm:attributes accessor returns the dynamic, unordered set of attribute nodes that
* have the node as their parent. It is defined only on element and document nodes; for
* other node kinds it returns the empty sequence."
*
* This method corresponds directly to that accessor.
*/
default List<Item> attributes() {
throw new UnsupportedOperationException("Operation not defined for type " + this.getDynamicType());
Expand All @@ -1475,6 +1481,8 @@ default List<Item> attributes() {
* "The dm:children accessor returns the dynamic, ordered sequence of child nodes of the
* node. It is defined on all node kinds except attribute and namespace nodes; for those
* node kinds it returns the empty sequence."
*
* This method corresponds directly to that accessor.
*/
default List<Item> children() {
throw new UnsupportedOperationException("Operation not defined for type " + this.getDynamicType());
Expand All @@ -1488,20 +1496,22 @@ default List<Item> children() {
* "The dm:namespace-nodes accessor returns the dynamic, unordered set of Namespace Nodes. It
* is defined on all seven node kinds."
*
* This default implementation is only a placeholder on the generic Item interface and must
* be overridden by XML node implementations that support namespaces.
* This method corresponds directly to that accessor. The default implementation is only a
* placeholder on the generic Item interface and must be overridden by XML node
* implementations that support namespaces.
*/
default List<Item> namespaceNodes() {
throw new UnsupportedOperationException("Operation not defined for type " + this.getDynamicType());
}

/**
* Helper accessor for XML element nodes: returns namespace nodes for the namespace bindings
* declared directly on the element. This does not include inherited or statically known
* namespaces — only the bindings explicitly declared on the element (for example via
* xmlns attributes).
* Helper derived from the XDM 3.1 {@code dm:namespace-nodes} accessor for XML element
* nodes: returns namespace nodes for the namespace bindings declared directly on the
* element. This does not include inherited or statically known namespaces, only the
* bindings explicitly declared on the element (for example via {@code xmlns} attributes).
*
* Non-element nodes must override this to return the empty sequence.
* Unlike {@link #namespaceNodes()}, this is not a standard XDM accessor; it exposes the
* subset of namespace nodes that are locally declared on the element.
*/
default List<Item> declaredNamespaceNodes() {
throw new UnsupportedOperationException("Operation not defined for type " + this.getDynamicType());
Expand Down Expand Up @@ -1611,7 +1621,10 @@ default List<Item> typeName() {
* atomic items in the XDM sense.
*/
default List<Item> typedValue() {
return this.atomizedValue();
if (isAtomic()) {
return Collections.singletonList(this);
}
throw new UnsupportedOperationException("Operation not defined for class " + this.getClass().getName());
}

/**
Expand Down Expand Up @@ -1669,24 +1682,6 @@ default Item parent() {
throw new UnsupportedOperationException("Operation not defined for type " + this.getDynamicType());
}

/**
* XDM 3.1 Section 5.12 string-value Accessor.
*
* dm:string-value($n as node()) as xs:string
*
* "The dm:string-value accessor returns the string-value of the node as defined for each
* node kind."
*
* In this API, node string values are exposed via getStringValue() and the default
* implementation of dm:typed-value delegates to atomizedValue().
*/
default List<Item> atomizedValue() {
if (isAtomic())
return Collections.singletonList(this);
else
throw new UnsupportedOperationException("Operation not defined for class " + this.getClass().getName());
}

default void setParent(Item parent) {
throw new UnsupportedOperationException("Operation not defined for type " + this.getDynamicType());
}
Expand Down
10 changes: 2 additions & 8 deletions src/main/java/org/rumbledb/items/AnnotatedItem.java
Original file line number Diff line number Diff line change
Expand Up @@ -771,7 +771,8 @@ public List<Item> typeName() {

@Override
public List<Item> typedValue() {
return this.itemToAnnotate.typedValue();
// An annotated atomic item yields itself as typed value so its annotation is preserved.
return this.isAtomic() ? List.of(this) : this.itemToAnnotate.typedValue();
}

@Override
Expand Down Expand Up @@ -869,13 +870,6 @@ public void setTopLevelOrder(double topLevelOrder) {
this.itemToAnnotate.setTopLevelOrder(topLevelOrder);
}

@Override
public List<Item> atomizedValue() {
// An annotated atomic item atomizes to itself. Delegating to the
// wrapped item would discard the annotation and lose its subtype.
return this.isAtomic() ? List.of(this) : this.itemToAnnotate.atomizedValue();
}

@Override
public String serialize() {
return Item.super.serialize();
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/org/rumbledb/items/ArrayItem.java
Original file line number Diff line number Diff line change
Expand Up @@ -328,10 +328,10 @@ public String getSparkSQLType() {
}

@Override
public List<Item> atomizedValue() {
public List<Item> typedValue() {
List<Item> result = new ArrayList<>();
for (Item member : this.arrayItems) {
result.addAll(member.atomizedValue());
result.addAll(member.typedValue());
}
return result;
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/rumbledb/items/FunctionItem.java
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,7 @@ public void setModuleDynamicContext(DynamicContext dynamicModuleContext) {
}

@Override
public List<Item> atomizedValue() {
public List<Item> typedValue() {
throw new CannotAtomizeException("tried to atomize Function", ExceptionMetadata.EMPTY_METADATA);
}

Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/rumbledb/items/MapEntryItem.java
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ public String getSparkSQLType() {
}

@Override
public List<Item> atomizedValue() {
public List<Item> typedValue() {
throw new CannotAtomizeException("tried to atomize Map", ExceptionMetadata.EMPTY_METADATA);
}

Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/rumbledb/items/MapItem.java
Original file line number Diff line number Diff line change
Expand Up @@ -479,7 +479,7 @@ public String getSparkSQLType() {
}

@Override
public List<Item> atomizedValue() {
public List<Item> typedValue() {
throw new CannotAtomizeException("tried to atomize Map", ExceptionMetadata.EMPTY_METADATA);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ public String getSparkSQLType() {
}

@Override
public List<Item> atomizedValue() {
public List<Item> typedValue() {
throw new CannotAtomizeException("tried to atomize Map", ExceptionMetadata.EMPTY_METADATA);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ public String getSparkSQLType() {
}

@Override
public List<Item> atomizedValue() {
public List<Item> typedValue() {
throw new CannotAtomizeException("tried to atomize Map", ExceptionMetadata.EMPTY_METADATA);
}

Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/rumbledb/items/ObjectItem.java
Original file line number Diff line number Diff line change
Expand Up @@ -550,7 +550,7 @@ public String getSparkSQLType() {
}

@Override
public List<Item> atomizedValue() {
public List<Item> typedValue() {
throw new CannotAtomizeException("tried to atomize Object", ExceptionMetadata.EMPTY_METADATA);
}

Expand Down
4 changes: 2 additions & 2 deletions src/main/java/org/rumbledb/items/SequenceArrayItem.java
Original file line number Diff line number Diff line change
Expand Up @@ -379,11 +379,11 @@ public String getSparkSQLType() {
}

@Override
public List<Item> atomizedValue() {
public List<Item> typedValue() {
List<Item> result = new ArrayList<>();
for (List<Item> memberSequence : this.memberSequences) {
for (Item item : memberSequence) {
result.addAll(item.atomizedValue());
result.addAll(item.typedValue());
}
}
return result;
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/rumbledb/items/xml/AttributeItem.java
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ public int hashCode() {
}

@Override
public List<Item> atomizedValue() {
public List<Item> typedValue() {
if (this.typeAnnotation != null) {
Item typedValue = CastIterator.castItemToType(
ItemFactory.getInstance().createUntypedAtomicItem(this.stringValue),
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/rumbledb/items/xml/CommentItem.java
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ public String getStringValue() {
}

@Override
public List<Item> atomizedValue() {
public List<Item> typedValue() {
return Collections.singletonList(ItemFactory.getInstance().createStringItem(this.content));
}

Expand Down
15 changes: 5 additions & 10 deletions src/main/java/org/rumbledb/items/xml/DocumentItem.java
Original file line number Diff line number Diff line change
Expand Up @@ -254,11 +254,14 @@ public List<Item> typeName() {
* For a Document Node, dm:typed-value returns the typed value of the document node as a
* sequence of zero or more atomic values.
*
* This implementation delegates to atomizedValue().
* This implementation delegates to the typed value of the document element.
*/
@Override
public List<Item> typedValue() {
return this.atomizedValue();
if (this.documentElement != null) {
return this.documentElement.typedValue();
}
return Collections.singletonList(ItemFactory.getInstance().createUntypedAtomicItem(this.stringValue));
}

/**
Expand Down Expand Up @@ -299,14 +302,6 @@ public int hashCode() {
return this.documentPos.hashCode();
}

@Override
public List<Item> atomizedValue() {
if (this.documentElement != null) {
return this.documentElement.typedValue();
}
return Collections.singletonList(ItemFactory.getInstance().createUntypedAtomicItem(this.stringValue));
}

@Override
public List<Item> namespaceNodes() {
return Collections.emptyList();
Expand Down
40 changes: 17 additions & 23 deletions src/main/java/org/rumbledb/items/xml/ElementItem.java
Original file line number Diff line number Diff line change
Expand Up @@ -369,13 +369,26 @@ public List<Item> typeName() {
* "For an Element Node, dm:typed-value returns the typed value of the element node as a
* sequence of zero or more atomic values."
*
* This implementation delegates to atomizedValue(), which currently computes a
* best-effort typed value by concatenating the atomized values of the element's
* children in document order.
* This implementation computes a best-effort typed value from the element's string value
* and optional type annotation.
*/
@Override
public List<Item> typedValue() {
return this.atomizedValue();
if (this.typeAnnotation != null) {
Item typedValue = CastIterator.castItemToType(
ItemFactory.getInstance().createUntypedAtomicItem(this.stringValue),
this.typeAnnotation,
org.rumbledb.exceptions.ExceptionMetadata.EMPTY_METADATA
);
return Collections.singletonList(typedValue);
}
// For untyped elements, atomization yields the element's typed value as xs:untypedAtomic.
// For element nodes, typed-value is based on the element's string value, which is the
// concatenation of descendant text nodes in document order and therefore excludes comment
// and processing-instruction content.
return Collections.singletonList(
ItemFactory.getInstance().createUntypedAtomicItem(this.stringValue)
);
}

@Override
Expand Down Expand Up @@ -464,25 +477,6 @@ public int hashCode() {
return this.documentPos.hashCode();
}

@Override
public List<Item> atomizedValue() {
if (this.typeAnnotation != null) {
Item typedValue = CastIterator.castItemToType(
ItemFactory.getInstance().createUntypedAtomicItem(this.stringValue),
this.typeAnnotation,
org.rumbledb.exceptions.ExceptionMetadata.EMPTY_METADATA
);
return Collections.singletonList(typedValue);
}
// For untyped elements, atomization yields the element's typed value as xs:untypedAtomic.
// For element nodes, typed-value is based on the element's string value, which is the
// concatenation of descendant text nodes in document order and therefore excludes comment
// and processing-instruction content.
return Collections.singletonList(
ItemFactory.getInstance().createUntypedAtomicItem(this.stringValue)
);
}

@Override
public boolean getEffectiveBooleanValue() {
return true;
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/rumbledb/items/xml/NamespaceItem.java
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ public int hashCode() {
}

@Override
public List<Item> atomizedValue() {
public List<Item> typedValue() {
// Spec: "dm: typed-value Returns the value of the uri property as an xs:string ."
return Collections.singletonList(ItemFactory.getInstance().createStringItem(this.uri));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ public boolean isProcessingInstructionNode() {
}

@Override
public List<Item> atomizedValue() {
public List<Item> typedValue() {
return Collections.singletonList(ItemFactory.getInstance().createStringItem(this.content));
}

Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/rumbledb/items/xml/TextItem.java
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ public List<Item> children() {
}

@Override
public List<Item> atomizedValue() {
public List<Item> typedValue() {
return Collections.singletonList(ItemFactory.getInstance().createUntypedAtomicItem(this.content));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ private HashMap<FlworKey, List<FlworTuple>> mapTuplesToPairs() {
.getLocalVariableValue(groupVariableName, getMetadata());
List<Item> atomizedGroupValues = new ArrayList<>();
for (Item groupVariableValue : groupVariableValues) {
atomizedGroupValues.addAll(groupVariableValue.atomizedValue());
atomizedGroupValues.addAll(groupVariableValue.typedValue());
}
if (atomizedGroupValues.size() > 1) {
throw new UnexpectedTypeException(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ private void fnDataAppend(Item item, List<Item> out) {
if (item.isFunction()) {
throw new CannotAtomizeException("The sequence cannot be atomized.", getMetadata());
}
out.addAll(item.atomizedValue());
out.addAll(item.typedValue());
}

private List<Item> invokeKeyFunction(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ private void initializeResults(DynamicContext context) {
this.keyIterator.materialize(context, rawKey);
List<Item> atomized = new ArrayList<>();
for (Item it : rawKey) {
atomized.addAll(it.atomizedValue());
atomized.addAll(it.typedValue());
}
if (atomized.size() != 1 || !atomized.get(0).isAtomic()) {
throw new UnexpectedTypeException(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ private void initializeResults(DynamicContext context) {

List<Item> atomized = new ArrayList<>();
for (Item it : rawKey) {
atomized.addAll(it.atomizedValue());
atomized.addAll(it.typedValue());
}

if (atomized.size() != 1 || !atomized.get(0).isAtomic()) {
Expand Down Expand Up @@ -146,4 +146,3 @@ public JSoundDataFrame getDataFrame(DynamicContext dynamicContext) {
throw new OurBadException("map:get is currently supported only in local execution mode.");
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public Item materializeFirstItemOrNull(DynamicContext context) {

List<Item> atomized = new ArrayList<>();
for (Item it : rawKey) {
atomized.addAll(it.atomizedValue());
atomized.addAll(it.typedValue());
}

if (atomized.size() != 1 || !atomized.get(0).isAtomic()) {
Expand Down Expand Up @@ -126,4 +126,3 @@ public Item materializeFirstItemOrNull(DynamicContext context) {
}
}
}

Loading
Loading