XSLT 基于多个元素/值删除重复节点

问题描述 投票:0回答:1

我有以下输入 XML 片段

   <Customer>
      <FirstName>ABC</FirstName>
      <LastName>XYZ</LastName>
      <Location>LOC_1</Location>
      <Location>LOC_2</Location>
   </Customer>
   <Customer>
      <FirstName>ABC</FirstName>
      <LastName>XYZ</LastName>
      <Location>LOC_1</Location>
   </Customer>
   <Customer>
      <FirstName>SOME_OTHER_CUSTOMER</FirstName>
      <LastName>XYZ</LastName>
      <Location>LOC_1</Location>
   </Customer>

我想从上述 XML 中过滤第二个节点,因为它具有相同的

FirstName
(ABC)、
LastName
(XYZ),并且使用 XSLT 2.0 与第一个节点的
Location
(LOC_1) 之一相匹配。

输出XML

 <Customer>
      <FirstName>ABC</FirstName>
      <LastName>XYZ</LastName>
      <Location>LOC_1</Location>
      <Location>LOC_2</Location>
   </Customer>
   <Customer>
      <FirstName>SOME_OTHER_CUSTOMER</FirstName>
      <LastName>XYZ</LastName>
      <Location>LOC_1</Location>
   </Customer>

我查看了一些使用

preceding-sibling
的示例,这些示例使用单个元素值来验证它是否重复,但不知何故,我无法使其适用于我检查多个/重复字段以检查重复项的场景。

非常感谢任何在 XSLT 中实现此功能的帮助/建议!

xml xslt
1个回答
0
投票

您的帖子提到了 XSLT 2,因为以前的 XSLT 2 处理器的当前版本(如如今的 Saxon 8.9-9.7(自 9.8 起))是 XSLT 3 处理器我首先展示 XSLT 3 解决方案

<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">
  
  <xsl:output indent="yes"/>

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

  <xsl:template match="Customers">
    <xsl:for-each-group select="Customer" composite="yes" group-by="LastName, FirstName">
      <xsl:copy>
        <xsl:copy-of select="FirstName, LastName"/>
        <xsl:for-each-group select="current-group()/Location" group-by=".">
          <xsl:copy-of select="."/>
        </xsl:for-each-group>
      </xsl:copy>
    </xsl:for-each-group>
  </xsl:template>
  
</xsl:stylesheet>

如果您使用的旧版本处理器确实只支持 XSLT 2 但不支持 3,那么请删除

xsl:mode
声明并使用分组作为

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="2.0"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  exclude-result-prefixes="xs">
  
  <xsl:output indent="yes"/>

  <xsl:template match="Customers">
    <xsl:for-each-group select="Customer" group-by="concat(LastName, '|',  FirstName)">
      <xsl:copy>
        <xsl:copy-of select="FirstName, LastName"/>
        <xsl:for-each-group select="current-group()/Location" group-by=".">
          <xsl:copy-of select="."/>
        </xsl:for-each-group>
      </xsl:copy>
    </xsl:for-each-group>
  </xsl:template>
  
</xsl:stylesheet>

我假设

Customer
元素位于公共父元素
Customers
中,根据您的输入元素结构,您需要将匹配模式中的名称调整为真实的父元素名称,或者,如果元素没有对于单个共同父级,请使用更广泛的选择,例如
select="//Customer"
作为外部
for-each-group

© www.soinside.com 2019 - 2024. All rights reserved.