当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>
关键修正点
- 添加
article-group键,用于按SupplierArticleNumber对Item节点分组。 - 根模板的测试条件改为:检查是否存在某个分组的首个
Item,其分组内存在其他Item的SalesPrice与它不同。满足条件时输出空内容,否则正常执行后续处理逻辑。
内容的提问来源于stack exchange,提问作者juls_pro_37
相关产品推荐
相关产品推荐

