我有一个XML文件结构如下:
<root>
<a>...</a>
<b>...</b>
<a>...</a>
<a>...</a>
<comment>...</comment>
<a>...</a>
<b>...</b>
<comment>...</comment>
<a>...</a>
<b>...</b>
</root>
我想使用XSLT对其进行转换,以便将a
和b
的每个序列收集到一个<div>
中,如下所示:
<root>
<div>
<a>...</a>
<b>...</b>
<a>...</a>
<a>...</a>
</div>
<comment>...</comment>
<div>
<a>...</a>
<b>...</b>
</div>
<comment>...</comment>
<div>
<a>...</a>
<b>...</b>
</div>
</root>
我的第一次尝试是将<div>...</div>
放入root
,然后将comment
包裹在</div>...<div>
中(请注意标记的反转),但是&#39 ;不允许在XSLT中使用。我怎么能这样做?
以下问题与我的相关,但它涉及计算固定个a
和b
s,而我想计算a
s和b
s直到我点击comment
:
答案 0 :(得分:3)
以下是如何在 XSLT 1.0中实现
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:key name="group-by-comment" match="root/*" use="count(preceding-sibling::comment)" />
<xsl:template match="/root">
<xsl:copy>
<!-- process children of root using group mode -->
<xsl:apply-templates select="*" mode="group"/>
</xsl:copy>
</xsl:template>
<!-- [group mode] for each child of root that is first in its group: -->
<xsl:template match="*[count(. | key('group-by-comment', count(preceding-sibling::comment))[1]) = 1]" mode="group">
<div>
<!-- process the entire group -->
<xsl:apply-templates select="key('group-by-comment', count(preceding-sibling::comment))"/>
</div>
</xsl:template>
<!-- [group mode] special rule for the dividing comment element -->
<xsl:template match="comment" mode="group">
<xsl:copy-of select="."/>
</xsl:template>
<!-- process group members -->
<xsl:template match="*">
<xsl:copy-of select="."/>
</xsl:template>
<!-- exclude the dividing comment element from the processed group -->
<xsl:template match="comment"/>
</xsl:stylesheet>
应用于以下测试输入:
<root>
<alpha id="1"/>
<bravo id="2"/>
<charlie id="3"/>
<alpha id="4"/>
<bravo id="5"/>
<comment id="6"/>
<charlie id="7"/>
<alpha id="8"/>
<bravo id="9"/>
<comment id="10"/>
<alpha id="11"/>
<charlie id="12"/>
</root>
结果是:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<div>
<alpha id="1"/>
<bravo id="2"/>
<charlie id="3"/>
<alpha id="4"/>
<bravo id="5"/>
</div>
<comment id="6"/>
<div>
<charlie id="7"/>
<alpha id="8"/>
<bravo id="9"/>
</div>
<comment id="10"/>
<div>
<alpha id="11"/>
<charlie id="12"/>
</div>
</root>
答案 1 :(得分:2)
John,考虑使用XSLT 2.0(自2007年开始使用)和XSLT 2.0处理器(如Saxon 9),您可以轻松使用
<xsl:template match="root">
<xsl:copy>
<xsl:for-each-group select="*" group-adjacent="boolean(self::a | self::b)">
<xsl:choose>
<xsl:when test="current-grouping-key()">
<div>
<xsl:copy-of select="current-group()"/>
</div>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="current-group()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>