2

When using XSLT how does one test to see if a variable has a value? Or more specifically, how do you properly nest the xsl:value-of method below so that it returns '' rather than failing to transform, when a value has not been assigned?

Declaration options could potentially be either...

<xsl:variable name="ID" select="//MessageID"/>

<xsl:variable name="ID" select=""/>

What needs to be added to this so that it does not to fail the transform?

<Container>
  <xsl:attribute name="ID" select="$ID"/>
</Container>

Desired output:

<Container ID=""/>

Currently, the transform will fail if the variable's select statement does not find the referenced node.

I have tried several different approaches:

<xsl:if test="$ID"><xsl:value-of select="$ID"/></xsl:if>

<xsl:if test="string-length($ID)&gt;0"><xsl:value-of select="$ID"/></xsl:if>

<xsl:if test="count($ID)&gt;0"><xsl:value-of select="$ID"/></xsl:if>

<xsl:if test="($ID) !=''"><xsl:value-of select="$ID"/></xsl:if>

and I have even attempted declaring an empty variable for comparison:

<xsl:variable name="empty_string"/>

<xsl:if test="($ID) != $empty_string"><xsl:value-of select="$ID"/></xsl:if>

I find this question to be very similar, but distinctly different than: In XSLT how do you test to see if a variable exists?

BDC
  • 63
  • 1
  • 9
  • An empty `select` expression as in `` does not compile so it is not clear what you want to achieve there. Can you post a minimal but complete sample that gives you an error, together with the exact error message and a description of the XSLT processor? – Martin Honnen Apr 04 '18 at 12:41
  • Great answer! Not sure how I overlooked that. – BDC Apr 05 '18 at 11:27
  • Still not sure what the problem is, other than that `` will not compile. You need to have an attribute value for the `select` attribute that is an XPath expression. – Martin Honnen Apr 05 '18 at 12:14

2 Answers2

2

Please try to put <xsl:choose> inside your variable as below:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="xml" indent="no"/>
    <xsl:template match="/">
        <xsl:variable name="ID">
            <xsl:choose>
                <!--check if path exists and if value is not empty-->
                <xsl:when test="//MessageID and string-length(//MessageID) &gt;0">
                    <xsl:value-of select="//MessageID"/>
                </xsl:when>
                <!--otherwise it will be assigned blank value-->
                <xsl:otherwise>
                    <xsl:value-of select="''"/>
                </xsl:otherwise>
            </xsl:choose>           
        </xsl:variable>
        <Container>
            <xsl:attribute name="ID">
                <xsl:value-of select="$ID"/>
            </xsl:attribute>
        </Container>   
    </xsl:template>    
</xsl:stylesheet>

So in case that input:

<Main>
    <Test>
        <MessageID>123</MessageID>
    </Test>
</Main>

Your output will be: <Container ID="123"/>

And in case of below inputs:

<?xml version="1.0" encoding="UTF-16"?>
<Main>
    <Test>
        <MessageID></MessageID>
    </Test>
</Main>

OR

<?xml version="1.0" encoding="UTF-16"?>
<Main>
    <Test>
    </Test>
</Main>

Your output will be: <Container ID=""/>

Hope it helped.

Alex Fomin
  • 485
  • 4
  • 7
0

If a variable exists at all in XSLT, then it has a value. What you are asking is how to test whether it has some particular special value.

I normally encourage people to avoid declarations like

<xsl:variable name="ID"><xsl:value-of select="//MessageID"/></xsl:variable>

in favour of

<xsl:variable name="ID" select="//MessageID"/>

because it's much simpler and faster. But let's suppose you have some good reason for using the more complex form. In that case the value of the variable in XSLT 1.0 will be a "result tree fragment" containing either a single text node child, or no child at all in the case where the xsl:value-of instruction creates a zero-length text node.

You can test whether the string value of the result tree fragment is zero length by testing <xsl:if test="string($ID)"/>. However, this will also return false, for example, for an RTF whose content is an element node with a zero-length string value.

Unfortunately you can't do very much with an RTF without using the node-set() extension function. If you have access to the node-set() extension function, you can do which tests whether the root node of the RTF has a child node. All very messy.

Suggestions:

(a) Try to use the form of xsl:variable binding with a select attribute whenever you can.

(b) Isn't it time you moved to XSLT 2.0+?

Michael Kay
  • 156,231
  • 11
  • 92
  • 164
  • I'll update the question to follow the format you recommended, you're right it would certainly be easier to read. – BDC Apr 05 '18 at 11:31