【问题标题】:Group XML file based on a given number using XSLT使用 XSLT 根据给定数字对 XML 文件进行分组
【发布时间】:2020-03-27 15:16:03
【问题描述】:

我想根据 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,基于 Group 编号值。就像第二个 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 中是否可行。
如果可以的话,你们能帮帮我吗?

【问题讨论】:

    标签: xml formatting grouping xslt-1.0 xslt-2.0


    【解决方案1】:

    您可以使用以下 XSLT-2.0 样式表实现所需的结果。它将&lt;EDICustomerLine&gt; 元素分组到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>
    

    这是如你所愿。

    【讨论】:

    • 嗨@zx485 非常感谢您的回答,它正在工作,您是一个真正的英雄:) 但是有一个小问题。当我把 1 放在那里时,它没有按预期显示,所有行记录都在一个 EDICustomer 标记内。没关系,我可以通过放置一个 if 来处理它,并检查 GroupNumber 是否为 1,如果 1 只是为每个行标签生成 EDICustomer。还有一件事我怎样才能得到那个组号,比如第一个 EDICustomer 标签是第 1 组,第二个是第 2 组。
    • 我可以从 position() 获取组号
    • 嗨@zx485 为什么它不适用于带有 514 EDICustomerLine 标签的 XML。基本上,我将 514 个文档划分为每组 50 个标签。所以应该有11个组。但是只有2组。
    • @RasangaAbeykoon:我很抱歉。 xsl:for-each-group 的 group-by 表达式错误。我现在修好了。
    • 我之前没有检查它是否有更大的行记录。现在它适用于更大的类似记录。谢谢!!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-19
    • 1970-01-01
    相关资源
    最近更新 更多