我有一个XML文件,如下所示......
<states>
<state>
<name>North Carolina</name>
<city>Charlotte</city>
</state>
<state>
<name>Alaska</name>
<city>Fairbanks</city>
</state>
<state>
<name>Virginia</name>
<city>Leesburg</city>
</state>
<state>
<name>Alaska</name>
<city>Coldfoot</city>
</state>
<state>
<name>North Carolina</name>
<city>Harrisburg</city>
</state>
<state>
<name>Virginia</name>
<city>Ashburn</city>
</state>
</states>
Run Code Online (Sandbox Code Playgroud)
我需要生成一份列出每个州的报告,按照每个城市的字母顺序排列......例如..
Alaska - Fairbanks, Coldfoot
North Carolina - Charlotte, Harrisburg
Virginia - Leesburg, Ashburn
Run Code Online (Sandbox Code Playgroud)
(城市不必按照alpha顺序排列,只需要按州规定)
我尝试通过对状态/状态执行for-each,按名称对其进行排序并对其进行处理来解决此问题.像这样....
<xsl:for-each select="states/state">
<xsl:sort select="name" data-type="text" order="ascending"/>
<xsl:value-of select="name"/>-<xsl:value-of select="city"/>
</xsl:for-each>
Run Code Online (Sandbox Code Playgroud)
这给了我......
Alaska - Fairbanks
Alaska - Coldfoot
North Carolina - Charlotte
North Carolina - Harrisburg
Virginia - Leesburg
Virginia - Ashburn
Run Code Online (Sandbox Code Playgroud)
排序工作,现在我想分组.我唯一能想到的就是比较之前的状态,因为它已经排序,它应该识别状态值是否没有改变.像这样...
<xsl:for-each select="states/state">
<xsl:sort select="name" data-type="text" order="ascending"/>
<xsl:variable name="name"><xsl:value-of select="name">
<xsl:variable name="previous-name"><xsl:value-of select="(preceding-sibling::state)/name">
<xsl:if test="$name != $previous-name">
<br/><xsl:value-of select="name"/>-
</xsl:if>
<xsl:value-of select="city"/>
</xsl:for-each>
Run Code Online (Sandbox Code Playgroud)
可悲的是,似乎前面的兄弟功能在这种情况下效果不佳,因此,第一次(在第一次阿拉斯加州)它看到第一次北卡罗来纳州作为前一个兄弟.这会导致一些奇怪的结果,这些结果根本不符合我的喜好.
所以,我正在使用XSLT1.0 ......有什么想法/建议吗?
谢谢
小智 5
这个样式表:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="kStateByName" match="state" use="name"/>
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:apply-templates
select="/*/state[count(.|key('kStateByName',name)[1])=1]">
<xsl:sort select="name"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="state">
<xsl:value-of select="concat(name,' - ')"/>
<xsl:apply-templates select="key('kStateByName',name)/city"/>
</xsl:template>
<xsl:template match="city">
<xsl:value-of select="concat(.,substring(', ',
1 div (position()!=last())),
substring('
',
1 div (position()=last())))"/>
</xsl:template>
</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)
输出:
Alaska - Fairbanks, Coldfoot
North Carolina - Charlotte, Harrisburg
Virginia - Leesburg, Ashburn
Run Code Online (Sandbox Code Playgroud)
注意:按州名称分组.分隔符子串表达式仅适用于拉式样式(将模板应用于城市)
XSLT 2.0解决方案:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="states">
<xsl:for-each-group select="state" group-by="name">
<xsl:sort select="name"/>
<xsl:value-of select="concat(name,
' - ',
string-join(current-group()/city,', '),
'
')"/>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)
只是为了好玩,这个XPath 2.0表达式:
string-join(for $state in distinct-values(/*/*/name)
return concat($state,
' - ',
string-join(/*/*[name=$state]/city,
', ')),
'
')
Run Code Online (Sandbox Code Playgroud)