将子元素拆分为子节

时间:2015-02-18 16:49:56

标签: xslt

给出以下XML

<section>
    <title>Title1</title>
    <item>Item1</item>
    <item>Item2</item>
    <title>Title2</title>
    <item>Item1</item>
    <item>Item2</item>
</section>

将第二个标题分成这个

的最简单方法是什么
<section>
    <subsection>
        <title>Title1</title>
        <item>Item1</item>
        <item>Item2</item>
    </subsection>
    <subsection>
        <title>Title2</title>
        <item>Item1</item>
        <item>Item2</item>
    </subsection>
</section>

例如,以下模板是一个想法,但xpath似乎很棘手。

<xsl:template match="section">
    <xsl:copy>
         <subsection>
              <xsl:apply-templates select="...those before second title..."/>
         </subsection>
         <subsection>
              <xsl:apply-templates select="...those including and after second title..."/>
         </subsection>
    </xsl:copy>
</xsl:template>

1 个答案:

答案 0 :(得分:3)

使用XSLT 2.0或更高版本,它可以直接使用for-each-group

<xsl:template match="section">
    <xsl:copy>
         <xsl:for-each-group select="*" group-starting-with="title">
             <subsection>
                  <xsl:apply-templates select="current-group()"/>
             </subsection>
         </xsl:for-each-group>
    </xsl:copy>
</xsl:template>

在1.0中,您可以通过这种逻辑实现类似的效果:

<xsl:template match="section">
    <xsl:copy>
         <xsl:for-each select="title">
             <subsection>
                  <xsl:apply-templates select=". | following-sibling::item[
                                  generate-id(preceding-sibling::title[1])
                                = generate-id(current())]"/>
             </subsection>
         </xsl:for-each>
    </xsl:copy>
</xsl:template>

谓词会查找当前item的兄弟title个元素,其中最近的前一个title是我们开始的元素。

这两种方法之间的一个区别是,如果您在第一个 section之前的title中有任何其他元素,那么for-each-group方法会将它们放入在一个领先的小节(没有标题),而1.0方法将忽略它们。


如果您总是希望正好两个小节(第二小节中的第二个title之后的所有内容,包括任何其他title个元素),那么您只需硬编码它是

<xsl:template match="section">
    <xsl:copy>
         <subsection>
              <xsl:apply-templates select="title[2]/preceding-sibling::*"/>
         </subsection>
         <subsection>
              <xsl:apply-templates select="title[2] | title[2]/following-sibling::*"/>
         </subsection>
    </xsl:copy>
</xsl:template>

(请注意,如果少于两个title元素,则会产生两个完全空<subsection/>个元素。