xmlxsltxslt-groupingmuenchian-grouping

grouping based on non-identical line items xsl1.0


I have requirement as below to implement transformation using only XSL1.0,

  1. First condition is Group line items based on parentLineNumber.
  2. Then the second condition is to ignore the invoice line when ParentLinenumber and LineNumber is same when only if group has more than one invoice line item.

Sample Input:

<InvoiceNotification>
    <Invoice>
        <InvoiceLineItem>
            <LineSection>
                <parentLineNumber>000010</parentLineNumber>
            </LineSection>
            <LineNumber>000010</LineNumber>
            <proprietaryInformation>
                <FreeFormText>PK06</FreeFormText>
            </proprietaryInformation>
        </InvoiceLineItem>
        <InvoiceLineItem>
            <LineSection>
                <parentLineNumber>000010</parentLineNumber>
            </LineSection>
            <LineNumber>000011</LineNumber>
            <proprietaryInformation>
                <FreeFormText>PK07</FreeFormText>
            </proprietaryInformation>
        </InvoiceLineItem>
        <InvoiceLineItem>
            <LineSection>
                <parentLineNumber>000010</parentLineNumber>
            </LineSection>
            <LineNumber>000012</LineNumber>
            <proprietaryInformation>
                <FreeFormText>PK08</FreeFormText>
            </proprietaryInformation>
        </InvoiceLineItem>
        <InvoiceLineItem>
            <LineSection>
                <parentLineNumber>000020</parentLineNumber>
            </LineSection>
            <LineNumber>000020</LineNumber>
            <proprietaryInformation>
                <FreeFormText>GK01</FreeFormText>
            </proprietaryInformation>
        </InvoiceLineItem>
    </Invoice>
</InvoiceNotification>

I have developed below XSLT which is partially working.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes"/>
    <xsl:key name="Invoices" match="InvoiceLineItem" use="LineSection/parentLineNumber"/>
    <xsl:template match="InvoiceNotification">
        <Invoices>
            <xsl:for-each select="Invoice/InvoiceLineItem [ count ( key('Invoices',LineSection/parentLineNumber)[1] | . ) = 1 ]">
                <Batchorder>
                    <xsl:for-each select="key('Invoices',LineNumber)">
                        <Items>
                            <LineItem>
                                <xsl:value-of select="proprietaryInformation"/>
                            </LineItem>
                        </Items>
                    </xsl:for-each>
                </Batchorder>
            </xsl:for-each>
        </Invoices>
    </xsl:template>
</xsl:stylesheet>

Resulted output:

<?xml version="1.0" encoding="UTF-8"?>
<Invoices>
    <Batchorder>
        <Items>
            <proprietaryInformation>PK06</proprietaryInformation>
        </Items>
        <Items>
            <proprietaryInformation>PK07</proprietaryInformation>
        </Items>
        <Items>
            <proprietaryInformation>PK08</proprietaryInformation>
        </Items>
    </Batchorder>
    <Batchorder>
        <Items>
            <proprietaryInformation>GK01</proprietaryInformation>
        </Items>
    </Batchorder>
</Invoices>

But I am expecting below output,

<?xml version="1.0" encoding="UTF-8"?>
<Invoices>
    <Batchorder>
        <Items>
            <proprietaryInformation>PK07</proprietaryInformation>
        </Items>
        <Items>
            <proprietaryInformation>PK08</proprietaryInformation>
        </Items>
    </Batchorder>
    <Batchorder>
        <Items>
            <proprietaryInformation>GK01</proprietaryInformation>
        </Items>
    </Batchorder>
</Invoices>

Solution

  • Almost the same solution as the one proposed by Martin Honnen, but probably a little bit more efficient:

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
        <xsl:key name="Invoices" match="InvoiceLineItem" use="LineSection/parentLineNumber"/>
        <xsl:template match="InvoiceNotification">
            <Invoices>
                <xsl:for-each select=
                "Invoice/InvoiceLineItem
                [count ( key('Invoices',LineSection/parentLineNumber)[1] | . ) = 1]">
                    <Batchorder>
                        <xsl:for-each select="key('Invoices',LineNumber)
                        [not(LineNumber = LineSection/parentLineNumber)
                        or not(key('Invoices',LineNumber)[2])]">
                            <Items>
                                <LineItem>
                                    <xsl:value-of select="proprietaryInformation"/>
                                </LineItem>
                            </Items>
                        </xsl:for-each>
                    </Batchorder>
                </xsl:for-each>
            </Invoices>
        </xsl:template>
    </xsl:stylesheet>
    

    When this transformation is applied on the provided source XML document:

    <InvoiceNotification>
        <Invoice>
            <InvoiceLineItem>
                <LineSection>
                    <parentLineNumber>000010</parentLineNumber>
                </LineSection>
                <LineNumber>000010</LineNumber>
                <proprietaryInformation>
                    <FreeFormText>PK06</FreeFormText>
                </proprietaryInformation>
            </InvoiceLineItem>
            <InvoiceLineItem>
                <LineSection>
                    <parentLineNumber>000010</parentLineNumber>
                </LineSection>
                <LineNumber>000011</LineNumber>
                <proprietaryInformation>
                    <FreeFormText>PK07</FreeFormText>
                </proprietaryInformation>
            </InvoiceLineItem>
            <InvoiceLineItem>
                <LineSection>
                    <parentLineNumber>000010</parentLineNumber>
                </LineSection>
                <LineNumber>000012</LineNumber>
                <proprietaryInformation>
                    <FreeFormText>PK08</FreeFormText>
                </proprietaryInformation>
            </InvoiceLineItem>
            <InvoiceLineItem>
                <LineSection>
                    <parentLineNumber>000020</parentLineNumber>
                </LineSection>
                <LineNumber>000020</LineNumber>
                <proprietaryInformation>
                    <FreeFormText>GK01</FreeFormText>
                </proprietaryInformation>
            </InvoiceLineItem>
        </Invoice>
    </InvoiceNotification>
    

    the wanted, correct result is produced:

    <Invoices>
       <Batchorder>
          <Items>
             <LineItem>
                    PK07
                </LineItem>
          </Items>
          <Items>
             <LineItem>
                    PK08
                </LineItem>
          </Items>
       </Batchorder>
       <Batchorder>
          <Items>
             <LineItem>
                    GK01
                </LineItem>
          </Items>
       </Batchorder>
    </Invoices>