Project

Profile

Help

Bug #4357

closed

XSLT using accumulator passes streamability analysis but crashed with java.lang.UnsupportedOperationException: net.sf.saxon.trans.XPathException: Navigation using preceding-sibling axis is not supported from a streamed input node

Added by Martin Honnen over 4 years ago. Updated over 4 years ago.

Status:
Closed
Priority:
Normal
Assignee:
-
Category:
Streaming
Sprint/Milestone:
-
Start date:
2019-10-22
Due date:
% Done:

0%

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

Description

I tried to solve a problem from the XSL list using streaming and an accumulator but both Saxon 9.9 EE and Saxon 9.8 EE crash running it.

The code:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    version="3.0">
    
    <xsl:mode on-no-match="shallow-copy" streamable="yes" use-accumulators="rev-change"/>
    
    <xsl:accumulator name="rev-change" as="xs:boolean" initial-value="false()" streamable="yes">
        <xsl:accumulator-rule match="topic" select="false()"/>
        <xsl:accumulator-rule match="topic/revst" select="true()"/>
        <xsl:accumulator-rule match="topic/revend" select="false()"/>
    </xsl:accumulator>
    
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>
  
    <xsl:template match="topic/*[accumulator-before('rev-change')]">
        <xsl:copy>
            <xsl:attribute name="rev">changed</xsl:attribute>
            <xsl:apply-templates select="@*"/>
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="revst | revend" priority="2"/>
    
</xsl:stylesheet>

Example input:

<root>

    <topic id="idm140322603719792">

        <chgdesc revnbr="42">Content</chgdesc>

        <title line-break="0">Content</title>

        <revst/>

        <para>Content</para>

        <revend/>

        <para>Content</para>

        <revst/>

        <note>

            <para>Content</para>

        </note>

        <revend/>

        <para>Content</para>

        <revst/>

        <para>Content</para>

        <para>Content</para>

        <revend/>

    </topic>

</root>

Stack trace of Saxon 9.9.1.5 EE Java:

java.lang.UnsupportedOperationException: net.sf.saxon.trans.XPathException: Navigation using preceding-sibling axis is not supported from a streamed input node
        at com.saxonica.ee.stream.om.FleetingNode.iterateAxis(FleetingNode.java:512)
        at com.saxonica.ee.stream.om.FleetingElementNode.iterateAxis(FleetingElementNode.java:98)
        at net.sf.saxon.tree.util.Navigator.getSiblingPosition(Navigator.java:1136)
        at net.sf.saxon.pattern.GeneralPositionalPattern.getActualPosition(GeneralPositionalPattern.java:273)
        at net.sf.saxon.pattern.GeneralPositionalPattern.internalMatches(GeneralPositionalPattern.java:242)
        at net.sf.saxon.pattern.GeneralPositionalPattern.matchesBeneathAnchor(GeneralPositionalPattern.java:222)
        at net.sf.saxon.pattern.AncestorQualifiedPattern.matchesBeneathAnchor(AncestorQualifiedPattern.java:211)
        at net.sf.saxon.pattern.AncestorQualifiedPattern.matches(AncestorQualifiedPattern.java:193)
        at net.sf.saxon.trans.rules.Rule.matches(Rule.java:255)
        at com.saxonica.ee.trans.ModeEE.ruleMatches(ModeEE.java:133)
        at net.sf.saxon.trans.SimpleMode.searchRuleChain(SimpleMode.java:661)
        at net.sf.saxon.trans.SimpleMode.getRule(SimpleMode.java:547)
        at com.saxonica.ee.stream.watch.ApplyTemplatesAction.getRule(ApplyTemplatesAction.java:260)
        at com.saxonica.ee.stream.watch.ApplyTemplatesAction.startSelectedParentNode(ApplyTemplatesAction.java:144)
        at com.saxonica.ee.stream.watch.Trigger.startSelectedParentNode(Trigger.java:85)
        at com.saxonica.ee.stream.watch.WatchManager.startElement(WatchManager.java:274)
        at net.sf.saxon.event.StartTagBuffer.startContent(StartTagBuffer.java:246)
        at com.saxonica.ee.stream.ContentDetector.flush(ContentDetector.java:97)
        at com.saxonica.ee.stream.ContentDetector.startElement(ContentDetector.java:33)
        at net.sf.saxon.event.Stripper.startElement(Stripper.java:115)
        at net.sf.saxon.event.ReceivingContentHandler.startElement(ReceivingContentHandler.java:367)
        at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.startElement(Unknown Source)
        at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.scanStartElement(Unknown Source)
        at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(Unknown Source)
        at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(Unknown Source)
        at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(Unknown Source)
        at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
        at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
        at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
        at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(Unknown Source)
        at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(Unknown Source)
        at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)
        at net.sf.saxon.event.Sender.sendSAXSource(Sender.java:435)
        at net.sf.saxon.event.Sender.send(Sender.java:167)
        at net.sf.saxon.trans.XsltController.applyStreamingTemplates(XsltController.java:1050)
        at net.sf.saxon.s9api.AbstractXsltTransformer.applyTemplatesToSource(AbstractXsltTransformer.java:339)
        at net.sf.saxon.s9api.Xslt30Transformer.applyTemplates(Xslt30Transformer.java:311)
        at net.sf.saxon.Transform.processFile(Transform.java:1283)
        at net.sf.saxon.Transform.doTransform(Transform.java:815)
        at net.sf.saxon.Transform.main(Transform.java:80)
