XSLT 模板不适用于新创建的元素
XSLT template not applying to newly-created elements
我正在使用 XSLT 2.0。在 xsl:template
(模板 1)中,我使用 xsl:analyze-string
创建具有 xml:lang
属性的新 span
元素。我有第二个模板 (template-2),它向包含 xml:lang
属性的元素添加 class
属性。在我的样式表中,由第一个模板创建的新创建的 span 元素没有被第二个模板处理。我该如何解决这个问题,并让第二个模板对第一个模板的结果进行操作?
示例:
输入:<p>The base form of a noun is technically called a <span xml:lang="sa-Latn">prātipadika</span> (प्रातिपदिक).</p>
期望的输出:<p>The base form of a noun is technically called a <span xml:lang="sa-Latn" class="lang-sa-latn">prātipadika</span> (<span xml:lang="sa-Deva" class="lang-sa-deva">प्रातिपदिक</span>).</p>
这个正确的输出有一个最终的 span
,同时具有 xml:lang
和 class
属性。
样式表输出:<p>The base form of a noun is technically called a <span xml:lang="sa-Latn" class="lang-sa-latn">prātipadika</span> (<span xml:lang="sa-Deva">प्रातिपदिक</span>).</p>
最终 span
.
中缺少此不正确的输出 class="sa-lang-deva"
(样式表生成的附加 类 有助于解决对某本电子书 reader 的不足 CSS 支持。)
这是我的样式表:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.w3.org/1999/xhtml"
xpath-default-namespace="http://www.w3.org/1999/xhtml"
xmlns:xml="http://www.w3.org/XML/1998/namespace"
xmlns:epub="http://www.idpf.org/2007/ops">
<xsl:output method="xhtml" encoding="utf-8" indent="no"/>
<xsl:template match="/">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops">
<xsl:apply-templates/>
</html>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<!-- Template-1: Add xml:lang attribute to Devanagari text. -->
<xsl:template match="element()/text()">
<xsl:variable name="textValue" select="."/>
<xsl:analyze-string select="$textValue" regex="([ऀ-ॿ]+)((\s+[ऀ-ॿ]+)*)">
<xsl:matching-substring>
<span xml:lang="sa-Deva"><xsl:value-of select="."/></span>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:template>
<!-- Template-2: Add lang-* class attribute when xml:lang attribute present. -->
<xsl:template match="*[@xml:lang]">
<xsl:call-template name="addClass">
<xsl:with-param name="newClass">lang-<xsl:value-of select="@xml:lang"/></xsl:with-param>
</xsl:call-template>
</xsl:template>
<!-- Add a class attribute to an element. -->
<xsl:template name="addClass">
<xsl:param name="newClass"/>
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:attribute name="class"><xsl:value-of select="normalize-space(concat(@class, ' ', lower-case($newClass)))"/></xsl:attribute>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
您需要将 analyze-string
创建的节点捕获到一个变量中,然后将模板应用于它们。您可以使用模板模式来避免无限递归。
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.w3.org/1999/xhtml"
xpath-default-namespace="http://www.w3.org/1999/xhtml"
xmlns:xml="http://www.w3.org/XML/1998/namespace"
xmlns:epub="http://www.idpf.org/2007/ops">
<xsl:output method="xhtml" encoding="utf-8" indent="no"/>
<xsl:template match="/">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops">
<xsl:apply-templates/>
</html>
</xsl:template>
<xsl:template match="@*|node()" mode="#all">
<xsl:copy>
<xsl:apply-templates select="@*|node()" mode="#current"/>
</xsl:copy>
</xsl:template>
<!-- Template-1: Add xml:lang attribute to Devanagari text. Note no
mode attribute, so only applies in default mode. -->
<xsl:template match="text()">
<xsl:variable name="textValue" select="."/>
<xsl:variable name="nodes" as="node()*">
<xsl:analyze-string select="$textValue" regex="([ऀ-ॿ]+)((\s+[ऀ-ॿ]+)*)">
<xsl:matching-substring>
<span xml:lang="sa-Deva"><xsl:value-of select="."/></span>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:variable>
<!-- apply templates to generated nodes, but with a mode that stops
this template from firing again -->
<xsl:apply-templates select="$nodes" mode="no-deva" />
</xsl:template>
<!-- Template-2: Add lang-* class attribute when xml:lang attribute present. -->
<xsl:template match="*[@xml:lang]" mode="#all">
<xsl:call-template name="addClass">
<xsl:with-param name="newClass">lang-<xsl:value-of select="@xml:lang"/></xsl:with-param>
</xsl:call-template>
</xsl:template>
<!-- Add a class attribute to an element. -->
<xsl:template name="addClass">
<xsl:param name="newClass"/>
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:attribute name="class"><xsl:value-of select="normalize-space(concat(@class, ' ', lower-case($newClass)))"/></xsl:attribute>
<xsl:apply-templates select="@*|node()" mode="#current"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
我对您的原始 XSLT 所做的更改是:
- 将
mode="#all"
添加到身份模板和"template 2",因此它们适用于所有模式,并将mode="#current"
添加到相关的apply-templates
指令中,因此它们递归使用无论当前模式是什么。
- 用
<xsl:variable>
包围 analyze-string
以捕获它生成的节点。
apply-templates
到这些节点使用不同的模式
由于我(故意)没有将 mode="#all"
添加到模板 1,它仅在初始传递期间匹配,而不是在 apply-templates mode="no-deva"
期间匹配。
我正在使用 XSLT 2.0。在 xsl:template
(模板 1)中,我使用 xsl:analyze-string
创建具有 xml:lang
属性的新 span
元素。我有第二个模板 (template-2),它向包含 xml:lang
属性的元素添加 class
属性。在我的样式表中,由第一个模板创建的新创建的 span 元素没有被第二个模板处理。我该如何解决这个问题,并让第二个模板对第一个模板的结果进行操作?
示例:
输入:<p>The base form of a noun is technically called a <span xml:lang="sa-Latn">prātipadika</span> (प्रातिपदिक).</p>
期望的输出:<p>The base form of a noun is technically called a <span xml:lang="sa-Latn" class="lang-sa-latn">prātipadika</span> (<span xml:lang="sa-Deva" class="lang-sa-deva">प्रातिपदिक</span>).</p>
这个正确的输出有一个最终的 span
,同时具有 xml:lang
和 class
属性。
样式表输出:<p>The base form of a noun is technically called a <span xml:lang="sa-Latn" class="lang-sa-latn">prātipadika</span> (<span xml:lang="sa-Deva">प्रातिपदिक</span>).</p>
最终 span
.
class="sa-lang-deva"
(样式表生成的附加 类 有助于解决对某本电子书 reader 的不足 CSS 支持。)
这是我的样式表:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.w3.org/1999/xhtml"
xpath-default-namespace="http://www.w3.org/1999/xhtml"
xmlns:xml="http://www.w3.org/XML/1998/namespace"
xmlns:epub="http://www.idpf.org/2007/ops">
<xsl:output method="xhtml" encoding="utf-8" indent="no"/>
<xsl:template match="/">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops">
<xsl:apply-templates/>
</html>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<!-- Template-1: Add xml:lang attribute to Devanagari text. -->
<xsl:template match="element()/text()">
<xsl:variable name="textValue" select="."/>
<xsl:analyze-string select="$textValue" regex="([ऀ-ॿ]+)((\s+[ऀ-ॿ]+)*)">
<xsl:matching-substring>
<span xml:lang="sa-Deva"><xsl:value-of select="."/></span>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:template>
<!-- Template-2: Add lang-* class attribute when xml:lang attribute present. -->
<xsl:template match="*[@xml:lang]">
<xsl:call-template name="addClass">
<xsl:with-param name="newClass">lang-<xsl:value-of select="@xml:lang"/></xsl:with-param>
</xsl:call-template>
</xsl:template>
<!-- Add a class attribute to an element. -->
<xsl:template name="addClass">
<xsl:param name="newClass"/>
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:attribute name="class"><xsl:value-of select="normalize-space(concat(@class, ' ', lower-case($newClass)))"/></xsl:attribute>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
您需要将 analyze-string
创建的节点捕获到一个变量中,然后将模板应用于它们。您可以使用模板模式来避免无限递归。
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.w3.org/1999/xhtml"
xpath-default-namespace="http://www.w3.org/1999/xhtml"
xmlns:xml="http://www.w3.org/XML/1998/namespace"
xmlns:epub="http://www.idpf.org/2007/ops">
<xsl:output method="xhtml" encoding="utf-8" indent="no"/>
<xsl:template match="/">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops">
<xsl:apply-templates/>
</html>
</xsl:template>
<xsl:template match="@*|node()" mode="#all">
<xsl:copy>
<xsl:apply-templates select="@*|node()" mode="#current"/>
</xsl:copy>
</xsl:template>
<!-- Template-1: Add xml:lang attribute to Devanagari text. Note no
mode attribute, so only applies in default mode. -->
<xsl:template match="text()">
<xsl:variable name="textValue" select="."/>
<xsl:variable name="nodes" as="node()*">
<xsl:analyze-string select="$textValue" regex="([ऀ-ॿ]+)((\s+[ऀ-ॿ]+)*)">
<xsl:matching-substring>
<span xml:lang="sa-Deva"><xsl:value-of select="."/></span>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:variable>
<!-- apply templates to generated nodes, but with a mode that stops
this template from firing again -->
<xsl:apply-templates select="$nodes" mode="no-deva" />
</xsl:template>
<!-- Template-2: Add lang-* class attribute when xml:lang attribute present. -->
<xsl:template match="*[@xml:lang]" mode="#all">
<xsl:call-template name="addClass">
<xsl:with-param name="newClass">lang-<xsl:value-of select="@xml:lang"/></xsl:with-param>
</xsl:call-template>
</xsl:template>
<!-- Add a class attribute to an element. -->
<xsl:template name="addClass">
<xsl:param name="newClass"/>
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:attribute name="class"><xsl:value-of select="normalize-space(concat(@class, ' ', lower-case($newClass)))"/></xsl:attribute>
<xsl:apply-templates select="@*|node()" mode="#current"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
我对您的原始 XSLT 所做的更改是:
- 将
mode="#all"
添加到身份模板和"template 2",因此它们适用于所有模式,并将mode="#current"
添加到相关的apply-templates
指令中,因此它们递归使用无论当前模式是什么。 - 用
<xsl:variable>
包围analyze-string
以捕获它生成的节点。 apply-templates
到这些节点使用不同的模式
由于我(故意)没有将 mode="#all"
添加到模板 1,它仅在初始传递期间匹配,而不是在 apply-templates mode="no-deva"
期间匹配。