1

我已将某些语句分开,以应用于单独模板中的特定元素。
该元素在一个模板中处理,其中包含一个语句<xsl:apply-templates/>
有没有办法让第一个模板中刚刚处理的元素在第二个(未命名的)模板中重新处理?
当然我知道我可以使用命名模板并从第一个模板中调用它,但我只是想知道是否可以这样完成。为了给你一些可以使用的东西,这里是我正在处理的东西的一个高度简化的模型。
我有一个包含表格的 html 输入文件:

<?xml version="1.0" encoding="UTF-8"?>
<table>
    <tbody>
        <tr>
            <td>content</td>
            <td></td>
            <td/>
        </tr>
    </tbody>
</table>

我希望block在每个td元素中都有一个元素,td如果有的话,它包含字符串内容,或者当td元素本身为空时为空。我尝试了以下方法(再次注意,我不希望对第一个模板进行重大更改!):

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

    <xsl:template match="*">
        <xsl:copy>
            <xsl:attribute name="test"><xsl:value-of select="local-name()"/></xsl:attribute>
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="td/text()">
        <block><xsl:value-of select="."/></block>
    </xsl:template>
</xsl:stylesheet>

添加的属性只是第一个模板中正在完成的内容的建模示例。

作为输出

<?xml version="1.0" encoding="UTF-8"?>
<table test="table">
    <tbody test="tbody">
        <tr test="tr">
            <td test="td">
                <block>content</block>
            </td>
            <td test="td"/>
            <td test="td"/>
        </tr>
    </tbody>
</table>

我希望得到

<?xml version="1.0" encoding="UTF-8"?>
<table test="table">
    <tbody test="tbody">
        <tr test="tr">
            <td test="td">
                <block>content</block>
            </td>
            <td test="td">
                <block/>
            </td>
            <td test="td">
                <block/>
            </td>
        </tr>
    </tbody>
</table>

很明显为什么它不起作用:空td元素中没有文本节点,因此第二个模板的 Xpath 表达式不匹配这些节点。
所以我开始思考如何td通过第二个模板重新处理元素本身。当然,我不能使用match="td[some condition]",因为那样第一个模板将不会被应用。
而且我也不能使用match= "self::td",因为self模板匹配属性中不允许使用轴(当然条件除外),或者更确切地说,它需要一个您在开始匹配时还没有的当前节点。
那么第二个模板是否有合适的 Xpath 表达式可以满足我的需求?
或者是否有另一种简单的方法可以为刚刚在一个模板中处理的元素触发另一个(未命名的)模板?
注意:我不是在寻找在第二个模板上添加属性的简单更新。我希望第一个模板添加属性,第二个添加块元素。

4

4 回答 4

2

xsl:next-match在 XSLT 2.0 或xsl:apply-importsXSLT 1.0 中查看。

于 2012-04-20T16:13:14.003 回答
2

尝试添加另一个“moded”模板。您应该可以使用xsl:apply-templates该模式。

示例 xsl:模板:

<xsl:template match="td" mode="test">
  <bar>test</bar>
</xsl:template>

示例 xsl:应用模板:

<xsl:template match="td">
  <foo><xsl:apply-templates select="ancestor-or-self::td" mode="test"/></foo>
</xsl:template>
于 2012-04-20T18:21:53.497 回答
1

一个 XSLT 1.0 解决方案,它使用<xsl:apply-imports>

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

    <xsl:import href="block.xsl" />

    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

    <xsl:template match="*">
        <xsl:copy>
            <xsl:attribute name="test"><xsl:value-of select="local-name()"/></xsl:attribute>
            <xsl:if test="self::td">
                <xsl:apply-imports/>
            </xsl:if>  
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

导入的样式表block.xsl

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

    <xsl:template match="td">
        <block><xsl:value-of select="."/></block>
    </xsl:template>

</xsl:stylesheet>

一个 XSLT 2.0 解决方案,它使用<xsl:next-match>

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

    <xsl:template match="*">
        <xsl:copy>
            <xsl:attribute name="test"><xsl:value-of select="local-name()"/></xsl:attribute>
            <xsl:if test="self::td">
                <!--apply the next template that would match this td element -->
                <xsl:next-match/>
            </xsl:if>  
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:template>

    <!--calculated priority of "td" would be higher than "*",
        so explicitly setting a lower priority -->
    <xsl:template match="td" priority="-1">
        <block><xsl:value-of select="."/></block>
    </xsl:template>

</xsl:stylesheet>
于 2012-04-20T23:51:28.467 回答
0

为了完整起见,我添加了我通过 DevNull 的回答得出的解决方案。

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

    <xsl:template match="*">
        <xsl:copy>
            <xsl:attribute name="test"><xsl:value-of select="local-name()"/></xsl:attribute>
            <xsl:apply-templates/>
            <xsl:apply-templates mode="td" select="self::td"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="td" mode="td">
        <block><xsl:value-of select="."/></block>
    </xsl:template>

    <xsl:template match="td/text()"/>
</xsl:stylesheet>

这导致

<?xml version="1.0" encoding="UTF-8"?>
<table test="table">
    <tbody test="tbody">
        <tr test="tr">
            <td test="td">
                <block>content</block>
            </td>
            <td test="td">
                <block></block>
            </td>
            <td test="td">
                <block></block>
            </td>
        </tr>
    </tbody>
</table>

注意添加的模板,以防止默认模板第二次处理 td 文本节点。

于 2012-04-20T18:53:51.760 回答