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 29434 - [XSLT30] xsl:on-empty/on-non-empty with attributes and use-attribute-sets
Summary: [XSLT30] xsl:on-empty/on-non-empty with attributes and use-attribute-sets
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-02-08 17:19 UTC by Abel Braaksma
Modified: 2016-10-06 18:42 UTC (History)
0 users

See Also:


Attachments

Description Abel Braaksma 2016-02-08 17:19:47 UTC
I think the text on xsl:on-empty (section 8.4.2), and by extension xsl:on-non-empty is not entirely unambiguous with respect to attributes:

  <empty xsl:use-attribute-sets="a">
    <xsl:on-empty select="42"/> 
  </empty>

vs

  <empty x="y">
    <xsl:on-empty select="42"/> 
  </empty>

vs

  <empty>
    <xsl:attribute name="x">y</xsl:attribute>
    <xsl:on-empty select="42"/> 
  </empty>

The way I read the spec is that the first two examples will activate the xsl:on-empty instruction, and the last example will not. This may be surprising and perhaps we should mention that.

Esp. wrt to use-attribute-sets, one could argue that it becomes part of creating the sequence constructor content, in which case it should *not* activate xsl:on-empty.
Comment 1 Michael Kay 2016-02-09 09:16:28 UTC
Good point, I think this is a bug.

I think the simplest fix is to change the sentence:

An xsl:on-empty instruction is evaluated only if every preceding sibling instruction, text node, and literal result element in the same sequence constructor returns either an empty sequence, or a sequence consisting entirely of zero-length text nodes and/or document nodes with no children.

to read:

An xsl:on-empty instruction is evaluated only if every preceding sibling instruction, text node, and literal result element in the same sequence constructor returns either an empty sequence, or a sequence consisting entirely of:

* attribute nodes
* namespace nodes
* zero-length text nodes 
* document nodes with no children
Comment 2 Abel Braaksma 2016-02-09 19:21:11 UTC
That is a change, I'm not sure we intended emptiness to mean a sequence of attributes. Since this instruction may be used in contexts where we are not constructing an element, I'm not sure that is desirable (though I can see benefits and downsides).

More importantly, I realize that we may not be defining this clearly enough in terms of "Constructing complex/simple content". I think it makes sense that xsl:on-empty kicks in *after* constructing the content leaves us with emptiness. If we do, the next ambiguity, about a document node with empty text node children becomes a no-brainer, as they are normalized away.

As such, I propose something along those lines instead:

When a sequence constructor contains an xsl:on-empty instruction, it is first removed (as if by use-when="false()") and the resulting sequence constructor is evaluated following the rules in [#REF: 5.7 Sequence Constructor]. If the result is a zero-length text node (or a sequence of zero-length strings, but the rules in 5.7 prevent that from happening), the sequence constructor result is discarded and replaced by the result of evaluating the sequence constructor or select attribute of the xsl:on-empty instruction.

-----
That, of course, does not answer the question whether attribute nodes created by the sequence constructor should be considered.

Example: a sequence ctor that adds lat/long as attributes

<xsl:template match="coor[lat|long]">
   <xsl:attribute name="lat" select="lat" />
   <xsl:attribute name="long" select="long" />
   <xsl:on-empty>
      <xsl:attribute name="lat" select="'#absent'" />
      <xsl:attribute name="long" select="'#absent'" />
   </xsl:on-empty>
</xsl:template>

If we change xsl:on-empty the way you suggest, the above would never trigger the xsl:on-empty. Is that really how we want it to behave? Shouldn't that be in the realm of xsl:where-populated?
Comment 3 Abel Braaksma 2016-02-09 19:21:47 UTC
> the above would never trigger the xsl:on-empty.
meant to say: would ALWAYS trigger xsl:on-empty. I think that is the surprise we should probably try to prevent.
Comment 4 Michael Kay 2016-02-09 20:29:38 UTC
Firstly, I think that attributes should be treated the same way whether created by explicit instructions within the sequence constructor (e.g. xsl:attribute, xsl:copy-of, xsl:apply-templates) or by LRE attributes or use-attribute-sets on the containing instruction. I think this can be achieved by extending the scope of "every preceding sibling instruction, text node, and literal result element in the same sequence constructor" to include also any attributes on a containing LRE and any [xsl:]use-attribute-sets instruction on the containing element.

Now, should we treat elements with attributes as empty, or not? I think that for common HTML use cases it makes sense to ignore attributes when assessing emptiness: consider

<div>
  <where-populated>
    <ul><xsl:for-each select="order">...</xsl:for-each></ul>
  </where-populated>
  <xsl:on-empty>There were no orders this month</xsl:on-empty>
</div>

I don't think this should stop working if a class attribute is added to the containing div, regardless of how it is added.

The point here is that *in HTML* attributes are conventionally used as metadata and if there is no (real) content then the attributes can safely be forgotten.

Namespaces should definitely be ignored when considering emptiness.

My proposal in comment 1 achieves this.

One could argue that the status quo gives users a choice whether to treat attributes as significant or not. But I think that making it depend on how the attribute is created would lead to too many surprises. Another complication is the rule about duplicate attributes, e.g.

<table class="x">
  <xsl:attribute name="class">y</xsl:attribute>
Comment 5 Michael Kay 2016-02-15 14:41:02 UTC
We reviewed this and decided there was no need to change the current rules, but it would be useful to have more examples and explanation as to how xsl:on-empty and xsl:on-non-empty interact with xsl:attribute (and other instructions that generate attributes or namespaces); we should also mention the workaround of using xsl:sequence to specify the scope more precisely, e.g.

<table>
  <xsl:attribute..../>
  <xsl:sequence>
    ...
    <xsl:on-empty.../>
  </xsl:sequence>
</table>

Could also add a Note that zero-length strings don't satisfy this definition of emptiness.
Comment 6 Michael Kay 2016-02-18 20:46:23 UTC
Note that the decisions on this bug were overridden by the subsequent decisions on 
bug #29455