XSLT 和 Muenchian 分组, 多级样本
Posted
技术标签:
【中文标题】XSLT 和 Muenchian 分组, 多级样本【英文标题】:XSLT and Muenchian Grouping , Multiple Level Sample 【发布时间】:2016-05-19 18:15:24 【问题描述】:我对 XSLT 还很陌生,以前从未使用过 Muenchian Grouping。我一直试图通过为自己创建一个示例来理解这个概念,但我无法理解如何获得所需的输出,尤其是在处理子记录时。
假设我们有一个如下所示的输入 XML:
<OrdersFF xmlns="http://Romp.BizTalk.MapTest">
<Order>
<OrderID>O1</OrderID>
<ItemID>I1</ItemID>
<TrackingID>T1</TrackingID>
</Order>
<Order>
<OrderID>O1</OrderID>
<ItemID>I2</ItemID>
<TrackingID>T2</TrackingID>
</Order>
<Order>
<OrderID>O1</OrderID>
<ItemID>I2</ItemID>
<TrackingID>T3</TrackingID>
</Order>
<Order>
<OrderID>O2</OrderID>
<ItemID>I3</ItemID>
<TrackingID>T4</TrackingID>
</Order>
<Order>
<OrderID>O2</OrderID>
<ItemID>I3</ItemID>
<TrackingID>T5</TrackingID>
</Order>
<Order>
<OrderID>O3</OrderID>
<ItemID>I4</ItemID>
<TrackingID>T6</TrackingID>
</Order>
</OrdersFF>
我们希望输出按 orderid、item、trackingcode 分组(我们假设每个订单可以有多个项目,每个项目可以有多个跟踪代码)。所以输出应该是这样的:
<ns0:orders xmlns:ns0="http://Romp.BizTalk.MapTest">
<order>
<orderid>O1</orderid>
<items>
<item>I1</item>
<shippingdetails>
<trackingcode>T1</trackingcode>
</shippingdetails>
</items>
<items>
<item>I2</item>
<shippingdetails>
<trackingcode>T2</trackingcode>
</shippingdetails>
<shippingdetails>
<trackingcode>T3</trackingcode>
</shippingdetails>
</items>
</order>
<order>
<orderid>O2</orderid>
<items>
<item>I3</item>
<shippingdetails>
<trackingcode>T4</trackingcode>
</shippingdetails>
<shippingdetails>
<trackingcode>T5</trackingcode>
</shippingdetails>
</items>
</order>
<order>
<orderid>O3</orderid>
<items>
<item>I4</item>
<shippingdetails>
<trackingcode>T6</trackingcode>
</shippingdetails>
</items>
</order>
</ns0:orders>
我尝试使用 XSLT,这是我目前所拥有的(不起作用):
<?xml version="1.0" encoding="UTF-16"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:var="http://schemas.microsoft.com/BizTalk/2003/var" exclude-result-prefixes="msxsl var s0" version="1.0" xmlns:s0="http://Romp.BizTalk.MapTest" xmlns:ns0="http://Romp.BizTalk.MapTest">
<xsl:output omit-xml-declaration="yes" method="xml" version="1.0" />
<!-- Create a key to match against groups in source schema -->
<xsl:key name="k1" match="Order" use="OrderID"/>
<xsl:key name="k2" match="Order" use="concat(OrderID,'|',ItemID)"/>
<xsl:key name="k3" match="Order" use="concat(OrderID,'|',ItemID,'|',TrackingID)"/>
<xsl:template match="/">
<xsl:apply-templates select="/s0:OrdersFF" />
</xsl:template>
<xsl:template match="/s0:OrdersFF">
<ns0:orders>
<!-- This will loop through our key ("OrderID") -->
<xsl:for-each select="Order[generate-id(.)=generate-id(key('k1',OrderID))]">
<order>
<orderid>
<xsl:value-of select="OrderID/text()" />
</orderid>
<!-- Another loop... -->
<xsl:for-each select="Order[generate-id(.)=generate-id(key('k2',concat(OrderID,'|',ItemID)))]">
<items>
<item>
<xsl:value-of select="ItemID" />
</item>
<!-- Another loop... -->
<xsl:for-each select="Order[generate-id(.)=generate-id(key('k3',concat(OrderID,'|',ItemID,'|',TrackingID)))]">
<shippingdetails>
<trackingcode>
<xsl:value-of select="TrackingID"/>
</trackingcode>
</shippingdetails>
</xsl:for-each>
</items>
</xsl:for-each>
</order>
</xsl:for-each>
</ns0:orders>
</xsl:template>
</xsl:stylesheet>
任何人都可以为我提供有关如何进行的任何帮助吗? 谢谢!
【问题讨论】:
【参考方案1】:实际上,您的 XSLT 并没有那么遥远,这是一个很好的开始,但是您需要纠正两个问题。第一个是名称空间。您正在某些地方处理命名空间,例如...
<xsl:apply-templates select="/s0:OrdersFF" />
但并非在所有地方。在您的情况下,s0
前缀需要为 XSLT 中的所有元素名称添加前缀,包括它们出现在键中时。例如
<xsl:key name="k2" match="s0:Order" use="concat(s0:OrderID,'|',s0:ItemID)"/>
第二个问题与嵌套循环有关。第一个嵌套循环是这样的(在我添加了命名空间前缀之后)
<xsl:for-each select="s0:Order[generate-id(.)=generate-id(key('k2',concat(s0:OrderID,'|',s0:ItemID)))]">
但是此时您当前定位在Order
元素上,所以这是在寻找不存在的子Order
元素!您需要在这里做的是选择当前“组”中的所有Order
元素。为此,您使用上一个键
<xsl:for-each select="key('k1',s0:OrderID)[generate-id(.)=generate-id(key('k2',concat(s0:OrderID,'|',s0:ItemID)))]">
对于嵌套在其中的for-each
也是如此。
试试这个稍微修改过的 XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:var="http://schemas.microsoft.com/BizTalk/2003/var" exclude-result-prefixes="msxsl var s0" version="1.0" xmlns:s0="http://Romp.BizTalk.MapTest" xmlns:ns0="http://Romp.BizTalk.MapTest">
<xsl:output omit-xml-declaration="yes" method="xml" version="1.0" indent="yes" />
<!-- Create a key to match against groups in source schema -->
<xsl:key name="k1" match="s0:Order" use="s0:OrderID"/>
<xsl:key name="k2" match="s0:Order" use="concat(s0:OrderID,'|',s0:ItemID)"/>
<xsl:key name="k3" match="s0:Order" use="concat(s0:OrderID,'|',s0:ItemID,'|',s0:TrackingID)"/>
<xsl:template match="/">
<xsl:apply-templates select="/s0:OrdersFF" />
</xsl:template>
<xsl:template match="/s0:OrdersFF">
<ns0:orders>
<!-- This will loop through our key ("OrderID") -->
<xsl:for-each select="s0:Order[generate-id(.)=generate-id(key('k1',s0:OrderID))]">
<order>
<orderid>
<xsl:value-of select="s0:OrderID/text()" />
</orderid>
<!-- Another loop... -->
<xsl:for-each select="key('k1',s0:OrderID)[generate-id(.)=generate-id(key('k2',concat(s0:OrderID,'|',s0:ItemID)))]">
<items>
<item>
<xsl:value-of select="s0:ItemID" />
</item>
<!-- Another loop... -->
<xsl:for-each select="key('k2',concat(s0:OrderID,'|',s0:ItemID))[generate-id(.)=generate-id(key('k3',concat(s0:OrderID,'|',s0:ItemID,'|',s0:TrackingID)))]">
<shippingdetails>
<trackingcode>
<xsl:value-of select="s0:TrackingID"/>
</trackingcode>
</shippingdetails>
</xsl:for-each>
</items>
</xsl:for-each>
</order>
</xsl:for-each>
</ns0:orders>
</xsl:template>
</xsl:stylesheet>
【讨论】:
非常感谢您的详细解释!你的回答非常有用! :)以上是关于XSLT 和 Muenchian 分组, 多级样本的主要内容,如果未能解决你的问题,请参考以下文章