XSLT:有效地测试是否存在'堂兄'节点

时间:2012-11-14 23:25:50

标签: xslt xpath xslt-1.0

我有以下XML:

<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>

我要将其转换为此输出:

derived
    D1

base
    B1

请注意,已跳过节点/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>&#x09;</xsl:text>
        <xsl:value-of select="name"/>
        <xsl:text>&#10;</xsl:text>
    </xsl:template>

    <xsl:template match="types/type">
        <xsl:value-of select="name"/>
        <xsl:text>&#10;</xsl:text>
        <xsl:apply-templates select="./properties"/>
        <xsl:text>&#10;</xsl:text>
    </xsl:template>

</xsl:stylesheet>

这可行(使用Notepad ++中的XML Tools插件),但not(//type[name=current()/../../superType]/properties/property[name=current()/name]) XPath表达式非常低效:当应用于200K行XML文件时,转换需要 280秒。如果没有此XPath表达式,转换只需 2秒

有什么方法可以加快速度吗?

2 个答案:

答案 0 :(得分:1)

测量速度......

<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('&#x09;',name,'&#x0A;')" /> 
  </xsl:if>  
</xsl:template>  

<xsl:template match="type">
  <xsl:value-of select="concat(name,'&#x0A;')" />
  <xsl:apply-templates select="properties" />
  <xsl:text>&#x0A;</xsl:text>
</xsl:template>  

</xsl:stylesheet>  

答案 1 :(得分:1)

加速它的最简单方法是使用优化的XSLT处理器--Saxon-EE应该将此表达式视为可以从哈希索引中受益的表达式,将其从O(n ^ 2)转换为O(n)。

下一个最好的方法是使用密钥手动优化它,如Durkin所建议的那样。