我有以下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="'
'"></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>
答案 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="'
'"></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>
</xsl:text>
</xsl:for-each-group>
</xsl:template>
<xsl:template match="item">
<xsl:value-of separator="," select="*[starts-with(name(), 'item_')]"/>
<xsl:text>
</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