Reputation: 77
I want to use 'variable' with condition and apply a template.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<document>
<body>
<aaa right="abc" />
<bbb right="zzz" />
</body>
<body>
<aaa left="def" />
</body>
</document>
I show a XSL(version="1.0") sample below.
<xsl:template match="body">
<xsl:variable name="leftA" select="body/aaa/@left" />
<xsl:variable name="leftB" select="body/bbb/@left" />
<xsl:variable name="left">
<xsl:if test="not($leftA)">
<xsl:value-of select="$leftB"/>
</xsl:if>
<xsl:value-of select="$leftA"/>
</xsl:variable>
<xsl:if test="$left">
<xsl:apply-templates select="$left">
</xsl:if>
</xsl:template>
<xsl:template match="@left">
code here
</xsl:template>
When both $leftA
and $leftB
don't exist in XML, I have a error. Doesn't my XSL make sense? How can I avoid errors? The error is Expression must evaluate to a node-set
.
Upvotes: 0
Views: 12441
Reputation: 116982
You did not post a reproducible example, so this is a guess.
How can I avoid errors? The error is Expression must evaluate to a node-set.
One way is to eliminate unnecessary variables and do directly what you want to do. For example, instead of all this:
<xsl:variable name="leftA" select="body/aaa/@left" />
<xsl:variable name="leftB" select="body/bbb/@left" />
<xsl:variable name="left">
<xsl:if test="not($leftA)">
<xsl:value-of select="$leftB"/>
</xsl:if>
<xsl:value-of select="$leftA"/>
</xsl:variable>
<xsl:if test="$left">
<xsl:apply-templates select="$left">
</xsl:if>
do just this:
<xsl:variable name="leftA" select="body/aaa/@left" />
<xsl:apply-templates select="$leftA" />
<xsl:if test="not($leftA)">
<xsl:apply-templates select="body/bbb/@left" />
</xsl:if>
The way you have it now, the $left
variable contains a result-tree-fragment. You cannot apply templates to a RTF directly, you must first convert it to a node-set using the extension node-set()
function:
<xsl:apply-templates select="exsl:node-set($left)">
after adding:
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl"
to the xsl:stylesheet
element - see: http://exslt.org/exsl/functions/node-set/index.html
Upvotes: 1
Reputation: 12729
I am assuming that you want to select or output either one of body/bbb/@left
, or body/aaa/@left
, but not both, and if both exist, preferencing body/bbb/@left
.
This XSLT 1.0 stylesheet ...
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="html" indent="yes" encoding="utf-8"/>
<xsl:strip-space elements="*" />
<xsl:template match="/">
<html>
<head>
<title>bbb or aaa</title>
</head>
<body>
<h1>bbb or aaa</h1>
<ul>
<xsl:apply-templates select="test-cases/test-case" />
</ul>
</body>
</html>
</xsl:template>
<xsl:template match="test-case">
<xsl:variable name="test-result" select="body/bbb/@left | body/aaa/@left[not(../../bbb/@left)]" />
<li>
<xsl:value-of select="concat('Test case ',@id,' has result: ',$test-result)" />
</li>
</xsl:template>
</xsl:stylesheet>
... when applied to this input ...
<test-cases>
<test-case id="1" description="a exists, but not b">
<body>
<aaa left="Moscow" />
</body>
</test-case>
<test-case id="2" description="b exists, but not a">
<body>
<bbb left="Sydney" />
</body>
</test-case>
<test-case id="3" description="both a and b exist">
<body>
<aaa left="Brandenburg" />
<bbb left="Edinburgh" />
</body>
</test-case>
<test-case id="4" description="neither a nor b exists">
<body />
</test-case>
</test-cases>
... will result in this output page ...
<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>bbb or aaa</title>
</head>
<body>
<h1>bbb or aaa</h1>
<ul>
<li>Test case 1 has result: Moscow</li>
<li>Test case 2 has result: Sydney</li>
<li>Test case 3 has result: Edinburgh</li>
<li>Test case 4 has result: </li>
</ul>
</body>
</html>
If you had no particular preference between bbb and aaa, you could simplify the $test-result with ...
<xsl:variable name="test-result" select="(body/bbb/@left | body/aaa/@left)[1]" />
Upvotes: 2
Reputation: 63
Initially, you check for leftA and if it's null then assign leftB as it value for left variable. But the very next statement assigns leftA value without any condition. So it always overrides with leftA value even if it is null.
<xsl:variable name="left">
<xsl:if test="not($leftA)">
<xsl:value-of select="$leftB"/>
</xsl:if>
**<xsl:value-of select="$leftA"/>**
</xsl:variable>
Use one more if condition or by replacing with where clause. Besides check for no null before applying the template.
Upvotes: 1