使用 XSLT 根据给定的数字对 XML 文件进行分组

Group XML file based on a given number using XSLT

我想根据 XML 标签值对 XML 文件进行分组。下面是我的输入 XML.

<Root>
    <GroupNumber>3</GroupNumber>
    <EDICustomer>
        <Company>IWS</Company>
        <Customer>150</Customer>
        <CreationDate>2020-03-15T10:29:08.813</CreationDate>
        <CreationTime>2020-03-15T10:29:08.813</CreationTime>
        <EDICustomerLine>
            <Barcode>447896130245</Barcode>
            <ItemDescription>Medium</ItemDescription>
            <Warehouse>B01</Warehouse>
            <Status>12</Status>
        </EDICustomerLine>
        <EDICustomerLine>
            <Barcode>447896130245</Barcode>
            <ItemDescription>Medium</ItemDescription>
            <Warehouse>B01</Warehouse>
            <Status>12</Status>
        </EDICustomerLine>
        <EDICustomerLine>
            <Barcode>447896130245</Barcode>
            <ItemDescription>Medium</ItemDescription>
            <Warehouse>B01</Warehouse>
            <Status>12</Status>
        </EDICustomerLine>
        <EDICustomerLine>
            <Barcode>447896130245</Barcode>
            <ItemDescription>Medium</ItemDescription>
            <Warehouse>B01</Warehouse>
            <Status>12</Status>
        </EDICustomerLine>
    </EDICustomer>
</Root>

我不知道那里会有多少个 EDICustomerLine 标签。如果 GroupNumber 值大于 EDICustomerLine 标签的数量,则保留 EDICustomer 子标签,但如果 GroupNumber 小于 EDICustomerLine 标签,我们必须根据 GroupNumber 标签值拆分 EDICustomerLine 标签。所以在这种情况下,预期的 XML 将如下所示。

<Root>
    <EDICustomer>
        <Company>IWS</Company>
        <Customer>150</Customer>
        <CreationDate>2020-03-15T10:29:08.813</CreationDate>
        <CreationTime>2020-03-15T10:29:08.813</CreationTime>
        <EDICustomerLine>
            <Barcode>447896130245</Barcode>
            <ItemDescription>Medium</ItemDescription>
            <Warehouse>B01</Warehouse>
            <Status>12</Status>
        </EDICustomerLine>
        <EDICustomerLine>
            <Barcode>447896130245</Barcode>
            <ItemDescription>Medium</ItemDescription>
            <Warehouse>B01</Warehouse>
            <Status>12</Status>
        </EDICustomerLine>
        <EDICustomerLine>
            <Barcode>447896130245</Barcode>
            <ItemDescription>Medium</ItemDescription>
            <Warehouse>B01</Warehouse>
            <Status>12</Status>
        </EDICustomerLine>
    </EDICustomer>
    <EDICustomer>
        <Company>IWS</Company>
        <Customer>150</Customer>
        <CreationDate>2020-03-15T10:29:08.813</CreationDate>
        <CreationTime>2020-03-15T10:29:08.813</CreationTime>
        <EDICustomerLine>
            <Barcode>447896130245</Barcode>
            <ItemDescription>Medium</ItemDescription>
            <Warehouse>B01</Warehouse>
            <Status>12</Status>
        </EDICustomerLine>
    </EDICustomer>
</Root>

第一个 EDICustomer 父标签包含 Company、Customer、CreationDate、CreationTime 和基于组编号值的 3。就像第二个 EDICustomer 应该包含 3 个或更少的标签。我们不知道那里会有多少 EDICustomerLine 标签和 Group Number 的值。还有

<Company>IWS</Company>
        <Customer>150</Customer>
        <CreationDate>2020-03-15T10:29:08.813</CreationDate>
        <CreationTime>2020-03-15T10:29:08.813</CreationTime>

以上部分应在所有 EDICustomer 组中重复(如果我们找到一种基于组号循环 EDICustomerLine 的方法,这部分将成为可能)。

首先我想知道这种情况在XSLT中是否可行。
如果可以的话,你们能帮帮我吗?

您可以使用以下 XSLT-2.0 样式表获得所需的结果。它将 <EDICustomerLine> 元素分组为 GroupNumber 组,然后遍历 current-group()。常量部分由第一个 xsl:copy-of.

创建
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>

  <xsl:template match="text()" />

  <!-- identity template -->
  <xsl:template match="node()|@*">
    <xsl:copy>
      <xsl:apply-templates select="node()|@*" />
    </xsl:copy>
   </xsl:template>  

   <xsl:template match="Root">
     <xsl:variable name="max" select="GroupNumber" />
     <xsl:copy>
        <!-- Handle the "zero-items" situation" -->
        <xsl:if test="count(EDICustomer/EDICustomerLine) = 0">
            <EDICustomer>
                <xsl:copy-of select="EDICustomer[1]/Company | EDICustomer[1]/Customer | EDICustomer[1]/CreationDate | EDICustomer[1]/CreationTime" />
            </EDICustomer>
        </xsl:if>
        <xsl:for-each-group select="EDICustomer/EDICustomerLine" group-by="(position()-1) idiv $max">
            <EDICustomer>
                <!-- Add a <GroupNr> element with the index of the group -->
                <GroupNr><xsl:value-of select="position()" /></GroupNr>
                <xsl:copy-of select="../Company | ../Customer | ../CreationDate | ../CreationTime" />
                <xsl:copy-of select="current-group()" />
            </EDICustomer>
        </xsl:for-each-group>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

其结果是:

<Root>
    <EDICustomer>
        <GroupNr>1</GroupNr>
        <Company>IWS</Company>
        <Customer>150</Customer>
        <CreationDate>2020-03-15T10:29:08.813</CreationDate>
        <CreationTime>2020-03-15T10:29:08.813</CreationTime>
        <EDICustomerLine>
            <Barcode>447896130245</Barcode>
            <ItemDescription>Medium</ItemDescription>
            <Warehouse>B01</Warehouse>
            <Status>12</Status>
        </EDICustomerLine>
        <EDICustomerLine>
            <Barcode>447896130245</Barcode>
            <ItemDescription>Medium</ItemDescription>
            <Warehouse>B01</Warehouse>
            <Status>12</Status>
        </EDICustomerLine>
        <EDICustomerLine>
            <Barcode>447896130245</Barcode>
            <ItemDescription>Medium</ItemDescription>
            <Warehouse>B01</Warehouse>
            <Status>12</Status>
        </EDICustomerLine>
    </EDICustomer>
    <EDICustomer>
        <GroupNr>2</GroupNr>
        <Company>IWS</Company>
        <Customer>150</Customer>
        <CreationDate>2020-03-15T10:29:08.813</CreationDate>
        <CreationTime>2020-03-15T10:29:08.813</CreationTime>
        <EDICustomerLine>
            <Barcode>447896130245</Barcode>
            <ItemDescription>Medium</ItemDescription>
            <Warehouse>B01</Warehouse>
            <Status>12</Status>
        </EDICustomerLine>
    </EDICustomer>
</Root>

如愿以偿。