You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

当SupplierArticleNumber重复且SalesPrice不同时生成空XML的XSLT问询

需求说明

当Item/SupplierArticleNumber出现重复值,且对应的Item/SalesPrice值不同时,需要生成一个无内容的XML。

示例XML

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<SALESINVOICE>
  <Interchange>
    <Interchange_Control_Number>1</Interchange_Control_Number>
  </Interchange>
  <HeaderInformation>
    <OrigInvoiceNumber>1</OrigInvoiceNumber>
  </HeaderInformation>
  <LineInformation>
    <Item>
      <LineNum>1</LineNum>
      <SupplierArticleNumber>860347</SupplierArticleNumber>
      <SalesPrice>425.0000</SalesPrice>
    </Item>
    <Item>
      <LineNum>2</LineNum>      
      <SupplierArticleNumber>860347</SupplierArticleNumber>      
      <SalesPrice>412.5000</SalesPrice>      
    </Item>
    <Item>
      <LineNum>3</LineNum>     
      <SupplierArticleNumber>881303</SupplierArticleNumber>     
      <SalesPrice>34.1300</SalesPrice>      
    </Item>
    <Item>
      <LineNum>4</LineNum>    
      <SupplierArticleNumber>881303</SupplierArticleNumber>     
      <SalesPrice>0.0000</SalesPrice>      
    </Item>
  </LineInformation>  
</SALESINVOICE>

原实现思路

<xsl:template match="/">   
  <xsl:choose>
      <xsl:when test="Item[SupplierArticleNumber = SupplierArticleNumber and SalesPrice != SalesPrice]"></xsl:when>            
                  <xsl:otherwise> <xsl:apply-templates select="@* | node()"/></xsl:otherwise>
  </xsl:choose>
</xsl:template>

完整原XSLT代码

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:exsl="http://exslt.org/common" extension-element-prefixes="exsl">

 <xsl:output method="xml" indent="yes" encoding="UTF-8"/>
 
  <xsl:strip-space elements="*" />
  
      <xsl:template match="/">   
        <xsl:choose>
            <xsl:when test="Item[SupplierArticleNumber = SupplierArticleNumber and SalesPrice != SalesPrice]"></xsl:when>            
                        <xsl:otherwise> <xsl:apply-templates select="@* | node()"/></xsl:otherwise>
        </xsl:choose>
    </xsl:template>

  
  <xsl:key name="item" match="Item" use="concat(LineNum, '|', GTIN, '|', Ordered, '|', LineNumSalesLine)"/>  
  <xsl:template match="Item[generate-id() != generate-id(key('item', concat(LineNum, '|', GTIN, '|', Ordered, '|', LineNumSalesLine))[1])]" />  

  <xsl:template match="Item">
    <Item>
      <xsl:apply-templates/>
      <xsl:call-template name="process1"/>
    </Item>
  </xsl:template>

  <xsl:template match="ItemDeliveryInformation"/>

  <xsl:template name="process1">
    <xsl:variable name="tempdoc">
      <temproot>
        <xsl:for-each select="ItemDeliveryInformation[generate-id() = generate-id(key('packing_slip', concat(LineNumDeliveryNote, '|', PackingSlipId, '|', DeliveryDate, '|', DeliveredQuantity, '|', RecId_InventTrans))[1])]">
          <xsl:copy-of select="."/>
        </xsl:for-each>
      </temproot>
    </xsl:variable>

    <xsl:call-template name="process2">
        <xsl:with-param name="nodes" select="exsl:node-set($tempdoc)"/>
        </xsl:call-template>
    </xsl:template>

  <xsl:template name="process2">
   
    <xsl:param name="nodes"/>
   
        <xsl:if test="$nodes//PackingSlipId != '' ">

    <ItemDeliveryInformation>

      <LineNumDeliveryNote>
        <xsl:value-of select="$nodes//LineNumDeliveryNote[1]"/>
      </LineNumDeliveryNote>
      <PackingSlipId_Created>
        <xsl:value-of select="$nodes//PackingSlipId_Created[1]"/>
      </PackingSlipId_Created>
      <PackingSlipId>
        <xsl:value-of select="$nodes//PackingSlipId[1]"/>
      </PackingSlipId>
      <DeliveryDate>
        <xsl:value-of select="$nodes//DeliveryDate[1]"/>
      </DeliveryDate>
      <DeliveredQuantity>
        <xsl:value-of select="format-number(sum($nodes//DeliveredQuantity), '#.00')"/>
      </DeliveredQuantity>
    <ShipFromAddressInformation>
        <xsl:copy-of select="$nodes//ShipFromAddressInformation/GLN[1]"/>
        <xsl:copy-of select="$nodes//ShipFromAddressInformation/Name[1]"/>      
        <xsl:copy-of select="$nodes//ShipFromAddressInformation/Street[1]"/>
        <xsl:copy-of select="$nodes//ShipFromAddressInformation/ZipCode[1]"/>
        <xsl:copy-of select="$nodes//ShipFromAddressInformation/City[1]"/>
        <xsl:copy-of select="$nodes//ShipFromAddressInformation/Country[1]"/>
        <xsl:copy-of select="$nodes//ShipFromAddressInformation/State[1]"/>
        <xsl:copy-of select="$nodes//ShipFromAddressInformation/VATNum[1]"/>
        <xsl:copy-of select="$nodes//ShipFromAddressInformation/InternalNumber[1]"/>   
    </ShipFromAddressInformation>
    </ItemDeliveryInformation>
        </xsl:if>
  </xsl:template>
  
