模板是否可以将自身用作for-each-group中的select属性?

时间:2015-01-27 11:14:51

标签: xml xslt xpath xslt-2.0

作为标题,是否有可能做出像这样的工作:

<xsl:template match="orderedlist">
    <xsl:for-each-group select="." group-adjacent="@level">
        <xsl:element name="{name(.)}">
            <xsl:for-each select="@*">
                <xsl:copy/>
            </xsl:for-each>
            <xsl:for-each select="current-group()">
                <xsl:apply-templates/>
            </xsl:for-each>
        </xsl:element>
    </xsl:for-each-group>
</xsl:template>

this transformation内使用,将具有相同orderedlist属性的两个level元素压缩为单个元素。

根据要求,这里是样本输入:

<?xml version="1.0" encoding="UTF-8"?>
<book xmlns="http://docbook.org/ns/docbook"
      xmlns:xlink="http://www.w3.org/1999/xlink"
      version="5.0"
      role="fullText"
      xml:lang="en">
   <info>
      <title/>
      <subtitle/>
      <edition/>
   </info>
    <chapnumber>Chapter 1</chapnumber>
    <chaptitle>Chapter Title</chaptitle>
    <head1>Heading 1</head1>
    <para>1st paragraph</para>
    <head2>Heading 2</head2>
    <itemizedlist level="1">
      <listitem>1st bullet</listitem>
      <listitem>2nd bullet</listitem>
   </itemizedlist>
    <orderedlist numeration="loweralpha" level="2">
      <listitem>2nd bullet – 1st letter</listitem>
   </orderedlist>
    <orderedlist numeration="loweralpha" level="2">
      <listitem>2nd bullet – 2nd letter</listitem>
      <listitem>2nd bullet – 3rd letter</listitem>
   </orderedlist>
    <itemizedlist level="1">
      <listitem>3rd bullet</listitem>
      <listitem>4th bullet</listitem>
   </itemizedlist>
    <head2>Heading 2 2</head2>
    <para>Last paragraph</para>
</book>

完整的样式表:

<xsl:output method="xml" indent="yes"/>

<xsl:template match="book">
    <xsl:copy>
        <xsl:for-each select="@*">
            <xsl:copy/>
        </xsl:for-each>
        <xsl:for-each-group select="*" group-starting-with="chapnumber">
            <xsl:choose>
                <xsl:when test="local-name() = 'chapnumber'">
                    <xsl:variable name="chapter_number" select="replace(., '.*([0-9]).*', '$1')"/>
                    <chapter label="{$chapter_number}">
                        <xsl:call-template name="nest_headings">
                            <xsl:with-param name="working_group" select="current-group() except ."/>
                            <xsl:with-param name="heading_level" select="1"/>
                        </xsl:call-template>
                    </chapter>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:apply-templates select="current-group()"/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:for-each-group>
    </xsl:copy>
</xsl:template>

<xsl:template name="nest_headings">
    <xsl:param name="working_group"/>
    <xsl:param name="heading_level"/>

    <xsl:variable name="heading_name" select="concat('head', string($heading_level))"/>

    <xsl:if test="$heading_level &lt; 10">
        <xsl:for-each-group select="$working_group" group-starting-with="*[local-name() eq $heading_name]">
            <xsl:choose>
                <xsl:when test="local-name() eq $heading_name">
                    <section>
                        <xsl:call-template name="nest_headings">
                            <xsl:with-param name="working_group" select="current-group()"/>
                            <xsl:with-param name="heading_level" select="$heading_level + 1"/>
                        </xsl:call-template>
                    </section>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:apply-templates select="current-group()"/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:for-each-group>
    </xsl:if>
</xsl:template>

<xsl:template match="orderedlist">
    <xsl:for-each-group select="." group-adjacent="@level">
        <xsl:element name="{name(.)}">
            <xsl:for-each select="@*">
                <xsl:copy/>
            </xsl:for-each>
            <xsl:for-each select="current-group()">
                <xsl:apply-templates/>
            </xsl:for-each>
        </xsl:element>
    </xsl:for-each-group>
</xsl:template>

<xsl:template match="*[matches(local-name(), '^head[0-9]$')]">
    <info>
        <title>
            <xsl:apply-templates/>
        </title>
    </info>
</xsl:template>

<xsl:template match="chaptitle">
    <info>
        <title>
            <xsl:apply-templates/>
        </title>
    </info>
</xsl:template>

<xsl:template match="*">
    <xsl:copy>
        <xsl:for-each select="@*">
            <xsl:copy/>
        </xsl:for-each>
        <xsl:apply-templates/>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

预期的产出:

<?xml version="1.0" encoding="UTF-8"?>
<book xmlns="http://docbook.org/ns/docbook"
      xmlns:xlink="http://www.w3.org/1999/xlink"
      version="5.0"
      role="fullText"
      xml:lang="en">
   <info>
      <title/>
      <subtitle/>
      <edition/>
   </info>
   <chapter label="1">
      <info>
         <title>Chapter Title</title>
      </info>
      <section>
         <info>
            <title>Heading 1</title>
         </info>
         <para>1st paragraph</para>
         <section>
            <info>
               <title>Heading 2</title>
            </info>
            <itemizedlist level="1">
               <listitem>1st bullet</listitem>
               <listitem>2nd bullet</listitem>
            </itemizedlist>
            <orderedlist numeration="loweralpha" level="2">
               <listitem>2nd bullet – 1st letter</listitem>
               <listitem>2nd bullet – 2nd letter</listitem>
               <listitem>2nd bullet – 3rd letter</listitem>
            </orderedlist>
            <itemizedlist level="1">
               <listitem>3rd bullet</listitem>
               <listitem>4th bullet</listitem>
            </itemizedlist>
         </section>
         <section>
            <info>
               <title>Heading 2 2</title>
            </info>
            <para>Last paragraph</para>
         </section>
      </section>
   </chapter>
</book>

1 个答案:

答案 0 :(得分:1)

不,您需要替换使用您的分组代码处理<xsl:apply-templates/>元素的<xsl:apply-templates select="orderedList"/>orderedList,例如<xsl:for-each-group select="current-group()" group-by="@level">...</xsl:for-each-group>。在带有match="orderedList"的模板中,您始终只有一个上下文节点,而不是一组节点,因此没有任何内容可以分组。

由于还有其他元素不能分组,我想你想用

                <xsl:for-each-group select="current-group()" group-adjacent="boolean(self::orderedlist)">
                  <xsl:choose>
                    <xsl:when test="current-grouping-key()">
                      <xsl:for-each-group select="current-group()" group-adjacent="@level">
                        <xsl:copy>
                          <xsl:copy-of select="@*"/>
                          <xsl:apply-templates select="current-group()/node()"/>
                        </xsl:copy>
                      </xsl:for-each-group>
                    </xsl:when>
                    <xsl:otherwise>
                      <xsl:apply-templates select="current-group()"/>
                    </xsl:otherwise>
                  </xsl:choose>
                </xsl:for-each-group>

而不是内部xsl:apply-templates

顺便说一下,如果要复制像所有属性一样的节点序列,只需使用<xsl:copy-of select="@*"/>,就不需要使用嵌套for-each的{​​{1}}。

所以我们得到了所有的一切

copy-of