Отличительные значения в XSL 1.0 внутри каждого - PullRequest
0 голосов
/ 13 июня 2018

Я хотел бы получить различные значения внутри цикла for или в какой-то группе.Поскольку xsl: key может быть объявлен только на верхнем уровне, как я смогу создать xsl: key для каждой группы?В приведенном ниже примере группа будет наиболее внешними тегами фруктов.Обратите внимание, что есть также xsl: sort.Если есть способ сделать это только с помощью xpaths (предшествующий брат), я бы тоже хотел узнать это решение.Я не уверен, что мне нужно было бы использовать метод Мюнхена для достижения этой цели, но вот что у меня есть:

Input.xml

<root>
<fruits>
    <fruit>
        <fruit id="2">
            <banana><taste>Yummy</taste></banana>
            <banana><taste>Disgusting</taste></banana>
        </fruit>
        <fruit id="1">
            <banana><taste>Eh</taste></banana>
            <banana><taste>Disgusting</taste></banana>
        </fruit>
    </fruit>
    <fruit>
        <fruit id="2">
            <banana><taste>Yummy</taste></banana>
            <banana><taste>Disgusting</taste></banana>
        </fruit>
        <fruit id="1">
            <banana><taste>Amazing</taste></banana>
            <banana><taste>Disgusting</taste></banana>
        </fruit>
    </fruit>    
</fruits>
</root>

Transform.xsl

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:key name="taste" use="." match="taste" />
    <xsl:template match="root">
    <xsl:apply-templates select="fruits" />
    </xsl:template>
    <xsl:template match="fruits">
        <xsl:element name="newFruits">
            <xsl:call-template name="test" />
        </xsl:element>
    </xsl:template>
    <xsl:template name="test">
        <xsl:for-each select="fruit">
        <xsl:sort select="fruit/@id" />
        <xsl:element name="newFruit">
            <!-- xsl:for-each select="fruit/banana/taste[not(.=preceding::taste)]/.." /> -->
            <xsl:for-each select="fruit/banana/taste[generate-id() = generate-id(key('taste',.)[1])]/..">
                <xsl:element name="fruit">
                    <xsl:value-of select="."/>
                </xsl:element>
            </xsl:for-each>
        </xsl:element>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

Вывод (комментарии в выводе - это нужные теги, которые должны появиться)

<?xml version="1.0" encoding="UTF-8"?>
<newFruits>
    <newFruit>
        <fruit>Yummy</fruit>
        <fruit>Disgusting</fruit>
        <fruit>Eh</fruit>
    </newFruit>
    <newFruit>
        <!-- <fruit>Yummy</fruit> -->
        <!-- <fruit>Disgusting</fruit> -->
        <fruit>Amazing</fruit>
    </newFruit>
</newFruits>

1 Ответ

0 голосов
/ 13 июня 2018

Проблема в том, что вы хотите, чтобы ваши элементы taste были различны для каждого элемента fruit верхнего уровня.Ваша текущая группировка получает отдельные элементы для всего документа.

Если вы не можете выполнить обновление до XSLT 2.0, откажитесь, так как вам придется использовать объединенный ключ в XSLT 1.0, чтобы включить уникальныйидентификатор для соответствующего элемента fruit, который может быть достигнут с помощью generate-id()

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

. Затем в своем «тестовом» шаблоне определите переменную для хранения идентификатора соответствующего фрукта ...

 <xsl:variable name="id" select="generate-id()" />

И ваше выражение, чтобы получить различные вкусы, становится таким ...

<xsl:for-each select="fruit/banana/taste[generate-id() = generate-id(key('taste', concat($id, '|', .))[1])]">

Попробуйте это XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
    <xsl:output method="xml" indent="yes" />

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

    <xsl:template match="root">
        <xsl:apply-templates select="fruits" />
    </xsl:template>

    <xsl:template match="fruits">
        <newFruits>
            <xsl:call-template name="test" />
        </newFruits>
    </xsl:template>

    <xsl:template name="test">
        <xsl:for-each select="fruit">
            <xsl:variable name="id" select="generate-id()" />
            <newFruit>
                <!-- xsl:for-each select="fruit/banana/taste[not(.=preceding::taste)]/.." /> -->
                <xsl:for-each select="fruit/banana/taste[generate-id() = generate-id(key('taste', concat($id, '|', .))[1])]">
                    <fruit>
                        <xsl:value-of select="."/>
                    </fruit>
                </xsl:for-each>
            </newFruit>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

Обратите внимание, вы на самом деле ненужен первый шаблон, и я не вижу смысла именованного шаблона, поэтому вы можете упростить приведенный выше XSLT до этого ...

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
    <xsl:output method="xml" indent="yes" />

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

    <xsl:template match="fruits">
        <newFruits>
            <xsl:apply-templates select="fruit" />
        </newFruits>
    </xsl:template>

    <xsl:template match="fruit">
        <xsl:variable name="id" select="generate-id()" />
        <newFruit>
            <!-- xsl:for-each select="fruit/banana/taste[not(.=preceding::taste)]/.." /> -->
            <xsl:for-each select="fruit/banana/taste[generate-id() = generate-id(key('taste', concat($id, '|', .))[1])]">
                <fruit>
                    <xsl:value-of select="."/>
                </fruit>
            </xsl:for-each>
        </newFruit>
    </xsl:template>
</xsl:stylesheet>
...