XSLT/мюнхенская группировка: как выбрать элемент с определенным подэлементом из группы?

Я хотел бы иметь возможность выбрать один элемент из группы дубликатов (сделано с мюнхианской группировкой), имеющей определенный подэлемент. Мой XML выглядит так:

<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>

и мой XSLT выглядит так:

<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>

Вывод теперь выглядит так:

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

поэтому мой XSLT теперь выберет первое попадание из сгруппированных элементов, и в результате я хотел бы получить следующее:

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

Таким образом, XSLT должен найти дубликаты из группы с наибольшим количеством данных. Не первый или последний, а тот, у которого есть определенный подэлемент (или в моем последнем случае: подподэлемент)

В этом случае не все элементы имеют подэлементы (здесь SSCC4), и их следует использовать с данными, которые у них есть (не следует игнорировать).

Как правильно найти «лучший» элемент из сгруппированных похожих элементов?

Любая помощь высоко ценится :)


person Vp Soini    schedule 15.11.2017    source источник


Ответы (1)


Вы можете перейти от key(), например:

<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) выберет все <parcel> элементы текущей группы и key('ean',sscc)/attention все <attention> элементы под ними.

В XSLT 2.0+ вы также можете использовать функции <xsl:for-each-group> и current-group() для того же эффекта.

Использование key('ean',sscc)/attention в <xsl:value-of> напечатает только значение первого совпадения, что в любом случае кажется вашим намерением.

Использование current() явно, как вы, на самом деле не обязательно. current() предназначен для использования внутри предикатов XPath, в обычном выражении select он не добавляет никакого значения.

person Tomalak    schedule 15.11.2017
comment
Привет. Я добавил элементы «дата» и «статус» под sscc1 в исходный xml выше. Мне нужно также вывести дату и статус, но только последнюю запись (здесь Date2/Status2). Я знаю, что [last()] должен помочь, но как мне использовать его при выборе с помощью ключа? Как я могу выбрать последний элемент сгруппированных SSCC1 с помощью клавиши? - person Vp Soini; 18.10.2018