首页 > 解决方案 > 按属性值排序时复制所有元素

问题描述

我有这个 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 属性的值对 testNodes 进行排序。

预期的输出是:

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

标签: xmlxsltxslt-1.0

解决方案


更新

鉴于您问题中的修订信息,您当前的 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 Fiddle: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 小提琴

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

推荐阅读