xml - XSLT 排序 - 如何使用属性对父节点内的 xml 子节点进行排序

标签 xml sorting xslt xpath xslt-grouping

对于 XSLT 菜鸟来说,一开始是一件简单的事情,结果却是相当麻烦。

尝试对子节点/降序进行排序,但在向其父节点添加属性后,在 VS2010 中调试时收到错误:

"Attribute and namespace nodes cannot be added to the parent element after a text, comment, pi, or sub-element node has already been added."

假设我有这个简单的 XML:

<posts>
    <year value="2013">
        <post postid="10030" postmonth="1">
            <othernode></othernode>
            <othernode2></othernode2>
        </post>
        <post postid="10040" postmonth="2">
            <othernode></othernode>
            <othernode2></othernode2>
        </post>
        <post postid="10050" postmonth="3">
             <othernode></othernode>
             <othernode2></othernode2>
        </post>
    </year>
    <year value="2012">
        <post postid="10010" postmonth="1">
            <othernode></othernode>
            <othernode2></othernode2>
        </post>
        <post postid="10015" postmonth="2">
            <othernode></othernode>
            <othernode2></othernode2>
        </post>
        <post postid="10020" postmonth="3">
             <othernode></othernode>
             <othernode2></othernode2>
        </post>
    </year>
</posts>

我将 XPATH 传递给 xml 数据源以检索相关的 <year>节点,例如2013. 然后我需要对它的 child <post> 进行排序使用 postid 降序的节点,因此对于 <year value=2013> , postid=10050 将在呈现时首先显示。

所以,要明确一点:我只对在一个 <year> 中排序感兴趣节点。

在我将节点拆分为单独的节点之前(即 xml 是/posts/post),以下 XSLT 有效:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="xml" indent="yes" omit-xml-declaration="no"/>
    <xsl:strip-space elements="*"/>
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()">
                <xsl:sort select="@postid" data-type="text" order="descending"/>
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

由于上述错误,现在运行时 xmldatasource 为空。如果我按升序传递,显然会返回相同的 xml(无转换)

问题:如何更新上面的(或新的)XSLT 以容纳父节点属性(<year value="">)?通过研究,一个答案说“我需要在元素创建之前添加属性创建”。这在观察调试器时是有意义的,子节点是按降序排列的,但是年份标签缺少它的属性。但我对 XSLT 真的一无所知。看不出它太复杂,但就是不懂语言。

任何帮助,不胜感激。谢谢

最佳答案

那么您是说您只是将 XML 文档的一部分(一个 <year> 节点)传递给 XSLT 处理器?

您应该为年份使用一个单独的模板,因此这是唯一使用排序的模板。以下是怎样的:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes" omit-xml-declaration="no"/>
  <xsl:strip-space elements="*"/>

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

  <xsl:template match="year">
    <xsl:copy>
      <xsl:apply-templates select="@*" />
      <xsl:apply-templates select="post">
        <xsl:sort select="@postid" data-type="number" order="descending"/>
      </xsl:apply-templates>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

我认为上面的方法更好,但我认为你的错误的根本原因是它在进行排序时将属性与元素混合在一起。如果您只是这样做,您的原始 XSLT 可能会无错误地运行:

<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*">
        <xsl:apply-templates select="node()">
            <xsl:sort select="@postid" data-type="text" order="descending"/>
        </xsl:apply-templates>
    </xsl:copy>
</xsl:template>

关于xml - XSLT 排序 - 如何使用属性对父节点内的 xml 子节点进行排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14647638/

相关文章:

JAVA发送包含XML字符串的Post请求

java - 按从最高-> 最低的每个字符串解析的整数对 ArrayList<String> 进行排序?

c++ - 递归合并排序算法实现

.net - 从 XSLT 输出根中删除 XML 命名空间声明?

xml - xslt 测试属性是否存在

xslt - XSL 与区域化/国际化数字格式

xml - 如何使用外部 jar 和 Maven 编译/打包 Spark 2.0 项目

xml - 在 Delphi XE2 中解析 XML 时出现访问冲突

找不到 XML 注释文件 - Swagger

wpf - 禁用对 WPF MVVM 中 DataGrid 中自动生成的列进行排序