【问题标题】:Copy all elements while sorting by attribute value按属性值排序时复制所有元素
【发布时间】:2018-08-08 16:01:07
【问题描述】:

我有这个 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>

【问题讨论】:

  • 您可以编辑您的问题以显示您尝试过的 XSLT 吗?此外,您提到了名称空间,但您在 XML 中声明的名称空间前缀实际上并未在任何地方使用。您的 XML 是否准确(即它真的是 &lt;temp:testNode&gt; 而不仅仅是 &lt;testNode&gt; 吗?谢谢!
  • 这只是示例代码,其格式与我实际需要转换的格式相似。
  • 重要的是显示一个代表性输入文档,即一个实际上导致您描述的问题的输入文档。请编辑问题。
  • 这个样本格式相同,完美代表我的问题

标签: xml xslt xslt-1.0


【解决方案1】:

更新

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

1) &lt;xsl:template name="temp:root"&gt; 应该是 &lt;xsl:template match="temp:root"&gt;。即您需要使用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 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>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-05-21
    • 2015-10-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-10
    • 1970-01-01
    相关资源
    最近更新 更多