Project

Profile

Help

Feature #3569

closed

Test if a Javascript property exists before calling ixsl:get()

Added by Pieter Masereeuw over 6 years ago. Updated about 4 years ago.

Status:
Closed
Priority:
Low
Category:
IXSL extensions
Sprint/Milestone:
-
Start date:
2017-12-12
Due date:
% Done:

0%

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

Description

It would be nice to be able to test if a property is present so that ixsl:get() does not issue a message in the console. I tried map:contains($obj, 'prop') but than the compiler complains that obj is not a map. So I wrote a small Javascript wrapper that performs the test:

    return object.hasOwnProperty(property);
Actions #1

Updated by Debbie Lockett over 6 years ago

With the changes for bug 3545 (https://saxonica.plan.io/issues/3545) map:contains($obj, 'prop') should work as required (in the next maintenance release). I'll add some further JS unit tests.

I think an alternative to your JavaScript wrapper would be to call ixsl:call($obj, 'hasOwnProperty', ['prop'])

Actions #2

Updated by Debbie Lockett about 6 years ago

JS unit test ixsl2/getlookup02 added to test use of ixsl:call($obj, 'hasOwnProperty', ['prop']), map:contains(), map:get() and lookup operator.

Note that using hasOwnProperty (in JavaScript, or using ixsl:call()) may return different results to using map:contains() - due to the difference between direct and inherited properties: hasOwnProperty only returns true for direct properties, not properties inherited through the prototype chain; map:contains() returns true for all properties.

Pieter, you said that "I tried map:contains($obj, 'prop') but than the compiler complains that obj is not a map. " - which version of Saxon-EE were you using to compile? I have not seen a compile time error.

Actions #3

Updated by Pieter Masereeuw about 6 years ago

I still have it with the Saxon-EE that comes with the newest Oxygen (version 20). According to the about dialog, the Saxon EE version is 9.8.0.8. Maybe Saxon is right and my code was wrong.

This was (I suppose) my call:

map:contains(ixsl:page(), $RUNNING_QUERY_IDS_PROPERTY)

I set the property with:

+<ixsl:set-property name="{$RUNNING_QUERY_IDS_PROPERTY}" select="string-join($running-query-ids, ' ')" object="ixsl:page()"/>+

The Javascript wrapper (listed above in this issue) is called as follows:

js:hasOwnProperty(ixsl:page(), $RUNNING_QUERY_IDS_PROPERTY)

The error message is:

Required item type of first argument of map:contains() is map(*); supplied value (ixsl:page()) has item type document-node()

Don't hit me if I am foolish...

Actions #4

Updated by Debbie Lockett about 6 years ago

Well, that's a shame isn't it! And I think it's us being foolish, not you...

In general, the (assessor) map functions can be used on JavaScript objects; but they do not work on nodes (even though in Saxon-JS nodes are also treated as objects), e.g. the document-node() returned from ixsl:page().

So we need to think further...

Actions #5

Updated by Pieter Masereeuw about 6 years ago

Yes, using map:contains() is obviously a foolish misinterpretation by me of some earlier comment.

But the question remains. Taking apart any possible orthogonality issues, if ixsl:get() could just return the empty sequence (and not issue a warning to the console), that might already be sufficient.

BTW: I believe that it impossible to use ixsl:set-property to set the empty sequence, so no confusion could arise (unlike the interpretation of null in Java Map:get()).

There may be a relation of this issue with [[Feature #3570

Actions #6

Updated by Debbie Lockett about 6 years ago

I think I suggested trying map:contains(). We claim that JavaScript objects are treated as XDM maps; but this is not quite true (see work for Issue #3545). Furthermore, it is not true for objects which get converted to something more specific (e.g. Node, Array, Date, null) by the JS to XDM conversion in Saxon-JS.

We are thinking that it may be useful to add a new IXSL extension function (probably just from Saxon-EE 9.9, and Saxon-JS 2.0) which allows any JavaScript object to be viewed like an XDM map - probably as the JSValue wrapped version, which allows use of map assessor functions, map:get(), map:contains() and map:find(). This would allow you to look up properties and methods of the object, e.g. map:contains(ixsl:as-map($obj), 'prop') or ixsl:as-map($obj)?prop. So ixsl:as-map($obj) means don't do the usual JS to XDM conversion, I want to look at the object in terms of its key-value pairs.

Indeed, taking a step back, an alternative direction for a solution to this specific problem would be to allow you to switch off warning messages. I did some work in this direction previously, but abandoned it - maybe time to resurrect!

Also, re your final point: I can't think of a good reason that we don't allow ixsl:set-property with the empty sequence as the @select expression. Indeed, you may want to be able to set properties to null. So this looks like an omission. Thanks for pointing it out - I hadn't quite picked it up from Issue #3570!

Actions #7

Updated by Debbie Lockett about 6 years ago

Separate bug(s) raised for last point about using ixsl:set-property to set properties to null, see bug #3738.

Actions #8

Updated by Debbie Lockett about 6 years ago

Note that in the next Saxon-JS release (1.1.0), it will be possible to turn off all warning messages by setting the logLevel using the Saxon-JS API. See Feature #3741.

Leaving this issue open because there are other changes left to think about for Saxon-JS 2.0.

Actions #9

Updated by Debbie Lockett over 4 years ago

  • Description updated (diff)
  • Status changed from New to In Progress
  • Assignee set to Debbie Lockett

Code committed on Saxon 10.0 dev branch to add the IXSL extension function ixl:contains(). The signature for the function is:

ixsl:contains($object as item(), $property as xs:string) ➔ xs:boolean

The intention is that this can be used to test if a property is present on an object, to avoid the warning messages in the console from ixsl:get(). The function should return false when ixsl:get() would return a warning (i.e. when the property is undefined on the object); and true otherwise.

Note that the signature is very similar, but not quite the same as the signature for ixsl:get():

ixsl:get($object as item()?, $property as xs:string) ➔ item()*

i.e. for ixsl:get() the supplied object is allowed to be empty. But I think it would be clearer if that is not allowed for ixsl:contains().

There is some discussion above about using object.hasOwnProperty(prop) to implement this test, but I don't think that is really what we want. hasOwnProperty returns false for inherited properties which are present on the object, when ixsl:get() would return a result. So this is not really the right test. I think we do want the results to align with ixl:get().

Actions #10

Updated by Debbie Lockett over 4 years ago

Implemented and committed in Saxon-JS 2.0 dev branch (in ExtraFn.js).

Various JS2 unit tests added: ixsl/contains01, 02, 03, 04; ixslErr/containsErr01.

Still TODO: documentation.

Actions #11

Updated by Debbie Lockett about 4 years ago

  • Status changed from In Progress to Resolved
  • Fix Committed on JS Branch Trunk added

Documentation added for Saxon-JS 2 (trunk development branch).

Actions #12

Updated by Debbie Lockett about 4 years ago

  • Status changed from Resolved to Closed
  • Fixed in JS Release set to Saxon-JS 2.0
  • Applies to JS Branch Trunk added
Actions #13

Updated by Debbie Lockett about 4 years ago

  • Category set to IXSL extensions

Please register to edit this issue

Also available in: Atom PDF Tracking page