我是一名支持工程师,我们公司的产品允许XSLT转换定制输出.
为此目的我做了一个xsl转换.它适用于典型大小的源文件(几个100k),但偶尔会有一个非常大的(10M)源文件.在这种情况下,即使我让它磨几天也不会产生输出.
SW工程团队对其进行了测试并发现,对于转换和大型源文件确实非常慢(>天),如果我们的产品被编译为使用.Net 1.1中的转换引擎,但是如果他们用.Net编译它2.0,速度快(约1-2分钟).
显而易见的长期解决方案是,等待下一个版本.
从短期来看,我想知道以下几点:1)XSLT是否足够灵活,以便有更高效,效率更低的方法来实现相同的结果?例如,有可能我构造xsl的方式,变换引擎必须多次从源文件的开头迭代,越长越长,因为下一个结果片从开始越走越远?(Schlemiel the Painter),或者2)它是否更依赖于变换引擎如何解释xsl?
如果是2,我不想浪费大量时间来改进xsl(我不是一个很大的xsl天才,我很难实现我所做的一点......).
谢谢!
我不熟悉.NET实现,但是通常可以做一些事情来加速大型文档的处理:
为了检测何时开始新部分,我这样做了:
Run Code Online (Sandbox Code Playgroud)<xsl:if test="@TheFirstCol>preceding-sibling::*[1]/@TheFirstCol"这会导致很多或重复吗?
确实。您选择的算法是 O(N 2 ),并且无论使用哪种实现语言,如果有足够数量的同级,该算法都会非常慢。
这是使用密钥的有效算法:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:key name="kC1Value" match="@c1" use="."/>
<xsl:template match="/">
<xsl:for-each select="*/x[generate-id(@c1) = generate-id(key('kC1Value',@c1)[1])]">
<xsl:value-of select="concat('
',@c1)"/>
<xsl:for-each select="key('kC1Value',@c1)">
<xsl:value-of select="'
'"/>
<xsl:for-each select="../@*[not(name()='c1')]">
<xsl:value-of select="concat(' ', .)"/>
</xsl:for-each>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)
不幸的是,XslTransform (.Net 1.1) 的函数实现效率非常低generate-id()。
使用 XslTransform 可能会更快:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:key name="kC1Value" match="@c1" use="."/>
<xsl:template match="/">
<xsl:for-each select="*/x[count(@c1 | key('kC1Value',@c1)[1]) = 1]">
<xsl:value-of select="concat('
',@c1)"/>
<xsl:for-each select="key('kC1Value',@c1)">
<xsl:value-of select="'
'"/>
<xsl:for-each select="../@*[not(name()='c1')]">
<xsl:value-of select="concat(' ', .)"/>
</xsl:for-each>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)
当应用于以下小型 XML 文档时:
<t>
<x c1="1" c2="0" c3="0" c4="0" c5="0"/>
<x c1="1" c2="0" c3="1" c4="0" c5="0"/>
<x c1="1" c2="2" c3="0" c4="0" c5="0"/>
<x c1="1" c2="1" c3="1" c4="0" c5="0"/>
<x c1="2" c2="0" c3="0" c4="0" c5="0"/>
<x c1="2" c2="0" c3="1" c4="0" c5="0"/>
<x c1="2" c2="2" c3="0" c4="0" c5="0"/>
<x c1="2" c2="1" c3="1" c4="0" c5="0"/>
<x c1="3" c2="0" c3="0" c4="0" c5="0"/>
<x c1="3" c2="0" c3="1" c4="0" c5="0"/>
<x c1="3" c2="2" c3="0" c4="0" c5="0"/>
<x c1="3" c2="1" c3="1" c4="0" c5="0"/>
<x c1="3" c2="0" c3="0" c4="0" c5="0"/>
<x c1="3" c2="0" c3="1" c4="0" c5="0"/>
<x c1="3" c2="2" c3="0" c4="0" c5="0"/>
<x c1="3" c2="1" c3="1" c4="0" c5="0"/>
<x c1="4" c2="0" c3="0" c4="0" c5="0"/>
<x c1="4" c2="0" c3="1" c4="0" c5="0"/>
<x c1="4" c2="2" c3="0" c4="0" c5="0"/>
<x c1="4" c2="1" c3="1" c4="0" c5="0"/>
<x c1="5" c2="0" c3="0" c4="0" c5="0"/>
<x c1="5" c2="0" c3="1" c4="0" c5="0"/>
<x c1="5" c2="2" c3="0" c4="0" c5="0"/>
<x c1="5" c2="1" c3="1" c4="0" c5="0"/>
<x c1="5" c2="0" c3="0" c4="0" c5="0"/>
<x c1="5" c2="0" c3="1" c4="0" c5="0"/>
<x c1="6" c2="2" c3="0" c4="0" c5="0"/>
<x c1="6" c2="1" c3="1" c4="0" c5="0"/>
<x c1="6" c2="0" c3="0" c4="0" c5="0"/>
<x c1="6" c2="0" c3="1" c4="0" c5="0"/>
<x c1="6" c2="2" c3="0" c4="0" c5="0"/>
<x c1="6" c2="1" c3="1" c4="0" c5="0"/>
<x c1="7" c2="0" c3="0" c4="0" c5="0"/>
<x c1="7" c2="0" c3="1" c4="0" c5="0"/>
<x c1="7" c2="2" c3="0" c4="0" c5="0"/>
<x c1="7" c2="1" c3="1" c4="0" c5="0"/>
<x c1="8" c2="0" c3="0" c4="0" c5="0"/>
<x c1="8" c2="0" c3="1" c4="0" c5="0"/>
<x c1="8" c2="2" c3="0" c4="0" c5="0"/>
<x c1="8" c2="1" c3="1" c4="0" c5="0"/>
</t>
Run Code Online (Sandbox Code Playgroud)
两种解决方案都产生了想要的结果:
1
0 0 0 0
0 1 0 0
2 0 0 0
1 1 0 0
2
0 0 0 0
0 1 0 0
2 0 0 0
1 1 0 0
3
0 0 0 0
0 1 0 0
2 0 0 0
1 1 0 0
0 0 0 0
0 1 0 0
2 0 0 0
1 1 0 0
4
0 0 0 0
0 1 0 0
2 0 0 0
1 1 0 0
5
0 0 0 0
0 1 0 0
2 0 0 0
1 1 0 0
0 0 0 0
0 1 0 0
6
2 0 0 0
1 1 0 0
0 0 0 0
0 1 0 0
2 0 0 0
1 1 0 0
7
0 0 0 0
0 1 0 0
2 0 0 0
1 1 0 0
8
0 0 0 0
0 1 0 0
2 0 0 0
1 1 0 0
Run Code Online (Sandbox Code Playgroud)
从上面的小 XML 文件中,我通过复制每个元素 6250 次(使用另一个 XSLT 转换:))生成了一个 10MB XML 文件。
使用 10MB xml 文件和 XslCompiledTransform (.Net 2.0 + ),两种解决方案的转换时间如下:
解1:3.3秒。
解2:2.8秒。
使用 XslTransform (.Net 1.1),Solution2 运行了 1622 秒;大约是27分钟。