XSLT:测试兄弟是否匹配条件列表

XSLT: test if sibling matches list of conditions

我有一个条件列表,我想检查元素的直接兄弟是否符合这些条件中的任何一个。

如果这些条件是简单的标签名称,这很容易。

<xsl:param name="tag-list" select="tokenize('img figure table', '\s+')"/>

<xsl:template match="* | text()">
<xsl:variable name="next-name" select="name(following-sibling::*[1])" />
<xsl:if test="$next-name = $tag-list">
<!-- DoSomething -->
</xsl:if>
</xsl:template>

此模板将匹配任何元素或文本节点,如果该节点的紧随其后的兄弟节点是 <img>, <figure> or <table>.

,则该模板将执行 DoSomething

但是,我想检查更复杂的条件。当模板与具有特定属性、子元素或文本值的同级元素匹配时,我如何才能只做一些事情?我更愿意使用单个 <xsl:if> 来执行此操作,因为此兄弟条件列表可能会很长。

<xsl:param name="tag-list" select="tokenize('img[@src] figure[text()] table[tbody]', '\s+')"/>

<xsl:template match="* | text()">
<xsl:if test="???">
<!-- DoSomething -->
</xsl:if>
</xsl:template>

如果您使用 XSLT 3,请考虑带有 shadow 属性的静态参数是否允许您在样式表编译之前即时构建正确的 XPath 表达式:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    version="3.0">

  <xsl:param name="tag-list" static="yes" select="tokenize('img[@src] figure[text()] table[tbody]', '\s+')"/>

  <xsl:template match="* | text()">
    <xsl:if _test="{string-join($tag-list ! ('following-sibling::*[1][self::' || . || ']'), ' | ')}">
        <xsl:comment>DoSomething</xsl:comment>
    </xsl:if>
    <xsl:next-match/>
  </xsl:template>

  <xsl:mode on-no-match="shallow-copy"/>

</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/3NSTbf3 转换

<root>
    <section><span>test</span><img src="foo.jpeg"/></section>
    <section>test<table><tbody>...</tbody></table><span>test</span><figure>...</figure></section>
</root>

进入

<root>
    <section><!--DoSomething--><span>test</span><img src="foo.jpeg"/></section>
    <section><!--DoSomething-->test<table><tbody>...</tbody></table><!--DoSomething--><span>test</span><figure>...</figure></section>
</root>

这个例子是为了展示 _test 作为影子属性的使用,我特意使用了不同的模板内容,因为它似乎更容易显示带有身份转换和注释的代码结果在 xsl:if 开始的地方输出。

定义一个表示复杂条件的函数:

<xsl:function name="my:condition" as="xs:boolean">
  <xsl:param name="node" as="node()"/>
  ... your condition goes here ...
</xsl:function>

然后测试是:

<xsl:if test="following-sibling::*[1][my:condition(.)]">...</xsl:if>

如果您想将条件模块化为单独的函数,那么您当然可以这样做:

<xsl:function name="my:condition" as="xs:boolean">
  <xsl:param name="node" as="node()"/>
  <xsl:sequence select="my:first($node) and my:second($node) and..."/>
</xsl:function>

如果你想让逻辑更动态一点,所以条件列表以某种方式动态提供,然后考虑使用高阶函数。