Project

Profile

Help

Bug #5046

Handling null and undefined objects in ixsl:get() and ixsl:set-property

Added by Debbie Lockett 2 months ago. Updated about 1 month ago.

Status:
Closed
Priority:
Normal
Category:
IXSL extensions
Sprint/Milestone:
-
Start date:
2021-07-22
Due date:
% Done:

100%

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

Description

(Having already spent lots of time working on this, it's time to try to get the issues in writing.)

We need to clarify how null and undefined JavaScript objects are handled within ixsl:get() and ixsl:set-property. Both the code and documentation need work.

Currently the documentation for ixsl:get() says:

If the specified object or property does not exist, then the function returns the empty sequence (with a console log warning in the latter case). (Note the difference to the similar function ixsl:call(), for which a run-time error is raised in this case.)

While for ixsl:set-property:

An error will be raised at run-time if the specified object does not exist or is not unique. If the specified property does not exist, then there is no error, but a warning is output in the console log.

Note that the property name string supplied to ixsl:get() and ixsl:set-property can be a dot separated list of names to access a nested property; but we are not clear about what happens when we encounter null or undefined objects in such a nested chain of objects.

For instance consider ixsl:get($object, 'a.b.c') and <ixsl:set-property object="$object" name="a.b.c" select="'value'"/>. What happens if in JavaScript $object.a or $object.a.b returns null or undefined? Currently if either of these is null, Saxon-JS 2.2 crashes with an uncaught TypeError, so there is definitely a bug here.

History

#1 Updated by Debbie Lockett 2 months ago

The proposed solution is that we should throw an error if we ever attempt to get a property of null or undefined. This is indeed what happens in JavaScript. So if at any point prior to the last step, while stepping down a chain of nested properties, we encounter null or undefined as the property value, then we should in fact throw an error.

However it would then be inconsistent not to throw an error if the initial object is null or undefined; i.e. ixsl:get($object, 'prop') should throw an error if $object is null or undefined. This would be a change in behaviour for Saxon-JS, which could potentially cause problems from unexpected errors in existing applications.

Note that we did previously look into what to do in this case (see Bug #3501: Error when object supplied to ixsl:get() is null), but it now seems that that solution was not fully thought through. At that time we decided that it would make sense for ixsl:get($object, 'prop') to return the empty sequence when $object is null; so that we get the same result as when using the lookup operator: $object?prop. Note that by the XPath specification, ()?prop always returns the empty sequence.

However, we subsequently clarified that ixsl:get($object, 'prop') and $object?prop are not always equivalent; see https://www.saxonica.com/saxon-js/documentation/index.html#!development/properties:

In order to use this $object?propName shorthand, the JavaScript object must be converted using "weak" conversion (as described in JavaScript to XDM Conversion), and must not be of a more specific type which is recognised (i.e. the object is not any of the following: null, undefined, String, Number, Boolean, Date, Node, Array, or Function). So that $object is treated as a JSValue wrapped external object.

And this specifically points out that you may not get the same result for null or undefined objects!

#2 Updated by Debbie Lockett 2 months ago

If we amend the definition of ixsl:get() to say that the supplied object must exist (i.e. not be null or undefined in JavaScript), then this brings the function better in line with ixsl:call, ixsl:contains() and ixsl:set-property, for which we already specify that the supplied object must exist. We should update the function signature to reflect this to provide the correct cardinality check - which means a change in IXSLFunctionSet.java for Saxon on Java, and in lib/xpath/xsltData.js for the XX compiler.

#3 Updated by Debbie Lockett 2 months ago

Committed:

  • Saxon-JS code changes (in ExtraFn.js and lib/xpath/xsltData.js)
  • New selenium browser tests: ixsl/get20; ixsl2/getlookup20, getlookup20b
  • Updated results for tests ixsl/getEmpty01, getEmpty02, getEmpty04

These now all align with the proposed solution above.

I have not yet done the following:

  • Commit update to IXSLFunctionSet.java for Saxon on Java
  • Documentation updates

#4 Updated by Debbie Lockett about 2 months ago

  • Status changed from New to Resolved
  • Fix Committed on JS Branch 2 added

Documentation updates committed.

Update to IXSLFunctionSet.java for Saxon on Java committed on saxon10 and saxondev branches.

#5 Updated by Debbie Lockett about 2 months ago

  • Status changed from Resolved to In Progress

Reopened because the new logic (that we should always throw an error if we ever attempt to get a property of null or undefined; in particular when accessing nested properties) is also relevant to ixsl:contains(), ixsl:call() and ixsl:remove-property.

#6 Updated by Debbie Lockett about 1 month ago

  • Status changed from In Progress to Resolved

New logic also applied for ixsl:call(), ixsl:contains(), and ixsl:remove-property; so marking resolved again.

Committed:

  • New selenium browser tests: ixsl/call20, ixsl/contains20, ixsl/removeProperty20
  • Saxon-JS code changes (in ExtraFn.js)
  • Further documentation updates

#7 Updated by Debbie Lockett about 1 month ago

  • % Done changed from 0 to 100
  • Fixed in JS Release set to Saxon-JS 2.3

Bug fix applied in the Saxon-JS 2.3 maintenance release.

#8 Updated by Debbie Lockett about 1 month ago

  • Status changed from Resolved to Closed

Please register to edit this issue

Also available in: Atom PDF Tracking page