Home > database >  What is the difference between <xsl:on-non-empty> and <xsl:where-populated> in XSLT 3.0?
What is the difference between <xsl:on-non-empty> and <xsl:where-populated> in XSLT 3.0?

Time:09-26

They appear identical to me. Is there any difference between the two?

XML:

<?xml version="1.0" encoding="UTF-8"?>
<a>
   <b>1<c>Cat</c></b>
   <b>2<c>Cow</c></b>
   <b>3<c>Dog</c></b>
   <b></b>
   <b>4<c>Fish</c></b>
   <b e="9">a<f>s</f></b>   
</a>

XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" 
   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"        
   xmlns:xs="http://www.w3.org/2001/XMLSchema" 
   xmlns:fn="http://www.w3.org/2005/xpath-functions">
   <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
   <xsl:template match="a/b">
      <xsl:where-populated>
        <xsl:value-of select="c"/>
      </xsl:where-populated>
      <xsl:on-non-empty>
        <xsl:value-of select="c"/>
      </xsl:on-non-empty>
      <xsl:on-empty>EMPTY</xsl:on-empty>
   </xsl:template>
</xsl:stylesheet>

Output:

<?xml version="1.0" encoding="UTF-8"?>
   CatCat
   CowCow
   DogDog
   EMPTY
   FishFish
   EMPTY

Also, why is the last line considered "EMPTY"?

CodePudding user response:

Have you read the explanations and examples in the spec at

https://www.w3.org/TR/xslt-30/#where-populated
https://www.w3.org/TR/xslt-30/#element-on-non-empty

?

The purpose of where-populated is to make it easier to avoid generating something like a list or a glossary if it's going to be empty. The problem it solves is that the normal way of doing this:

<xsl:if test="exists(glossary-item)">
  <glossary>
     <xsl:for-each select="glossary-item">
        ...
     </xsl:for-each>
  </glossary>
</xsl:if>

isn't streamable, because it involves two passes over the glossary contents.

The on-non-empty instruction is subtly different: it allows you to output a heading (etc) so long as it's not the only thing present. So you can write

  <glossary>
     <xsl:on-non-empty>
       <h1>Here is the glossary</h1>
     </xsl:on-non-empty>
     <xsl:for-each select="glossary-item">
        ...
     </xsl:for-each>
  </glossary>

and the h1 will be omitted if no other content is generated. Again, it's provided because the usual way of writing this would involve two passes over the input.

CodePudding user response:

I don't think your sample captures the use case of these instructions, https://www.w3.org/TR/xslt-30/#where-populated-example is one where the three instructions are used together to construct content. I would say, generally the xsl:where-populated wraps a result element container like an ol or ul or a table that is only supposed to be present if there are input items that map to e.g. li/list items or tr/table rows.

The xsl:on-none-empty looks at any sibling content/sequence constructors, or as the text in the spec says: "The xsl:on-non-empty instruction is typically used to generate headers or footers appearing before or after a list of items, where the header or footer is to be omitted if there are no items in the list.".

Finally, xsl:on-empty looks at whether "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 vacuous items", and only outputs its content in that case.

  • Related