如何使用XSLT1通过标记折叠一组选定的(邻居)标记?

时间:2013-08-19 10:06:08

标签: 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>

必须由fold标记括起来,(在XSLT之后):

  <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>

所以,我有一个“分组标签”(@gr),但不能想象如何制作正确的折叠标签。


我正在尝试使用this questionthis other one的线索......但我有一个“分组标签”,所以我理解我的解决方案不需要使用{{1功能。

我的非一般解决方案是:

key()

我需要一个通用解决方案(!),循环所有@gr并且应对(身份)所有没有@gr的上下文...也许使用身份转换

另一个(未来)问题是递归地执行此操作,折叠折叠。

1 个答案:

答案 0 :(得分:1)

在XSLT 1.0中,处理此类事情的标准技术称为Muenchian分组,并涉及使用 key 定义如何对节点进行分组以及使用{{1}仅提取每个组中的第一个节点作为整个组的代理。

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> a元素之间的缩进和空白文本节点,即它将给你

b

请注意,如果您能够使用XSLT 2.0,那么整个事情就变成一个<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>

for-each-group