Project

Profile

Help

Bug #5721

closed

Saxon EE 10.8J optimizations break order of XPath selectors

Added by Andy Yar about 1 month ago. Updated about 24 hours ago.

Status:
Resolved
Priority:
Normal
Assignee:
Category:
Internals
Sprint/Milestone:
-
Start date:
2022-10-26
Due date:
% Done:

0%

Estimated time:
Legacy ID:
Applies to branch:
10, 11, trunk
Fix Committed on Branch:
11, trunk
Fixed in Maintenance Release:
Platforms:
.NET, Java

Description

Following XSLT fails on Saxon EE 10.8J using the default optimization level (-opt:10). Turning the optimization off via -opt:0 returns correct results.

It seems, in this case the optimization does not keep the order of the XPath "selectors".

Error:

  FORG0001  Cannot convert string "" to double
     invoked by built-in template rule (text-only)
Cannot convert string "" to double

Test XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns="http://www.w3.org/2005/xpath-functions" exclude-result-prefixes="#all" version="3.0" xmlns:saxon="http://saxon.sf.net/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:f="http://aimtec.cz/EDI" xmlns:aim="http://aimtec.cz/INT/mappingDescription">
    <xsl:output encoding="UTF-8" indent="no" method="xml"/>

    <xsl:template match="root">
        <test>
            <!-- Filter in order: name - content - numeric value -->
            <xsl:for-each select="test/*[contains(name(), 'LieferscheinNummer')][. != ''][. != 0]">
                <number>
                    <xsl:value-of select="."/>
                </number>
            </xsl:for-each>
        </test>
    </xsl:template>
</xsl:stylesheet>

Test input:

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <test>
        <LieferscheinNummer_1>1</LieferscheinNummer_1>
        <LieferscheinNummer_2>0</LieferscheinNummer_2>
    </test>
    <test>
        <LieferscheinNummer_1>2</LieferscheinNummer_1>
        <LieferscheinNummer_2/>
    </test>
</root>

Expected output:

<?xml version="1.0" encoding="UTF-8"?>
<test xmlns="http://www.w3.org/2005/xpath-functions">
    <number>1</number>
    <number>2</number>
</test>
Actions #1

Updated by Michael Kay about 1 month ago

Reordering of predicates is allowed by the XPath specification.

Whether it should be allowed is another matter - see https://github.com/qt4cg/qtspecs/issues/71

But at the moment, the spec allows it and Saxon takes advantage of the fact for optimisation. The only way to guarantee order of evaluation of conditionals is to use an if-then-else construct.

Actions #2

Updated by Michael Kay about 1 month ago

  • Status changed from New to In Progress
  • Assignee set to Michael Kay
  • Applies to branch 11, trunk added
  • Fix Committed on Branch 11, trunk added
  • Platforms .NET added

As a quick fix, I'm adding an optimization flag so -opt:-p will suppress this optimization. This will be in 12.x and the next maintenance release of 11.x.

Leaving the issue open, because I think a better (but more difficult) fix would be to do the optimization in such a way that reordering of predicates does not cause spurious errors.

Actions #3

Updated by Andy Yar about 1 month ago

Thank you for the explanation.

Changing the behavior for XSLT/XPath 4.0 would be great.

Actions #4

Updated by Michael Kay about 1 month ago

  • Assignee deleted (Michael Kay)
  • Applies to branch deleted (11, trunk)
  • Fix Committed on Branch deleted (11, trunk)
  • Platforms deleted (.NET)
Actions #6

Updated by Michael Kay about 1 month ago

  • Category set to Internals
  • Assignee set to Michael Kay
  • Applies to branch 11, trunk added
  • Fix Committed on Branch 11, trunk added
  • Platforms .NET added
Actions #7

Updated by Michael Kay about 24 hours ago

  • Status changed from In Progress to Resolved
  • Priority changed from Low to Normal

On the 11.x branch I added a partial fix that allows the optimization to be suppressed.

For 12.x, predicates can stll be reordered, but this should not generate any spurious errors. A composite filter expression A[P1][P2][P3] is now rewritten as A[P1 and P2 and P3], and an "and" expression is evaluated so that if the first operand throws an error, we catch it and save it; if any operand is false, we return false and ignore the error, which means that re-ordering the operands no longer generates spurious errors.

So in the example given, test/*[contains(name(), 'LieferscheinNummer')][. != ''][. != 0] we might still evaluate the predicates in reverse order, but we will only throw an error if contains(name(), 'LieferscheinNummer')] is true.

Please register to edit this issue

Also available in: Atom PDF