Reputation: 687
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
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
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