Xslt 1将非唯一元素转换为网格属性

时间:2014-12-18 11:26:50

标签: xml xslt xslt-1.0 xslt-grouping

我有一个具有此结构的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的标题中提到过,所以最好将此作为一个单独的问题。

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

<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

参考文献:

  1. XSLT concat string, remove last comma