Xml 计算XSLT中的关键字数
假设我有以下XML结构:Xml 计算XSLT中的关键字数,xml,xslt,Xml,Xslt,假设我有以下XML结构: <entry> <countries>USA, Australia, Canada</countries> </entry> <entry> <countries>USA, Australia</countries> </entry> <entry> <countries>Australia, Belgium</countries
<entry>
<countries>USA, Australia, Canada</countries>
</entry>
<entry>
<countries>USA, Australia</countries>
</entry>
<entry>
<countries>Australia, Belgium</countries>
</entry>
<entry>
<countries>Croatia</countries>
</entry>
美国、澳大利亚、加拿大
美国、澳大利亚
澳大利亚、比利时
克罗地亚
我想统计一下这些条目中出现的每个国家的实例数。我只能使用客户端XSLT(不允许自定义服务器代码)。最终结果需要如下所示:
Country | Count
-----------|--------
Australia | 3
USA | 2
Belgium | 1
Canada | 1
Croatia | 1
国家|计数
-----------|--------
澳大利亚| 3
美国| 2
比利时| 1
加拿大| 1
克罗地亚| 1
正如Mike指出的,这个XML结构可以改进,但是它是由第三方系统生成的,我无法更改它
是否可以实现此XSLT?如果可以,如何实现?是否有不使用此格式的原因:
<entry>
<countries>
<country>USA</country>
<country>Australia</country>
<country>Canada</country>
</countries>
</entry>
美国
澳大利亚
加拿大
您当前的方式与XML数据的存储方式并不匹配
正如您所说,您不能更改数据格式,请尝试和的组合(如果您有XSLT2支持,否则我认为您会走运)。在XSLT1.0中,最好使用两步方法
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
<xsl:template match="/root">
<countries>
<xsl:apply-templates select="entry" />
</countries>
</xsl:template>
<xsl:template match="entry">
<xsl:call-template name="tokenize">
<xsl:with-param name="input" select="countries" />
</xsl:call-template>
</xsl:template>
<xsl:template name="tokenize">
<xsl:param name="input" />
<xsl:variable name="list" select="concat($input, ',')" />
<xsl:variable name="head" select="substring-before($list, ',') " />
<xsl:variable name="tail" select="substring-after($list, ',') " />
<xsl:if test="normalize-space($head) != ''">
<country>
<xsl:value-of select="normalize-space($head)" />
</country>
<xsl:call-template name="tokenize">
<xsl:with-param name="input" select="$tail" />
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
在node-set()
扩展函数的帮助下,该过程可以在单个转换中完成。但是,您将无法使用XSL键,这可能会导致大型输入的性能降低。YMMV
第1步的必要修改是(使用MSXSL扩展,其他供应商在名称空间声明方面有所不同,这降低了这种方法的可移植性):
使用这种方法,不需要单独的步骤2。结果与上述相同。对于较小的输入,性能上的差异不会明显。
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:str="http://exslt.org/strings" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="xsl str msxsl" version="1.0">
<xsl:import href="str.split.template.xsl"/>
<xsl:output indent="yes"/>
<xsl:template match="/">
<xsl:variable name="countries">
<xsl:call-template name="get-counties" />
</xsl:variable>
<table>
<xsl:for-each select="msxsl:node-set($countries)/country[not(. = preceding::country)]">
<xsl:variable name="name" select="./text()"/>
<tr>
<td>
<xsl:value-of select="$name" />
</td>
<td>
<xsl:value-of select="count(msxsl:node-set($countries)/country[. = $name])" />
</td>
</tr>
</xsl:for-each>
</table>
</xsl:template>
<xsl:template name="get-counties">
<xsl:for-each select="//countries">
<xsl:variable name="countries-raw">
<xsl:call-template name="str:split">
<xsl:with-param name="string" select="text()"/>
<xsl:with-param name="pattern" select="','" />
</xsl:call-template>
</xsl:variable>
<xsl:for-each select="msxsl:node-set($countries-raw)/token">
<country>
<xsl:value-of select="normalize-space(.)"/>
</country>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
str.split.template.xsl是EXSLT()的str模块的一部分。我知道,我也同意,但这个输出是由第三方系统生成的,我无法更改。我已经更新了答案,介绍了如何解决这个问题。这是什么处理器,最重要的是XSLT 1.0还是XSLT 2.0?我认为对输出进行排序是任务的一部分。
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
<xsl:output method="text" />
<xsl:key name="kCountry" match="country" use="." />
<xsl:template match="/countries">
<xsl:apply-templates select="country">
<xsl:sort select="count(key('kCountry', .))" data-type="number" order="descending" />
<xsl:sort select="." data-type="text" order="ascending" />
</xsl:apply-templates>
</xsl:template>
<xsl:template match="country">
<xsl:if test="generate-id() = generate-id(key('kCountry', .)[1])">
<xsl:value-of select="." />
<xsl:text>	</xsl:text>
<xsl:value-of select="count(key('kCountry', .))" />
<xsl:text> </xsl:text>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Australia 3
USA 2
Belgium 1
Canada 1
Croatia 1
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
exclude-result-prefixes="msxsl"
>
<xsl:template match="/root">
<!-- store the list of <country>s as a result-tree-fragment -->
<xsl:variable name="countries">
<xsl:apply-templates select="entry" />
</xsl:variable>
<!-- convert the result-tree-fragment to a usable node-set -->
<xsl:variable name="country" select="msxsl:node-set($countries)/country" />
<!-- iteration, sorting and grouping in one step -->
<xsl:for-each select="$country">
<xsl:sort select="count($country[. = current()])" data-type="number" order="descending" />
<xsl:sort select="." data-type="text" order="ascending" />
<xsl:if test="generate-id() = generate-id($country[. = current()][1])">
<xsl:value-of select="." />
<xsl:text>	</xsl:text>
<xsl:value-of select="count($country[. = current()])" />
<xsl:text> </xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:template>
<!-- ... the remainder of the stylesheet #1 is unchanged ... -->
</xsl:stylesheet>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:str="http://exslt.org/strings" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="xsl str msxsl" version="1.0">
<xsl:import href="str.split.template.xsl"/>
<xsl:output indent="yes"/>
<xsl:template match="/">
<xsl:variable name="countries">
<xsl:call-template name="get-counties" />
</xsl:variable>
<table>
<xsl:for-each select="msxsl:node-set($countries)/country[not(. = preceding::country)]">
<xsl:variable name="name" select="./text()"/>
<tr>
<td>
<xsl:value-of select="$name" />
</td>
<td>
<xsl:value-of select="count(msxsl:node-set($countries)/country[. = $name])" />
</td>
</tr>
</xsl:for-each>
</table>
</xsl:template>
<xsl:template name="get-counties">
<xsl:for-each select="//countries">
<xsl:variable name="countries-raw">
<xsl:call-template name="str:split">
<xsl:with-param name="string" select="text()"/>
<xsl:with-param name="pattern" select="','" />
</xsl:call-template>
</xsl:variable>
<xsl:for-each select="msxsl:node-set($countries-raw)/token">
<country>
<xsl:value-of select="normalize-space(.)"/>
</country>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>