2

I would like to be able to select one element from group of duplicates (done with Muenchian grouping) having certain sub-element. My XML looks like this:

<waybill>
<shipment>
    <parcel>
        <sscc>SSCC1</sscc>
        <consignee>Receiver1</consignee>
        <date>Date1</date>
        <status>Status1</status>
    </parcel>
    <parcel>
        <sscc>SSCC2</sscc>
        <consignee>Receiver2</consignee>
        <attention>Note2</attention>
    </parcel>
    <parcel>
        <sscc>SSCC3</sscc>
        <consignee>Receiver3</consignee>
    </parcel>
    <parcel>
        <sscc>SSCC4</sscc>
        <consignee>Receiver4</consignee>
    </parcel>
    <parcel>
        <sscc>SSCC1</sscc>
        <consignee>Receiver1</consignee>
        <attention>Note1</attention>
        <date>Date2</date>
        <status>Status2</status>
    </parcel>
    <parcel>
        <sscc>SSCC3</sscc>
        <consignee>Receiver3</consignee>
        <attention>Note3</attention>
    </parcel>
</shipment>
</waybill>

and my XSLT looks like this:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" version="2.0">
<xsl:output method="text" version="1.0" encoding="ISO-8859-1" indent="yes"/>
<xsl:key name="ean" match="parcel" use="sscc"/>
<xsl:template match="/">
    <xsl:for-each select="/waybill/shipment/parcel[generate-id()=generate-id(key('ean',sscc))]">
        <xsl:value-of select="current()/sscc"/>
        <xsl:text>§</xsl:text>
        <xsl:value-of select="current()/consignee"/>
        <xsl:text>§</xsl:text>
        <xsl:value-of select="current()/attention"/>
        <xsl:text>&#xd;</xsl:text>
    </xsl:for-each>
</xsl:template>
</xsl:stylesheet>

The output now looks like this:

SSCC1§Receiver1§
SSCC2§Receiver2§Note2
SSCC3§Receiver3§
SSCC4§Receiver4§

so my XSLT will now pick the first hit from the grouped elements and what I would like to have as a the result is:

SSCC1§Receiver1§Note1
SSCC2§Receiver2§Note2
SSCC3§Receiver3§Note3
SSCC4§Receiver4§

So the XSLT should find those duplicates from group with has the most data. Not first or last one, but the one with certain sub-element (or in my final case: sub-sub-element)

In this case not all of the element has the sub-element (here SSCC4) and those should be used with the data they have (should not be ignored).

What is the correct way to find the "best" element from the grouped similar elements?

Any help is highly appreciated :)

Vp Soini
  • 61
  • 4

1 Answers1

2

You can navigate from the key(), like this:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" version="2.0">
    <xsl:output method="text" version="1.0" encoding="ISO-8859-1" indent="yes"/>
    <xsl:key name="ean" match="parcel" use="sscc"/>

    <xsl:template match="/">
        <xsl:for-each select="/waybill/shipment/parcel[generate-id()=generate-id(key('ean',sscc))]">
            <xsl:variable name="group" select="key('ean',sscc)" />
            <xsl:value-of select="sscc"/>
            <xsl:text>§</xsl:text>
            <xsl:value-of select="$group/consignee"/>
            <xsl:text>§</xsl:text>
            <xsl:value-of select="$group/attention"/>
            <xsl:text>&#xd;</xsl:text>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

key('ean',sscc) would select all <parcel> elements of the current group and key('ean',sscc)/attention all <attention> elements beneath them.

In XSLT 2.0+ you can also use <xsl:for-each-group> and the current-group() function for the same effect.

Using key('ean',sscc)/attention in a <xsl:value-of> would only print the value of the first match, which is what your intention seems to be anyway.

Using current() explicitly like you did is not really necessary. current() is meant to be used inside XPath predicates, in a normal select expression it doesn't add any value.

Tomalak
  • 332,285
  • 67
  • 532
  • 628
  • Hello. I have added and elements under sscc1 to the original xml above. I have a need to get the date and status also out to output, but only the last entry (here Date2 / Status2). I know that [last()] should do the trick, but how should I use it in the selecting using key? Hos can I select the last element of the grouped SSCC1s using key? – Vp Soini Oct 18 '18 at 09:16
  • 1
    `($group/date)[last()]` – Tomalak Oct 18 '18 at 09:27