- From: <bugzilla@jessica.w3.org>
- Date: Tue, 07 Feb 2017 11:52:48 +0000
- To: public-qt-comments@w3.org
https://www.w3.org/Bugs/Public/show_bug.cgi?id=30060
Bug ID: 30060
Summary: [XSLT30]xsl:iterate example "Collecting Multiple
Values in a Single Pass" not working
Product: XPath / XQuery / XSLT
Version: Member-only Editors Drafts
Hardware: PC
OS: Windows NT
Status: NEW
Severity: editorial
Priority: P2
Component: XSLT 3.0
Assignee: mike@saxonica.com
Reporter: martin.honnen@gmx.de
QA Contact: public-qt-comments@w3.org
Target Milestone: ---
Today I tried to run the example "Collecting Multiple Values in a Single Pass"
in https://www.w3.org/XML/Group/qtspecs/specifications/xslt-30/html/#iterate,
it has the source code
<xsl:source-document streamable="yes" href="employees.xml">
<xsl:iterate select="employees/employee">
<xsl:param name="highest" as="element(employee)*"/>
<xsl:param name="lowest" as="element(employee)*"/>
<xsl:on-completion>
<highest-paid-employees>
<xsl:value-of select="$highest/name"/>
</highest-paid-employees>
<lowest-paid-employees>
<xsl:value-of select="$lowest/name"/>
</lowest-paid-employees>
</xsl:on-completion>
<xsl:variable name="is-new-highest" as="xs:boolean"
select="empty($highest[@salary ge current()/@salary])"/>
<xsl:variable name="is-equal-highest" as="xs:boolean"
select="exists($highest[@salary eq current()/@salary])"/>
<xsl:variable name="is-new-lowest" as="xs:boolean"
select="empty($lowest[@salary le current()/@salary])"/>
<xsl:variable name="is-equal-lowest" as="xs:boolean"
select="exists($lowest[@salary eq current()/@salary])"/>
<xsl:variable name="new-highest-set" as="element(employee)*"
select="if ($is-new-highest) then .
else if ($is-equal-highest) then ($highest, .)
else $highest"/>
<xsl:variable name="new-lowest-set" as="element(employee)*"
select="if ($is-new-lowest) then .
else if ($is-equal-lowest) then ($lowest, .)
else $lowest"/>
<xsl:next-iteration>
<xsl:with-param name="highest" select="$new-highest-set"/>
<xsl:with-param name="lowest" select="$new-lowest-set"/>
</xsl:next-iteration>
</xsl:iterate>
</xsl:source-document>
Reading it I wondered whether it is possible to pass on streamed nodes on as
parameters and furthermore whether it would be possible to use "." at several
places in the body of the xsl:iterate.
So I constructed a sample input document
<employees>
<employee salary="3000">
<name>Employee a</name>
</employee>
<employee salary="1000">
<name>Employee b</name>
</employee>
<employee salary="3000">
<name>Employee c</name>
</employee>
<employee salary="2000">
<name>Employee d</name>
</employee>
</employees>
and a complete stylesheet with
<?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"
xmlns:math="http://www.w3.org/2005/xpath-functions/math"
exclude-result-prefixes="xs math"
version="3.0">
<xsl:template name="main">
<xsl:source-document streamable="yes"
href="test2017020702.xml">
<xsl:iterate select="employees/employee">
<xsl:param name="highest"
as="element(employee)*"/>
<xsl:param name="lowest"
as="element(employee)*"/>
<xsl:on-completion>
<highest-paid-employees>
<xsl:value-of
select="$highest/name"/>
</highest-paid-employees>
<lowest-paid-employees>
<xsl:value-of
select="$lowest/name"/>
</lowest-paid-employees>
</xsl:on-completion>
<xsl:variable name="is-new-highest"
as="xs:boolean"
select="empty($highest[@salary ge
current()/@salary])"/>
<xsl:variable name="is-equal-highest"
as="xs:boolean"
select="exists($highest[@salary eq
current()/@salary])"/>
<xsl:variable name="is-new-lowest"
as="xs:boolean"
select="empty($lowest[@salary le
current()/@salary])"/>
<xsl:variable name="is-equal-lowest"
as="xs:boolean"
select="exists($lowest[@salary eq
current()/@salary])"/>
<xsl:variable name="new-highest-set"
as="element(employee)*"
select="
if ($is-new-highest) then
.
else
if ($is-equal-highest)
then
($highest, .)
else
$highest"/>
<xsl:variable name="new-lowest-set"
as="element(employee)*"
select="
if ($is-new-lowest) then
.
else
if ($is-equal-lowest)
then
($lowest, .)
else
$lowest"/>
<xsl:next-iteration>
<xsl:with-param name="highest"
select="$new-highest-set"/>
<xsl:with-param name="lowest"
select="$new-lowest-set"/>
</xsl:next-iteration>
</xsl:iterate>
</xsl:source-document>
</xsl:template>
</xsl:stylesheet>
however when I try to run that with Saxon-EE 9.7.0.14J it refuses to run it,
telling me
Static error on line 8 column 67 of test2017020702.xsl:
XTSE3430: The body of the xsl:stream instruction is not streamable
* Operand if($is-new-highest) then ... else ... of let $new-highest-set :=
... selects
streamed nodes in a context that allows arbitrary navigation (line 36)
I looked into the test cases of the test suite whether it has some input/xslt
sample similar to that spec example but I couldn't find anything.
So I tried fixing the example based on what I have learned in the past trying
to get code working as streamable with Saxon 9.7 and I had to make sure I
construct a copy-of() first of the context node in a variable and use that copy
then in all occasions:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:math="http://www.w3.org/2005/xpath-functions/math"
exclude-result-prefixes="xs math"
version="3.0">
<xsl:output indent="yes"/>
<xsl:template name="main">
<xsl:source-document streamable="yes"
href="test2017020702.xml">
<xsl:iterate select="employees/employee">
<xsl:param name="highest"
as="element(employee)*"/>
<xsl:param name="lowest"
as="element(employee)*"/>
<xsl:on-completion>
<highest-paid-employees>
<xsl:value-of
select="$highest/name" separator=","/>
</highest-paid-employees>
<lowest-paid-employees>
<xsl:value-of
select="$lowest/name" separator=","/>
</lowest-paid-employees>
</xsl:on-completion>
<xsl:variable name="copy" select="copy-of()"/>
<xsl:variable name="is-new-highest"
as="xs:boolean"
select="empty($highest[@salary ge
$copy/@salary])"/>
<xsl:variable name="is-equal-highest"
as="xs:boolean"
select="exists($highest[@salary eq
$copy/@salary])"/>
<xsl:variable name="is-new-lowest"
as="xs:boolean"
select="empty($lowest[@salary le
$copy/@salary])"/>
<xsl:variable name="is-equal-lowest"
as="xs:boolean"
select="exists($lowest[@salary eq
$copy/@salary])"/>
<xsl:variable name="new-highest-set"
as="element(employee)*"
select="
if ($is-new-highest) then
$copy
else
if ($is-equal-highest) then
($highest, $copy)
else
$highest"/>
<xsl:variable name="new-lowest-set"
as="element(employee)*"
select="
if ($is-new-lowest) then
$copy
else
if ($is-equal-lowest) then
($lowest, $copy)
else
$lowest"/>
<xsl:next-iteration>
<xsl:with-param name="highest"
select="$new-highest-set"/>
<xsl:with-param name="lowest"
select="$new-lowest-set"/>
</xsl:next-iteration>
</xsl:iterate>
</xsl:source-document>
</xsl:template>
</xsl:stylesheet>
I am not sure that rewrite is the intended implementation of that example but I
think the example in the spec should be fixed to work with an implementation
like Saxon.
--
You are receiving this mail because:
You are the QA Contact for the bug.
Received on Tuesday, 7 February 2017 11:52:57 UTC