Mike Dole
Mike Dole

Reputation: 687

Incorrect group by (level) in XSLT?

I have an xml with TripOverview elements where I want to group the /MultiTripOverview/TripOverview/HeaderDetails/DropItems/DropItem in each individual TripOverview element but once again I can't get this to work :(

Example / link: https://xsltfiddle.liberty-development.net/jyH7UDA/2

Input xml

<?xml version="1.0" encoding="UTF-8"?>
<MultiTripOverview>
    <ShipmentDate>07.07.2023</ShipmentDate>
    <PrinterId>PRINTERXYZ</PrinterId>
    <ReportType>1</ReportType>
        <TripOverview>
        <HeaderDetails>
            <ShipmentNumber>0000303137</ShipmentNumber>
            <DropItems>
                <DropItem>
                    <DropNr>1</DropNr>
                    <Customer>0000013120</Customer>
                    <Name>OBI</Name>
                    <DeliveryNr>0082048820</DeliveryNr>
                </DropItem>
                <DropItem>
                    <DropNr>1</DropNr>
                    <Customer>0000013120</Customer>
                    <Name>OBI</Name>
                    <DeliveryNr>0082048821</DeliveryNr>
                </DropItem>
                <DropItem>
                    <DropNr>1</DropNr>
                    <Customer>0000013120</Customer>
                    <Name>OBI</Name>
                    <DeliveryNr>0082048040</DeliveryNr>
                </DropItem>
            </DropItems>
        </HeaderDetails>
    </TripOverview>
<TripOverview>
        <HeaderDetails>
            <ShipmentNumber>0000303138</ShipmentNumber>
            <Block>LPB1</Block>
            <DropItems>
                <DropItem>
                    <DropNr>1</DropNr>
                    <Customer>0000013590</Customer>
                    <Name>Hornbach Berlin</Name>
                    <DeliveryNr>0082048143</DeliveryNr>
                </DropItem>
            </DropItems>
        </HeaderDetails>
    </TripOverview>
    <TripOverview>
        <HeaderDetails>
            <ShipmentNumber>0000303139</ShipmentNumber>
            <DropItems>
                <DropItem>
                    <DropNr>1</DropNr>
                    <Customer>0000016536</Customer>
                    <Name>Hubo Amsterdam</Name>
                    <DeliveryNr>0082048979</DeliveryNr>
                </DropItem>
            </DropItems>
        </HeaderDetails>
    </TripOverview>
    <TripOverview>
        <HeaderDetails>
            <Organization>0200</Organization>
            <ShipmentNumber>400117</ShipmentNumber>
            <DropItems>
                <DropItem>
                    <DropNr>1</DropNr>
                    <Name>Home Depot Lancaster PA</Name>
                    <DeliveryNr>0082048179</DeliveryNr>
                </DropItem>
                <DropItem>
                    <DropNr>1</DropNr>
                    <Name>Home Depot Lancaster PA</Name>
                    <DeliveryNr>0082048180</DeliveryNr>
                </DropItem>
                <DropItem>
                    <DropNr>1</DropNr>
                    <Name>Home Depot Lancaster PA</Name>
                    <DeliveryNr>0082048181</DeliveryNr>
                </DropItem>
                <DropItem>
                    <DropNr>2</DropNr>
                    <Name>Hubo Londen</Name>
                    <DeliveryNr>0082048150</DeliveryNr>
                </DropItem>
                <DropItem>
                    <DropNr>2</DropNr>
                    <Name>Hubo Londen</Name>
                    <DeliveryNr>0082048182</DeliveryNr>
                </DropItem>
                <DropItem>
                    <DropNr>3</DropNr>
                    <Name>Hubo Kopenhagen</Name>
                    <DeliveryNr>0082048183</DeliveryNr>
                </DropItem>
                <DropItem>
                    <DropNr>3</DropNr>
                    <Name>Hubo Kopenhagen</Name>
                    <DeliveryNr>0082048190</DeliveryNr>
                </DropItem>
            </DropItems>
        </HeaderDetails>
    </TripOverview>
</MultiTripOverview>

XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:key name="dropItemsGroup" match="DropItem" use="DropNr" />

  <!-- Define the output format -->
  <xsl:output method="xml" indent="yes"/>

  <!-- Identity template to copy all elements and attributes as is -->
  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>

 
  <!-- Template to handle DropItem grouping -->
  <xsl:template match="DropItem">
    <xsl:variable name="currentGroup" select="key('dropItemsGroup', DropNr)" />
    <xsl:if test="generate-id() = generate-id($currentGroup[1])">
      <DropItem>
        <xsl:apply-templates select="DropNr|Name"/>
      </DropItem>
    </xsl:if>
  </xsl:template>
</xsl:stylesheet>

Current Output

