【问题标题】:XSL: affecting the same nodes with more than one templateXSL:使用多个模板影响相同的节点
【发布时间】:2011-10-28 09:11:22
【问题描述】:

据我了解,通常在 XSL 中,每个节点可能只受一个模板的影响。一旦一个节点受到模板的影响,它 - 并且至关重要的是,它的子/后代 - 不会受到任何其他模板的进一步影响。

但有时,您希望使用一个模板影响外部节点,然后使用另一个模板影响其子/后代。以下是解决此问题的可取方法吗?其目的是为每个节点添加属性“attr”。

源 XML: 你好! 孙子>

XSL:

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

    <xsl:template match='child'>
        <child>
            <xsl:attribute name='attr'>val</xsl:attribute>
            <xsl:apply-templates select='./*' />
        </child>
    </xsl:template>

    <xsl:template match='greatgrandchild'>
        <greatgrandchild>
            <xsl:attribute name='attr'>val</xsl:attribute>
            <xsl:value-of select='.' />
        </greatgrandchild>
    </xsl:template>

</xsl:stylesheet>

我在正确的路线上吗?

提前致谢。

【问题讨论】:

    标签: xml templates xslt


    【解决方案1】:

    坦率地说,是否处理节点完全取决于您的模板和内置模板(可以覆盖)。如果foo 元素节点的模板执行&lt;xsl:apply-templates/&gt;,则处理子节点,如果执行&lt;xsl:apply-templates select="ancestor::*"/&gt;,则处理其祖先元素,仅举两个示例。当然,如果您为某个不使用apply-templates 进行进一步处理的元素编写模板,那么处理就会停止。

    对于您的示例,如果您想为所有元素节点添加一个属性,那么您只需要

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

    即标识转换模板加一为元素节点添加新属性。

    【讨论】:

    • 非常感谢。几个问题:1)第一个模板是否与根不匹配?如果是这样,为什么有'@* | node()' 而不仅仅是'/'? 2) 你能解释一下第二个模板中发生了什么吗? 3) 我原来的 XSL 只有一个 xsl:copy - 之后,节点是手动创建的( 等)。为什么你的每个模板中都有一个 xsl:copy?感谢您的耐心 - XSL 创建 XML 而不是 HTML 的想法对我来说有点新。
    • 第一个模板匹配属性节点(@*)和node()匹配的所有类型节点,即元素节点、注释节点、处理指令节点、文本节点(或者描述为其他方式“节点()匹配除属性节点和根节点之外的任何节点”)。不必有带有match="/" 的模板,因为它是内置的。至于有两个模板的方法,第一个单独逐个节点,逐级复制节点。它可以作为样式表的起始方法,您可以通过添加模板有选择地添加/删除/更改节点。
    【解决方案2】:

    据我了解,通常在 XSL 中,每个节点可能只受一个节点的影响 模板。一旦节点受到模板的影响, 它——重要的是,它的孩子/后代——不受影响 通过任何其他模板进一步。

    这些陈述均不属实。可以选择不同的模板在同一个节点上执行——这完全取决于&lt;xsl:apply-templates&gt; 指令,这些指令导致选择特定的模板执行。在如何应用和选择模板方面有很大的灵活性,例如导入优先级、优先级、模式等。

    甚至可以使模板对节点(用作节点)具有双重性,就像在 FXSL 中所做的那样。

    但有时,您想用一个模板影响外部节点, 然后用另一个模板影响其子/后代。会不会 以下是一个明智的方法吗?其目的是添加 将“attr”属性赋予每个节点。

    这是使用最基本的 XSLT 设计模式轻松实现的——覆盖identity rule

    <xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output omit-xml-declaration="yes" indent="yes"/>
     <xsl:strip-space elements="*"/>
    
     <xsl:template match="node()|@*">
         <xsl:copy>
           <xsl:apply-templates select="node()|@*"/>
         </xsl:copy>
     </xsl:template>
    
     <xsl:template match="*">
      <xsl:variable name="val" select="count(ancestor::node())"/>
      <xsl:copy>
        <xsl:attribute name="depth">
          <xsl:value-of select="$val"/>
        </xsl:attribute>
          <xsl:apply-templates select="node()|@*"/>
      </xsl:copy>
     </xsl:template>
    </xsl:stylesheet>
    

    在提供的 XML 文档上应用此转换时(已更正为格式正确):

    <root>
        <child>
            <grandchild>
                <greatgrandchild>hello! </greatgrandchild>
            </grandchild>
        </child>
    </root>
    

    它复制每个节点并为每个元素添加一个depth 属性。新增属性的值是元素的“深度”

    <root depth="1">
       <child depth="2">
          <grandchild depth="3">
             <greatgrandchild depth="4">hello! </greatgrandchild>
          </grandchild>
       </child>
    </root>
    

    【讨论】:

    • 谢谢,迪米特。我确实说过“据我所知”:) 一直在学习。
    猜你喜欢
    • 2023-03-29
    • 1970-01-01
    • 2014-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-02
    • 1970-01-01
    • 2018-03-25
    相关资源
    最近更新 更多