【问题标题】:How to add a new node at the innermost level如何在最内层添加新节点
【发布时间】:2017-10-13 09:17:43
【问题描述】:

在我的 xsl 中,已经为 para、graphic 等元素定义了模板。示例如下:

    <xsl:template match="para">    
            <fo:block>
            <xsl:apply-templates />             
      </fo:block>
  </xsl:template>

但是我想在最内层添加一个额外的节点以防特定属性值。例如,如果元素的属性值为 changeStatus = new/changed,我需要在其他节点内添加 'fo:change-bar-begin' 元素。示例 xml:

    <para changeStatus="new">
This is a paragraph that has change bars applied to the whole paragraph. </para>

输出应该是(这里 fo:block 节点来自 xsl 中的其他模板):

<fo:block>
<fo:change-bar-begin change-bar-style="solid"/>
            This is a paragraph that has change bars applied to the whole paragraph.
<fo:change-bar-end/>            
      </fo:block>

我正在使用此代码,但在某些情况下,它会在外部级别添加节点,而在其他情况下,它会删除其他模板中定义的节点(例如 fo:block)。

 <xsl:template match="*[@changeStatus='new' or @changeStatus='changed']">
         <fo:change-bar-begin change-bar-style="solid"/>

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

         <fo:change-bar-end/>
 </xsl:template>

在这里,para 只是一个示例,我需要此代码来处理许多元素,因此不能选择使用 call-template。 请建议最好的方法。

【问题讨论】:

  • 这并不容易,如果属性只是在其他内容之前添加内容,您可以将&lt;fo:block&gt;&lt;xsl:apply-templates /&gt;&lt;/fo:block&gt; 更改为&lt;fo:block&gt;&lt;xsl:apply-templates select="@* | node()" /&gt;&lt;/fo:block&gt; 并添加匹配@changeStatus[. = ('new', 'changed')] 的模板以输出例如&lt;fo:change-bar-begin change-bar-style="solid"/&gt;。但是,如果您需要让属性在不同位置创建结果元素,则需要 apply-templates 两次并使用不同的模式。

标签: xml xslt


【解决方案1】:

每次选择一个节点进行转换时,只有一个模板与之匹配并应用,除非所选模板可能指示其他模板应用于同一节点。因此,如果您添加一个模板来匹配已经具有匹配模板的节点,那么您将获得一个模板或另一个模板的效果,而不是两者的组合。

现在,如果您想将change-bar 围绕现有模板生成的最外层元素,那将是一回事,但将change-bar 放在里面 em> 他们将需要修改或克隆所有需要此类处理的现有模板。我强烈推荐“修改”替代方案,因为维护它会容易得多。

例如,让您的模板匹配para 元素。你可以这样修改它:

<xsl:template match="para">
  <fo:block>
    <xsl:apply-templates select="." mode="cb-begin-choice"/>
    <xsl:apply-templates />             
    <xsl:apply-templates select="." mode="cb-end-choice"/>
  </fo:block>
</xsl:template>

对于所有模板,您会支持这一点,如下所示:

<xsl:template match="*" mode="cb-begin-choice">
  <xsl:if test="@changeStatus='new' or @changeStatus='changed'">
    <fo:change-bar-begin change-bar-style="solid"/>
  </xsl:if>
</xsl:template>

<xsl:template match="*" mode="cb-end-choice">
  <xsl:if test="@changeStatus='new' or @changeStatus='changed'">
    <fo:change-bar-end/>
  </xsl:if>
</xsl:template>

将更改栏详细信息提取到这两个附加模板可以更轻松地进行这些更改,并使修改后的模板更加清晰。它还为您提供了一个地方来控制更改栏的详细信息,因此,如果您想更改它们,只需在这两个模板中即可。

如果您愿意,您可以在命名模板和xsl:call-template 之上实现相同的东西,而不是模式和xsl:apply-templates。

【讨论】:

    猜你喜欢
    • 2017-10-06
    • 1970-01-01
    • 1970-01-01
    • 2022-09-22
    • 1970-01-01
    • 2022-01-22
    • 1970-01-01
    • 1970-01-01
    • 2018-01-28
    相关资源
    最近更新 更多