如何使用XSLT1按标记折叠一组选定(相邻)标记?
我有一组顺序节点,它们必须包含在新元素中。例如:如何使用XSLT1按标记折叠一组选定(相邻)标记?,xslt,fold,Xslt,Fold,我有一组顺序节点,它们必须包含在新元素中。例如: <root> <c>cccc</c> <a gr="g1">aaaa</a> <b gr="g1">1111</b> <a gr="g2">bbbb</a> <b gr="g2">2222</b> </root> 因此,我有一个“分组标签”(@gr),但无法想象
<root>
<c>cccc</c>
<a gr="g1">aaaa</a> <b gr="g1">1111</b>
<a gr="g2">bbbb</a> <b gr="g2">2222</b>
</root>
因此,我有一个“分组标签”(@gr
),但无法想象如何生成正确的折叠标签
我正试图利用……的线索。。。但是我有一个“分组标签”,所以我知道我的解决方案不需要使用
key()
函数
我的非通用解决方案是:
<xsl:template match="/">
<root>
<xsl:copy-of select="root/c"/>
<fold><xsl:for-each select="//*[@gr='g1']">
<xsl:copy-of select="."/>
</xsl:for-each></fold>
<fold><xsl:for-each select="//*[@gr='g2']">
<xsl:copy-of select="."/>
</xsl:for-each></fold>
</root>
</xsl:template>
我需要一个通用的解决方案(!),通过所有@gr循环并处理(标识)所有没有@gr的上下文。。。也许使用身份转换
另一个(未来的)问题是使用折叠递归地执行此操作。在XSLT 1.0中,处理这类事情的标准技术称为Muenchian分组,其中包括使用一个键定义节点应如何分组,以及使用
generate id
仅提取每个组中的第一个节点作为整个组的代理的技巧
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:strip-space elements="*" />
<xsl:output indent="yes" />
<xsl:key name="elementsByGr" match="*[@gr]" use="@gr" />
<xsl:template match="@*|node()" name="identity">
<xsl:copy><xsl:apply-templates select="@*|node()"/></xsl:copy>
</xsl:template>
<!-- match the first element with each @gr value -->
<xsl:template match="*[@gr][generate-id() =
generate-id(key('elementsByGr', @gr)[1])]" priority="2">
<fold>
<xsl:for-each select="key('elementsByGr', @gr)">
<xsl:call-template name="identity" />
</xsl:for-each>
</fold>
</xsl:template>
<!-- ignore subsequent ones in template matching, they're handled within
the first element template -->
<xsl:template match="*[@gr]" priority="1" />
</xsl:stylesheet>
请注意,如果您能够使用XSLT 2.0,那么对于每个组,整个过程将变成一个
:
<xsl:template match="root">
<xsl:for-each-group select="*" group-adjacent="@gr">
<xsl:choose>
<!-- wrap each group in a fold -->
<xsl:when test="@gr">
<fold><xsl:copy-of select="current-group()" /></fold>
</xsl:when>
<!-- or just copy as-is for elements that don't have a @gr -->
<xsl:otherwise>
<xsl:copy-of select="current-group()" />
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:template>
每个组的gr
值在根中是否总是不同的,如果不是,那么如果你有a1b1 a2b2 a3b3
那么应该给你三个折叠元素(a1/b1,a2/b2,a3/b3)还是两个(a1/b1/a3/b3,a2/b2)?你可以使用“两个”假设,但在我真正的问题中,@gr是一个不重复的序列,也就是说,如果一个序列停止,它就不再出现了(下一组将是g3,g2之后不可能是g1)。好的,这个示例是完整的XML文档还是有几个不同的根元素需要单独“折叠”?我编辑了。。。并在问题标题中添加“邻居”。关于“褶皱的褶皱”现在不是问题,但我想我将来会遇到这个问题,还有。很好的解释和优雅的解决方案@PeterKrauss我还添加了一个可能的XSLT2.0解决方案,用于比较。是的,使用XSLT2非常简单直观。。。我讨厌XSLT1(!!),但PHP只提供XSLT1…PS:我将在下一期中向您介绍我的未来。
<root>
<c>cccc</c>
<fold>
<a gr="g1">aaaa</a>
<b gr="g1">1111</b>
</fold>
<fold>
<a gr="g2">bbbb</a>
<b gr="g2">2222</b>
</fold>
</root>
<xsl:template match="root">
<xsl:for-each-group select="*" group-adjacent="@gr">
<xsl:choose>
<!-- wrap each group in a fold -->
<xsl:when test="@gr">
<fold><xsl:copy-of select="current-group()" /></fold>
</xsl:when>
<!-- or just copy as-is for elements that don't have a @gr -->
<xsl:otherwise>
<xsl:copy-of select="current-group()" />
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:template>