我正在尝试找到以下问题的解决方案。
我正在开发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 ..请帮助!...
答案 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>