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 29887 - [XSLT30] Assertion on attributes of xsl:for-each-group is too strict, does not take shadow attribs into account
Summary: [XSLT30] Assertion on attributes of xsl:for-each-group is too strict, does no...
Status: RESOLVED 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-09-29 22:12 UTC by Abel Braaksma
Modified: 2016-10-13 21:38 UTC (History)
0 users

See Also:


Attachments

Description Abel Braaksma 2016-09-29 22:12:12 UTC
This bug is courtesy of Charles Foster, he noticed it in a Skype chat.

In de XSD we have:

count((@group-by, @group-adjacent, @group-starting-with, @group-ending-with)) = 1

But this doesn't work with shadow-attributes. I propose something like the following should work (not tested):

count((
(@group-by|@_group-by)[1], 
(@group-adjacent|@_group-adjacent)[1], 
(@group-starting-with|@_group-starting-with)[1],
(@group-ending-with|@_group-ending-with)[1]
)) = 1

Rationale: if both the shadow- and normal attribute exists, the shadow attribute takes precedence. This also accounts for situations where you would end up with @_group-by and @group-ending-with appearing, which is wrong, because the first will end up after de-shadowing as @group-by.
Comment 1 Michael Kay 2016-10-13 15:23:00 UTC
There are a few other cases of the same problem.

Line 180
<xs:assert test="not(exists(@select) and (exists(* except xsl:fallback) or exists(text()[normalize-space()])))"/>

exists(@select) ==> exists(@select|@_select)

Line 327, 690, 728, 1374
<xs:assert test="every $e in subsequence(xsl:sort, 2) satisfies empty($e/@stable)">

$e/@stable ==> $e/(@stable|@_stable)

Line 371, 503, 530, 552, 615
<xs:assert test="not(exists(@type) and exists(@validation))">

==> not(exists(@type|@_type) and exists(@validation|@_validation))

Line 737

count((@group-by, @group-adjacent, @group-starting-with, @group-ending-with)) = 1

==> count((@group-by|@_group-by, @group-adjacent|@_group-adjcent, @group-starting-with|@_group-starting-with, @group-ending-with|@_group-ending-with)) = 1

(could use the comma operator throughout but it feels more expressive this way)

Line 746

if (exists(@collation) or exists(@composite)) then (exists(@group-by) or exists(@group-adjacent)) else true()"

==> as elsewhere, replace @X by @X|@_X

Line 807, 814, 821, 890, 

Line 1085
test="not(exists(@name) and normalize-space(@visibility) = 'private' and exists(xsl:context-item))"

this one is more tricky because it's looking at attribute values. But the rule is obsolete because xsl:mode no longer has an xsl:context-item child. Slightly surprised Saxon's static type checking lets that through.

line 1182
<xs:assert test="every $prefix in (@stylesheet-prefix, @result-prefix)[. ne '#default']
            satisfies $prefix = in-scope-prefixes(.)"/>

we can keep this as is.

line 1186
test="if (exists(@value)) then empty((@select, @count, @from)) and @level='single' else true()">
            
Usual @X by @X|@_X except that @level='single' becomes (@level='single' or @_level)

line 1134
<xs:assert test="if (normalize-space(@static) = 'yes')
                           then empty((*,text()))
                           else true()">
Leave as is.

etc. etc. All the remaining assertions fit into one of the above patterns.
Comment 2 Michael Kay 2016-10-13 21:38:47 UTC
The schema has been updated and tested to fix these problems.