Caused by: net.sf.saxon.trans.XPathException: Navigation using preceding-sibling axis is not supported from a streamed input node
        at com.saxonica.ee.stream.om.FleetingNode.iterateAxis(FleetingNode.java:509)
        ... 39 more
Fatal error during transformation: java.lang.UnsupportedOperationException: net.sf.saxon.trans.XPathException: Navigation using preceding-sibling axis is not supported from a streamed input node

The code works fine with Saxon 9.9.1.5 HE, i.e. not using streaming.


Related issues

Has duplicate Saxon - Bug #4362: positional predicate not recognized by streamability analysis: execution fails with java.lang.UnsupportedOperationException: net.sf.saxon.trans.XPathException: Navigation using preceding-sibling axis is not supported from a streamed input nodeDuplicateMichael Kay2019-10-26

Actions
Actions #1

Updated by Michael Kay over 4 years ago

Reproduced as accumulator-078s in the XSLT3 test suite.

It's a rather interesting one. In the general case, the accumulator name passed to accumulator-before() isn't known statically, therefore the type of the result of accumulator-before() isn't known statically, therefore we have to allow for the possibility that it is numeric. If $yyy is numeric then the match pattern match="xxx[$yyy]" is not streamable, because it depends on knowing the sibling position of the node. So I think we should have reported this as non-streamable, but I will check the spec.

If you wrap the call on accumulator-before() in a call of boolean() then it works fine.

Actions #2

Updated by Michael Kay over 4 years ago

Firstly, I think GeneralPositionalPattern.isMotionless() should simply return false. It is currently testing the streamability of the predicate without regards to its type; but we only create a GeneralPositionalPattern if there is a possibility it will be numeric or positional.

Secondly, in GeneralPositionalPattern.matches(), we are computing the sibling position of a node in a case where the position is not actually needed. This is an unnecessary cost. There is some logic to try and avoid this (the flag "usesPosition" can be set to false, but that is not the case in this example).

Thirdly, we could be smarter about evaluating the static type of accumulator-before() and accumulator-after() in the case where the function argument is known statically. That would enable us to avoid using a GeneralPositionalPattern, and hence to make this streamable (the spec, in my view, allows more precise type inferencing than the rules in the spec, so long as it's consistent with the spec).

Actions #3

Updated by Michael Kay over 4 years ago

  • Status changed from New to Resolved
  • Applies to branch trunk added
  • Fix Committed on Branch 9.9, trunk added

Fixed (1) and (3) in 9.9 and trunk.

Not fixing (2) for now because it seems a bit complicated, and not strictly necessary.

Added a second test case -079s which forces the test to be streamable by casting the predicate to boolean; the test case -078s gives alternative results because it depends how smart the type inferencing is.

Actions #4

Updated by Michael Kay over 4 years ago

  • Has duplicate Bug #4362: positional predicate not recognized by streamability analysis: execution fails with java.lang.UnsupportedOperationException: net.sf.saxon.trans.XPathException: Navigation using preceding-sibling axis is not supported from a streamed input node added
Actions #5

Updated by O'Neil Delpratt over 4 years ago

  • Status changed from Resolved to Closed
  • Fixed in Maintenance Release 9.9.1.6 added

Patch committed to the Saxon 9.9.1.6 maintenance release.

Please register to edit this issue

Also available in: Atom PDF