Reputation: 2807
Every now and then I want to match missing elements, i.e. an empty sequence/nodeset
(this is completely untested/run...its just for illustation and could be any XSLT version)
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<xsl:apply-templates select="stuff/SomeStuff"/>
<xsl:if test="count(stuff/SomeStuff) = 0">
<xsl:call-template name="noStuff"/>
</xsl:if>
</xsl:template>
<xsl:template name="noStuff">
<bar/>>
</xsl:template>
<xsl:template match="SomeStuff">
<foo/>
</xsl:template>
</xsl:stylesheet>
bit clumsy, be quite nice to go something like
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<xsl:apply-templates select="stuff/SomeStuff"/>
</xsl:template>
<xsl:template match="Empty(SomeStuff)">
<bar/>>
</xsl:template>
<xsl:template match="SomeStuff">
<foo/>
</xsl:template>
</xsl:stylesheet>
is this lurking somewhere i can't find? I think an empty sequence is 'special' enough to have something. In a functional language the sequence would exist as a datatype you could match directly on, so it feels missing to me, a bit like matching Some/None on an Option/Maybe.
Upvotes: 0
Views: 69
Reputation: 163625
XSLT 3.0 has an instruction xsl:on-empty allowing
<xsl:template match="/">
<xsl:apply-templates select="stuff/SomeStuff"/>
<xsl:on-empty>
<xsl:call-template name="noStuff"/>
</xsl:on-empty>
</xsl:template>
The semantics aren't quite the same: this is testing that the output of the apply-templates is empty, not that its input is empty.
The drafts for XSLT 4.0 have an otherwise
operator, allowing
<xsl:variable name="noStuff" as="element()">
<noStuff/>
</xsl:variable>
...
<xsl:apply-templates select="stuff/SomeStuff otherwise $noStuff"/>
...
<xsl:template match="noStuff">
...
</xsl:template>
Upvotes: 1
Reputation: 2807
So based on sebastiens comment
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<xsl:apply-templates select="stuff"/>
</xsl:template>
<xsl:template match="stuff[not(SomeStuff)]" priority="1">
<bar/>>
</xsl:template>
<xsl:template match="stuff">
<xsl:apply-templates select="SomeStuff"/>
</xsl:template>
<xsl:template match="SomeStuff">
<foo/>
</xsl:template>
</xsl:stylesheet>
which to be fair, matches how you would do it in a FPL.
having actually written the code in a proper context, its actually quite verbose in anything but a trivial context, because you have to pass all the parameters through - in most FPs these would be 'captured' as the match would be inside the calling code.
It IS the sensible answer, just not as cost free as hoped.
Upvotes: 0
Reputation: 2714
You could use something like : stuff[not(SomeStuff)]
Example :
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<xsl:apply-templates select="stuff"/>
</xsl:template>
<xsl:template match="stuff[not(SomeStuff)]">
<bar/>>
</xsl:template>
<xsl:template match="stuff">
<xsl:apply-templates select="SomeStuff"/>
</xsl:template>
<xsl:template match="SomeStuff">
<foo/>
</xsl:template>
</xsl:stylesheet>
Upvotes: 0