Is there a neat XPath expression to count string tokens of a set of nodes? Eg;
<set>
<hi>hello, there, world</hi>
<hi>foo, bar</hi>
</set>
The answer I want for the above example is the value 5
. The first <hi>
has 3 tokens. The second <hi>
has 2 tokens.
The <set>
may contain any number of <hi>
nodes, each of which may contain any number of tokens. A token is a string separated by a comma followed by space.
I've tried;
<xsl:value-of select="count(str:tokenize(/set//hi, ', '))"/>
but that returns the number of tokens of the first node, ie. 3
.
I'm using XSLT 1.0. (PHP libxml version 2.7.3)
You would need the expressive power of XPath 2.0 or XQuery 1.0 like count(/set/hi/tokenize(., ', '))
to do it with a single expression.
With XSLT 1.0 you need to iterate and sum up the values, perhaps using a result tree fragment as a data structure for intermediary results which you then convert (with exsl:node-set
) to a node-set for summing up the pieces.
Given your definition
A token is a string separated by a comma followed by space.
... all you want to do is count the number of commas and add 1 for each string.
Here is a bit of a hack that works in XSLT 1.0, and it exploits a translate()
idiom that sometimes proves useful. Think about what it is doing (it takes a moment to sink in for a first-time user of the idiom).
T:\ftemp>type commas.xml
<set>
<hi>hello, there, world</hi>
<hi>foo, bar</hi>
</set>
T:\ftemp>xslt commas.xml commas.xsl
5
T:\ftemp>type commas.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output omit-xml-declaration="yes"/>
<xsl:template match="set">
<xsl:variable name="commas">
<xsl:for-each select="hi">
<xsl:value-of select="translate(.,translate(.,',',''),'')"/>
<xsl:text>,</xsl:text>
</xsl:for-each>
</xsl:variable>
<xsl:value-of select="string-length($commas)"/>
</xsl:template>
</xsl:stylesheet>
T:\ftemp>
This is the kind of thing that's easy in XPath 2.0, but unfortunately requires some extra work in XPath 1.0. There are a number of ways you can do this with an extra step. This is the one I would use:
<xsl:variable name="tmp">
<xsl:for-each select="//hi">
<xsl:value-of select="concat(., ', ')"/>
</xsl:for-each>
</xsl:variable>
<xsl:value-of select="count(str:tokenize($tmp, ', '))"/>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.