Exist: fn:serialize should default to adaptive serialisation method

Created on 7 Dec 2018  路  10Comments  路  Source: eXist-db/exist

What is the problem

Serializing function types with fn:serialize should default to the adaptive method.
At the moment fn:serialize([1]), fn:serialize(map{1:0}) both return an empty string.

What did you expect

The serialisation to default to the adaptive method.

  • fn:serialize([1]) => "[1]"
  • fn:serialize(map{1:0}) => "map{1:0}"

Describe how to reproduce or add a test

let $data := (
  [1, 2, [1, 2]],
  map{"this": "is", "just": ("a", "test")}
)
return fn:serialize($data) eq fn:serialize($data, map {"method": "adaptive"})

Context information

  • eXist-db 5.0.0-RC3 / bfdcc8406
  • Java8
  • MacOs
  • 64 bit
  • GitHub clone
  • no custom changes
enhancement needs documentation needs XQSuite test xquery

Most helpful comment

[1] instance of array(*), [1,2] instance of array(*) returns true(), true(), so eXist knows it's an array.

The spec for fn:serialize says:

If the second argument is omitted, or is supplied in the form of an output:serialization-parameters element, then the values of any serialization parameters that are not explicitly specified is 路implementation-defined路, and may depend on the context.

This leads to the question, what is eXist's default set of serialization parameters?

If, however, we supply a serialization method, then eXist should respect it. Let's try "text":

xquery version "3.1";

serialize([1], map {"method": "text"})

This also returns "". Thus I think we have a serialization bug. The relevant portion of the spec is https://www.w3.org/TR/xslt-xquery-serialization-31/#serdm, which states:

Each item in the sequence that is an array is flattened by calling the function array:flatten() before being copied.

If we do this manually (via serialize(array:flatten([1])), we get the expected result, "1".

In other words, eXist is failing to flatten arrays during sequence normalization.

All 10 comments

I am also wondering what the expected behaviour for maps is.
BaseX just throws an error while existdb will return an empty string again.
When I have time to look at the spec I might expand this issue.

Same behaviour applies to util:log("debug", [1,2])

maybe in fn:serialize([1]) the [1] is seen as a predicate.....

saxon returns "1" anyway

[1] instance of array(*), [1,2] instance of array(*) returns true(), true(), so eXist knows it's an array.

The spec for fn:serialize says:

If the second argument is omitted, or is supplied in the form of an output:serialization-parameters element, then the values of any serialization parameters that are not explicitly specified is 路implementation-defined路, and may depend on the context.

This leads to the question, what is eXist's default set of serialization parameters?

If, however, we supply a serialization method, then eXist should respect it. Let's try "text":

xquery version "3.1";

serialize([1], map {"method": "text"})

This also returns "". Thus I think we have a serialization bug. The relevant portion of the spec is https://www.w3.org/TR/xslt-xquery-serialization-31/#serdm, which states:

Each item in the sequence that is an array is flattened by calling the function array:flatten() before being copied.

If we do this manually (via serialize(array:flatten([1])), we get the expected result, "1".

In other words, eXist is failing to flatten arrays during sequence normalization.

Thanks @joewiz for your thorough investigation of the issue. I already learned a lot.

One thing keeps bugging me:
array:flatten([1]) should yield [1] and thus both should be identical.
To me array:flatten would only be necessary for nested arrays (serialize([1, [2, 3]])).
The outcome 1 2 3 would also not meet my expectations. If the spec says so for text then I would argue that exist should use JSON as the default.

When serializing maps

xquery version "3.1";
let $m := map{"key":"1"}
return (
  serialize($m),
  serialize($m, map{'method':'text'}),
  serialize($m, map{'method':'json'}),
  serialize($m, map{'method':'xml'})
)

(: yields ("", "", "{\"key\": \"1\"}", "") :)

Only JSON serialisation does return the expected output.

Digging a little deeper I found that there is an 'adaptive' method which does things as one would expect

xquery version "3.1";
let $m := (map {"key":"1"}, [1, [2, 3]])
return (
  serialize($m),
  serialize($m, map {'method':'adaptive'}),
  serialize($m, map {'method':'text'}),
  serialize($m, map {'method':'json'}),
  serialize($m, map {'method':'xml'})
)

Just read the spec for array:flatten to learn that is indeed a function that returns a sequence of all members of nested arrays.

This problem still affects eXist 5.2.0.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

lguariento picture lguariento  路  5Comments

mathias-goebel picture mathias-goebel  路  4Comments

merenyics picture merenyics  路  3Comments

opax picture opax  路  3Comments

ahenket picture ahenket  路  4Comments