在 group-starting-with 中使用变量
Using a variable in group-starting-with
我有一个样式表,旨在添加一些目前看起来像这样的结构:
<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:for-each select="@*">
<xsl:copy/>
</xsl:for-each>
<xsl:copy-of select="info"/>
<xsl:for-each-group select="*" group-starting-with="chapnumber">
<xsl:choose>
<xsl:when test="current-group()[1]/name() = 'chapnumber'">
<xsl:variable name="chapter_number" select="replace(., '.*([0-9]).*', '')"/>
<chapter label="{$chapter_number}">
<xsl:call-template name="nest_head1">
<xsl:with-param name="working_group" select="current-group() except ."/>
</xsl:call-template>
</chapter>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="nest_head1">
<xsl:with-param name="working_group" select="current-group() except ."/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
<xsl:template name="nest_head1">
<xsl:param name="working_group"/>
<xsl:for-each-group select="$working_group" group-starting-with="head1">
<xsl:choose>
<xsl:when test="current-group()[1]/name() = 'head1'">
<section>
<xsl:call-template name="nest_head2">
<xsl:with-param name="working_group" select="current-group()"/>
</xsl:call-template>
</section>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="nest_head2">
<xsl:with-param name="working_group" select="current-group()"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:template>
<xsl:template name="nest_head2">
<xsl:param name="working_group"/>
<xsl:for-each-group select="$working_group" group-starting-with="head2">
<xsl:choose>
<xsl:when test="current-group()[1]/name() = 'head2'">
<section>
<xsl:apply-templates select="current-group()"/>
</section>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-group()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:template>
<xsl:template match="head1|head2|head3|head4|head5">
<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:for-each select="@*">
<xsl:copy/>
</xsl:for-each>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
我不喜欢每个标题级别都有自己的模板(特别是因为理论上可能有更多级别的标题)并且认为它可以浓缩为一个单一的,更有用的模板,带有标题级别的变量,像这样:
<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:for-each select="@*">
<xsl:copy/>
</xsl:for-each>
<xsl:copy-of select="info"/>
<xsl:for-each-group select="*" group-starting-with="chapnumber">
<xsl:choose>
<xsl:when test="current-group()[1]/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: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>
</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">
<xsl:value-of select="concat('head', string($heading_level))"/>
</xsl:variable>
<xsl:if test="$heading_level < 6">
<xsl:for-each-group select="$working_group" group-starting-with="$heading_name">
<xsl:choose>
<xsl:when test="current-group()[1]/name() = $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: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>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:if>
</xsl:template>
<xsl:template match="head1|head2|head3|head4|head5">
<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:for-each select="@*">
<xsl:copy/>
</xsl:for-each>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
但是此样式表无法通过 A variable reference is not allowed in an XSLT pattern (except in a predicate)
编译
我找到的一个邮件列表建议 group-starting-with="*[name()=$heading_name]
。使用它会创建 section
个节点,但它们将为空。
有没有办法实现我正在寻找的东西?
示例输入:
<?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">
<chapnumber>Chapter 1</chapnumber>
<chaptitle>Chapter Title</chaptitle>
<head1>Heading 1</head1>
<para>1st paragraph</para>
<head2>Heading 2</head2>
<para>2nd paragraph</para>
<head2>Heading 2 2</head2>
<para>Final paragraph</para>
</book>
预期输出:
<?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">
<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>
<para>2nd paragraph</para>
</section>
<section>
<info>
<title>Heading 2 2</title>
</info>
<para>Final paragraph</para>
</section>
</section>
</chapter>
</book>
您需要确保在分组完成后处理这些项目,因此请在 xsl:otherwise
:
中使用 <xsl:apply-templates select="current-group()"/>
<xsl:template name="nest_headings">
<xsl:param name="working_group"/>
<xsl:param name="heading_level"/>
<xsl:variable name="heading_name" select="concat('head', $heading_level)"/>
<xsl:if test="$heading_level < 6">
<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>
test="current-group()[1]/name() = $heading_name"
可以缩短为 test="local-name() eq $heading_name"
。
有关完整示例,请参阅 http://xsltransform.net/pPqsHTm/1。
我有一个样式表,旨在添加一些目前看起来像这样的结构:
<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:for-each select="@*">
<xsl:copy/>
</xsl:for-each>
<xsl:copy-of select="info"/>
<xsl:for-each-group select="*" group-starting-with="chapnumber">
<xsl:choose>
<xsl:when test="current-group()[1]/name() = 'chapnumber'">
<xsl:variable name="chapter_number" select="replace(., '.*([0-9]).*', '')"/>
<chapter label="{$chapter_number}">
<xsl:call-template name="nest_head1">
<xsl:with-param name="working_group" select="current-group() except ."/>
</xsl:call-template>
</chapter>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="nest_head1">
<xsl:with-param name="working_group" select="current-group() except ."/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
<xsl:template name="nest_head1">
<xsl:param name="working_group"/>
<xsl:for-each-group select="$working_group" group-starting-with="head1">
<xsl:choose>
<xsl:when test="current-group()[1]/name() = 'head1'">
<section>
<xsl:call-template name="nest_head2">
<xsl:with-param name="working_group" select="current-group()"/>
</xsl:call-template>
</section>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="nest_head2">
<xsl:with-param name="working_group" select="current-group()"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:template>
<xsl:template name="nest_head2">
<xsl:param name="working_group"/>
<xsl:for-each-group select="$working_group" group-starting-with="head2">
<xsl:choose>
<xsl:when test="current-group()[1]/name() = 'head2'">
<section>
<xsl:apply-templates select="current-group()"/>
</section>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-group()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:template>
<xsl:template match="head1|head2|head3|head4|head5">
<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:for-each select="@*">
<xsl:copy/>
</xsl:for-each>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
我不喜欢每个标题级别都有自己的模板(特别是因为理论上可能有更多级别的标题)并且认为它可以浓缩为一个单一的,更有用的模板,带有标题级别的变量,像这样:
<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:for-each select="@*">
<xsl:copy/>
</xsl:for-each>
<xsl:copy-of select="info"/>
<xsl:for-each-group select="*" group-starting-with="chapnumber">
<xsl:choose>
<xsl:when test="current-group()[1]/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: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>
</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">
<xsl:value-of select="concat('head', string($heading_level))"/>
</xsl:variable>
<xsl:if test="$heading_level < 6">
<xsl:for-each-group select="$working_group" group-starting-with="$heading_name">
<xsl:choose>
<xsl:when test="current-group()[1]/name() = $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: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>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:if>
</xsl:template>
<xsl:template match="head1|head2|head3|head4|head5">
<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:for-each select="@*">
<xsl:copy/>
</xsl:for-each>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
但是此样式表无法通过 A variable reference is not allowed in an XSLT pattern (except in a predicate)
我找到的一个邮件列表建议 group-starting-with="*[name()=$heading_name]
。使用它会创建 section
个节点,但它们将为空。
有没有办法实现我正在寻找的东西?
示例输入:
<?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">
<chapnumber>Chapter 1</chapnumber>
<chaptitle>Chapter Title</chaptitle>
<head1>Heading 1</head1>
<para>1st paragraph</para>
<head2>Heading 2</head2>
<para>2nd paragraph</para>
<head2>Heading 2 2</head2>
<para>Final paragraph</para>
</book>
预期输出:
<?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">
<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>
<para>2nd paragraph</para>
</section>
<section>
<info>
<title>Heading 2 2</title>
</info>
<para>Final paragraph</para>
</section>
</section>
</chapter>
</book>
您需要确保在分组完成后处理这些项目,因此请在 xsl:otherwise
:
<xsl:apply-templates select="current-group()"/>
<xsl:template name="nest_headings">
<xsl:param name="working_group"/>
<xsl:param name="heading_level"/>
<xsl:variable name="heading_name" select="concat('head', $heading_level)"/>
<xsl:if test="$heading_level < 6">
<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>
test="current-group()[1]/name() = $heading_name"
可以缩短为 test="local-name() eq $heading_name"
。
有关完整示例,请参阅 http://xsltransform.net/pPqsHTm/1。