Хороший вопрос, + 1.
Это преобразование:
<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="*[not(self::h3)]"
use="generate-id(preceding-sibling::h3[1])"/>
<xsl:template match="/*">
<xsl:apply-templates select="h3"/>
</xsl:template>
<xsl:template match="h3">
<xsl:if test="position() > 1">
<br />
</xsl:if>
<sec>
<br />
<secHead><xsl:value-of select="."/></secHead>
<xsl:copy-of select="key('kFollowing', generate-id())"/>
</sec>
</xsl:template>
</xsl:stylesheet>
при применении к предоставленному источнику (HTML должен быть преобразован в хорошо сформированный XML !!!):
<root>
<br/>
<h3>The first H3 text</h3><br/>
<p>para1 content in first H3</p><br/>
<p>para2 content in first H3</p><br/>
<h3>The second H3 text</h3><br/>
<p>para1 content in second H3</p><br/>
<p>para2 content in second H3</p><br/>
<p>para3 content in second H3</p><br/>
<p>para4 content in second H3</p><br/>
</root>
дает желаемый, правильный результат :
<sec>
<br/>
<secHead>The first H3 text</secHead>
<br/>
<p>para1 content in first H3</p>
<br/>
<p>para2 content in first H3</p>
<br/>
</sec>
<br/>
<sec>
<br/>
<secHead>The second H3 text</secHead>
<br/>
<p>para1 content in second H3</p>
<br/>
<p>para2 content in second H3</p>
<br/>
<p>para3 content in second H3</p>
<br/>
<p>para4 content in second H3</p>
<br/>
</sec>
Объяснение
Ключевым моментом в этом решении является то, что мы определяем xsl:key
, который фиксирует связь между элементом h3
и всеми его ближайшими соседними элементами (так что они сами не являются h3
и этим h3
их первый h3
предшествующий родной брат).