<!-- 删除空节点 -->
 <xsl:template match="node()|@*">
     <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
 </xsl:template>
 
 <xsl:template match="*[not(@*|*|comment()|processing-instruction()) and normalize-space()='']"/>

</xsl:stylesheet>

正确实现方案

原思路的测试条件逻辑错误,它仅在单个Item节点内做无意义的自比较,无法检测同一SupplierArticleNumber对应多个不同SalesPrice的情况。正确的做法是通过key按SupplierArticleNumber分组,再检查分组内是否存在不同的SalesPrice值。

以下是修正后的完整XSLT代码:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:exsl="http://exslt.org/common" extension-element-prefixes="exsl">

 <xsl:output method="xml" indent="yes" encoding="UTF-8"/>
 
  <xsl:strip-space elements="*" />

  <!-- 按SupplierArticleNumber对Item节点分组 -->
  <xsl:key name="article-group" match="Item" use="SupplierArticleNumber"/>

  <!-- 根模板:检测重复编号且价格不同的情况 -->
  <xsl:template match="/">   
    <xsl:choose>
      <!-- 测试条件:存在某个SupplierArticleNumber分组内,存在不同的SalesPrice值 -->
      <xsl:when test="SALESINVOICE/LineInformation/Item[
        generate-id() = generate-id(key('article-group', SupplierArticleNumber)[1])
        and key('article-group', SupplierArticleNumber)/SalesPrice != SalesPrice
      ]">
        <!-- 生成无内容XML -->
      </xsl:when>            
      <xsl:otherwise> 
        <xsl:apply-templates select="@* | node()"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <!-- 保留原有的Item去重逻辑 -->
  <xsl:key name="item" match="Item" use="concat(LineNum, '|', GTIN, '|', Ordered, '|', LineNumSalesLine)"/>  
  <xsl:template match="Item[generate-id() != generate-id(key('item', concat(LineNum, '|', GTIN, '|', Ordered, '|', LineNumSalesLine))[1])]" />  

  <xsl:template match="Item">
    <Item>
      <xsl:apply-templates/>
      <xsl:call-template name="process1"/>
    </Item>
  </xsl:template>

  <xsl:template match="ItemDeliveryInformation"/>

  <xsl:template name="process1">
    <xsl:variable name="tempdoc">
      <temproot>
        <xsl:for-each select="ItemDeliveryInformation[generate-id() = generate-id(key('packing_slip', concat(LineNumDeliveryNote, '|', PackingSlipId, '|', DeliveryDate, '|', DeliveredQuantity, '|', RecId_InventTrans))[1])]">
          <xsl:copy-of select="."/>
        </xsl:for-each>
      </temproot>
    </xsl:variable>

    <xsl:call-template name="process2">
        <xsl:with-param name="nodes" select="exsl:node-set($tempdoc)"/>
        </xsl:call-template>
    </xsl:template>

  <xsl:template name="process2">
   
    <xsl:param name="nodes"/>
   
        <xsl:if test="$nodes//PackingSlipId != '' ">

    <ItemDeliveryInformation>

      <LineNumDeliveryNote>
        <xsl:value-of select="$nodes//LineNumDeliveryNote[1]"/>
      </LineNumDeliveryNote>
      <PackingSlipId_Created>
        <xsl:value-of select="$nodes//PackingSlipId_Created[1]"/>
      </PackingSlipId_Created>
      <PackingSlipId>
        <xsl:value-of select="$nodes//PackingSlipId[1]"/>
      </PackingSlipId>
      <DeliveryDate>
        <xsl:value-of select="$nodes//DeliveryDate[1]"/>
      </DeliveryDate>
      <DeliveredQuantity>
        <xsl:value-of select="format-number(sum($nodes//DeliveredQuantity), '#.00')"/>
      </DeliveredQuantity>
    <ShipFromAddressInformation>
        <xsl:copy-of select="$nodes//ShipFromAddressInformation/GLN[1]"/>
        <xsl:copy-of select="$nodes//ShipFromAddressInformation/Name[1]"/>      
        <xsl:copy-of select="$nodes//ShipFromAddressInformation/Street[1]"/>
        <xsl:copy-of select="$nodes//ShipFromAddressInformation/ZipCode[1]"/>
        <xsl:copy-of select="$nodes//ShipFromAddressInformation/City[1]"/>
        <xsl:copy-of select="$nodes//ShipFromAddressInformation/Country[1]"/>
        <xsl:copy-of select="$nodes//ShipFromAddressInformation/State[1]"/>
        <xsl:copy-of select="$nodes//ShipFromAddressInformation/VATNum[1]"/>
        <xsl:copy-of select="$nodes//ShipFromAddressInformation/InternalNumber[1]"/>   
    </ShipFromAddressInformation>
    </ItemDeliveryInformation>
        </xsl:if>
  </xsl:template>
  
<!-- 删除空节点 -->
 <xsl:template match="node()|@*">
     <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
 </xsl:template>
 
 <xsl:template match="*[not(@*|*|comment()|processing-instruction()) and normalize-space()='']"/>

</xsl:stylesheet>

关键修正点

  1. 添加article-group键,用于按SupplierArticleNumber对Item节点分组。
  2. 根模板的测试条件改为:检查是否存在某个分组的首个Item,其分组内存在其他Item的SalesPrice与它不同。满足条件时输出空内容,否则正常执行后续处理逻辑。

内容的提问来源于stack exchange,提问作者juls_pro_37

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 05:08:09