Да, есть способ сделать это намного эффективнее: см. Мюнхенская группировка . Если вам нужно больше информации, сообщите нам об этом. Ключ вам понадобится что-то вроде:
<xsl:key name="elements-by-group" match="*[not(self::b)]"
use="generate-id(preceding-sibling::b[1])" />
Затем вы можете перебрать элементы <b>
, и для каждого из них используйте key('elements-by-group', generate-id())
, чтобы получить элементы, следующие сразу за этим <b>
.
Задача «сделать XML более иерархичным» иногда называется повышающим преобразованием, и ваш сценарий является классическим примером для этого. Как вы, возможно, знаете, XSLT 2.0 имеет очень полезные функции группировки, которые проще в использовании, чем метод Мюнхена.
В вашем случае это звучит так, как будто вы используете <xsl:for-each-group group-starting-with="b" />
или, чтобы параметризовать имя элемента, <xsl:for-each-group group-starting-with="*[local-name() = 'b']" />
. Но, возможно, вы уже рассмотрели это и не можете использовать XSLT 2.0 в своей среде.
Обновление:
В ответ на запрос параметризации, вот способ сделать это без ключа.
Обратите внимание, что это может быть намного медленнее, в зависимости от вашего процессора XSLT.
<xsl:template match="D0011">
<xsl:for-each select="*[local-name() = $sep]">
<xsl:copy>
<xsl:copy-of select="following-sibling::*[not(local-name() = $sep)
and generate-id(preceding-sibling::*[local-name() = $sep][1]) =
generate-id(current())]" />
</xsl:copy>
</xsl:for-each>
</xsl:template>
Как отмечено в комментарии, вы можете сохранить выигрыш в производительности ключей, задав несколько различных ключей, по одному для каждого возможного значения параметра. Затем вы выбираете, какую клавишу использовать, используя <xsl:choose>
.
Обновление 2:
Чтобы элемент, начинающий группу, определялся на основе /*/*[2]
, а не на основе параметра, используйте
<xsl:key name="elements-by-group"
match="*[not(local-name(.) = local-name(/*/*[2]))]"
use="generate-id(preceding-sibling::*
[local-name(.) = local-name(/*/*[2])][1])" />
<xsl:template match="D0011">
<xsl:for-each select="*[local-name(.) = local-name(../*[2])]">
<xsl:copy>
<xsl:copy-of select="key('elements-by-group', generate-id())"/>
</xsl:copy>
</xsl:for-each>
</xsl:template>