我有一个具有此结构的XML文件
<levels>
<level id="0" qd="NE">
<gate>99</gate>
<zone>2</zone>
<laydown>4</laydown>
</level>
<level id="0" qd="SE">
<gate>1</gate>
<zone>6</zone>
<laydown>1</laydown>
<laydown>2</laydown>
<zone>5</zone>
<laydown>3</laydown>
</level>
</levels>
我需要将其转换为类似的内容以在网格中显示
<level id="0" qd="NE" gate="99" zone="2" laydown="4">
<level id="0" qd="SE" gate="1" zone="6,5" laydown="1,2,3">
逗号分隔列表的顺序对我来说并不重要。 我是一个xsl / xslt新手,所以任何注释都会有所帮助。我使用VS2013,我收集的只支持XSLT 1.之前在XSLT 2的标题中提到过,所以最好将此作为一个单独的问题。
答案 0 :(得分:2)
这是一种非常有效的方法:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes" />
<xsl:key name="kDistinctChildren" match="level/*"
use="concat(generate-id(..), '+', name())" />
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="level">
<xsl:copy>
<xsl:apply-templates select="@*" />
<xsl:apply-templates mode="group"
select="*[generate-id() =
generate-id(key('kDistinctChildren',
concat(generate-id(..), '+', name()))[1])]" />
</xsl:copy>
</xsl:template>
<xsl:template match="*" mode="group">
<xsl:attribute name="{name()}">
<xsl:apply-templates select="key('kDistinctChildren',
concat(generate-id(..), '+', name()))"
mode="joinWithCommas"/>
</xsl:attribute>
</xsl:template>
<xsl:template match="*" mode="joinWithCommas">
<xsl:value-of select="concat(., substring(',', 1, position() != last()))"/>
</xsl:template>
</xsl:stylesheet>
在样本输入上运行时,输出为:
<levels>
<level id="0" qd="NE" gate="99" zone="2" laydown="4" />
<level id="0" qd="SE" gate="1" zone="6,5" laydown="1,2,3" />
</levels>
答案 1 :(得分:1)
回答一个在试图回答问题时没有付出努力的问题,这不是一个好主意...... 但是,无论如何它都在这里。
<xsl:template match="//level">
<xsl:element name="level">
<xsl:copy-of select="@*" />
<xsl:for-each select="*">
<xsl:call-template name="groupByName" />
</xsl:for-each>
</xsl:element>
</xsl:template>
<xsl:template name="groupByName">
<xsl:variable name="name" select="local-name()" />
<xsl:variable name="nodes" select="../*[$name=local-name()]" />
<xsl:attribute name="{local-name($nodes)}">
<xsl:for-each select="$nodes">
<xsl:value-of select="." />
<xsl:if test="not(position() = last())">,</xsl:if>
</xsl:for-each>
</xsl:attribute>
</xsl:template>
<level id="0" qd="NE" gate="99" zone="2" laydown="4"></level>
<level id="0" qd="SE" gate="1" zone="6,5" laydown="1,2,3"></level>
http://www.xsltcake.com/slices/e3si2j/3