【问题标题】:How can I pass HTML-element as parameter to XSLT function?如何将 HTML 元素作为参数传递给 XSLT 函数?
【发布时间】:2012-05-22 13:54:58
【问题描述】:

我在 XSLT 文件中使用以下 XSLT 函数来生成 XHTML 输出:

<xsl:function name="local:if-not-empty">
   <xsl:param name="prefix"/>
   <xsl:param name="str"/>
   <xsl:param name="suffix"/>
   <xsl:if test="$str != ''"><xsl:value-of select="concat($prefix, $str, $suffix)"/></xsl:if>
</xsl:function>

它只是检查字符串 str 是否不为空,如果是,则返回字符串,并与前缀和后缀连接。

只要我只传递简单的字符串,该函数就可以正常工作。但是当我尝试将 HTML 元素作为前缀或后缀传递时,例如:

<xsl:value-of select="local:if-not-empty('', /some/xpath/expression, '<br/>')"/>

我收到以下错误消息:

SXXP0003: Error reported by XML parser: The value of attribute "select"
associated with an element type "null" must not contain the '<' character.

接下来我尝试定义一个变量:

<xsl:variable name="br"><br/></xsl:variable>

并将其传递给函数:

<xsl:value-of select="local:if-not-empty('', /some/xpath/expression, $br)"/>

但在这里,当然,我得到一个空字符串,因为元素的值被提取,而不是元素本身被复制。

我最后一次绝望的尝试是在变量中定义一个文本元素:

<xsl:variable name="br">
   <xsl:text disable-output-escaping="yes"><br/></xsl:text>
</xsl:variable>

并将其传递给函数,但这也是不允许的。

XTSE0010: xsl:text must not contain child elements

我可能不了解 XSLT 复杂的内部工作原理,但在我看来,通过通用函数在 XSLT 转换中添加 &lt;br/&gt; 元素似乎是合法的...

无论如何...如果有人能给我一个替代解决方案,我将不胜感激。我也想了解为什么这不起作用...

PS:我使用的是 Saxon-HE 9.4.0.1J,Java 版本 1.6.0_24

【问题讨论】:

  • 感谢所有回答我问题的人。最适合我的解决方案是 Dimitre Novatchev 下面的解决方案。

标签: xslt xslt-2.0


【解决方案1】:

试试这个:

<xsl:value-of select="local:if-not-empty('', /some/xpath/expression, '&lt;br/&gt;')" disable-output-escaping="yes"/>

【讨论】:

  • 谢谢,这行得通……尽管它有点难看和罗嗦……也许我会为&amp;lt;br/&amp;gt; 使用一个专用函数,不过
  • 此解决方案不是将&amp;lt;br/&amp;gt; 添加为字符串而不是元素吗? IE。你在输出中得到&amp;lt;br/&amp;gt;
  • @PeterNeuhaus:由于 disable-output-escaping 指令,它可以工作 - 但如果您的字符串包含 &gt;&lt;,您最终会得到无效的 XML 输出
【解决方案2】:

代替concat,使用:&lt;xsl:copy-of&gt;并作为参数传递items而不是字符串:

   <xsl:copy-of select="$pPrefix"/>
   <xsl:copy-of select="$pStr"/>
   <xsl:copy-of select="$pSuffix"/>

这是一个完整的例子

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:local="my:local" exclude-result-prefixes="local">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:variable name="vBr"><br/></xsl:variable>

 <xsl:template match="/">
  <xsl:sequence select="local:if-not-empty('a', 'b', $vBr/*)"/>
 </xsl:template>

  <xsl:function name="local:if-not-empty">
  <xsl:param name="pPrefix"/>
  <xsl:param name="pStr"/>
  <xsl:param name="pSuffix"/>

  <xsl:if test="$pStr != ''">
   <xsl:copy-of select="$pPrefix"/>
   <xsl:copy-of select="$pStr"/>
   <xsl:copy-of select="$pSuffix"/>
  </xsl:if>
 </xsl:function>
</xsl:stylesheet>

当此转换应用于任何 XML 文档(未使用)时,会产生所需的正确结果

a b<br/>

【讨论】:

  • 谢谢,这很好用。我不熟悉xsl:sequence。当使用 XPath 表达式作为参数调用时,如我最初的示例所示,可能需要选择所选元素的文本节点:&lt;xsl:value-of select="local:if-not-empty('', /some/xpath/expression/text(), $br)"/&gt;
  • @PeterNeuhaus:您不能将元素的文本表示形式作为参数传递。此解决方案创建一个临时树,其子 node 作为函数的第三个参数传递。你需要明白"&lt;br&gt;"只是一个字符串——不是一个节点——但是你不想生成一个字符串——你想生成一个节点。
【解决方案3】:

问题在于&lt;br/&gt; 不是字符串——它是一个XML 元素,因此不能使用字符串函数对其进行操作。你需要一个像这样的单独函数:

<xsl:function name="local:br-if-not-empty"> 
   <xsl:param name="prefix"/> 
   <xsl:param name="str"/> 
   <xsl:if test="$str != ''">
       <xsl:value-of select="concat($prefix, $str)"/>
       <br/>
    </xsl:if> 
</xsl:function> 

或者像这样的“技巧”,您将&lt;br/&gt; 作为一个单独的案例处理:

<xsl:function name="local:if-not-empty"> 
   <xsl:param name="prefix"/> 
   <xsl:param name="str"/> 
   <xsl:param name="suffix"/> 
   <xsl:if test="$str != ''">
       <xsl:value-of select="concat($prefix, $str)"/>
       <xsl:choose>
          <xsl:when test="$suffix = '&lt;br/&gt;'>
             <br/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:value-of select="$suffix"/>
          </xsl:otherwise>
       </xsl:choose>
    </xsl:if> 
</xsl:function> 

【讨论】:

  • 单独的函数或案例可以工作,但我必须为每个可能的参数添加一个新函数或 when-block。这将导致大量重复代码,维护起来将是一场噩梦。
  • @PeterNeuhaus:那么上面的 Dimitre 解决方案是可行的方法
猜你喜欢
  • 1970-01-01
  • 2012-05-24
  • 2017-10-01
  • 2015-05-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-18
  • 1970-01-01
相关资源
最近更新 更多