模板是否可以将自身用作每个组中的 select 属性?
Is it possible for a template to use itself as the select attribute in a for-each-group?
如题,是否可以做出这样的作品:
<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 中使用,将具有相同 level
属性的两个 orderedlist
元素压缩为一个元素。
根据要求,这是示例输入:
<?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]).*', '')"/>
<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 < 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>
不,您需要用您的分组代码替换处理 orderedList
元素的 <xsl:apply-templates/>
或 <xsl:apply-templates select="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="@*"/>
就足够了,没有必要使用嵌套copy-of
的for-each
].
所以综合起来我们得到
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://docbook.org/ns/docbook" xpath-default-namespace="http://docbook.org/ns/docbook">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="book">
<xsl:copy>
<xsl:copy-of select="@*"/>
<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]).*', '')"/>
<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 < 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: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:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:if>
</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="italic">
<emphasis role="italic">
<xsl:apply-templates/>
</emphasis>
</xsl:template>
<xsl:template match="bold">
<emphasis role="bold">
<xsl:apply-templates/>
</emphasis>
</xsl:template>
<xsl:template match="*">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
如题,是否可以做出这样的作品:
<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 中使用,将具有相同 level
属性的两个 orderedlist
元素压缩为一个元素。
根据要求,这是示例输入:
<?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]).*', '')"/>
<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 < 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>
不,您需要用您的分组代码替换处理 orderedList
元素的 <xsl:apply-templates/>
或 <xsl:apply-templates select="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="@*"/>
就足够了,没有必要使用嵌套copy-of
的for-each
].
所以综合起来我们得到
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://docbook.org/ns/docbook" xpath-default-namespace="http://docbook.org/ns/docbook">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="book">
<xsl:copy>
<xsl:copy-of select="@*"/>
<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]).*', '')"/>
<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 < 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: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:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:if>
</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="italic">
<emphasis role="italic">
<xsl:apply-templates/>
</emphasis>
</xsl:template>
<xsl:template match="bold">
<emphasis role="bold">
<xsl:apply-templates/>
</emphasis>
</xsl:template>
<xsl:template match="*">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>