如何使用XSLT 2.0 </div>用<div>包围XHTML节点组

时间:2012-06-27 21:47:33

标签: xslt xhtml xslt-2.0

我的XHTML输入:

<h1 class="section">Text</h1>
<h2 class="section">More text</h2>

所需的XHTML输出:

<div class="section">
<h1 class="section">Text</h1>
<h2 class="section">More text</h2>
</div>

因此,group-adjacent方法似乎合适。下面的代码会对h1h2节点执行正确的操作,但它会删除<body>节点中包含<body>标记本身的所有其他内容。

显然我犯了一个错误,但我不足以让for-each-group的专家了解它的位置。

感谢。

<xsl:template match="xhtml:body"> 
    <xsl:for-each-group select="xhtml:h1|xhtml:h2" group-adjacent="@class"> 
        <xsl:choose>
            <xsl:when test="current-grouping-key()='section'">
                <xsl:element name="div">
                    <xsl:attribute name="class">
                        <xsl:value-of select="current-grouping-key()"/>
                    </xsl:attribute>
                    <xsl:apply-templates select="current-group()"/> 
                </xsl:element>
            </xsl:when>
            <xsl:otherwise>
                <xsl:copy-of select="." />    
            </xsl:otherwise>
        </xsl:choose>            
    </xsl:for-each-group>  
</xsl:template>

更新:我不明白的是for-each-group基本上可以作为您指向的任何节点的过滤器。因此,如果要保留每个子节点,则原始命令必须包含select="*"。此外,分组规则必须确保每个子节点最终都在一个组中。这意味着group-adjacent不适合工作; group-starting-with是。

下面的模板将XHTML文件的整个<body>分隔为以h1开头的组。 (请注意:此分组规则依赖于h1始终是XHTML的<body>中的第一个子节点的假设。)然后我循环遍历组,使用条件查看第一个每组中有两个节点,看它们是否符合我的标准。如果是这样,我将它们包裹在我的<div>

我仍然感兴趣是否有一个更惯用的XSLT解决方案,因为我所做的基本上是在XSLT中编写Python。

<xsl:template match="xhtml:body"> 
    <xsl:copy>            
    <!--Divide file into groups of nodes starting with h1 tags-->
    <xsl:for-each-group select="*" group-starting-with="xhtml:h1"> 
        <xsl:choose>
            <!-- if the group starts with h1.section + h2.section -->
            <xsl:when test="current-group()[1][@class='section'] and current-group()[2][name() = 'h2'] and current-group()[2][@class = 'section']">
                <!--wrap in a div tag-->
                <div class="section">
                    <xsl:apply-templates select="current-group()[1]"/>
                    <xsl:apply-templates select="current-group()[2]"/>
                </div>                    
                <!--then process the rest of the nodes in this group normally-->
                <xsl:apply-templates select="current-group()[position()>=3]"/> 
            </xsl:when>
            <xsl:otherwise>
                <!--process normally-->
                <xsl:apply-templates select="current-group()"/> 
            </xsl:otherwise>
        </xsl:choose>
    </xsl:for-each-group> 
    </xsl:copy>  
</xsl:template>

1 个答案:

答案 0 :(得分:2)

在您对问题的更新中,您已确定部分答案。但是,可以通过群组相邻来解决这种问题。通常的模式是计算&#34; true&#34;的分组键。将元素作为一个组包装,并且&#34; false&#34;为了其他人。所以编码模式是:

<xsl:for-each-group select="*" group-adjacent="self::h1 or self::h2">
  <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>