在XSLT中优化递归

问题描述 投票:3回答:1

我有以下XML。它包含书籍和参考。一些参考文献追溯到第1册,例如第4册参考第3册,第3册涉及第1册。

<?xml version="1.0" encoding="UTF-8"?>
<sandbox>
    <book xml:id="h1">
        <name>Book 1</name>
    </book>
    <book xml:id="h2">
        <name>Book 2</name>
    </book>
    <book xml:id="h3">
        <name>Book 3</name>
        <ref target="#h1"/>
    </book>
    <book xml:id="h4">
        <name>Book 4</name>
        <ref target="#h3"/>
    </book>
</sandbox>

我编写了以下XSLT,它通过追溯对原始源的引用并添加相应的文本语句来丰富代码:

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="2.0" xmlns:sandbox="sandbox.org"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>

    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:function name="sandbox:trace">
        <xsl:param name="target"/>
        <xsl:choose>
            <xsl:when test="document($target)/ref">
                <xsl:value-of select="sandbox:trace(document($target)/ref/@target)"/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="document($target)/name"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:function>

    <xsl:template match="ref">
        <xsl:copy>
            <xsl:copy-of select="@*"/>
            <xsl:text>This book refers to </xsl:text>
            <xsl:value-of select="sandbox:trace(@target)"/>
            <xsl:text>!</xsl:text>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

它产生所需的输出:

<?xml version="1.0" encoding="UTF-8"?>
<sandbox>
    <book xml:id="h1">
        <name>Book 1</name>
    </book>
    <book xml:id="h2">
        <name>Book 2</name>
    </book>
    <book xml:id="h3">
        <name>Book 3</name>
        <ref target="#h1">This book refers to Book 1!</ref>
    </book>
    <book xml:id="h4">
        <name>Book 4</name>
        <ref target="#h3">This book refers to Book 1!</ref>
    </book>
</sandbox>

我的问题:这是一种“好”的方式还是更适合这项任务的解决方案?

xml xslt recursion xslt-2.0
1个回答
3
投票

给定引用和id我通常很想使用xsl:keykey函数,在你的情况下因为输入使用xml:id属性甚至不是必要的,因为你可以简单地使用id函数然后找到引用的元素。所以这看起来更简单:

<xsl:stylesheet version="2.0" xmlns:sandbox="sandbox.org"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    exclude-result-prefixes="xs sandbox">
    <xsl:output indent="yes"/>

    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:function name="sandbox:check-ref" as="xs:string">
        <xsl:param name="target" as="element(book)"/>
        <xsl:sequence select="if ($target/ref)
                              then sandbox:check-ref($target/ref/id(substring(@target, 2)))
                              else $target/name"/>
    </xsl:function>

    <xsl:template match="ref">
        <xsl:copy>
            <xsl:copy-of select="@*"/>
            <xsl:text>This book refers to </xsl:text>
            <xsl:value-of select="sandbox:check-ref(id(substring(@target, 2)))"/>
            <xsl:text>!</xsl:text>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

我还添加了类型注释作为XSLT 2处理器的实现者,如Michael Kay通常指出它是一种提高类型安全性和代码性能的方法。

© www.soinside.com 2019 - 2024. All rights reserved.