This is an archived snapshot of W3C's public bugzilla bug tracker, decommissioned in April 2019. Please see the home page for more details.

Bug 28130 - [xslt 3.0] xsl:merge and accumulators
Summary: [xslt 3.0] xsl:merge and accumulators
Status: CLOSED FIXED
Alias: None
Product: XPath / XQuery / XSLT
Classification: Unclassified
Component: XSLT 3.0 (show other bugs)
Version: Last Call drafts
Hardware: PC All
: P2 normal
Target Milestone: ---
Assignee: Michael Kay
QA Contact: Mailing list for public feedback on specs from XSL and XML Query WGs
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2015-03-03 14:03 UTC by Michael Kay
Modified: 2015-04-24 20:31 UTC (History)
1 user (show)

See Also:


Attachments

Description Michael Kay 2015-03-03 14:03:17 UTC
We have added an attribute use-accumulators to xsl:merge-source to indicate which accumulators are available on the streamed input document.

However, because xsl:merge only makes nodes available by means of current-merge-group(), and current-merge-group() does not return the original streamed node, but rather a snapshot, accumulators are not useful during merging. An attempt to use accumulator-before() or accumulator-after() returns the accumulator value for the snapshotted node, not the value for the original streamed node.

We could try and fix this by preserving accumulator values across a snapshot but it would get pretty messy. It would mean that the accumulator is no longer a pure function of the node (within its tree), but also depends on how the node was created, which we would have to represent in the data model.
Comment 1 Abel Braaksma 2015-03-13 16:58:03 UTC
I think this touches on a potentially larger issue with surprising effects when using accumulators. Assume an accumulator that counts para elements (+1 on each para):

<xsl:template match="para">
   <xsl:value-of select="accumulator-before('para')" />
</xsl:template>

<xsl:template match="/">
    <xsl:apply-templates select="//para" />
    <xsl:apply-templates select="//para/copy-of(.)" />
</xsl:template>

The first apply-templates will give 1 2 3 4 etc, the second will result in 1 1 1 1 etc. This may not (necessarily) be what users would expect.

The same problem arises with xsl:copy, xsl:copy-of, fn:snapshot etc. But another reading of this outcome could be: learn to understand semantics of copying, this is by design.

I think that the problem is related, or similar to, whether a copy action would copy inherited namespaces or not.

I can think of several ways forward:

1. Force inheritance of accumulator values (this may also force early evaluation of accumulators) when copying, as suggested above.

2. Make inheritance of accumulator values optional, similar to xsl:copy/@copy-namespaces (an option that is, btw, absent in fn:copy-of and fn:snapshot), defaulting to NO, except for xsl:merge's implicit snapshot, where it defaults to YES.

3. Special-case the xsl:merge situation. Since it is an *implicit* fn:snapshot, we can define the implicit snapshot to retain the accumulator values. After all, in streaming, early evaluation of accumulators is always required anyway. This result would then be grounded as it is now, but will have the accumulator values as if it was not grounded. Whether this is easy to define spec-wise, I do not know.

4. As any of the previous options, but only available with streaming. This makes sense, because early evaluation is not possible in that case, a processor *must* evaluate all required accumulators, so there would not be a performance hit. The big drawback in this scenario is that the outcome of a streaming and non-streaming version of the stylesheet would be different.

5. Live with it: in that case, accumulators make no sense with xsl:merge, which means we would drop an important use-case, as it is far from trivial to maintain state between node visits in another way while merging.

Maybe there is a more elegant solution than any of the above. If not, my preferences are with option 2, 1, 3, in that order.
Comment 2 Michael Kay 2015-04-17 09:14:08 UTC
A suggested way forward is outlined in

https://lists.w3.org/Archives/Member/w3c-xsl-wg/2015Apr/0037.html

(member-only)

After writing this I realise it has strong similarities with Abel's proposal in comment #1. The proposal is essentially that accumulator values are always copied/inherited when a copy is made using fn:snapshot(), and never under any other circumstances.
Comment 3 Michael Kay 2015-04-24 20:30:58 UTC
The proposed changes were accepted and have been applied to the spec.