xslt sort输出xml

时间:2011-10-03 00:56:55

标签: xslt sorting xslt-2.0

我正在尝试找到以下问题的解决方案。

我正在开发XSLT转换(现在大约40KB大),它正在将非常复杂的XML转换为一个非常简单的结构,它希望如下:

<Records>
<Record key="XX">
</Record> 
<Record key="XX1">
</Record>
<Record key="XX2">
</Record>
<Record key="XX3">
</Record>
</Records>

我希望根据Records/Record/@key值对此输出XML进行排序。 问题是我的XSLT产生的输出未排序,由于其复杂性,我无法在那里排序。 是否可以在输出XML上应用xsl:sort?我知道我可以准备另一个XSLT转换,但在我的情况下,这不是解决方案,因为我只限于一个XSLT ..请帮助!...

3 个答案:

答案 0 :(得分:3)

  

是否可以在输出XML上应用xsl:sort?

是的,多通道处理 可能,尤其是在XSLT 2.0中,您甚至不需要在结果上应用xxx:node-set()扩展名,因为臭名昭着的RTF类型不再存在:

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="/">
  <xsl:variable name="vPass1">
   <!--
        Put/Invoke your cirrent code here   
        to generate the following           
-->
    <Records>
      <Record key="XX3">
      </Record>
      <Record key="XX2">
      </Record>
      <Record key="XX4">
      </Record>
      <Record key="XX1">
      </Record>
    </Records>
  </xsl:variable>

  <xsl:apply-templates select="$vPass1/*"/>
 </xsl:template>

 <xsl:template match="Records">
  <Records>
   <xsl:perform-sort select="*">
    <xsl:sort select="@key"/>
   </xsl:perform-sort>
  </Records>
 </xsl:template>
</xsl:stylesheet>

对任何XML文档执行此转换(未使用/忽略)时,会生成所需的,正确的,已排序的结果

<Records>
   <Record key="XX1"/>
   <Record key="XX2"/>
   <Record key="XX3"/>
   <Record key="XX4"/>
</Records>

在XSLT 1.0中,结果从RTF类型到普通树的额外转换几乎相同

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:ext="http://exslt.org/common"
 exclude-result-prefixes="ext">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="/">
  <xsl:variable name="vrtfPass1">
   <!--
        Put/Invoke your cirrent code here   
        to generate the following           
-->
    <Records>
      <Record key="XX3">
      </Record>
      <Record key="XX2">
      </Record>
      <Record key="XX4">
      </Record>
      <Record key="XX1">
      </Record>
    </Records>
  </xsl:variable>

  <xsl:variable name="vPass1"
                select="ext:node-set($vrtfPass1)"/>

  <xsl:apply-templates select="$vPass1/*"/>
 </xsl:template>

 <xsl:template match="Records">
  <Records>
   <xsl:for-each select="*">
    <xsl:sort select="@key"/>

    <xsl:copy-of select="."/>
   </xsl:for-each>
  </Records>
 </xsl:template>
</xsl:stylesheet>

答案 1 :(得分:1)

40Kb是一个样式表的很多代码。当事情达到这种规模时,通常最好将转换分成较小的转换管道。如果您有这样的管道架构,那么在最后添加排序步骤是微不足道的。根据您的要求,有许多技术可用于管理转换管道(XProc,Orbeon,xmlsh,ant,Coccoon)。流水线操作的好处是它可以使代码保持模块化和可重用。

答案 2 :(得分:0)

作为上面Dimitre优秀解决方案的附录,如果您使用的是XSLT 1.0处理器(例如.NET),以下内容可以为您提供有关如何使用节点集的指针: http://www.xml.com/pub/a/2003/07/16/nodeset.html#tab.namespaces

就我而言,我使用的是.NET 1.1(即MSXML),解决方案看起来像是:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:msxsl="urn:schemas-microsoft-com:xslt">
    <xsl:template match="/">            
        <xsl:variable name="vrtfPass1">
            <Records xmlns="">  
                    <xsl:apply-templates />
            </Records >            
        </xsl:variable>
        <xsl:variable name="vPass1" select="msxsl:node-set($vrtfPass1)"/>
        <xsl:apply-templates select="$vPass1/*" mode="sorting"/>
    </xsl:template>
    <xsl:template match="Records" mode="sorting">
        <Records>
       <xsl:for-each select="Record">
        <xsl:sort select="@key"/>
        <xsl:copy-of select="."/>
       </xsl:for-each>
      </Records>
    </xsl:template>
</xsl:stylesheet>