XSLT 3.0 xsl:mode on-no-match="shallow-skip"

Posted

技术标签:

【中文标题】XSLT 3.0 xsl:mode on-no-match="shallow-skip"【英文标题】: 【发布时间】:2021-12-21 15:51:13 【问题描述】:

我想从 XSLT 3 和 Saxon HE 10.6 的响应中过滤 XML 元素

<!-- https://mvnrepository.com/artifact/net.sf.saxon/Saxon-HE -->
<dependency>
    <groupId>net.sf.saxon</groupId>
    <artifactId>Saxon-HE</artifactId>
    <version>10.6</version>
</dependency>

我在https://xsltfiddle.liberty-development.net/3MP42Pc 和https://xsltfiddle.liberty-development.net/3MP42Pc/1 上保存了案例

我希望能够使用

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

(即:跳过与过滤器不匹配的元素。)

所以我想复制所有匹配更深属性值的元素

该结构就像带有状态的鞋子数据集,看起来像账单上的通用项目。

bill.xml

  <bill>
    <item>
      <shoes>
        <status>0</status>
      </shoes>
    </item>
    <item>
      <shoes>
        <status>1</status>
      </shoes>
    </item>
    <item>
      <shoes>
        <status>2</status>
      </shoes>
    </item>
  </bill>

我想要 status=0 的通用物品(任何种类(鞋子))

(否则说:跳过 '*/[status=0'] 不匹配的项目)

bill.xslt

<xsl:stylesheet version="3.0">
  <xsl:mode on-no-match="shallow-skip" />
  <xsl:template match="item/*[status=0]"/>
</xsl:stylesheet>

结果应该是

<bill>
  <item>
    <shoes><status>0</status></shoes>
  </item>
</bill>

唉,这个脚本什么也没找到

但是。在

的情况下
<xsl:mode on-no-match="shallow-copy" />

它找到(如预期的那样)所有不是 status=0 的项目

<bill>
  <item/>
  <item>
    <shoes><status>1</status></shoes>
  </item>
  <item>
    <shoes><status>2</status></shoes>
  </item>
</bill>

如果我使用

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

它找到所有项目(不过滤)。

对我来说这似乎不太合乎逻辑,即使 item 元素具有上下文。

我用的是SAXON HE 10.6版本,和javax.xml.transform的代码唯一不同的是使用

TransformerFactory factory = new **BasicTransformerFactory**();

问题是如何制作一个优雅的小脚本来执行此操作:输出整个 xml,跳过不匹配的项目。

【问题讨论】:

您想要得到的确切结果是什么? 【参考方案1】:

我认为您想将&lt;xsl:mode on-no-match="shallow-copy"/&gt;&lt;xsl:template match="item[not(*/status = 0)]"/&gt; 一起使用(或&lt;xsl:template match="item/*[not(status = 0)]"/&gt;,如果item 元素都需要被复制,则只需要过滤它们的子元素)。

我不确定你从哪里得到&lt;xsl:mode on-no-match="shallow-skip" /&gt; 应该这样做的想法,除非你明确添加了&lt;xsl:template match="item[*/status = 0]"&gt;&lt;xsl:copy-of select="."/&gt;&lt;/xsl:template&gt;。即使那样你也会失去根元素。

如果您查看https://www.w3.org/TR/xslt-30/#built-in-templates-shallow-skip,它会说:

使用指定模式处理树的效果 on-no-match="shallow-skip" 是删除文本内容和 结果文档中的标记,除非有明确的 用户编写的模板规则,另有规定。

【讨论】:

【参考方案2】:

谢谢马丁

所以逻辑更进一步。

从根标签中显式写入未命中节点的提示

https://xsltfiddle.liberty-development.net/3MP42Pc/2

所以解决方案是使用

<xsl:mode on-no-match="shallow-copy"/> 
<xsl:template match="item/*[not(status = 0)]"/>

https://xsltfiddle.liberty-development.net/3MP42Pc/3

Michael 的 on-no-match="shallow-skip" 建议也适用,包括根标签,潜入后代。

<xsl:template match="*[descendant-or-self::status=0] | status[.=0]/text()">
    <xsl:copy>
        <xsl:apply-templates/>
    </xsl:copy>
</xsl:template>

https://xsltfiddle.liberty-development.net/3MP42Pc/4

但对我来说,使用后裔或自我是新的

【讨论】:

【参考方案3】:

在使用时获得您(显然)期望的结果:

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

默认情况下,您必须制作模板:

<xsl:template match="*[descendant-or-self::status=0] | status[.=0]/text()">
    <xsl:copy>
        <xsl:apply-templates/>
    </xsl:copy>
</xsl:template>

为了完整复制通向&lt;status&gt;0&lt;/status&gt; 叶的所有分支。


如前所述,制作起来要简单得多:

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

默认值。那么你只需要添加:

<xsl:template match="*[not(descendant-or-self::status=0)]"/>

为了抑制没有&lt;status&gt;0&lt;/status&gt; 叶的分支。

【讨论】:

以上是关于XSLT 3.0 xsl:mode on-no-match="shallow-skip"的主要内容,如果未能解决你的问题,请参考以下文章

XSLT3 未命名的 xsl:mode on-no-match 行为是不是应该应用于没有模式匹配但模式在应用模板上指定的元素?

XSLT 3.0 - 无法在 XSLT 3.0 xml-to-json() 中获取对象数组

XSLT 3.0 - 在 XSLT 3.0 xml-to-json() 中出现错误“重复键值”

Marklogic xml 转换中的 XSLT 3.0 支持

BizTalk Server 2016 映射中是不是支持 XSLT 2.0 或 3.0?

BizTalk 2020 XSLT 3.0 - 样式表编译期间报告错误