Перегруппировка пары узлов в шаблоне

#xml #xslt-1.0

#xml #xslt-1.0

Вопрос:

У меня есть XML-файл, содержащий список событий. Каждое событие, по сути, является begin end событием и периодом. Предположим, что следующий XML :

 <Events>
    <Event id="1" type="begin" date="xxxx"/>
    <Event id="2" type="end" date="xxxy"/>
    <Event id="3" type="begin" date="xxyx"/>
    <Event id="4" type="end" date="xyxx"/>
    <Event id="5" type="begin" date="yxxx"/>
    <Event id="6" type="end" date="xxyy"/>
</Events>
 

То, что я хочу применить, выглядит примерно так :

 <Events>
    <xsl:apply-templates select="//Event"/>
</Events>

<xsl:template match="Event">
    <Period>
        <Begin>
            <Event>
                <xsl:attribute name="id" select="[@type='begin']/@id"/>
                <xsl:attribute name="date" select="[@type='begin']/@date"/>
            </Event>
        </Begin>
        <End>
            <Event>
                <xsl:attribute name="id" select="[@type='end']/@id"/>
                <xsl:attribute name="date" select="[@type='end']/@date"/>
            </Event>
        </End>
    </Period>
</xsl:template>
 

И ожидаемый результат будет таким :

 <Events>
    <Period>
        <Begin>
            <Event id="1" type="begin" date="xxxx"/>
        </Begin>

        <End>
            <Event id="2" type="end" date="xxxy"/>
        </End>
    </Period>

    <Period>
        <Begin>
            <Event id="3" type="begin" date="xxyx"/>
        </Begin>

        <End>
            <Event id="4" type="end" date="xyxx"/>
        </End>
    </Period>

    <Period>
        <Begin>
            <Event id="5" type="begin" date="yxxx"/>
        </Begin>

        <End>
            <Event id="6" type="end" date="xxyy"/>
        </End>
    </Period>
</Events>
 

Но результат такой :

 <Events>
    <Period>
        <Begin>
            <Event id="1" type="begin" date="xxxx"/>
        </Begin>

        <End>
            <Event id="" type="end" date=""/>
        </End>
    </Period>

    <Period>
        <Begin>
            <Event id="" type="begin" date=""/>
        </Begin>

        <End>
            <Event id="2" type="end" date="xxxy"/>
        </End>
    </Period>

    ...

</Events>
 

Я понимаю, почему я получил этот результат, поскольку шаблон сопоставляет элементы по элементам один за другим, но я хочу знать, есть ли способ достичь моей цели, используя шаблон, соответствующий «двум узлам одновременно»? Я просмотрел SO, но единственное, что я нашел, что находится рядом с решением, которое я хочу, — это группировка Muenchian (которая кажется действительно сложной для настройки для небольшого набора данных, подобного приведенному выше).

Ответ №1:

Ну, что-то вроде этого должно выполнить эту работу — я предполагаю, что за <Event type="begin"> ним всегда сразу следует соответствующее <Event type="end"> .

 <xsl:template match="Event[@type='begin']">
    <Period>
        <Begin>
            <xsl:copy-of select="."/>
        </Begin>
        <End>
            <xsl:copy-of select="following-sibling::Event[1]"/>
        </End>
    </Period>
</xsl:template>
 

Демонстрация здесь: http://xsltransform.net/ejivdH4

Комментарии:

1. Если ваш шаблон соответствует событию, [@type='begin'] то почему следующий тип -sibling является end типом? Разве вы не должны сопоставлять каждый Event ?

2. Потому что я выбираю и выполняю точную копию Event[@type='end'] явно. В этом случае мне не нужно «совпадение» для обработки Event — более того, мне нужно избегать сопоставления этих элементов в процессе преобразования.

3. Хорошо, я понял. Большое вам спасибо за ваш ответ, following-sibling это то, чего не хватало в моем случае, и это сделало свое дело. Еще раз спасибо!