I have xml like this:
<article>
<title> Test title - <literal> Compulsory - </literal> <fn> ABC </fn>
<comments> a comment</comments>
</title>
</article>
I want to get all child node + self text in a variable e.g.
$full_title = "Test title - Compulsory - ABC"
Except comments node text.
Following is my unsuccessful try where i miss title node text.
<xsl:template name="test">
<xsl:variable name="full_title" select="article/title/*[not(self::comments)][1]" />
<xsl:variable name="width" select="45" />
<xsl:choose>
<xsl:when test="string-length($full_title) > $width">
<xsl:value-of select="concat(substring($full_title,1,$width),'..')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$full_title"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Change *
to node()
. That will select both elements and text nodes that are children of the <title>
element. Then take out the [1]
since you want all children of <title>
:
<xsl:variable name="full_title"
select="string-join(article/title/node()[not(self::comments)], '')" />
A more reliable way to do it, so that you won't get tripped up if you have multiple levels under <title>
and <comments>
elements occur as grandchildren, would be this:
<xsl:variable name="full_title"
select="string-join(article/title//text()[not(ancestor::comments)], '')" />
Since you want the variable to hold a string value, and since you're passing it to functions like concat()
and string-length()
which cannot take a sequence of multiple nodes as a first argument, using string-join(..., '')
around the sequence converts it to a string by concatenating the string values of each node.