XSLT - XSLT <xsl:where-populated> for Conditional Result Construction
<xsl:where-populated> is an instruction introduced in XSLT 3.0 that helps control whether generated content should actually appear in the transformation result. Its main purpose is to evaluate a sequence constructor and include its result only when that result contains something meaningful. If the sequence constructor produces an empty sequence, the surrounding result element or content can be omitted.
This is particularly useful when generating XML documents where many elements are optional. Instead of creating empty elements such as <phone/>, <email/>, or <address/>, you can use <xsl:where-populated> to ensure that an element is created only when its corresponding data is available.
1. Why <xsl:where-populated> Is Needed
Consider an XML source containing customer information:
<customer>
<name>John</name>
<email>[email protected]</email>
<phone/>
<address/>
</customer>
Suppose the desired output should contain only information that is actually available.
Without conditional construction, a transformation might produce:
<customer>
<name>John</name>
<email>[email protected]</email>
<phone/>
<address/>
</customer>
The empty elements may not be desirable. You might instead want:
<customer>
<name>John</name>
<email>[email protected]</email>
</customer>
<xsl:where-populated> provides a convenient way to construct output only when the generated sequence contains content.
2. Basic Syntax
The general structure is:
<xsl:where-populated>
<!-- sequence constructor -->
</xsl:where-populated>
The instructions inside <xsl:where-populated> are evaluated first. If they produce a non-empty sequence, that sequence is included in the result. If they produce an empty sequence, nothing is added to the result.
For example:
<xsl:where-populated>
<xsl:value-of select="$email"/>
</xsl:where-populated>
If $email contains:
[email protected]
the result contains that value.
If $email is empty, the result is empty.
3. Conditional XML Element Creation
One of the most useful applications is conditional creation of XML elements.
Suppose the source XML is:
<employee>
<name>John</name>
<department>Sales</department>
<email>[email protected]</email>
<phone/>
</employee>
An XSLT stylesheet could use:
<xsl:template match="employee">
<employee>
<name>
<xsl:value-of select="name"/>
</name>
<xsl:where-populated>
<email>
<xsl:value-of select="email"/>
</email>
</xsl:where-populated>
<xsl:where-populated>
<phone>
<xsl:value-of select="phone"/>
</phone>
</xsl:where-populated>
</employee>
</xsl:template>
For the supplied data, the email element contains information, while the phone element does not.
The output can therefore contain:
<employee>
<name>John</name>
<email>[email protected]</email>
</employee>
The important point is that the test is based on whether the enclosed sequence constructor produces something.
4. How It Differs from <xsl:if>
At first glance, <xsl:where-populated> may appear similar to <xsl:if>, but they solve different problems.
With <xsl:if>, you explicitly test a condition:
<xsl:if test="email">
<email>
<xsl:value-of select="email"/>
</email>
</xsl:if>
Here, the stylesheet asks:
"Does the email node satisfy this condition?"
With <xsl:where-populated>, the approach is different:
<xsl:where-populated>
<email>
<xsl:value-of select="email"/>
</email>
</xsl:where-populated>
Here, the stylesheet effectively asks:
"Did this sequence constructor produce anything?"
This can make the stylesheet more convenient when the condition depends on the final generated content rather than on a simple Boolean test.
5. Working with Multiple Optional Values
Consider a product:
<product>
<name>Laptop</name>
<description>Business laptop</description>
<manufacturer/>
<warranty/>
</product>
You may want to generate a <details> element only if at least one optional piece of information exists.
For example:
<xsl:where-populated>
<details>
<xsl:if test="manufacturer">
<manufacturer>
<xsl:value-of select="manufacturer"/>
</manufacturer>
</xsl:if>
<xsl:if test="warranty">
<warranty>
<xsl:value-of select="warranty"/>
</warranty>
</xsl:if>
</details>
</xsl:where-populated>
If both manufacturer and warranty are empty, the content generated inside <xsl:where-populated> is empty, so the <details> element does not need to appear in the result.
If one of them contains data, the generated <details> element becomes populated and is retained.
This is especially useful when constructing hierarchical XML structures with many optional sections.
6. Using It with Calculated Values
The instruction is not limited to source elements. It can also be used with calculated values.
For example:
<xsl:where-populated>
<total>
<xsl:value-of select="sum(item/price)"/>
</total>
</xsl:where-populated>
The sequence constructor can calculate the value and create the corresponding output.
It can also be combined with conditions:
<xsl:where-populated>
<discount>
<xsl:if test="discount > 0">
<xsl:value-of select="discount"/>
</xsl:if>
</discount>
</xsl:where-populated>
If the condition does not produce content, the resulting structure can be omitted.
7. Nested Use
<xsl:where-populated> can also be used around more complicated output structures.
For example:
<xsl:where-populated>
<contact>
<xsl:if test="email">
<email>
<xsl:value-of select="email"/>
</email>
</xsl:if>
<xsl:if test="phone">
<phone>
<xsl:value-of select="phone"/>
</phone>
</xsl:if>
<xsl:if test="website">
<website>
<xsl:value-of select="website"/>
</website>
</xsl:if>
</contact>
</xsl:where-populated>
If all three values are absent, the generated contact structure can be suppressed.
If at least one value is available, the structure is retained with the available information.
This makes the instruction useful for optional groups of related data.
8. Difference Between Empty Strings and Empty Sequences
Understanding the distinction between an empty sequence and an empty string is important in XSLT.
An empty sequence is represented by:
()
An empty string is:
''
They are not identical.
For example:
<xsl:sequence select="()"/>
produces an empty sequence.
However:
<xsl:sequence select="''"/>
produces a zero-length string.
When using <xsl:where-populated>, you should understand what the enclosed instructions actually generate. The instruction is concerned with whether the resulting sequence is populated, so the distinction can affect the transformation's behavior.
9. Useful for Optional API and Data Exchange XML
Modern applications frequently exchange XML containing optional fields.
For example:
<customer>
<firstName>John</firstName>
<lastName>Smith</lastName>
<email/>
<phone/>
<company/>
</customer>
An application may prefer:
<customer>
<firstName>John</firstName>
<lastName>Smith</lastName>
</customer>
rather than sending multiple empty elements.
<xsl:where-populated> can simplify this kind of transformation because the stylesheet can construct optional structures and let the generated content determine whether those structures should appear.
10. Advantages
The main advantages of <xsl:where-populated> include:
-
It reduces unnecessary empty output.
-
It is useful for optional XML structures.
-
It allows the result of a sequence constructor to determine whether content should be retained.
-
It can reduce repetitive Boolean tests in complex transformations.
-
It works well with dynamically constructed XML content.
-
It is particularly useful when an entire generated structure should disappear if it contains no useful content.
-
It can make XSLT 3.0 stylesheets easier to maintain when dealing with many optional fields.
11. <xsl:where-populated> vs <xsl:if>
| Feature | <xsl:if> |
<xsl:where-populated> |
|---|---|---|
| Primary purpose | Test a Boolean condition | Retain generated content when it is populated |
| Requires explicit test | Yes | No direct Boolean test is required |
| Focus | Condition | Generated result |
| Useful for optional fields | Yes | Yes |
| Useful for optional groups | Yes | Particularly useful |
| XSLT version | Earlier versions and XSLT 3.0 | XSLT 3.0 |
The two instructions are not replacements for one another. <xsl:if> is appropriate when you have a clear Boolean condition. <xsl:where-populated> is particularly useful when you want the presence or absence of generated content to control the result.
12. Practical Example
Suppose the input XML is:
<student>
<name>David</name>
<email>[email protected]</email>
<phone/>
<course/>
</student>
An XSLT 3.0 stylesheet could contain:
<xsl:template match="student">
<student>
<name>
<xsl:value-of select="name"/>
</name>
<xsl:where-populated>
<contact>
<xsl:if test="email">
<email>
<xsl:value-of select="email"/>
</email>
</xsl:if>
<xsl:if test="phone">
<phone>
<xsl:value-of select="phone"/>
</phone>
</xsl:if>
</contact>
</xsl:where-populated>
<xsl:where-populated>
<course>
<xsl:value-of select="course"/>
</course>
</xsl:where-populated>
</student>
</xsl:template>
The resulting XML can be:
<student>
<name>David</name>
<contact>
<email>[email protected]</email>
</contact>
</student>
The empty phone, course, and their corresponding empty structures are avoided.
13. When Should You Use <xsl:where-populated>?
This instruction is most appropriate when:
-
An output element is optional.
-
A generated section should exist only when it contains data.
-
Several optional fields contribute to one output structure.
-
You want to avoid unnecessary empty elements.
-
The presence of output depends on the result of several XSLT instructions.
-
You are developing an XSLT 3.0 stylesheet and want cleaner conditional construction.
Conclusion
<xsl:where-populated> is a useful XSLT 3.0 conditional construction mechanism for situations where output should be retained only when the enclosed sequence constructor produces meaningful content. Unlike <xsl:if>, which starts with an explicit Boolean condition, <xsl:where-populated> focuses on the content that is actually generated.
Its greatest practical value appears when transforming XML containing numerous optional fields or optional groups of information. By allowing empty generated structures to be suppressed, it can produce cleaner XML and reduce unnecessary empty elements. It is therefore a useful XSLT 3.0 feature for designing maintainable transformations involving complex, optional XML data.