XSLT中for-each-group输出line_amount为多值的原因咨询
XSLT分组转换中line_amount输出多值的问题分析
问题描述
我是XSLT新手,在用for-each-group结合for-each做XML转换时,发现输出的lineitem-position能对应每个组元素输出单个值,但line_amount却输出所有值的列表。我期望line_amount和lineitem-position一样,每个条目输出单个对应值。
输入XML
<order order-no="60058554"> <product-lineitems> <product-lineitem> <gross-price>76.00</gross-price> <position>1</position> <quantity unit=""></quantity> <custom-attributes> <custom-attribute attribute-id="associatedPromotionId">Reward1Band2</custom-attribute> <custom-attribute attribute-id="associatedPromotionId">Reward2Band3</custom-attribute> </custom-attributes> <price-adjustments> <price-adjustment> <gross-price>-38.00</gross-price> <promotion-id>Reward1Band2</promotion-id> </price-adjustment> <price-adjustment> <gross-price>-38.00</gross-price> <promotion-id>Reward2Band3</promotion-id> </price-adjustment> </price-adjustments> </product-lineitem> <product-lineitem> <gross-price>50.00</gross-price> <position>2</position> <quantity unit=""></quantity> <custom-attributes> <custom-attribute attribute-id="associatedPromotionId">Reward3Band3</custom-attribute> </custom-attributes> <price-adjustments> <price-adjustment> <gross-price>-50.00</gross-price> <promotion-id>Reward3Band3</promotion-id> </price-adjustment> </price-adjustments> </product-lineitem> <product-lineitem> <gross-price>28.00</gross-price> <position>3</position> <quantity unit=""></quantity> <custom-attributes> <custom-attribute attribute-id="associatedPromotionId">Reward2Band3</custom-attribute> </custom-attributes> <price-adjustments> <price-adjustment> <gross-price>-28.00</gross-price> <promotion-id>Reward2Band3</promotion-id> </price-adjustment> </price-adjustments> </product-lineitem> </product-lineitems> </order>
XSLT代码
<?xml version="1.0" encoding="UTF-8" ?> <xsl:stylesheet version="3.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns1="http://schemas.xmlsoap.org/soap/http" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsd="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xsi xsl ns1 soap wsdl xsd dw"> <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="no"/> <xsl:template match="/dw:order"> <xsl:variable name="associatedPromotions"> <xsl:for-each-group select="dw:product-lineitems/dw:product-lineitem" group-by="dw:custom-attributes/dw:custom-attribute[@attribute-id='associatedPromotionId']"> <xsl:for-each select="current-group()"> <line> <xsl:attribute name="lineitem-position"> <xsl:value-of select="dw:position"/> </xsl:attribute> <xsl:attribute name="line_amount"> <xsl:value-of select="dw:gross-price"/> </xsl:attribute> </line> </xsl:for-each> </xsl:for-each-group> </xsl:variable> etc etc </xsl:template> </xsl:stylesheet>
输出片段
<lineitem-position>1</lineitem-position> <line_amount>76.00 76.00 28.00 50.00</line_amount> <lineitem-position>1</lineitem-position> <line_amount>76.00 76.00 28.00 50.00</line_amount> <lineitem-position>3</lineitem-position> <line_amount>76.00 76.00 28.00 50.00</line_amount> <lineitem-position>2</lineitem-position> <line_amount>76.00 76.00 28.00 50.00</line_amount>
问题原因及解决建议
核心原因
问题不在for-each-group的分组逻辑里,而是出在后续处理$associatedPromotions变量的代码中:
- 分组部分生成的
<line>元素是正确的,每个元素的lineitem-position和line_amount属性都对应单个product-lineitem的数值。变量$associatedPromotions里会生成4个独立的<line>元素,每个元素的两个属性都是单个值。 - 你最终输出时,错误地全局选择了所有
<line>元素的@line_amount属性(比如使用$associatedPromotions//@line_amount),而没有针对每个<line>元素提取它自身的@line_amount,导致每次输出都把所有line_amount值拼接成了列表。 - 而
lineitem-position输出正确,是因为你针对每个<line>元素提取了自身的@lineitem-position属性(上下文是当前<line>元素)。
另外,你的XSLT代码存在一个潜在的致命问题:未声明dw命名空间前缀。代码中exclude-result-prefixes包含dw,但没有定义xmlns:dw="...",这会导致所有带dw:前缀的节点选择失效(比如dw:order、dw:product-lineitem等)。如果输入XML确实使用了dw命名空间,必须在<xsl:stylesheet>根元素中添加对应的命名空间声明,否则处理器无法匹配到目标节点。
解决方法
- 修复命名空间:在
<xsl:stylesheet>根元素中添加dw命名空间的声明,确保与输入XML的命名空间一致,示例:xmlns:dw="http://你的命名空间URI" - 修正输出逻辑:遍历
$associatedPromotions中的每个<line>元素,针对每个元素提取自身的属性值,示例代码如下:<xsl:for-each select="$associatedPromotions/line"> <lineitem-position><xsl:value-of select="@lineitem-position"/></lineitem-position> <line_amount><xsl:value-of select="@line_amount"/></line_amount> </xsl:for-each>
内容的提问来源于stack exchange,提问作者Nick C
相关产品推荐
相关产品推荐

