XSLT 3.0多循环代码问题求助:无法生成预期XML输出
XSLT多循环代码输出异常问题排查与修正
问题说明
我并非经常使用XSLT的开发者,编写了一段包含多循环的XSLT代码,但无法生成预期的XML输出。现提供相关输入、代码及预期输出,恳请技术建议。
XML输入
<Order> <OrderTypes> <SalesOrder>3000016154</SalesOrder> <SoldToParty>1</SoldToParty> <ItemPartner> <PartnerTypes> <PFunction>SH</PFunction> <Customer>A</Customer> <Address> <AddressType> <Name>Test_FinalCustomer1</Name> <Address>Test_FinalCustomer1</Address> </AddressType> </Address> </PartnerTypes> <PartnerTypes> <PFunction>FC</PFunction> <Customer>B</Customer> <Address> <AddressType> <Name>Test_FinalCustomer2</Name> <Address>Test_FinalCustomer2</Address> </AddressType> </Address> </PartnerTypes> </ItemPartner> <ItemTypes> <Types> <Unit>KG</Unit> <NetAmount>5000.00</NetAmount> <PricingElementsType> <PrElementType> <RateValue>2000</RateValue> <Quantity>1</Quantity> <Type>PR00</Type> </PrElementType> <PrElementType> <RateValue>3000</RateValue> <Quantity>2</Quantity> <Type>PR01</Type> </PrElementType> </PricingElementsType> </Types> <Types> <Unit>ML</Unit> <NetAmount>6000.00</NetAmount> <PricingElementsType> <PrElementType> <RateValue>4000</RateValue> <Quantity>1</Quantity> <Type>PR00</Type> </PrElementType> <PrElementType> <RateValue>2000</RateValue> <Quantity>2</Quantity> <Type>PR01</Type> </PrElementType> </PricingElementsType> </Types> </ItemTypes> </OrderTypes> </Order>
当前XSLT代码
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:java="http://xml.apache.org/xslt/java" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:map="http://www.w3.org/2005/xpath-functions/map" xmlns:n0="http://sap.com/xi/SAPGlobal20/Global" exclude-result-prefixes="xs" xmlns:exsl="http://exslt.org/common" xmlns:ext="http://exslt.org/common"> <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/> <xsl:strip-space elements="*"/> <xsl:template match="Order"> <xsl:for-each select="OrderTypes"> <data> <xsl:if test="SalesOrder"> <VBELN> <xsl:value-of select="SalesOrder"/> </VBELN> </xsl:if> <HEAD> <xsl:if test="SalesOrder"> <VBELN> <xsl:value-of select="SalesOrder"/> </VBELN> </xsl:if> <xsl:if test="SoldToParty"> <KUNNR_AG> <xsl:value-of select="SoldToParty"/> </KUNNR_AG> </xsl:if> <xsl:for-each select="//PartnerTypes"> <xsl:if test="PFunction = 'SH'"> <xsl:if test=" Customer"> <KUNNR_SH> <xsl:value-of select="Customer"/> </KUNNR_SH> </xsl:if> <xsl:for-each select="//AddressType"> <xsl:if test="Address"> <Address> <xsl:value-of select="Address"/> </Address> </xsl:if> </xsl:for-each> </xsl:if> </xsl:for-each> <xsl:for-each select="//Types"> <HEAD_ENTRIES> <xsl:if test="Unit"> <UNIT> <xsl:value-of select="Unit"/> </UNIT> </xsl:if> <xsl:if test="NetAmount"> <NET_AMOUNT> <xsl:value-of select="NetAmount"/> </NET_AMOUNT> </xsl:if> <xsl:for-each select="//PrElementType"> <xsl:if test="Type ='PR00'"> <xsl:if test="RateValue"> <RATE_VALUE> <xsl:value-of select="RateValue"/> </RATE_VALUE> </xsl:if> <xsl:if test="Quantity"> <QUANTITY> <xsl:value-of select="Quantity"/> </QUANTITY> </xsl:if> </xsl:if> </xsl:for-each> </HEAD_ENTRIES> </xsl:for-each> </HEAD> </data> </xsl:for-each> </xsl:template> </xsl:stylesheet>
预期输出
<data xmlns:java="http://xml.apache.org/xslt/java" xmlns:map="http://www.w3.org/2005/xpath-functions/map" xmlns:n0="http://sap.com/xi/SAPGlobal20/Global" xmlns:exsl="http://exslt.org/common" xmlns:ext="http://exslt.org/common"> <VBELN>3000016154</VBELN> <HEAD> <VBELN>3000016154</VBELN> <KUNNR_AG>1</KUNNR_AG> <KUNNR_SH>A</KUNNR_SH> <Address>Test_FinalCustomer1</Address> <HEAD_ENTRIES> <UNIT>KG</UNIT> <NET_AMOUNT>5000.00</NET_AMOUNT> <RATE_VALUE>2000</RATE_VALUE> <QUANTITY>1</QUANTITY> </HEAD_ENTRIES> <HEAD_ENTRIES> <UNIT>ML</UNIT> <NET_AMOUNT>6000.00</NET_AMOUNT> <RATE_VALUE>4000</RATE_VALUE> <QUANTITY>1</QUANTITY> </HEAD_ENTRIES> </HEAD> </data>
问题分析
原代码的核心问题是错误使用了绝对路径//,导致循环时选取了文档中所有匹配的节点,而非当前上下文的关联节点:
- 遍历
PartnerTypes时,用//AddressType会选取所有AddressType节点,包括FC类型下的地址,不符合预期;应改为当前PartnerTypes下的Address/AddressType。 - 遍历
Types时,用//PrElementType会选取所有PrElementType节点,导致每个HEAD_ENTRIES都包含所有PR00类型的RateValue和Quantity,而非当前Types对应的内容;应改为当前Types下的PricingElementsType/PrElementType。 - 遍历
PartnerTypes时,原路径//PartnerTypes会选取所有PartnerTypes,虽然加了PFunction=SH的判断,但更高效的写法是直接选取当前OrderTypes下的ItemPartner/PartnerTypes[PFunction='SH']。
修正后的XSLT代码
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:java="http://xml.apache.org/xslt/java" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:map="http://www.w3.org/2005/xpath-functions/map" xmlns:n0="http://sap.com/xi/SAPGlobal20/Global" exclude-result-prefixes="xs" xmlns:exsl="http://exslt.org/common" xmlns:ext="http://exslt.org/common"> <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/> <xsl:strip-space elements="*"/> <xsl:template match="Order"> <xsl:for-each select="OrderTypes"> <data> <xsl:if test="SalesOrder"> <VBELN> <xsl:value-of select="SalesOrder"/> </VBELN> </xsl:if> <HEAD> <xsl:if test="SalesOrder"> <VBELN> <xsl:value-of select="SalesOrder"/> </VBELN> </xsl:if> <xsl:if test="SoldToParty"> <KUNNR_AG> <xsl:value-of select="SoldToParty"/> </KUNNR_AG> </xsl:if> <!-- 仅选取当前OrderTypes下PFunction为SH的PartnerTypes --> <xsl:for-each select="ItemPartner/PartnerTypes[PFunction='SH']"> <xsl:if test="Customer"> <KUNNR_SH> <xsl:value-of select="Customer"/> </KUNNR_SH> </xsl:if> <!-- 选取当前PartnerTypes下的AddressType --> <xsl:for-each select="Address/AddressType"> <xsl:if test="Address"> <Address> <xsl:value-of select="Address"/> </Address> </xsl:if> </xsl:for-each> </xsl:for-each> <!-- 遍历当前OrderTypes下的Types节点 --> <xsl:for-each select="ItemTypes/Types"> <HEAD_ENTRIES> <xsl:if test="Unit"> <UNIT> <xsl:value-of select="Unit"/> </UNIT> </xsl:if> <xsl:if test="NetAmount"> <NET_AMOUNT> <xsl:value-of select="NetAmount"/> </NET_AMOUNT> </xsl:if> <!-- 选取当前Types下的PR00类型PrElementType --> <xsl:for-each select="PricingElementsType/PrElementType[Type='PR00']"> <xsl:if test="RateValue"> <RATE_VALUE> <xsl:value-of select="RateValue"/> </RATE_VALUE> </xsl:if> <xsl:if test="Quantity"> <QUANTITY> <xsl:value-of select="Quantity"/> </QUANTITY> </xsl:if> </xsl:for-each> </HEAD_ENTRIES> </xsl:for-each> </HEAD> </data> </xsl:for-each> </xsl:template> </xsl:stylesheet>
验证结果
修正后的代码会生成与预期完全一致的XML输出,解决了原代码中路径选取错误导致的内容重复、关联节点匹配错误问题。
内容的提问来源于stack exchange,提问作者Sateesh
相关产品推荐
相关产品推荐

