Testing for Empty, Blank, and Missing Values in XSLT
In XPath/XSLT there is no concept of null. You check whether nodes exist and whether their string value is empty or non-empty. The following patterns cover common cases when deciding whether to output a value or a fallback.
Basic boolean tests with xsl:if
- A node-set is true if at least one node exists.
- An element’s string value is the concatenation of its descendant text nodes.
Examples:
<!-- element exists -->
<xsl:if test="User/FirstName">First name element exists</xsl:if>
<!-- element does not exist -->
<xsl:if test="not(User/FirstName)">First name element missing</xsl:if>
<!-- element exists but string value is exactly empty -->
<xsl:if test="User/FirstName = ''">First name is an empty string</xsl:if>
<!-- element has a non-empty string value -->
<xsl:if test="User/FirstName != ''">First name has content</xsl:if>
<!-- treat whitespace-only as empty -->
<xsl:if test="normalize-space(User/FirstName) = ''">First name is blank or whitespace</xsl:if>
Choose/when fallback based on content
Use normalize-space to collapse whitespace and ensure you don’t treat spaces as content. Compute once and reuse:
<xsl:variable name="label" select="normalize-space(categoryName[1])"/>
<xsl:choose>
<xsl:when test="$label != ''">
<xsl:value-of select="$label"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="other"/>
</xsl:otherwise>
</xsl:choose>
If you prefer not to introduce a variable, inline the test:
<xsl:choose>
<xsl:when test="normalize-space(categoryName)">
<xsl:value-of select="categoryName[1]"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="other"/>
</xsl:otherwise>
</xsl:choose>
Using string() for coercion
string() converts a node-set to a string. If the node-set is empty, it yields ''. If the element exists but has no text, it also yeilds ''. This makes empty checks concise:
<xsl:choose>
<xsl:when test="not(string(categoryName))">
<xsl:value-of select="other"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="categoryName"/>
</xsl:otherwise>
</xsl:choose>
To ignore whitespace-only content:
<xsl:when test="not(normalize-space(string(categoryName)))">
<!-- fallback -->
</xsl:when>
Template-driven (declarative) solution for multiple/optional names
When an element may appear zero, one, or many times, perfer template matching to deeply nested conditionals.
Sample input:
<categories>
<category>
<categoryName>Books</categoryName>
</category>
<category>
<categoryName>Magazines</categoryName>
<categoryName>Periodicals</categoryName>
<categoryName>Journals</categoryName>
</category>
<category>
<categoryName><!-- please fill in category --></categoryName>
</category>
<category>
<categoryName/>
</category>
<category/>
</categories>
Stylesheet fragments:
<!-- categories with at least one non-blank categoryName -->
<xsl:template match="category[categoryName[normalize-space()]]">
<xsl:apply-templates select="categoryName[normalize-space()]"/>
</xsl:template>
<!-- all other categories (no name, empty, comments only, etc.) -->
<xsl:template match="category">
<xsl:text>Category: Other</xsl:text>
</xsl:template>
<!-- how to render each valid categoryName; handles multiples automatically -->
<xsl:template match="categoryName">
<xsl:text>Category: </xsl:text>
<xsl:value-of select="normalize-space()"/>
</xsl:template>
The predicate in the first template gives it higher priority than the generic cateogry template, so valid categories are handled separately from falllbacks.
XSLT 2.0+ conveniences
If you’re using XSLT 2.0 or newer, exists() and empty() make intent explicit:
<!-- at least one non-blank name exists -->
<xsl:when test="exists(categoryName[normalize-space()])">
<xsl:value-of select="categoryName[normalize-space()][1]"/>
</xsl:when>
<!-- no non-blank names -->
<xsl:when test="empty(categoryName[normalize-space()])">
<xsl:value-of select="other"/>
</xsl:when>
Coercion rule reminder
For a non-existent or empty element, string() returns the empty string, so the following is true in XPath 1.0:
string(/Node/ErrorCode) = ''
XML note
XML has no null value. xsi:nil="true" can signal a nilled element when XML Schema is in use, but in untyped XPath/XSLT you typically test for element existence and empty string content instead.