复制所有元素,同时按属性值排序

时间:2018-08-08 16:01:08

标签: xml xslt xslt-1.0

我有这个XML

<root xmlns:temp ="temp.com">
  <testNode name="a">
    <sample/>
  </testNode>
  <testNode name="b">
    <sample/>
  </testNode>
  <testNode name="c">
    <sample/>
  </testNode>
  <testNode name="d">
    <sample/>
  </testNode>
  <testNode name="b">
    <sample/>
  </testNode>
</root>

我想编写一个转换,复制所有内容,同时按name属性的值对testNode进行排序。

预期输出为:

<root xmlns:temp ="temp.com">
      <testNode name="a">
        <sample/>
      </testNode>
      <testNode name="b">
        <sample/>
      </testNode>
      <testNode name="b">
        <sample/>
      </testNode>
      <testNode name="c">
        <sample/>
      </testNode>
      <testNode name="d">
        <sample/>
      </testNode>
</root>

名称空间可能使我失望,但我似乎无法对结果进行排序。

到目前为止,我尝试过的XSLT是:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:temp="temp.com"
>
    <xsl:output method="xml" indent="yes"/>

    <xsl:template match="@* | node()">
        <xsl:copy>
          <xsl:apply-templates select="@* | node()">
          </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>

  <xsl:template name="temp:root">
    <xsl:copy>
      <xsl:apply-templates select="temp:testNode">
        <xsl:sort select="@name"/>
      </xsl:apply-templates>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

1 个答案:

答案 0 :(得分:1)

更新

鉴于您问题中的修订信息,当前的XSLT和源XML存在一些问题:

1)<xsl:template name="temp:root">应该是<xsl:template match="temp:root">。也就是说,您需要使用match来定位要转换的元素,而不是使用name来调用模板。

2)您的源XML声明了temp前缀,但未使用它。您应该使用:

<root xmlns="temp.com">
  <testNode name="a">
    <sample/>

...以创建默认的名称空间(前缀与XSLT的前缀不同并不重要;它们只是真实名称空间的别名)。然后,这意味着没有命名空间的所有元素都采用temp.com命名空间。

<temp:root xmlns:temp="temp.com">
  <temp:testNode name="a">
    <temp:sample/>

因此,您在temp.com命名空间中定义的元素加上temp前缀。

这是一个XSLT小提琴,其中的两个都已修复:http://xsltfiddle.liberty-development.net/3NzcBto

注意:如果您希望XSLT与名称空间无关,则还可以使用local-name()函数。

<xsl:template match="*[local-name()='root']">
  <xsl:copy>
    <xsl:apply-templates select="*[local-name()='testNode']">
      <xsl:sort select="@name"/>
    </xsl:apply-templates>
  </xsl:copy>
</xsl:template>

通常这不是一个好主意,因为调用该函数会带来性能开销,并且您会失去名称空间的好处;但在各种情况下都可能有帮助;特别是在不确定不确定性是否与命名空间相关的问题有关的开发过程中。


原始答案

使用此处记录的xsl:sort元素:https://www.w3schools.com/xml/xsl_sort.asp

示例:XSLT Fiddle

<xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:output method="xml" indent="yes" encoding="utf-8" /> <!-- keeping utf 8 rather than 16 as this will be big -->
  <xsl:strip-space elements="*"/>

  <!-- By default, copy everything as is -->
  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>

  <!-- but sort the child elements of our root element by their name attribute -->
  <xsl:template match="/root">
    <xsl:copy>
        <xsl:apply-templates select="@* | node()">
            <xsl:sort select="./@name" />
        </xsl:apply-templates>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>
相关问题