Re: [xsl] xsl:if test = empty string, returns true

Subject: Re: [xsl] xsl:if test = empty string, returns true
From: "G. Ken Holman" <gkholman@xxxxxxxxxxxxxxxxxxxx>
Date: Sun, 13 May 2012 16:24:37 -0400
At 2012-05-13 22:03 +0200, Jorge wrote:
According to http://www.w3.org/TR/xpath/#section-Boolean-Functions:

> The boolean function converts [] a string to
true if and only if its length is non-zero.

My XSLT 2.0 stylesheet has an xsl:if element
testing a function that seems to be returning a
string of length zero, and yet the test
evaluates to true. I am processing the
stylesheet with Saxon-HE 9.2.1.2J with this command line:

> java -jar saxon/saxon9he.jar -it:main -xsl:./test.xsl

This is the stylesheet `test.xsl`:

> <?xml version="1.0" encoding="UTF-8"?>
> <xsl:stylesheet version="2.0"
>                 xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
>                 xmlns:me="null">
>
>       <xsl:variable name="PLIST" select="'./test.plist'"/>
>
>       <!-- Load external plist into variable -->
>       <xsl:variable name="metadata"
select="document(iri-to-uri($PLIST))"/>
>
>       <!-- Function to fetch value of a key-string pair in plist -->
>       <xsl:function name="me:metadata">

Not having added an as= constraint, you are creating a temporary tree with a text node child.

Change it to the following to work:

<xsl:function name="me:metadata" as="xsd:string?">


>               <xsl:param name="label"/>
>               <xsl:value-of

select="normalize-space($metadata/plist/dict/key[text()=$label]/following::no
de()[1]/text())"/>

Note that the following:: axis looks all the way
to the end of the document.  And, you are looking
for the adjacent node (which in your example is a
text node), rather than the adjacent element
(unless you are invoking saxon with the option to
strip white-space text nodes from your input, in
which case that is not true).  So I suggest using
following-sibling::* in case you do end up with white-space text nodes.

BTW, I very rarely ever have to address text()
nodes and the above would be better written as:

<xsl:value-of
select="normalize-space($metadata/plist/dict/key[.=$label]/following-sibling:
:*[1])"/>

This is not just a matter of style ... consider
how your code would not work when there is more than one text node:

<key>test<!--used to end here-->key</key>


>       </xsl:function>
>
>       <xsl:output method="text" encoding="UTF-8"/>
>
>       <xsl:template name="main" exclude-result-prefixes="me">


Why not put the exclude-result-prefixes on the document element?


>               <xsl:choose>
>                       <xsl:when test="me:metadata('testkey')">
> testkey = "<xsl:value-of select="me:metadata('testkey')"/>"
> testkey's length = <xsl:value-of
select="string-length(me:metadata('testkey'))"/>
>                       </xsl:when>
>                       <xsl:otherwise>
>                               "testkey" is empty or does not exist.
>                       </xsl:otherwise>
>               </xsl:choose>
>       </xsl:template>
>
> </xsl:stylesheet>
...
Any idea why the test evaluates to true?

Because the returned data type of the function value is a temporary tree and while it may or may not have a text node child, the document node in the tree makes the test true().

Please note that I am not wondering whether the
way I wrote the stylesheet is the most
appropriate way to do what it is supposed to do,
but why the test is evaluating to true.

Nevertheless I hope the additional comments are considered helpful and not critical. I wouldn't want readers of the archive to use text() as you are.

. . . . . . . . Ken

--
Public XSLT, XSL-FO, UBL and code list classes in Europe -- Oct 2012
Contact us for world-wide XML consulting and instructor-led training
Free 5-hour lecture: http://www.CraneSoftwrights.com/links/udemy.htm
Crane Softwrights Ltd.            http://www.CraneSoftwrights.com/s/
G. Ken Holman                   mailto:gkholman@xxxxxxxxxxxxxxxxxxxx
Google+ profile: https://plus.google.com/116832879756988317389/about
Legal business disclaimers:    http://www.CraneSoftwrights.com/legal

Current Thread