如何使用XSLT更改标记放置,但不提及节点名称

时间:2017-11-20 12:48:22

标签: xslt

如何使用XSLT更改标记位置,但不提及元素名称。即我们不知道该元素应该是<br/>标记的父元素。

示例:如果<br/>标记为任何元素的第一个子节点,但不是<p><td>。此案例<br/>标记应放在元素之外。在这里,我给出了输入和所需的输出:

输入:

<p>Test <b><i><br/>case</i></b></p>

必需输出:

<p>Test <br/><b><i>case</i></b></p>

2 个答案:

答案 0 :(得分:1)

从身份转换开始。为模板提供名称(例如idt-elem)。

添加与第一个孩子为br的任何元素匹配的模板。如果您的输入是XHTML,并且您已将前缀xh绑定到XHTML命名空间,则此模板的可能匹配模式为*[child::node()[1]/self::xh:br]。在该模板中,首先发出br元素,然后调用模板idt-elem

如果这应该仅匹配ptd以外的元素,则为这两个元素添加更高优先级,调用idt-elem

br元素添加模板,这些元素是除ptd以外的任何元素的第一个子元素。让它什么都不做。

生成的样式表会将初始br元素移出父母,并立即让他们的父母留下兄弟姐妹。要处理像<b><i><br/>...</i></b>这样的情况,您需要运行两次样式表。通常,运行它直到其输出不再与其输入不同。 (或者为根节点添加模板,测试是否要移动任何br元素,否则发出消息。)

答案 1 :(得分:0)

我们了解到,您需要将<br>作为第一个孩子移动,而不需要在树上添加文本到<p><td>级别。我已经扩展了示例以涵盖更多可能的案例:

<test>
    <!-- these cases are ok -->
    <p>Test <br/>case</p>
    <p>Test <br/><b>case</b></p>
    <p>Test <br/><i>case</i></p>
    <p>Test <i>case<br/></i></p>
    <p>Test <b><i>case</i><br/></b></p>
    <p>Test <b><i>case<br/>case<br/></i></b></p>
    <!-- here should happen something -->
    <p>Test <b><br/>case</b></p>
    <p>Test <b><i><br/>case</i></b></p>
    <p>Test <i><br/><b>case</b></i></p>
    <!-- mixed case -->
    <p>Test <i><b><br/>case<br/></b></i></p>
    <!-- edit: additional example -->
    <p><br/><x>0.03-</x></p>
</test>

现在,替换过程需要组件:首先,删除位于错误位置的所有br,然后,在所需位置创建它们的副本。以这种方式识别相关的br:如果前兄弟或其后代是文本节点,则br需要保持原样。在其他情况下,它可以在树上复制。就是这样。可以通过身份模板复制所有其他元素。

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

<xsl:template
    match="p/*
           [descendant::br
           [not(preceding-sibling::node()
           /descendant-or-self::text())]]">
    <xsl:copy-of select="descendant::br
           [not(preceding-sibling::node()
           /descendant-or-self::text())]"/>
    <xsl:copy>
        <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
</xsl:template>

<!--<xsl:template match="p//br
    [not(preceding-sibling::node()/descendant-or-self::text())]"/>-->
<!-- edit: fixed version -->
<xsl:template match="p/*//br
                     [not(preceding-sibling::node()
                     /descendant-or-self::text())]"/>

这应该产生以下结果:

<test>
    <!-- these cases are ok -->
    <p>Test <br/>case</p>
    <p>Test <br/><b>case</b></p>
    <p>Test <br/><i>case</i></p>
    <p>Test <i>case<br/></i></p>
    <p>Test <b><i>case</i><br/></b></p>
    <p>Test <b><i>case<br/>case<br/></i></b></p>
    <!-- here should happen something -->
    <p>Test <br/><b>case</b></p>
    <p>Test <br/><b><i>case</i></b></p>
    <p>Test <br/><i><b>case</b></i></p>
    <!-- mixed case -->
    <p>Test <br/><i><b>case<br/></b></i></p>
    <!-- edit: additional example -->
    <p><br/><x>0.03-</x></p>
</test>