XSLT 和 Muenchian 分组, 多级样本

XSLT and Muenchian Grouping , Multiple Level Sample

我对 XSLT 还很陌生,以前从未使用过 Muenchian 分组。我一直试图通过为自己创建示例来理解这个概念,但我无法理解如何获得所需的输出,尤其是在处理子记录时。

假设我们有一个如下所示的输入 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 分组,然后是项目,然后是跟踪代码(我们假设每个订单可以有多个项目,每个项目可以有多个跟踪代码)。所以输出应该是这样的:

<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>

任何人都可以为我提供有关如何进行的任何帮助吗? 谢谢!

您的 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 的子元素,这些元素不存在!这里需要做的是select当前"group"中的所有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>