问题:SVG <use>元素在XSL模板中转换为字符串

时间:2019-05-03 15:05:09

标签: xslt svg xlink

我对XSL,XPATH等还很陌生。一些代码是我的,有些是别人的。

问题::当下面的模板与我在下面进一步概述的模板一起调用时,if测试之后的所有xsl:text节点都将输出为字符串而不是HTML节点,因此不会呈现图标。

这个问题与理解为什么?发生了什么有关。我的确切问题在这篇文章的底部。

因此,我有一个模板,该模板可生成带有<use>元素的SVG元素,以与SVG精灵一起使用。

<xsl:template name="svg-link">

  <xsl:param name="svg-id"/>
  <xsl:param name="svg-class"/>
  <xsl:param name="svg-title"/>

  <span class="{$svg-class} svgstore svgstore--{$svg-loc}">
    <svg>
      <xsl:if test="$svg-title != ''">
        <title><xsl:value-of select="$svg-title"/></title>
      </xsl:if>
      <xsl:text disable-output-escaping="yes">&lt;use xlink:href="</xsl:text>
      <xsl:value-of select="concat('#', $svg-loc)" />
      <xsl:text disable-output-escaping="yes">"&gt;&lt;/use&gt;</xsl:text>
    </svg>
  </span>

</xsl:template>

各种模板都调用/应用此模板。我特别有一个问题。我们有两个由CMS实施的代码段,它们输出相同的标记,但是这些代码段的配置实施方式不同,即页面模板A与页面模板B。所涉及的代码段由多个XSL模板组成。模板的组织方式如下:

  • 摘要模板:所有呼叫者的摘要的入口点。接受与CSS类有关的几个参数。为代码段创建一些包装器元素。调用以下模板。
  • “模型”模板:是每个页面模板都需要定义的模板。如上所述,每个页面模板使用不同的方法来实现代码段的配置选项。这样做的目的是使以下模板与该代码段的配置方式无关,因为该模板负责了解这些详细信息并将其传递给以下模板。
  • 代码段项目模板:根据“模型”模板传递给它的信息,呈现代码段的大部分标记。

这是上面演示的一些简化的伪代码:

<xsl:template name="snippet">

  <xsl:param name="outer-classes"/>
  <xsl:param name="inner-classes"/>

  <xsl:variable name="items">
    <xsl:call-template name="snippet-model"/>
  </xsl:variable>

  <!-- Render Snippet if it has content. -->
  <xsl:if test="count( $items )">
    <div class="{ $outer-classes }">
      <div class="{ $inner-classes }">
        <xsl:copy-of select="$items">
      </div>
    </div>
  </xsl:if>

</xsl:template>

<!-- Placeholder. Defined by each page template. -->
<xsl:template name="snippet-model"/>

<xsl:template name="snippet-item">

  <xsl:param name="a"/>
  <xsl:param name="b"/>
  <xsl:param name="b"/>

  <div class="snippet-item {$a}">

    <xsl:apply-templates select="$b"/>

    <xsl:call-template name="svg-link">
      <xsl:with-param name="svg-id">alpha</xsl:with-param>
      <xsl:with-param name="svg-class">alpha</xsl:with-param>
      <xsl:with-param name="svg-title">The Title</xsl:with-param>
    </xsl:call-template>
  </div>

</xsl:template>

以及页面模板如何使用上述内容的示例:

<xsl:template match="table[@class = 'snippet-alpha']">

  <xsl:call-template="snippet">
    <xsl:with-param name="outer-classes">page-template-a other</xsl:with-param>
    <xsl:with-param name="inner-classes">some-template-modifier</xsl:with-param>
  </xsl:call-template>

</xsl:template>

<!-- Template definition of `snippet-model` template. -->
<xsl:template name="snippet-model">

  <!-- Another page template might not use `tbody/tr` to loop over. -->
  <xsl:for-each select="tbody/tr">
    <xsl:call-template="snippet-item">
      <xsl:with-param name="a" select="td[1]"/>
      <xsl:with-param name="b" select="td[2]"/>
      <xsl:with-param name="c" select="td[3]"/>
    </xsl:call-template>
  </xsl:for-each>

</xsl:template>

我已将问题范围缩小为xsl:variable捕获xsl:call-template模板中snippet的结果。和/或稍后使用xsl:copy-of对该变量进行引用。

我尝试了什么?

在下面,我有工作非工作解决方案,但我都没有完全理解为什么它们可能起作用或不起作用。

  • 工作:为包含xmlns:xlink="http://www.w3.org/1999/xlink"模板的文件向xsl:stylesheet添加svg-link,然后修改svg-link模板,请参见下面的代码清单。
  • 工作::而不是输出xsl:variable的值,该值用xsl:call-template捕获xsl:copy-of的结果。我用另一个xsl:copy-of替换了xsl:call-template,该变量与在变量内进行的调用相同。
  • 不起作用:使用xsl:sequence代替了xsl:copy-of
  • 不起作用::尝试使用xsl:variable属性捕获xsl:call-template结果的as数据类型(?)。即as="node()*"
<xsl:template name="svg-link">

  <xsl:param name="svg-id"/>
  <xsl:param name="svg-class"/>
  <xsl:param name="svg-title"/>

  <span class="{$svg-class} svgstore svgstore--{$svg-loc}">
    <svg>
      <xsl:if test="$svg-title != ''">
        <title><xsl:value-of select="$svg-title"/></title>
      </xsl:if>
      <use xlink:href="{concat( '#', $svg-loc )}"></use>
    </svg>
  </span>

</xsl:template>

问题:为什么基于调用svg-link的结果,xsl:call-template模板的某些内容作为字符串(而不是HTML)输出为字符串(而不是HTML)被捕获/被呼叫?如您所见,我有有效的和无效的解决方案-我想知道为什么。谢谢!

1 个答案:

答案 0 :(得分:1)

首先,disable-output-escaping是可选的序列化功能。此外,当XSLT 2或3规格根本无法使用时,它们会列出来,请参阅https://www.w3.org/TR/xslt-30/#disable-output-escaping

  

如果为xsl:value-ofxsl:text禁用了输出转义   指令在临时输出状态有效时进行评估,   禁用输出转义的请求将被忽略。

https://www.w3.org/TR/xslt-30/#dt-temporary-output-state

  

xsl:变量,xsl:param,xsl:with-param,xsl:function,xsl:key,   xsl:sort,xsl:accumulator-rule和xsl:merge-key始终会评估   临时包含在其包含的序列构造函数中的指令   输出状态

因此在您的xsl:variable内,任何disable-output-escaping都无法工作。

完全不需要使用它来构造SVG use元素,您可以创建任何结果元素作为文字结果元素,例如<use xlink:href="{concat( '#', $svg-loc )}"></use>(在该名称空间的属性范围内具有适当的XLink名称空间声明),或者,如果需要计算名称或名称空间的一部分,请使用xsl:element