<?xml version="1.0" encoding="UTF-8"?>
<MultiTripOverview>
   <ShipmentDate>07.07.2023</ShipmentDate>
   <PrinterId>PRINTERXYZ</PrinterId>
   <ReportType>1</ReportType>
   <TripOverview>
      <HeaderDetails>
         <ShipmentNumber>0000303137</ShipmentNumber>
         <DropItems>
            <DropItem>
               <DropNr>1</DropNr>
               <Name>OBI</Name>
            </DropItem>
         </DropItems>
      </HeaderDetails>
   </TripOverview>
   <TripOverview>
      <HeaderDetails>
         <ShipmentNumber>0000303138</ShipmentNumber>
         <Block>LPB1</Block>
         <DropItems>
            </DropItems>
      </HeaderDetails>
   </TripOverview>
   <TripOverview>
      <HeaderDetails>
         <ShipmentNumber>0000303139</ShipmentNumber>
         <DropItems>
            </DropItems>
      </HeaderDetails>
   </TripOverview>
   <TripOverview>
      <HeaderDetails>
         <Organization>0200</Organization>
         <ShipmentNumber>400117</ShipmentNumber>
         <DropItems>
            <DropItem>
               <DropNr>2</DropNr>
               <Name>Hubo Londen</Name>
            </DropItem>
            <DropItem>
               <DropNr>3</DropNr>
               <Name>Hubo Kopenhagen</Name>
            </DropItem>
         </DropItems>
      </HeaderDetails>
   </TripOverview>
</MultiTripOverview>

Required result

<?xml version="1.0" encoding="UTF-8"?>
<MultiTripOverview>
    <ShipmentDate>07.07.2023</ShipmentDate>
    <PrinterId>PRINTERXYZ</PrinterId>
    <ReportType>1</ReportType>
    <TripOverview>
        <HeaderDetails>
            <ShipmentNumber>0000303137</ShipmentNumber>
            <DropItems>
                <DropItem>
                    <DropNr>1</DropNr>
                    <Name>OBI</Name>
                </DropItem>
            </DropItems>
        </HeaderDetails>
    </TripOverview>
    <TripOverview>
        <HeaderDetails>
            <ShipmentNumber>0000303138</ShipmentNumber>
            <Block>LPB1</Block>
            <DropItem>
                <DropNr>1</DropNr>
                <Customer>0000013590</Customer>
                <Name>Hornbach Berlin</Name>
            </DropItem>
        </HeaderDetails>
    </TripOverview>
    <TripOverview>
        <HeaderDetails>
            <ShipmentNumber>0000303139</ShipmentNumber>
            <DropItem>
                <DropNr>1</DropNr>
                <Customer>0000016536</Customer>
                <Name>Hubo Amsterdam</Name>
            </DropItem>
        </HeaderDetails>
    </TripOverview>
    <TripOverview>
        <HeaderDetails>
            <Organization>0200</Organization>
            <ShipmentNumber>400117</ShipmentNumber>
            <DropItems>
                <DropItem>
                    <DropNr>1</DropNr>
                    <Name>Home Depot Lancaster PA</Name>
                </DropItem>
                <DropItem>
                    <DropNr>2</DropNr>
                    <Name>Hubo Londen</Name>
                </DropItem>
                <DropItem>
                    <DropNr>3</DropNr>
                    <Name>Hubo Kopenhagen</Name>
                </DropItem>
            </DropItems>
        </HeaderDetails>
    </TripOverview>
</MultiTripOverview>

I suspect my key (level) is incorrect?

Regards,

Mike

Upvotes: 0

Views: 38

Answers (2)

michael.hor257k
michael.hor257k

Reputation: 117165

It seems you could do:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:key name="k1" match="DropItem" use="concat(DropNr, '|', generate-id(..))"/>

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

<xsl:template match="DropItems">
    <xsl:copy>
        <xsl:for-each select="DropItem[generate-id()=generate-id(key('k1', concat(DropNr, '|', generate-id(..)))[1])]">
            <xsl:copy>
                <xsl:copy-of select="DropNr|Customer|Name"/>
            </xsl:copy>
        </xsl:for-each >
    </xsl:copy>
</xsl:template>
      
</xsl:stylesheet>

Or possibly:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:key name="k1" match="DropItem" use="concat(DropNr, '|', generate-id(..))"/>

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

<xsl:template match="DropItems">
    <xsl:copy>
        <xsl:apply-templates select="DropItem[generate-id()=generate-id(key('k1', concat(DropNr, '|', generate-id(..)))[1])]"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="DeliveryNr"/>

</xsl:stylesheet>

Upvotes: 1

Martin Honnen
Martin Honnen

Reputation: 167716

That stuff is easier with XSLT 2 or 3, for XSLT 1 with Muenchian grouping the right key is e.g.

<xsl:key name="dropItemsGroup" match="DropItem" use="concat(generate-id(ancestor::TripOverview), '|', DropNr)" />

and

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:key name="dropItemsGroup" match="DropItem" use="concat(generate-id(ancestor::TripOverview), '|', DropNr)" />

  <!-- Define the output format -->
  <xsl:output method="xml" indent="yes"/>

  <!-- Identity template to copy all elements and attributes as is -->
  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="DropItem[not(generate-id() = generate-id(key('dropItemsGroup', concat(generate-id(ancestor::TripOverview), '|', DropNr))[1]))]"/>

</xsl:stylesheet>

eliminates duplicates at least, I have not quite grasped which kind of grouping output you want, perhaps

<xsl:template match="DropItem[generate-id() = generate-id(key('dropItemsGroup', concat(generate-id(ancestor::TripOverview), '|', DropNr))[1])]/*[not(self::DropNr|self::Name)]"/>

Upvotes: 1

Related Questions