#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
это то, чего не хватало в моем случае, и это сделало свое дело. Еще раз спасибо!