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 29604 - [XSLT30] Request for clarification of statement in section https://www.w3.org/TR/xslt-30/#stream-examples
Summary: [XSLT30] Request for clarification of statement in section https://www.w3.org...
Status: CLOSED FIXED
Alias: None
Product: XPath / XQuery / XSLT
Classification: Unclassified
Component: XSLT 3.0 (show other bugs)
Version: Candidate Recommendation
Hardware: PC Windows NT
: 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: 2016-04-30 10:20 UTC by Martin Honnen
Modified: 2016-06-02 19:31 UTC (History)
0 users

See Also:


Attachments

Description Martin Honnen 2016-04-30 10:20:23 UTC
The section https://www.w3.org/TR/xslt-30/#stream-examples shows two uses of xsl:stream with the accumulator functions count and max and the examples work fine for me with Saxon 9.7. However that sections ends with the statement "To compute both the count and the maximum value in a single pass over the input, it is possible to use two variables.". I would like to see an example that does that as it appears the naive approach of 

	<xsl:template name="xsl:initial-template">
		<xsl:stream href="transactions.xml">
			<xsl:variable name="count" select="count(transactions/transaction)"/>
			<xsl:variable name="max" select="max(transactions/transaction/xs:decimal(@value))"/>
			<count>
				<xsl:value-of select="$count"/>
			</count>
			<maxValue>
				<xsl:value-of select="$max"/>
			</maxValue>
		</xsl:stream>
	</xsl:template>

does not work with Saxon, it complains 

Static error in xsl:stream/@href on line 10 column 41 of test201604300104.xsl:
  XTSE3430: The body of the xsl:stream instruction is not streamable
  *  There is more than one consuming operand: {count(...)} on line 11, and {let $max :=
  ...} on line 10

What I got to work is an example using a map

	<xsl:template name="xsl:initial-template">
		<xsl:stream href="transactions.xml">
			<xsl:variable name="map" as="map(xs:string, xs:decimal)"
				select="map{'count': count(transactions/transaction),
				            'max': max(transactions/transaction/xs:decimal(@value))}"/>
			<count>
				<xsl:value-of select="$map('count')"/>
			</count>
			<maxValue>
				<xsl:value-of select="$map('max')"/>
			</maxValue>
		</xsl:stream>
	</xsl:template>
	
but that is no a use of two variables. 

So I hope the comment "To compute both the count and the maximum value in a single pass over the input, it is possible to use two variables." could be accompanied by an example that shows how to do that.
Comment 1 Michael Kay 2016-05-12 10:15:57 UTC
I really have no idea what we were thinking of when we wrote the sentence:

"To compute both the count and the maximum value in a single pass over the input, it is possible to use two variables."

Perhaps the spec was different when we wrote that, and we failed to notice the effect of a change.

In fact the way I would recommend computing multiple aggregates is to use a map:

<xsl:template name="xsl:initial-template" expand-text="yes">
  <xsl:stream href="transactions.xml">
    <xsl:variable name="aggregates" 
      select="map{'count': count(transactions/transaction),
                  'maxValue': "max(transactions/transaction/xs:decimal(@value))}"/>
    <count>{$count}</count>
    <maxValue>{$max}</maxValue>
  </xsl:stream>
</xsl:template>

I haven't tested this under Saxon but it ought to work, and I think it would be a good idea to add the example to the spec.

(We decided to special-case map constructors so that multiple consuming operands are allowed: they therefore become a convenient way to capture multiple results during a single scan of the input. This can also be achieved using xsl:fork or using accumulators, but those mechanisms are much more complex.)
Comment 2 Michael Kay 2016-05-12 10:18:04 UTC
Whoops, I wish that Bugzilla allowed you to edit your submissions! Here's an improvement:

<xsl:template name="xsl:initial-template" expand-text="yes">
  <xsl:stream href="transactions.xml">
    <xsl:variable name="aggregates" 
      select="map{'count': count(transactions/transaction),
                  'maxValue': "max(transactions/transaction/xs:decimal(@value))}"/>
    <count>{$aggregates?count}</count>
    <maxValue>{$aggregates?maxValue}</maxValue>
  </xsl:stream>
</xsl:template>
Comment 3 Michael Kay 2016-05-26 16:21:04 UTC
The editor has an action to improve the examples to show how to solve this:

ACTION  2016-05-12-002: Michael Kay to work out a map, fork and accumulator examples as in comment 2 of bug 29604, to be added to the spec, and to remove XP31 specific syntax
Comment 4 Michael Kay 2016-05-27 09:50:40 UTC
I have removed the offending sentence, and have included an example along the lines of comment #2 showing how to solve the problem with maps. I also mention the possibility of using xsl:fork or xsl:accumulator to solve the problem; but I decided not to include fully-worked examples of these approaches because (a) it's not the best way of solveing the problem, and (b) it goes off at a tangent in terms of the concepts we are trying to introduce at this point in the spec.
Comment 5 Martin Honnen 2016-06-02 14:11:59 UTC
The example in https://www.w3.org/XML/Group/qtspecs/specifications/xslt-30/html/#stream-examples has a slight syntax error as the key name of the second map entry is written as 
  'max":
so the second quote is a mismatch, it should be
  'max':

Probably more a cosmetic problem but as it one day goes into an official recommendation it might be worth fixing it so that people reading it and new to both streaming and maps don't stumble over the syntax error.
Comment 6 Michael Kay 2016-06-02 19:31:38 UTC
Thanks, I have fixed the typo.

The WG reviewed and accepted the changes.