Skip to content

Commit a40f0dc

Browse files
committed
[fix] flatten arrays before normalizing sequence
1 parent a3eb77c commit a40f0dc

File tree

2 files changed

+31
-14
lines changed

2 files changed

+31
-14
lines changed

exist-core/src/main/java/org/exist/xquery/functions/fn/FunSerialize.java

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -145,40 +145,51 @@ private static boolean isSerializationParametersElement(final Item item) {
145145
* @throws XPathException in case of dynamic error.
146146
*/
147147
public static Sequence normalize(final Expression callingExpr, final XQueryContext context, final Sequence input, final String itemSeparator) throws XPathException {
148-
if (input.isEmpty())
149-
// "If the sequence that is input to serialization is empty, create a sequence S1 that consists of a zero-length string."
150-
{return StringValue.EMPTY_STRING;}
151-
final ValueSequence temp = new ValueSequence(input.getItemCount());
148+
// "If the sequence that is input to serialization is empty, create a sequence S1 that consists of a zero-length string."
149+
if (input.isEmpty()) {
150+
return StringValue.EMPTY_STRING;
151+
}
152+
// flatten arrays
153+
final ValueSequence step1 = new ValueSequence();
152154
for (final SequenceIterator i = input.iterate(); i.hasNext(); ) {
155+
final Item next = i.nextItem();
156+
if (next.getType() != Type.ARRAY) {
157+
step1.add(next);
158+
continue;
159+
}
160+
final Sequence sequence = ArrayType.flatten(next);
161+
if (sequence.isEmpty()) {
162+
continue;
163+
}
164+
for (final SequenceIterator si = sequence.iterate(); si.hasNext(); ) {
165+
step1.add(si.nextItem());
166+
}
167+
}
168+
169+
final ValueSequence step2 = new ValueSequence(step1.getItemCount());
170+
for (final SequenceIterator i = step1.iterate(); i.hasNext(); ) {
153171
final Item next = i.nextItem();
154172
final int itemType = next.getType();
155173
if (Type.subTypeOf(itemType, Type.NODE)) {
156174
if (itemType == Type.ATTRIBUTE || itemType == Type.NAMESPACE || itemType == Type.FUNCTION_REFERENCE) {
157175
throw new XPathException(callingExpr, FnModule.SENR0001,
158176
"It is an error if an item in the sequence to serialize is an attribute node or a namespace node.");
159177
}
160-
temp.add(next);
161-
} else if (itemType == Type.ARRAY) {
162-
final Sequence sequence = ArrayType.flatten(next);
163-
if (sequence.isEmpty()) {
164-
continue;
165-
}
166-
temp.add(new StringValue(callingExpr, sequence.getStringValue()));
178+
step2.add(next);
167179
} else {
168180
// atomic value
169181
// "For each item in S1, if the item is atomic, obtain the lexical representation of the item by
170182
// casting it to an xs:string and copy the string representation to the new sequence;"
171183
final StringValue stringRepresentation = new StringValue(callingExpr, next.getStringValue());
172-
// skip values that evaluate to an empty string
173-
temp.add(stringRepresentation);
184+
step2.add(stringRepresentation);
174185
}
175186
}
176187

177188
context.pushDocumentContext();
178189
try {
179190
final MemTreeBuilder builder = context.getDocumentBuilder();
180191
final DocumentBuilderReceiver receiver = new DocumentBuilderReceiver(callingExpr, builder, true);
181-
for (final SequenceIterator i = temp.iterate(); i.hasNext(); ) {
192+
for (final SequenceIterator i = step2.iterate(); i.hasNext(); ) {
182193
final Item next = i.nextItem();
183194
if (Type.subTypeOf(next.getType(), Type.NODE)) {
184195
next.copyTo(context.getBroker(), receiver);

exist-core/src/test/xquery/xquery3/serialize.xql

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -993,3 +993,9 @@ declare
993993
function ser:sequence-of-empty-arrays-serializes-to-empty-string() {
994994
serialize(([],[]), map{"item-separator": "|"})
995995
};
996+
997+
declare
998+
%test:assertEquals("1|2")
999+
function ser:item-separator-applies-to-array-members() {
1000+
serialize(([1,2]), map{"item-separator":"|"})
1001+
};

0 commit comments

Comments
 (0)