Bug #2435
closedEquality fails due to type comparison
100%
Description
Consider the following XSD:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.xpathtest.com/test"
xmlns:test="http://www.xpathtest.com/test"
elementFormDefault="qualified">
<xs:element name="comparables">
<xs:complexType>
<xs:sequence>
<xs:element ref="test:comparable" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="comparable">
<xs:complexType>
<xs:sequence>
<xs:element name="string" type="xs:string"/>
<xs:element name="int" type="xs:integer"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
and the following instance:
<comparables xmlns="http://www.xpathtest.com/test">
<comparable>
<string>hello</string>
<int>1</int>
</comparable>
<comparable>
<string>hello</string>
<int>1</int>
</comparable>
</comparables>
If I run the following XPath expression using Saxon 9.6.0-4:
//test:comparable[1]/test:int eq //test:comparable[2]/test:int
it fails with the message "Cannot compare xs:integer to xs:integer". If I replace this expression with the following:
//test:comparable[1]/test:int*1 eq //test:comparable[2]/test:int*1
it returns "true" as expected. It seems that something is amiss in the way Saxon is handling the types of the expressions being compared.
Updated by Michael Kay over 9 years ago
- Status changed from New to In Progress
It works for me on Saxon 9.6.0.6. Could you check it please on the latest release? I haven't been able to track down a specific bug fix.
I've added the test case to the QT3 test suite as prod-ValueComp/value-comparison-12.
Updated by Nick Evans over 9 years ago
Thanks for your response. I have just tried it on the latest (9.6.0-6) release but unfortunately still get the same error. This is how I am running the expression (I have just translated this from scala code, sorry if some errors have crept in):
Boolean licensedEdition = true;
Processor processor = new Processor(licensedEdition);
SchemaManager sm = processor.getSchemaManager();
//Load the xsd serialized as a string
sm.load(new StreamSource(new StringReader(xsd.toString())));
SchemaValidator sv = sm.newSchemaValidator();
XdmDestination xdmDest = new XdmDestination();
sv.setDestination(xdmDest);
//Load the instance serialized as a string
sv.validate(new StreamSource(new StringReader(xml.toString())));
String xpathExpr = "//test:comparable[1]/test:int eq //test:comparable[2]/test:int";
XPathCompiler comp = processor.newXPathCompiler();
comp.declareNamespace("test", "http://www.xpathtest.com/test");
XPathExecutable xpathExec = comp.compile(xpathExpr);
XPathSelector selector = xpathExec.load();
selector.setContextItem(xdmDest.getXdmNode());
Boolean result = selector.effectiveBooleanValue();
Updated by Michael Kay over 9 years ago
- Category set to Schema-Aware processing
- Assignee set to Michael Kay
OK, thanks, problem now reproduced. (I was previously running it from the XQuery command line and the XQuery API).
A note on this strange error message: at the deepest levels, a value comparison is evaluated by comparing two Java Comparables. The Comparable.compare() operation has no checked exceptions, and in general what you get back if you try to compare non-comparable objects is a ClassCastException. Saxon catches the ClassCastException several levels up, and produces this rather surreal message; the ClassCastException was probably from a completely different cause.
Updated by Michael Kay over 9 years ago
OK, the problem is that the XPathCompiler has not been declared schema-aware - you need to call compiler.setSchemaAware(true).
The expression has been compiled in non-schema-aware mode, which means that the code that's generated assumes that the operands to the value comparison will be strings; it tries to cast them to strings, gets a ClassCastException, and this results in the strange message.
There's a good reason why the default is NOT schema aware, which is that in the common case where documents are untyped, you can generate faster code if you know in advance that they will be untyped; generating schema-aware code for a case where it's not needed would incur unnecessary costs. (Conversely, of course, if the document is going to be schema-validated then it's useful to know that, as well).
Of course, what's wrong here is the diagnostics. If you've compiled the code without schema-awareness enabled, then Saxon ought to complain very clearly when you supply a schema-validated input document. I'll now look at what I can do to fix that.
The problem is specific to the XPath API; at this level, XSLT and XQuery behave differently.
Updated by Michael Kay over 9 years ago
- Assignee changed from Michael Kay to O'Neil Delpratt
- Found in version changed from 9.6.0-4 to 9.6
I have committed a patch on the 9.6 and 9.7 branches (with an incorrect commit message, sorry!). It changes XPathSelector.setContextItem() to make a check and report an error if the supplied context item is a node in a typed (schema-validated) document and the XPathCompiler used to compile the expression was not schema-aware.
Added JUnit test cases TestXPathCompiler/trySchemaAwareEquality.
Leaving the bug open and assigning to O'Neil to produce an equivalent patch on the .NET path.
Updated by Nick Evans over 9 years ago
Thanks very much for your quick analysis and solution! Making the XPathCompiler schema aware indeed solves the problem. And the improved error message will certainly help diagnosing this problem in the future.
Updated by O'Neil Delpratt over 9 years ago
- Status changed from In Progress to Resolved
- % Done changed from 0 to 100
Patch made to the .NET API
Updated by O'Neil Delpratt over 9 years ago
- Status changed from Resolved to Closed
- Fixed in version set to 9.6.0.7
Bug fix applied in the Saxon 9.6.0.7 maintenance release.
Updated by O'Neil Delpratt almost 9 years ago
- Applies to branch 9.6 added
- Fix Committed on Branch 9.6 added
- Fixed in Maintenance Release 9.6.0.7 added
Please register to edit this issue