Skip to content

Commit 351ddb4

Browse files
authored
Merge pull request #4456 from evolvedbinary/bugfix/serialization-item-separator
Bugfix/serialization item separator
2 parents f7a0a1b + d267aca commit 351ddb4

File tree

3 files changed

+105
-6
lines changed

3 files changed

+105
-6
lines changed

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

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.exist.dom.memtree.DocumentBuilderReceiver;
2626
import org.exist.dom.memtree.DocumentImpl;
2727
import org.exist.dom.memtree.MemTreeBuilder;
28+
import org.exist.storage.serializers.EXistOutputKeys;
2829
import org.exist.util.serializer.XQuerySerializer;
2930
import org.exist.xquery.*;
3031
import org.exist.xquery.functions.map.AbstractMapType;
@@ -41,6 +42,8 @@
4142

4243
public class FunSerialize extends BasicFunction {
4344

45+
private final static String DEFAULT_ITEM_SEPARATOR = " ";
46+
4447
public final static FunctionSignature[] signatures = {
4548
new FunctionSignature(
4649
new QName("serialize", Function.BUILTIN_FUNCTION_NS, FnModule.PREFIX),
@@ -81,7 +84,8 @@ public Sequence eval(Sequence[] args, Sequence contextSequence) throws XPathExce
8184

8285
Sequence seq = args[0];
8386
if (xqSerializer.normalize()) {
84-
seq = normalize(this, context, seq);
87+
final String itemSeparator = outputProperties.getProperty(EXistOutputKeys.ITEM_SEPARATOR, DEFAULT_ITEM_SEPARATOR);
88+
seq = normalize(this, context, seq, itemSeparator);
8589
}
8690

8791
xqSerializer.serialize(seq);
@@ -133,7 +137,7 @@ private static boolean isSerializationParametersElement(final Item item) {
133137
* @return normalized sequence
134138
* @throws XPathException in case of dynamic error
135139
*/
136-
public static Sequence normalize(final Expression callingExpr, final XQueryContext context, final Sequence input) throws XPathException {
140+
public static Sequence normalize(final Expression callingExpr, final XQueryContext context, final Sequence input, final String itemSeparator) throws XPathException {
137141
if (input.isEmpty())
138142
// "If the sequence that is input to serialization is empty, create a sequence S1 that consists of a zero-length string."
139143
{return StringValue.EMPTY_STRING;}
@@ -144,7 +148,11 @@ public static Sequence normalize(final Expression callingExpr, final XQueryConte
144148
if (next.getType() == Type.ATTRIBUTE || next.getType() == Type.NAMESPACE || next.getType() == Type.FUNCTION_REFERENCE)
145149
{throw new XPathException(callingExpr, FnModule.SENR0001,
146150
"It is an error if an item in the sequence to serialize is an attribute node or a namespace node.");}
147-
temp.add(next);
151+
if (itemSeparator != null && itemSeparator.length() > 0 && !temp.isEmpty()) {
152+
temp.add(new StringValue(itemSeparator + next.getStringValue()));
153+
} else {
154+
temp.add(next);
155+
}
148156
} else {
149157
// atomic value
150158
Item last = null;
@@ -154,7 +162,7 @@ public static Sequence normalize(final Expression callingExpr, final XQueryConte
154162
// "For each subsequence of adjacent strings in S2, copy a single string to the new sequence
155163
// equal to the values of the strings in the subsequence concatenated in order, each separated
156164
// by a single space."
157-
{((StringValue)last).append(" " + next.getStringValue());}
165+
{((StringValue)last).append((itemSeparator == null ? " " : itemSeparator) + next.getStringValue());}
158166
else
159167
// "For each item in S1, if the item is atomic, obtain the lexical representation of the item by
160168
// casting it to an xs:string and copy the string representation to the new sequence;"

exist-core/src/main/java/org/exist/xquery/functions/util/Eval.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,7 @@ private Sequence doEval(final XQueryContext evalContext, final Sequence contextS
404404

405405
final Sequence seq;
406406
if (xqSerializer.normalize()) {
407-
seq = FunSerialize.normalize(this, context, result);
407+
seq = FunSerialize.normalize(this, context, result, null);
408408
} else {
409409
seq = result;
410410
}

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

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,18 @@ declare %private function ser:adaptive-map-params($data) {
6161
ser:adaptive-map-params($data, ())
6262
};
6363

64+
declare %private function ser:serialize-with-item-separator($data as item()*, $method as xs:string) {
65+
let $options :=
66+
<output:serialization-parameters
67+
xmlns:output="http://www.w3.org/2010/xslt-xquery-serialization">
68+
<output:method value="{$method}"/>
69+
<output:indent>no</output:indent>
70+
<output:item-separator>--</output:item-separator>
71+
</output:serialization-parameters>
72+
return
73+
fn:serialize($data, $options)
74+
};
75+
6476
declare variable $ser:atomic :=
6577
<atomic:root xmlns:atomic="http://www.w3.org/XQueryTest" xmlns:foo="http://www.example.com/foo"
6678
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
@@ -754,4 +766,83 @@ declare
754766
function ser:exist-process-xsl-pi-false() {
755767
let $doc := doc($ser:collection || "/test-xsl.xml")
756768
return fn:serialize($doc, map {xs:QName("exist:process-xsl-pi"): false()})
757-
};
769+
};
770+
771+
declare
772+
%test:assertEquals("1--2")
773+
function ser:item-separator-text-method() {
774+
let $data := (1, 2)
775+
return ser:serialize-with-item-separator($data, "text")
776+
};
777+
778+
declare
779+
%test:assertEquals("1--2")
780+
function ser:item-separator-html-method() {
781+
let $data := (1, 2)
782+
return ser:serialize-with-item-separator($data, "html")
783+
};
784+
785+
declare
786+
%test:assertEquals("1--2")
787+
function ser:item-separator-xhtml-method() {
788+
let $data := (1, 2)
789+
return ser:serialize-with-item-separator($data, "xhtml")
790+
};
791+
792+
declare
793+
%test:assertEquals("1--2")
794+
function ser:item-separator-xml-method() {
795+
let $data := (1, 2)
796+
return ser:serialize-with-item-separator($data, "xml")
797+
};
798+
799+
declare
800+
%test:assertEquals("1--2")
801+
function ser:item-separator-adaptive-method() {
802+
let $data := (1, 2)
803+
return ser:serialize-with-item-separator($data, "adaptive")
804+
};
805+
806+
declare
807+
%test:assertEquals("1|2|3|4|5|6|7|8|9|10")
808+
function ser:serialize-xml-033() {
809+
let $params :=
810+
<output:serialization-parameters xmlns:output="http://www.w3.org/2010/xslt-xquery-serialization">
811+
<output:method value="xml"/>
812+
<output:item-separator value="|"/>
813+
</output:serialization-parameters>
814+
return serialize(1 to 10, $params)
815+
};
816+
817+
declare
818+
%test:assertEquals("1==2==3==4")
819+
function ser:serialize-xml-034() {
820+
let $params :=
821+
<output:serialization-parameters xmlns:output="http://www.w3.org/2010/xslt-xquery-serialization">
822+
<output:method value="xml"/>
823+
<output:omit-xml-declaration value="yes"/>
824+
<output:item-separator value="=="/>
825+
</output:serialization-parameters>
826+
return serialize(1 to 4, $params)
827+
};
828+
829+
declare
830+
%test:assertEquals("1|2|3|4|5|6|7|8|9|10")
831+
function ser:serialize-xml-133() {
832+
let $params := map {
833+
"method" : "xml",
834+
"item-separator" : "|"
835+
}
836+
return serialize(1 to 10, $params)
837+
};
838+
839+
declare
840+
%test:assertEquals("1==2==3==4")
841+
function ser:serialize-xml-134() {
842+
let $params := map {
843+
"method" : "xml",
844+
"omit-xml-declaration" : true(),
845+
"item-separator" : "=="
846+
}
847+
return serialize((1 to 4)!text{.}, $params)
848+
};

0 commit comments

Comments
 (0)