XSLT:分组和排序......如何?

标签 xslt xsl-grouping

我有一个如下所示的 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>

我需要生成一份报告,列出每个州,按字母顺序排列,每个城市如下....例如..

Alaska - Fairbanks, Coldfoot
North Carolina - Charlotte, Harrisburg
Virginia - Leesburg, Ashburn

(城市不必按字母顺序排列,只需按州排列即可)

我尝试通过对 states/state 执行 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>   

这给了我......

 Alaska - Fairbanks
 Alaska - Coldfoot
 North Carolina - Charlotte
 North Carolina - Harrisburg
 Virginia - Leesburg
 Virginia - Ashburn

排序成功了,现在我想分组。我唯一能想到做的就是与之前的状态进行比较,因为它是排序的,所以它应该识别状态值是否没有改变。像这样...

<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>

遗憾的是,前同级特征似乎不能很好地与排序配合使用,因此,第一次通过(在第一个阿拉斯加),它将第一个北卡罗来纳州视为前同级。这会导致一些奇怪的结果,这根本不符合我的喜好。

那么,我正在使用 XSLT1.0...有什么想法/建议吗?

谢谢

最佳答案

这个样式表:

<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('&#xA;',
                                                 1 div (position()=last())))"/>
    </xsl:template>
</xsl:stylesheet>

输出:

Alaska - Fairbanks, Coldfoot
North Carolina - Charlotte, Harrisburg
Virginia - Leesburg, Ashburn

注意:按州名称分组。分隔符子字符串表达式仅适用于拉式样式(将模板应用于城市)

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,', '),
                                         '&#xA;')"/>
        </xsl:for-each-group>
    </xsl:template>
</xsl:stylesheet>

只是为了好玩,这个 XPath 2.0 表达式:

string-join(for $state in distinct-values(/*/*/name)
            return concat($state,
                          ' - ',
                          string-join(/*/*[name=$state]/city,
                                      ', ')),
            '&#xA;')

关于XSLT:分组和排序......如何?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3782219/

相关文章:

XSLT 分组和子分组

xml - 我们必须为模板标签中的匹配赋予什么值?

xml - XSLT 上的 HTML 编码

xml - 在删除根节点之前,XSLT转换不起作用

visual-studio-2010 - 尝试在 Visual Studio 中调试 XSLT 时出现 System.Xml.Xsl.CompiledQuery.Query.staticData 错误

xml - 子节点中的命名空间为空

xml - Muenchian 分组 - 在节点内分组,而不是在整个文档内分组

xml - 使用 xslt 的组相邻节点