Пределы группировки XSLT?

Мне нужно изменить фрагмент ниже в иерархическую структуру, группируя связанные элементы в новый элемент группы. XSLT звучит как подходящая технология для использования здесь, но я не знаю достаточно об этом, чтобы оценить, способна ли она на то, что мне нужно. Примером критерия группировки является "1" d "узел, за которым следует некоторое количество" 3 "узлов, за которым следует 1" f "узел". Я должен выполнить эту задачу по нескольким отдельным критериям, поэтому я хотел бы знать, возможны ли запросы такого рода в XSLT или мне будет лучше, если я просто откажусь и обработаю DOM процедурно. Я полностью открыт и для других стратегий. Для конкретного примера мне нужно преобразовать это

<root>
    <a>foo</a>
    <b>bar</b>
    <c>baz</c>
    <d>location</d>
    <e>3.14</e>
    <e>6.02</e>
    <e>1.23</e>
    <f>2015</f>
    <d>location</d>
    <e>3.14</e>
    <e>6.02</e>
    <f>2015</f>
</root>

В это-

<root>
    <a>foo</a>
    <b>bar</b>
    <c>baz</c>
    <sample>
        <d>location</d>
        <e>3.14</e>
        <e>6.02</e>
        <e>1.23</e>
        <f>2015</f>
    </sample>
    <sample>
        <d>location</d>
        <e>3.14</e>
        <e>6.02</e>
        <f>2015</f>
    </sample>
</root> 

2 ответа

Решение

Если это то, что вы хотите сгруппировать элементы, начиная с dВы можете использовать следующий подход. XSLT-1.0

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes" method="xml" />
    <xsl:strip-space elements="*"/>

    <!-- key to select following (e|f) elements using the first preceding d's id -->
    <xsl:key name="following" match="e | f" use="generate-id(preceding::d[1])"/>

    <!-- identity transform template -->
    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>

    <!-- template to group d and its following (e|f) elements under sample element-->
    <xsl:template match="d">
        <sample>
            <xsl:copy-of select="current() | key('following', generate-id())"/>
        </sample>
    </xsl:template>

    <!-- template to do nothing for e|f elements -->
    <xsl:template match="e|f"/>

</xsl:stylesheet>

И, конечно же, XSLT не ограничивается такой простой группировкой.

Вот мой подход, учитывая, что я обычно работаю в среде XSLT 1.0.

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

    <!-- any nodes that I don't address specifically, I copy -->
    <xsl:template match="*">
        <xsl:copy-of select="."/>
    </xsl:template>

    <!-- from the root, deal with a, b, c, d nodes -->
    <xsl:template match="root">
        <root>
            <xsl:apply-templates select="a|b|c|d"/>
        </root>
    </xsl:template>

    <!-- the d node is the fun one -->
    <xsl:template match="d">
        <!-- add the wrapper -->
        <sample>
            <!-- first, copy the d node -->
            <xsl:copy-of select="."/>
            <!--
            process any following sibling e nodes if that
            e node's immediately preceding d sibling is the
            "current" node - i.e. the d node that got us here

            We use the fact that in XSLT 1.0, a union of nodes
            will never contain duplicates, so if the count is
            one, that means the two parts of the union are the
            same node
            -->
            <xsl:apply-templates select="following-sibling::e
                [count(current() | preceding-sibling::d[1]) = 1]"/>
            <!-- same logic for f nodes -->
            <xsl:apply-templates select="following-sibling::f
                [count(current() | preceding-sibling::d[1]) = 1]"/>
        </sample>
    </xsl:template>
</xsl:stylesheet>

Теперь, я полагаю, убедит ли вас, что XSLT является правильным инструментом или вызывает у вас крик в ужасе, зависит от вашей личности.

Другие вопросы по тегам