在XSLT中正确使用for-each-group

时间:2012-02-06 21:39:14

标签: xslt

我有以下xml示例:

<items>
    <item>
        <item_id>1</item_id>
        <item_name>item 1</item_name>
        <group_id>1</group_id>
        <group_name>group 1</group_name>
    </item>
    <item>
        <item_id>2</item_id>
        <item_name>item 2</item_name>
        <group_id>1</group_id>
        <group_name>group 1</group_name>
    </item>
    <item>
        <item_id>3</item_id>
        <item_name>item 3</item_name>
        <group_id>2</group_id>
        <group_name>group 2</group_name>
    </item>
</items>

我需要转换成以下csv格式:

1,item 1
2,item 2
3,item 3
1,group 1
2,group 2

在xml中,item_id将始终后跟item_name。项目名称并不总是concat('item _',#)。它可能是一种描述,如'牙膏'。项目永远不会在文件中重复,但有时group_id-&gt; group_name配对并不总是1-1。在这种情况下,最好采取第一次配对。

我使用'for-each-group'语句完成了这个,但它看起来有点hacky。这种方法有什么缺点吗?有什么更好的方法来实现这个目标?

    

<xsl:template match="/">
    <xsl:call-template name="list_format">
        <xsl:with-param name="list" select="'item'"/>
    </xsl:call-template>
    <xsl:call-template name="list_format">
        <xsl:with-param name="list" select="'group'"/>
    </xsl:call-template>
</xsl:template>



<xsl:template name="list_format">
    <xsl:param name="list"/>

    <xsl:variable name="linefeed" select="'&#xA;'"></xsl:variable>
    <xsl:variable name="list_id" select="concat($list,'_id')"></xsl:variable>
    <xsl:variable name="list_name" select="concat($list,'_name')"></xsl:variable>

    <xsl:for-each-group select="/items/item" group-by="*[name()=$list_id]">
        <xsl:sort select="*[name()=$list_id]"/>
        <xsl:value-of select="*[name()=$list_id]"/>
        <xsl:text>,</xsl:text>
        <xsl:value-of select="*[name()=$list_name]"/> 
        <xsl:value-of select="$linefeed"/>
    </xsl:for-each-group>
</xsl:template>

2 个答案:

答案 0 :(得分:1)

嗯...并不是真的有缺点但它在XSLT 1.0中不起作用,因为它不支持for-each-group: - /

我认为你不需要XSLT 1.0解决方案..但仍然在发布我的工作:)看看这个!

<?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="/items">
    <xsl:call-template name="items_grouping">
      <xsl:with-param name="list" select="'item'"/>
    </xsl:call-template>
    <xsl:call-template name="items_grouping">
      <xsl:with-param name="list" select="'group'"/>
    </xsl:call-template>
  </xsl:template>

    <xsl:template name="items_grouping">
    <xsl:param name="list"/>
    <xsl:variable name="linefeed" select="'&#xA;'"></xsl:variable>
    <xsl:variable name="list_id" select="concat($list,'_id')"></xsl:variable>
    <xsl:variable name="list_name" select="concat($list,'_name')"></xsl:variable>
    <xsl:for-each select="item">
      <xsl:for-each select="*[name()=$list_id and not(.= ../preceding-sibling::item/*[name()=$list_id]/.)]">
        <xsl:value-of select="concat(.,',')"/>
        <xsl:value-of select="../*[name()=$list_name]"/>
        <xsl:value-of select="$linefeed"/>
      </xsl:for-each>
    </xsl:for-each>
  </xsl:template>

  <xsl:template match="text()"/>

</xsl:stylesheet>

使用与您相同的方法..仅更改为'preceding-sibling'
对于此代码, <item>的子节点顺序无关紧要

答案 1 :(得分:0)

这是一个简单而简短的XSLT 2.0(根据要求)解决方案

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>

 <xsl:template match="/">
  <xsl:apply-templates/>
  <xsl:for-each-group select="/*/*/group_id" group-by=".">
    <xsl:value-of separator="," select="../*[starts-with(name(), 'group_')]"/>
    <xsl:text>&#xA;</xsl:text>
  </xsl:for-each-group>
 </xsl:template>

 <xsl:template match="item">
     <xsl:value-of separator="," select="*[starts-with(name(), 'item_')]"/>
   <xsl:text>&#xA;</xsl:text>
 </xsl:template>
</xsl:stylesheet>

将此转换应用于提供的XML文档

<items>
    <item>
        <item_id>1</item_id>
        <item_name>item 1</item_name>
        <group_id>1</group_id>
        <group_name>group 1</group_name>
    </item>
    <item>
        <item_id>2</item_id>
        <item_name>item 2</item_name>
        <group_id>1</group_id>
        <group_name>group 1</group_name>
    </item>
    <item>
        <item_id>3</item_id>
        <item_name>item 3</item_name>
        <group_id>2</group_id>
        <group_name>group 2</group_name>
    </item>
</items>

产生了想要的正确结果

1,item 1
2,item 2
3,item 3
1,group 1
2,group 2