XSL-мюнхианская группировка и фильтрация

Сценарий такой: у меня есть магазин, в котором продается мебель от двух производителей, CompanyA и CompanyB, а также импортная мебель от одного импортера, CompanyC.

Мой файл выглядит так

<shop>
    <product>
        <name>Chair</name>
        <colour>Green</colour>
        <producer>CompanyA</producer>
    </product>
    <product>
        <name>Chair</name>
        <colour>Green</colour>
        <producer>CompanyB</producer>
    </product>
    <product>
        <name>Chair</name>
        <colour>Blue</colour>
        <producer>CompanyA</producer>
    </product>
    <product>
        <name>Chair</name>
        <colour>Blue</colour>
        <importer>CompanyC</importer>
    </product>
    <product>
        <name>Table</name>
        <colour>Green</colour>
        <importer>CompanyC</importer>
    </product>
    <product>
        <name>Table</name>
        <colour>Green</colour>
        <producer>CompanyA</producer>
    </product>
    <product>
        <name>Table</name>
        <colour>Blue</colour>
        <producer>CompanyB</producer>
    </product>
    <product>
        <name>Table</name>
        <colour>Blue</colour>
        <importer>CompanyC</importer>
    </product>
</shop>

Я хочу сократить свои запасы, поэтому мне нужен список аналогичных продуктов от CompanyA и CompanyC. Я не хочу перечислять похожие продукты от CompanyA и CompanyB, а также мне не нужен список похожих продуктов от CompanyB и CompanyC. Желаемый результат - это

<shop>
    <product>
        <name>Chair</name>
        <colour>Blue</colour>
        <producer>CompanyA</producer>
    </product>
    <product>
        <name>Chair</name>
        <colour>Blue</colour>
        <importer>CompanyC</importer>
    </product>
    <product>
        <name>Table</name>
        <colour>Green</colour>
        <importer>CompanyC</importer>
    </product>
    <product>
        <name>Table</name>
        <colour>Green</colour>
        <producer>CompanyA</producer>
    </product>
</shop>

Я скопировал старую таблицу стилей, которая дает мне список всех похожих продуктов, поэтому моя проблема заключается в следующем: как я могу отфильтровать список, чтобы он давал только те пары, где один поступает от CompanyA, а другой - от CompanyC?

Я могу использовать только XSL 1.0 без расширений

<?xml version="1.0"?>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="xml" indent="no"/>

<xsl:key name="duplo" match="product" use="concat(name,colour)"/>

<xsl:template match="/">
    <shop>
        <xsl:for-each select="//product[generate-id(.)=generate-id(key('duplo', concat(name,colour))[2])]">
            <xsl:for-each select="key('duplo', concat(name,colour))">
                <product>
                    <name><xsl:value-of select="name"/></name>
                    <colour><xsl:value-of select="colour"/></colour>
                    <producer><xsl:value-of select="producer"/></producer>
                    <importer><xsl:value-of select="importer"/></importer>
                </product>
            </xsl:for-each>
        </xsl:for-each>
    </shop>
</xsl:template>

</xsl:stylesheet>

person Klas Blomberg    schedule 22.02.2017    source источник


Ответы (1)


Один из способов сделать это - вложить существующий xsl:for-each в состояние xsl:if.

<xsl:if test="key('duplo', concat(name,colour))[producer = 'CompanyA'] and key('duplo', concat(name,colour))[importer = 'CompanyC']">
    <xsl:for-each select="key('duplo', concat(name,colour))[producer = 'CompanyA' or importer = 'CompanyC']">
        <product>
            <name><xsl:value-of select="name"/></name>
            <colour><xsl:value-of select="colour"/></colour>
            <producer><xsl:value-of select="producer"/></producer>
            <importer><xsl:value-of select="importer"/></importer>
        </product>
    </xsl:for-each>
</xsl:if>

Возможно, вы могли бы уменьшить размер выражений с помощью переменных. Например

<xsl:variable name="group" select="key('duplo', concat(name,colour))" />
<xsl:variable name="A" select="$group[producer = 'CompanyA']" />
<xsl:variable name="B" select="$group[importer = 'CompanyC']" />
<xsl:if test="$A and $B">
    <xsl:for-each select="$A|$B">
        <product>
            <name><xsl:value-of select="name"/></name>
            <colour><xsl:value-of select="colour"/></colour>
            <producer><xsl:value-of select="producer"/></producer>
            <importer><xsl:value-of select="importer"/></importer>
        </product>
    </xsl:for-each>
</xsl:if>
person Tim C    schedule 22.02.2017