XSLT:有效地测试a';表亲';节点存在
我有以下XML:XSLT:有效地测试a';表亲';节点存在,xslt,xpath,xslt-1.0,Xslt,Xpath,Xslt 1.0,我有以下XML: <types> <type> <name>derived</name> <superType>base</superType> <properties> <property> <name>B1</name> </prop
<types>
<type>
<name>derived</name>
<superType>base</superType>
<properties>
<property>
<name>B1</name>
</property>
<property>
<name>D1</name>
</property>
</properties>
</type>
<type>
<name>base</name>
<properties>
<property>
<name>B1</name>
</property>
</properties>
</type>
</types>
请注意,已跳过节点/types/type[name='derived']/properties/property[name='B1']
,因为它在基类型中的形式为:/types/type[name='base']/properties/property[name='B1']
我提出了以下XSLT:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" omit-xml-declaration="yes"/>
<xsl:strip-space elements="*"/>
<!-- Do nothing for base class properties -->
<!-- Wouldn't be necessary if the match criteria could be applied in the select -->
<xsl:template match="property"/>
<xsl:template match="property[not(//type[name=current()/../../superType]/properties/property[name=current()/name])]">
<xsl:text>	</xsl:text>
<xsl:value-of select="name"/>
<xsl:text> </xsl:text>
</xsl:template>
<xsl:template match="types/type">
<xsl:value-of select="name"/>
<xsl:text> </xsl:text>
<xsl:apply-templates select="./properties"/>
<xsl:text> </xsl:text>
</xsl:template>
</xsl:stylesheet>
;
这是可行的(使用记事本++中的XML工具插件),但是不是(//type[name=current()/../../superType]/properties/properties[name=current()/name])
XPath表达式的效率非常低:当应用于一个200K行的XML文件时,转换需要280秒。如果没有此XPath表达式,转换只需2秒
有什么方法可以加快速度吗?测量一下速度
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="utf-8"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kPropertyByName" match="property" use="name" />
<xsl:template match="property">
<xsl:variable name="supertype" select="../../superType/text()" />
<xsl:if test="($supertype = '') or not ( key('kPropertyByName',name)/../../name[.=$supertype])">
<xsl:value-of select="concat('	',name,'
')" />
</xsl:if>
</xsl:template>
<xsl:template match="type">
<xsl:value-of select="concat(name,'
')" />
<xsl:apply-templates select="properties" />
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>
;
提高速度的最简单方法是使用优化的XSLT处理器——Saxon EE应该发现这个表达式可以从哈希索引中获益,将它从O(n^2)转换为O(n)
第二个最好的方法是按照Durkin的建议,使用键手动优化它。您确定使用的是XSLT 1.0处理器吗?在XSLT 1.0中,模式中不允许使用
current()。。。在一台现代个人电脑上,要比阿波罗号的飞行计算机进行更多的计算,才能把人们带到月球上和带回来。要提高性能,你可以做的一件事是使用更明确的路径(即/types/type
,而不是/type
)。否则,处理器将被迫遍历树中的每个节点,搜索类型元素。@Mads:同意这将在一定程度上加快速度;但是对于遍历树的每个节点:从概念上讲,可能是这样,但是好的处理器(例如Saxon)会在有利的时候按名称索引元素。因此,一个//foo
表达式并不像一个简单的实现那样昂贵。@DevNull:好问题。XMLTools插件不做XSLT,只做XPath,因此OP显然通过将其作为XPath表达式应用来测试其匹配模式。谢谢-这将时间缩短到了~7秒,这对于我来说足够快了。
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="utf-8"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kPropertyByName" match="property" use="name" />
<xsl:template match="property">
<xsl:variable name="supertype" select="../../superType/text()" />
<xsl:if test="($supertype = '') or not ( key('kPropertyByName',name)/../../name[.=$supertype])">
<xsl:value-of select="concat('	',name,'
')" />
</xsl:if>
</xsl:template>
<xsl:template match="type">
<xsl:value-of select="concat(name,'
')" />
<xsl:apply-templates select="properties" />
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>