基于XSLT 1.0实现多级BOM XML到单层级父子结构XML的转换(不支持Muenchian分组)
解决方案:无key函数支持下的多级BOM转单层级XML(XSLT 1.0)
我明白你的困境——在XSLT 1.0环境里没法用key函数,没法依赖Muenchian分组来处理多级BOM的扁平化。别担心,咱们可以用递归模板来搞定这个需求,完全不需要key函数,靠层级遍历和参数传递就能实现父子关系的拆解。
下面是修改后的完整XSLT代码,我替换了你原框架里的transform模板部分:
<?bpc.pltype.out bpm.pltype=xml?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:b1e="urn:com.sap.b1i.sim:b1event" xmlns:b1ie="urn:com.sap.b1i.sim:b1ievent" xmlns:b1im="urn:com.sap.b1i.sim:b1imessage" xmlns:bfa="urn:com.sap.b1i.bizprocessor:bizatoms" xmlns:exslt="http://exslt.org/common" xmlns:jdbc="urn:com.sap.b1i.adapter:jdbcadapter" xmlns:js="com.sap.b1i.bpc_tools.Javascript" xmlns:rev="urn:com.sap.b1i.adapter:revaadapter" xmlns:rfc="urn:sap-com:document:sap:rfc:functions" xmlns:sim="urn:com.sap.b1i.sim:entity" xmlns:utils="com.sap.b1i.bpc_tools.Utilities" xmlns:vpf="urn:com.sap.b1i.vplatform:entity" xmlns:xci="urn:com.sap.b1i.xcellerator:intdoc" version="1.0" exclude-result-prefixes="b1e b1ie b1im bfa jdbc js rfc utils xci vpf exslt sim rev" b1e:force="" b1ie:force="" b1im:force="" bfa:force="" jdbc:force="" js:force="" rfc:force="" utils:force="" xci:force="" vpf:force="" exslt:force="" sim:force="" rev:force=""> <?prodver 1.0.0?> <!--<xsl:include href="../../com.sap.b1i.dev.repository/IDE/init.xsl" />--> <xsl:variable name="msg" select="/vpf:Msg/vpf:Body/vpf:Payload[./@Role='S']" /> <xsl:template match="/"> <Msg xmlns="urn:com.sap.b1i.vplatform:entity"> <xsl:copy-of select="/vpf:Msg/@*" /> <xsl:copy-of select="/vpf:Msg/vpf:Header" /> <Body> <xsl:copy-of select="/vpf:Msg/vpf:Body/*" /> <Payload Role="X" id="999999"> <xsl:call-template name="transform" /> </Payload> </Body> </Msg> </xsl:template> <xsl:template name="transform"> <Items> <!-- 遍历所有顶层level01物料 --> <xsl:for-each select="$msg/Items/level01"> <!-- 生成顶层Item(无父项) --> <Item> <xsl:copy-of select="itemcode | quantity | whs" /> </Item> <!-- 处理level02的子项,传递顶层物料编码作为父ID --> <xsl:call-template name="process-child-rows"> <xsl:with-param name="parent-code" select="itemcode" /> <xsl:with-param name="rows" select="level02/row" /> </xsl:call-template> </xsl:for-each> </Items> </xsl:template> <!-- 递归处理子项行的模板 --> <xsl:template name="process-child-rows"> <xsl:param name="parent-code" /> <xsl:param name="rows" /> <xsl:for-each select="$rows"> <!-- 生成当前子项的Item记录,带父项编码 --> <Item> <father><xsl:value-of select="$parent-code" /></father> <xsl:copy-of select="itemcode | quantity | whs" /> </Item> <!-- 如果当前行有下一级子项(比如level03),递归处理 --> <xsl:if test="level03"> <xsl:call-template name="process-child-rows"> <xsl:with-param name="parent-code" select="itemcode" /> <xsl:with-param name="rows" select="level03/row" /> </xsl:call-template> </xsl:if> </xsl:for-each> </xsl:template> </xsl:stylesheet>
代码逻辑说明
- 顶层物料处理:
transform模板先遍历所有level01节点,生成无father字段的顶层Item,然后调用递归模板处理它的子层级。 - 递归子项处理:
process-child-rows模板接收两个参数:parent-code(父项编码)和rows(需要处理的子项行)。对于每一行,先输出带father的Item,然后检查是否有下一级子节点(比如level03),如果有就再次调用自己,把当前行的编码作为新的父ID传递下去。 - 灵活性:这个方案不局限于三级BOM,哪怕有更多层级(比如level04、level05),递归都会自动遍历处理,完全适配任意深度的BOM结构。
注意事项
你给出的期望输出里,<Item>和<item>大小写不一致,我在代码里统一用了大写的<Item>,如果需要和你的期望完全匹配,只需要把代码里的<Item>改成<item>即可。
用这个代码处理你的示例XML,会生成和你期望一致的单层级XML结果,每个父子关系都拆分成独立的记录。
内容的提问来源于stack exchange,提问作者Mark
相关产品推荐
相关产品推荐

