添加SAP PI信封后XSLT转换失效,求可行解决方案
解决SAP PI信封下XSLT转换失效问题
问题背景
我有一套可正常运行的XSLT,处理不带信封的目标命名空间XML时能得到预期转换结果。但当SAP PI为XML添加带有http://sap.com/xi/XI/SplitAndMerge命名空间的<ns0:Messages>信封后,XSLT转换仅输出空的<Containers>节点。希望修改XSLT,既能保留信封结构,又能正确转换内部的Containers内容。
输入XML(无信封)
<Containers xmlns="https://www.uniconcreation.com/2021/IvenzaShippingContainer"> <Container> <Name>INTERIEUR1</Name> <Number>1</Number> <SSCC>111</SSCC> <SubContainers> <Container> <Id>I1371851</Id> <SalesOrderNumber>2012231</SalesOrderNumber> <ProductionOrderNumber>I2017658</ProductionOrderNumber> <Name>ACCESSOIRE1</Name> <Barcode>181001371851</Barcode> <Items> <Item> <Id>I8709475</Id> <SalesOrderRowId>I671068</SalesOrderRowId> <SalesOrderRowExternalReference>1</SalesOrderRowExternalReference> <Quantity>1</Quantity> </Item> <Item> <Id>I8709476</Id> <SalesOrderRowId>I671068</SalesOrderRowId> <SalesOrderRowExternalReference>1</SalesOrderRowExternalReference> <Quantity>1</Quantity> </Item> </Items> </Container> <Container> <Id>I1371852</Id> <SalesOrderNumber>2012231</SalesOrderNumber> <ProductionOrderNumber>I2017658</ProductionOrderNumber> <Name>PANEEL1</Name> <Barcode>181001371852</Barcode> <Items> <Item> <Id>I8709492</Id> <SalesOrderRowId>I671068</SalesOrderRowId> <SalesOrderRowExternalReference>1</SalesOrderRowExternalReference> <Quantity>1</Quantity> </Item> </Items> </Container> </SubContainers> </Container> </Containers>
原XSLT
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="2.0" xpath-default-namespace="https://www.uniconcreation.com/2021/IvenzaShippingContainer" xmlns="https://www.uniconcreation.com/2021/IvenzaShippingContainer" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> <xsl:template match="Containers"> <xsl:variable name="sscc" select="Container/SSCC"/> <xsl:copy> <xsl:for-each select="//Container"> <xsl:variable name="level" select="count(ancestor::*)"/> <xsl:choose> <xsl:when test="$level = 1"> <xsl:copy> <xsl:copy-of select="Id"/> <xsl:copy-of select="SalesOrderNumber"/> <xsl:copy-of select="ProductionOrderNumber"/> <xsl:copy-of select="Name"/> <xsl:copy-of select="Type"/> <xsl:copy-of select="Number"/> <xsl:copy-of select="SSCC"/> <xsl:copy-of select="Barcode"/> <xsl:copy-of select="StartedAt"/> <xsl:copy-of select="CompletedAt"/> <xsl:choose> <xsl:when test="SubContainers"> <Items> <xsl:for-each select="SubContainers"> <Item> <Id> <xsl:value-of select="Container[1]/Id"/> </Id> <SalesOrderRowId> <xsl:value-of select="Container[1]/Items/Item[1]/SalesOrderRowId"/> </SalesOrderRowId> <Quantity>1</Quantity> </Item> </xsl:for-each> </Items> </xsl:when> <xsl:otherwise> <xsl:copy-of select="Items"/> </xsl:otherwise> </xsl:choose> </xsl:copy> </xsl:when> <xsl:otherwise> </xsl:otherwise> </xsl:choose> </xsl:for-each> </xsl:copy> </xsl:template> </xsl:stylesheet>
原转换结果
<?xml version="1.0" encoding="UTF-8"?> <Containers xmlns="https://www.uniconcreation.com/2021/IvenzaShippingContainer"> <Container> <Name>INTERIEUR1</Name> <Number>1</Number> <SSCC>111</SSCC> <Items> <Item> <Id>I1371851</Id> <SalesOrderRowId>I671068</SalesOrderRowId> <Quantity>1</Quantity> </Item> </Items> </Container> </Containers>
带SAP PI信封的输入XML
<?xml version="1.0" encoding="UTF-8"?> <ns0:Messages xmlns:ns0="http://sap.com/xi/XI/SplitAndMerge"> <ns0:Message1> <Containers xmlns="https://www.uniconcreation.com/2021/IvenzaShippingContainer"> <Container> <Name>INTERIEUR1</Name> <Number>1</Number> <SSCC>111</SSCC> <SubContainers> <Container> <Id>I1371851</Id> <SalesOrderNumber>2012231</SalesOrderNumber> <ProductionOrderNumber>I2017658</ProductionOrderNumber> <Name>ACCESSOIRE1</Name> <Barcode>181001371851</Barcode> <Items> <Item> <Id>I8709475</Id> <SalesOrderRowId>I671068</SalesOrderRowId> <SalesOrderRowExternalReference>1</SalesOrderRowExternalReference> <Quantity>1</Quantity> </Item> <Item> <Id>I8709476</Id> <SalesOrderRowId>I671068</SalesOrderRowId> <SalesOrderRowExternalReference>1</SalesOrderRowExternalReference> <Quantity>1</Quantity> </Item> </Items> </Container> <Container> <Id>I1371852</Id> <SalesOrderNumber>2012231</SalesOrderNumber> <ProductionOrderNumber>I2017658</ProductionOrderNumber> <Name>PANEEL1</Name> <Barcode>181001371852</Barcode> <Items> <Item> <Id>I8709492</Id> <SalesOrderRowId>I671068</SalesOrderRowId> <SalesOrderRowExternalReference>1</SalesOrderRowExternalReference> <Quantity>1</Quantity> </Item> </Items> </Container> </SubContainers> </Container> </Containers> </ns0:Message1> </ns0:Messages>
当前错误输出
<?xml version="1.0" encoding="UTF-8"?> <Containers xmlns="https://www.uniconcreation.com/2021/IvenzaShippingContainer" xmlns:ns0="http://sap.com/xi/XI/SplitAndMerge"/>
期望输出
<?xml version="1.0" encoding="UTF-8"?> <ns0:Messages xmlns:ns0="http://sap.com/xi/XI/SplitAndMerge"> <ns0:Message1> <Containers xmlns="https://www.uniconcreation.com/2021/IvenzaShippingContainer"> <Container> <Name>INTERIEUR1</Name> <Number>1</Number> <SSCC>111</SSCC> <Items> <Item> <Id>I1371851</Id> <SalesOrderRowId>I671068</SalesOrderRowId> <Quantity>1</Quantity> </Item> </Items> </Container> </Containers> </ns0:Message1> </ns0:Messages>
解决方案
添加身份模板复制SAP PI信封节点,同时保留原有Containers处理逻辑,无需手动处理所有命名空间。
修改后的XSLT
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="2.0" xpath-default-namespace="https://www.uniconcreation.com/2021/IvenzaShippingContainer" xmlns="https://www.uniconcreation.com/2021/IvenzaShippingContainer" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:pi="http://sap.com/xi/XI/SplitAndMerge"> <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> <!-- 身份模板:复制所有未被匹配的节点和属性,保留SAP PI信封结构 --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <!-- 保留原有的Containers处理逻辑,仅针对目标命名空间节点转换 --> <xsl:template match="Containers"> <xsl:copy> <xsl:for-each select="//Container"> <xsl:variable name="level" select="count(ancestor::*)"/> <xsl:choose> <xsl:when test="$level = 1"> <xsl:copy> <xsl:copy-of select="Id"/> <xsl:copy-of select="SalesOrderNumber"/> <xsl:copy-of select="ProductionOrderNumber"/> <xsl:copy-of select="Name"/> <xsl:copy-of select="Type"/> <xsl:copy-of select="Number"/> <xsl:copy-of select="SSCC"/> <xsl:copy-of select="Barcode"/> <xsl:copy-of select="StartedAt"/> <xsl:copy-of select="CompletedAt"/> <xsl:choose> <xsl:when test="SubContainers"> <Items> <xsl:for-each select="SubContainers"> <Item> <Id> <xsl:value-of select="Container[1]/Id"/> </Id> <SalesOrderRowId> <xsl:value-of select="Container[1]/Items/Item[1]/SalesOrderRowId"/> </SalesOrderRowId> <Quantity>1</Quantity> </Item> </xsl:for-each> </Items> </xsl:when> <xsl:otherwise> <xsl:copy-of select="Items"/> </xsl:otherwise> </xsl:choose> </xsl:copy> </xsl:when> <xsl:otherwise> </xsl:otherwise> </xsl:choose> </xsl:for-each> </xsl:copy> </xsl:template> </xsl:stylesheet>
方案说明
- 身份模板:匹配所有节点和属性,默认执行复制操作,确保SAP PI信封节点完整保留,无需单独编写模板处理该命名空间。
- 原有
Containers模板逻辑不变,仅对目标命名空间下的节点进行转换,不干扰信封结构。 - 声明SAP PI命名空间前缀
pi,避免命名空间解析冲突,确保XSLT能正确识别信封节点。
内容的提问来源于stack exchange,提问作者Mike Dole
相关产品推荐
相关产品推荐

