Project

Profile

Help

Bug #5656

closed

XDM array is not converted to a true JS array?

Added by Martynas Jusevicius over 2 years ago. Updated 4 months ago.

Status:
Resolved
Priority:
Normal
Category:
IXSL extensions
Sprint/Milestone:
Start date:
2022-08-22
Due date:
% Done:

0%

Estimated time:
Applies to JS Branch:
2, Trunk
Fix Committed on JS Branch:
Trunk
Fixed in JS Release:
SEF Generated with:
Platforms:
Company:
-
Contact person:
-
Additional contact persons:
-

Description

According to XDM to JavaScript Conversion array(*) should be converted to a JS array.

However this code:

<xsl:variable name="array" select="[ 'a' ]" as="array(*)"/>
<xsl:sequence select="ixsl:call($array, 'push', [ 'b' ])"/>

gives error:

ixsl:call: object method 'push' not found

Same error for this code (note that @as is absent here):

<xsl:variable name="array" select="js:Array([ 'a' ])"/>
<xsl:sequence select="ixsl:call($array, 'push', [ 'b' ])"/>

Related issues

Related to SaxonJS - Bug #4815: Conversion of XDM maps to JS objectsResolvedDebbie Lockett2020-10-30

Actions
Actions #1

Updated by Michael Kay over 2 years ago

The specification of ixsl:call at https://www.saxonica.com/saxon-js/documentation2/index.html#!ixsl-extension/functions/call says

See Type Conversion for details on how the supplied parameters in $arguments are converted from XDM to JavaScript, and how any returned JavaScript objects are converted to XDM.

I believe that no conversion is applied to the $object and $method arguments of ixsl:call, only to the values supplied in $arguments.

Actions #2

Updated by Martynas Jusevicius over 2 years ago

Hmm, okay. Any workarounds for this then?

Actions #3

Updated by Michael Kay over 2 years ago

It rather depends on what you are trying to achieve, which isn't clear. What's wrong with array:append()?

I would discourage any attempt to modify an XDM array in-situ. Saxon is going to assume that the contents of a variable remain unchanged once bound, and any attempt to subvert that is going to have very unpredictable consequences. I think that the conversion rules mean you'll normally get a copy of the array anyway.

Actions #4

Updated by Martynas Jusevicius over 2 years ago

There is still something weird going on, if not with array conversion then with ixsl:set-property in combination with arrays.

<xsl:variable name="js-array" select="ixsl:eval('Array(1, 2)')"/>
<xsl:value-of select="ixsl:call(ixsl:get(ixsl:window(), 'Array'), 'isArray', [ $js-array ])"/> <!-- true -->
<xsl:value-of select="ixsl:call(ixsl:get(ixsl:window(), 'JSON'), 'stringify', [ $js-array ])"/> <!-- [1, 2] -->

<ixsl:set-property name="prop" select="$js-array"/>
<xsl:value-of select="ixsl:call(ixsl:get(ixsl:window(), 'Array'), 'isArray', [ ixsl:get(ixsl:window(), 'prop') ])"/> <!-- false -->
<xsl:value-of select="ixsl:call(ixsl:get(ixsl:window(), 'JSON'), 'stringify', [ ixsl:get(ixsl:window(), 'prop') ])"/> <!-- 1 -->

This test case shows that $js-array is an array as expected, but after it's been set as the value of window.prop, it's not an array anymore.

Actions #5

Updated by Norm Tovey-Walsh about 2 years ago

  • Sprint/Milestone set to SaxonJS 2.5
Actions #7

Updated by Norm Tovey-Walsh about 2 years ago

I think Mike is right about the attempt to call push on an XDM array. The first argument to ixsl:call is expected to be a (native) JavaScript object.

The ixsl:set-property problem is trickier. It feels like that should work, and I have managed to make it work, but I'm not sure I like my workaround.

Actions #8

Updated by Norm Tovey-Walsh about 2 years ago

  • Sprint/Milestone changed from SaxonJS 2.5 to SaxonJS 3.0
  • Applies to JS Branch deleted (2)

The "problem" here is that the type conversion rules apply to the return value of ixsl:get. So when you get the JavaScript array, it's converted into an XDM array, and then it isn't a JSON array anymore.

I don't think we can fix this in 2.x. What we need is a new function, ixsl:get-javascript or ixsl:get-raw or ixsl:get-unconverted or something (or an additional, optional argument on ixsl:get perhaps) that returns the value without type conversion. Then what you'd get back is a JavaScript object and it would still be an array.

Actions #9

Updated by Debbie Lockett 4 months ago

  • Related to Bug #4815: Conversion of XDM maps to JS objects added
Actions #11

Updated by Debbie Lockett 4 months ago

  • Status changed from New to Resolved
  • Assignee set to Debbie Lockett
  • Applies to JS Branch 2, Trunk added
  • Fix Committed on JS Branch Trunk added

For SaxonJS 3, a number of improvements have been made to make it easier for users to work directly with JavaScript objects inside XSLT, and avoid the usual SaxonJS type conversions between JavaScript and XDM.

The new IXSL functions ixsl:json-parse() and ixsl:new() are added to create JavaScript objects, where (by default) the result is not converted to XDM, it is just returned as a JSValue-wrapped object.

A new $options argument is added for ixsl:apply(), ixsl:call(), ixsl:eval(), and ixsl:get(), which is an XDM map which can be used to control (enable or disable) XDM to JS conversion of the supplied arguments (as applicable), and JS to XDM conversion of the result. The new ixsl:json-parse() and ixsl:new() functions also have an $options argument.

I believe these changes will make it possible to solve the coding problems raised in this issue.

Please register to edit this issue

Also available in: Atom PDF Tracking page