Project

Profile

Help

Bug #3251

closed

Possible error in XSLT when choosing overloaded method in reflexive function

Added by Nick Nunes almost 7 years ago. Updated almost 7 years ago.

Status:
Closed
Priority:
Normal
Assignee:
Category:
Saxon extensions
Sprint/Milestone:
-
Start date:
2017-06-08
Due date:
% Done:

100%

Estimated time:
Legacy ID:
Applies to branch:
Fix Committed on Branch:
9.8
Fixed in Maintenance Release:
Platforms:

Description

I'm attempting to write a function which will allow me to perform XPath syntax checking (without evaluating the context, in scope prefixes or variables). My initial approach was to use reflexive extension functions and the s9api, as I'm not sure I will have control over the classpath where the function is executed (but I do know it will be using Saxon). I understand that reflexive functions are not ideal but speed is not of particular concern, ease of use is favored in this situation.

My intention was to follow this documentation http://www.saxonica.com/html/documentation/xpath-api/s9api-xpath.html and simply catch a failure to compile(). However, I ran into difficulty creating the Processor. Regardless of the types of the arguments supplied to Processor:new() it always selects the constructor which expects a javax.xml.transform.Source. I've attempted calling Processor:new() with an xs:boolean argument, a java Boolean, and a net.sf.saxon.Configuration argument. This is the error message I get from a -TJ trace while passing in a Configuration:

Finding best fit method for arguments
Trying option 1: public net.sf.saxon.s9api.Processor(javax.xml.transform.Source) throws net.sf.saxon.s9api.SaxonApiException
Conversion preferences are [22]
Trying option 2: public net.sf.saxon.s9api.Processor(net.sf.saxon.Configuration)
Conversion preferences are [80]
Trying option 3: public net.sf.saxon.s9api.Processor(boolean)
Conversion preferences are [80]
Eliminating option 1
Eliminating option 2
Number of candidate methods remaining: 1
Error on line 17 column 89 of check.xpath.xsl:
  External object has wrong class (is net.sf.saxon.Configuration, expected javax.xml.transform.Source)

This appears to reject the constructor with the javax.xml.transform.Source signature, then proceeds to generate an error consistent with not rejecting it. Perhaps I'm misinterpreting the trace messages though.

I've attached a stylesheet which triggers this error.


Files

check.xpath.xsl (964 Bytes) check.xpath.xsl Nick Nunes, 2017-06-09 00:48
Actions #1

Updated by Michael Kay almost 7 years ago

  • Category set to Saxon extensions
  • Status changed from New to In Progress
  • Assignee set to Michael Kay
  • Priority changed from Low to Normal

Thanks: problem confirmed. The code here has been unchanged for years and seems fairly bizarre, I'll need to study it closely to try and discern what was in the author's mind when he wrote it ;-)

Actions #2

Updated by Michael Kay almost 7 years ago

A word about what you're trying to do: I think that checking syntax alone, without any reference to the static context, is going to be difficult: Saxon resolves references to many aspects of the static context in the course of parsing. There might be some tricks that you can use, for example setting the "scanOnly" flag in the XPathParser - this is used when processing embedded expressions in XQuery attributes, because these can appear before the relevant namespace declarations; but you would be into some very low-level interfaces here. In some ways you might be better off using the JAXP XPath compiler because this resolves all context references using callbacks - managing the callbacks within XSLT code would be challenging, but perhaps you could write a Java wrapper that does it.

Actions #3

Updated by Michael Kay almost 7 years ago

There are a number of things happening here.

Firstly, when we try to determine the static type of the argument to Processor.new(), we get item(). The call on Configuration.new() is a JavaExtensionFunctionCall, its resultConverter is null, and in this situation getItemType() returns item(). It seems we could do better than this.

Secondly, when we assess the possible overloads of Processor.new(), the code decides that Processor.new(Source) is the most promising, because NodeInfo implements source, and an item that happens to be a node can therefore be passed without conversion.

As a workaround, try Processor:new(Configuration:new() treat as Q{http://saxon.sf.net/java-type}net.sf.saxon.Configuration)

Actions #4

Updated by Michael Kay almost 7 years ago

  • Status changed from In Progress to Resolved

The key problem is that UnresolvedExtensionFunctionCall.typeCheck() does not call typeCheck() on its arguments, which means that it is working with inadequate information about the static types of the arguments. Adding a call to typeCheckChildren() fixes this test case.

However, this change causes regression for a unit test which is calling j:process($x) where there are two overloads of the Java process() method, one expecting String and the other byte[], and $x has static type xs:string? and is bound to an empty sequence. The current code is choosing the String version (and passing null); with the type-checking change, it decides that the call is ambiguous. This is because given

let $x as xs:string? := () return ....

type-checking reduces the type of $x to empty-sequence(), losing the fact that it was originally declared as xs:string?.

It's hard to see a way to make this change without breaking compatibility for at least some applications. I'm therefore proposing to make the change on the 9.8 branch but not for 9.7.

Actions #5

Updated by Michael Kay almost 7 years ago

  • Fix Committed on Branch 9.8 added
Actions #6

Updated by O'Neil Delpratt almost 7 years ago

  • Status changed from Resolved to Closed
  • % Done changed from 0 to 100
  • Fixed in Maintenance Release 9.8.0.2 added

Patch applied in the Saxon 9.8.0.2 maintenance release

Please register to edit this issue

Also available in: Atom PDF