我想使用XSLT来计算XML文档中特定节点中字符串出现次数。 考虑这个例子
<mainNode>
<book>
<price> 100 </price>
<city> chennai </city>
<list>
<language> c java ruby </language>
</list>
</book>
<book>
<price> 200 </price>
<city> banglore </city>
<list>
<language> c java </language>
</list>
</book>
<book>
<price> 300 </price>
<city> delhi </city>
<list>
<language> java ruby </language>
</list>
</book>
</mainNode>
这里我想计算“java”
的出现次数我希望输出像这样:: java - 3
怎么做?任何想法???
答案 0 :(得分:7)
使用强>:
count(/*/*/list/language[contains(., 'java')])
完整的XSLT转换:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/">
java -- <xsl:value-of select=
"count(/*/*/list/language[contains(., 'java')]) "/>
</xsl:template>
</xsl:stylesheet>
应用于提供的XML文档:
<mainNode>
<book>
<price> 100 </price>
<city> chennai </city>
<list>
<language> c java ruby </language>
</list>
</book>
<book>
<price> 200 </price>
<city> banglore </city>
<list>
<language> c java </language>
</list>
</book>
<book>
<price> 300 </price>
<city> delhi </city>
<list>
<language> java ruby </language>
</list>
</book>
</mainNode>
产生了想要的正确结果:
java -- 3
<强>更新强>:
如果我们计算所有字符串的出现次数 - 而不仅仅是包含字符串的所有节点 - 以下是如何做到的:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes"/>
<xsl:param name="pWord" select="' java '"/>
<xsl:template match="/">
<xsl:variable name="vResult">
<xsl:apply-templates/>
</xsl:variable>
<xsl:value-of select="concat($pWord, '--- ')"/>
<xsl:value-of select="string-length($vResult)"/>
</xsl:template>
<xsl:template match="list/language" name="countWord">
<xsl:param name="pText" select="."/>
<xsl:if test="contains($pText, $pWord)">
<xsl:text>X</xsl:text>
<xsl:call-template name="countWord">
<xsl:with-param name="pText"
select="concat(' ', substring-after($pText, $pWord))"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
在此XML文档上应用此转换时:
<mainNode>
<book>
<price> 100 </price>
<city> chennai </city>
<list>
<language> c java ruby </language>
</list>
</book>
<book>
<price> 200 </price>
<city> banglore </city>
<list>
<language> c java </language>
</list>
</book>
<book>
<price> 300 </price>
<city> delhi </city>
<list>
<language> java java ruby </language>
</list>
</book>
</mainNode>
产生了想要的正确结果:
java --- 4
答案 1 :(得分:2)
也许你可以尝试这个XSL Template to count substrings:
<xsl:template name="substring-count">
<xsl:param name="string"/>
<xsl:param name="substr"/>
<xsl:choose>
<xsl:when test="contains($string, $substr) and $string and $substr">
<xsl:variable name="rest">
<xsl:call-template name="substring-count">
<xsl:with-param name="string" select="substring-after($string, $substr)"/>
<xsl:with-param name="substr" select="$substr"/>
</xsl:call-template>
</xsl:variable>
<xsl:value-of select="$rest + 1"/>
</xsl:when>
<xsl:otherwise>0</xsl:otherwise>
</xsl:choose>
</xsl:template>
用法:
<xsl:call-template name="substring-count">
<xsl:with-param name="string" select="'mary had a little lamb'" />
<xsl:with-param name="substr" select="'lamb'" />
</xsl:call-template>
答案 2 :(得分:1)
在<xsl:value-of>
声明中尝试此操作:
count(//language[contains(concat(' ',.,' '), ' java ')])
如果您的文档结构是相对静态的,或者您在其他地方有language
个节点用于其他目的,则可以将//language
替换为/mainNode/book/list/language
。
concat
位可能看起来有些复杂,但是要确保在您正在查看的文本的开头和结尾有一个空格,并且在任意一侧搜索' java '
空格,您不会错误地包含恰好包含java
的其他字词,例如javascript
。
如果'java'可能在节点中不止一次存在,那么您将需要使用递归模板。这是一种方式:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" />
<xsl:template match="/">
<xsl:variable name="list">
<xsl:for-each select="//language">
<xsl:call-template name="count">
<xsl:with-param name="lang">java</xsl:with-param>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
<xsl:value-of select="concat('java -- ',string-length($list))" />
</xsl:template>
<xsl:template name="count">
<xsl:param name="lang" />
<xsl:param name="text" select="text()" />
<xsl:if test="contains(concat(' ',$text,' '),concat(' ',$lang,' '))">
<xsl:text>0</xsl:text>
<xsl:call-template name="count">
<xsl:with-param name="lang" select="$lang" />
<xsl:with-param name="text" select="substring-after($text,$lang)" />
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
这实际上创建了一个0
的字符串,每次出现一个java
,然后只使用该字符串的长度。
如果您可以选择使用XSLT 2.0,则可以创建一个计算字符串中出现次数的函数,并使用<xsl:value-of select="sum(mycountfunction(//language))" />
或类似的东西。
正如我在您的问题评论中指出的那样,更好地设计源XML会有很大帮助;如果每种语言都有自己的元素,那么这一切都不是必需的。当然,这可能超出了您的控制范围,但如果您可以选择更改它(或说服提供商更改它),我强烈推荐它。
答案 3 :(得分:0)
http://www.xsltfunctions.com/xsl/functx_number-of-matches.html
count(tokenize($arg,$pattern)) - 1
我在这里也回答过:Find the number of occurences of a substring in a string in xslt