Вот эффективное и довольно короткое решение XSLT 1.0 :
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kFollowing" match="alert"
use="generate-id(preceding-sibling::*
[
self::proc
or
self::para
]
[1]
[self::proc]
)"/>
<xsl:template match="node()|@*" name="identity">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="proc">
<proc>
<xsl:apply-templates select="key('kFollowing', generate-id())" mode="copy"/>
</proc>
</xsl:template>
<xsl:template match="alert" mode="copy">
<xsl:call-template name="identity"/>
</xsl:template>
<xsl:template match="alert[preceding-sibling::*
[
self::proc
or
self::para
]
[1]
[self::proc]
]"
/>
</xsl:stylesheet>
, когда это преобразование применяется к предоставленному XML-документу (исправлено, чтобы быть корректным ):
<body>
<proc>Test</proc>
<alert>Test1: alert 1</alert>
<alert>Test1: alert 2</alert>
<para>Test para 1</para>
<alert>Test2: alert 1</alert>
<alert>Test2: alert 2</alert>
<alert>Test2: alert 3</alert>
<proc>Test</proc>
<alert>Test3: alert 1</alert>
<alert>Test3: alert 2</alert>
<alert>Test3: alert 3</alert>
</body>
желаемый результат получен :
<body>
<proc>
<alert>Test1: alert 1</alert>
<alert>Test1: alert 2</alert>
</proc>
<para>Test para 1</para>
<alert>Test2: alert 1</alert>
<alert>Test2: alert 2</alert>
<alert>Test2: alert 3</alert>
<proc>
<alert>Test3: alert 1</alert>
<alert>Test3: alert 2</alert>
<alert>Test3: alert 3</alert>
</proc>
</body>
Примечание : использование ключей делает это преобразованиево много раз быстрее (в случае многих братьев и сестер alert
), чем при использовании осей preceding-sibling::
или following-sibling::
.