xsl 通配符匹配以排除自身

Posted

技术标签:

【中文标题】xsl 通配符匹配以排除自身【英文标题】:xsl wildcard match to exclude itself 【发布时间】:2021-11-17 13:47:02 【问题描述】:

如果Childs 在Identifier 元素中有重复值,我想创建新元素create_duplicate,但我不想匹配当前节点本身。目前//Identifier/text() 也匹配自身。有没有办法排除它,只匹配所有其他Child/Identifiers?

XML:

<Document>
    <List>
        <Child>
            <Identifier>19961202</Identifier>
        </Child>
        <Child>
            <Identifier>19961203</Identifier>
        </Child>
    </List>
    <WebResponse>
        <Product>
            <WebIdentifier>19961202</WebIdentifier>
        </Product>
        <Product>
            <WebIdentifier>19961203</WebIdentifier>
        </Product>
    </WebResponse>
</Document>

XSLT:

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xsl:strip-space elements="*"/>
    <xsl:output indent="yes"></xsl:output>

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

    <xsl:template match="Child">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"></xsl:apply-templates>
            <operation>
                <xsl:choose>
                    <xsl:when test="Identifier/text() = //Identifier/text()">
                        <xsl:value-of select="'create_duplicate'"/>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:choose>
                            <xsl:when test="Identifier/text() = //WebIdentifier/text()">
                                <xsl:value-of select="'update'"/>
                            </xsl:when>
                            <xsl:otherwise>
                                <xsl:value-of select="'create'"/>
                            </xsl:otherwise>
                        </xsl:choose>
                    </xsl:otherwise>
                </xsl:choose>
            </operation>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

结果:

<Document>
   <List>
      <Child>
         <Identifier>19961202</Identifier>
         <!-- I would expect 'update' here as it should skip itself-->
         <operation>create_duplicate</operation>
      </Child>
      <Child>
         <Identifier>19961203</Identifier>
         <!-- I would expect 'update' here as it should skip itself-->
         <operation>create_duplicate</operation>
      </Child>
   </List>
   <WebResponse>
      <Product>
         <WebIdentifier>19961202</WebIdentifier>
      </Product>
      <Product>
         <WebIdentifier>19961203</WebIdentifier>
      </Product>
   </WebResponse>
</Document>

【问题讨论】:

您是否考虑过将List/ChildIdentifier&lt;xsl:for-each-group select="List/Child" group-by="Identifier"&gt; 分组?然后使用一个键来引用Product by WebIdentifier 【参考方案1】:

我猜你可以分组,然后用一个键检查是否有交叉引用:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="3.0"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  exclude-result-prefixes="#all"
  expand-text="yes">
  
  <xsl:template match="Document/List">
    <xsl:copy>
      <xsl:for-each-group select="Child" group-by="Identifier">
        <xsl:apply-templates select="current-group()"/>
      </xsl:for-each-group>
    </xsl:copy>
  </xsl:template>
  
  <xsl:template match="Child[key('webid', Identifier)]">
    <xsl:copy>
      <operation>if (position() eq 1) then 'update' else 'duplicate'</operation>
    </xsl:copy>
  </xsl:template>
  
  <xsl:template match="Child[not(key('webid', Identifier))]">
    <xsl:copy>
      <operation>if (position() eq 1) then 'create' else 'duplicate'</operation>
    </xsl:copy>
  </xsl:template>

  <xsl:output method="xml" indent="yes"/>
  
  <xsl:key name="webid" match="Product" use="WebIdentifier"/>

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

</xsl:stylesheet>

或者使用两个键,一个用于“分组”,第二个用于交叉引用检查:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="3.0"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  exclude-result-prefixes="#all"
  expand-text="yes">
  
  <xsl:key name="id" match="Child" use="Identifier"/>
  
  <xsl:template match="Child[. is key('id', Identifier)[1]][key('webid', Identifier)]">
    <xsl:copy>
      <operation>update</operation>
    </xsl:copy>
  </xsl:template>
  
  <xsl:template match="Child[not(. is key('id', Identifier)[1])][key('webid', Identifier)]">
    <xsl:copy>
      <operation>duplicate</operation>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="Child[. is key('id', Identifier)[1]][not(key('webid', Identifier))]">
    <xsl:copy>
      <operation>create</operation>
    </xsl:copy>
  </xsl:template>
  
  <xsl:template match="Child[not(. is key('id', Identifier)[1])][not(key('webid', Identifier))]">
    <xsl:copy>
      <operation>duplicate</operation>
    </xsl:copy>
  </xsl:template>

  <xsl:output method="xml" indent="yes"/>
  
  <xsl:key name="webid" match="Product" use="WebIdentifier"/>

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

【讨论】:

这可能是要走的路,但不幸的是问题是关于xslt-2.0,因此xsl:mode 不可用。 我只是用那个专注于主要代码来解决问题中提出的问题,你当然可以将xsl:mode声明替换为身份模板&lt;xsl:template match="@* | node()"&gt;&lt;xsl:copy&gt;&lt;xsl:apply-templates select="@* | node()"/&gt;&lt;/xsl:copy&gt;&lt;/xsl:template&gt;。在第一个示例中,您还需要将内联文本 模板替换为 xsl:value-of 谢谢!这个解决方案非常优雅,但目前在您的解决方案中,如果 Identifiers 相同,那么 operation 仅在第二个 Child 中是 duplicate 。因为我想全部匹配,所以 operation 应该是 duplicate 在两者中。 @Moontego,也许用更多的示例数据来编辑问题,显示输入变化和想要的结果。我无法从样本中推断出结果应该是什么,因为您只想为任何第二次这样的匹配查找重复项,我认为上述匹配项。也许key('id', Identifier)[2] 是检查是否存在重复并且您想要输出的条件。

以上是关于xsl 通配符匹配以排除自身的主要内容,如果未能解决你的问题,请参考以下文章

Ant风格路径匹配的通配符

排除包含字符串'x'的通配符

mysql 通配符 正则

mysql 通配符 正则

仅去除带有通配符排除的二进制文件的函数名称

Elasticsearch 前缀搜索、通配符搜索、正则搜索、不匹配搜索