这是一个通用的 XSLT 1.0 问题,我需要知道它来编写用于处理 docbook xml 文件的 XSLT 语句。 在我的文档手册XML中,我正在尝试在XSLT 1.0中编写一个复合xpath语句,该语句说,在html输出中为p标签硬编码一个新属性"class = "play"。
我希望为每个没有这些属性的<para>
标签执行此操作
- 角色="正常播放段落"和
- 角色 ="无缩进" 和
- "角色="行诗"
这是我的 XML 源:
<chapter xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
version="5.0" xml:id="play">
<title> Hamlet </title>
<para role="no-indent"> SPHINX. Do you think about it very much?</para>
<para role="normal-play-para"> INTERVIEWER. I do so say. </para>
<para>SPHINX. Hello </para>
<para> INTERVIEWER. dddddWhy I do so say. </para>
<para> SPHINX. Yes. </para>
<para role="line-verse"> Cosmologists have theorized or guessed</para>
</chapter>
我希望 HTML 输出在 Docbook XSLT 处理后看起来像这样:
<html>
<body>
<p class="no-indent">SPHINX. Do you think about it very much? much. </p>
<p class="normal-play-para"> INTERVIEWER. I do so say. </p>
<p class="play">SPHINX. Hello </p>
<p class="play">INTERVIEWER. dddddWhy I do so say. </p>
<p class="play">SPHINX. Yes. </p>
<p class="line-verse"> Cosmologists have theorized or guessed</p>
</body>
<html>
文档手册 xslt 有 2 种机制在工作,您真的不需要了解。
首先,在<para role="">
元素中,角色的值变为p类。这是默认行为。其次,我使用特殊模式将"class='play'"
硬编码为 p 标签。
<xsl:template match="d:chapter[@xml:id = 'play']/d:para" mode="class.attribute" >
<xsl:param name="class" select="local-name(.)"/>
<xsl:attribute name="class">play</xsl:attribute>
</xsl:template>
但是,我希望class="play"仅在不存在其他属性和值时才进行硬编码。 我可以修改上面的语句以排除所有属性为 role="line-verse" 的 para 标签:
<xsl:template match="d:chapter[@xml:id = 'play']/d:para[@role != 'line-verse']" mode="class.attribute" >
<xsl:param name="class" select="local-name(.)"/>
<xsl:attribute name="class">play</xsl:attribute>
</xsl:template>
但我需要的不止这些。我不仅要排除角色="行诗句",还要排除角色="无缩进"和角色="正常播放"。
所以我必须更改 match 属性中 xpath 语句的值,以便它排除三个属性值。我不知道该怎么做。有人知道吗?谢谢。
关于答案的更新:
首先,我要感谢大家花时间理解我的问题并制定答案。我应该提到,我仍然是这方面的新手,而且,我的问题有点不公平,因为我正在使用一些复杂/复杂的 Docbook XSL。因此,我需要一个不会导致与 Docbook XSL 样式表冲突的答案。另外,我意识到您编写的转换可能是生成 html 输出的完全有效的答案,如果我不导入文档手册 xsl。
我在这里选择的"最佳"答案可能不是最优雅的,而只是在我导入 epub3 docbook-ns 样式表时对我有用的答案。 所以里什先生的一句话回答实际上正是我需要做的,即使它不那么优雅。
我真的不知道我开始的这个自定义中发生了什么:
<xsl:template match="d:chapter[@xml:id = 'play']/d:para" mode="class.attribute" >
<xsl:param name="class" select="local-name(.)"/>
<xsl:attribute name="class">play</xsl:attribute>
</xsl:template>
我所知道的是,它正在调用一个 <xsl:template name="generate.class.attribute">
在这里找到。 http://50.56.245.89/xsl-ns/xhtml-1_1/html.xsl
另一件事。迪米特雷·诺瓦切夫的 2 个答案看起来好像会起作用。顺便说一下,你忘了包含<xsl:param name="class" select="local-name(.)"/>
语句 - 这很容易修复 - 并且该解决方案有效。
但是,迪米特雷,我还有一个问题。您给出的第二个答案使用了变量,它看起来简单且功能强大。 如果我尝试一下,我的 Saxon 6.5 解析器会给出验证错误。(E [Saxon6.5.5] xsl:template 中的匹配模式可能不包含对变量的引用)。也许这是一些简单的东西,比如一个错别字。但是,XSLT 1.0 模板匹配中是否可能不允许变量?
你能试一试吗:
<!-- Special handling for paras with one of the three roles -->
<xsl:template
match="d:chapter[@xml:id = 'play']/d:para[@role = 'line-verse' or @role = 'normal-play-para' or @role - 'line-indent']"
mode="class.attribute" >
<xsl:attribute name="class">
<xsl:value-of select="@role" />
</xsl:attribute>
</xsl:template>
<!-- Other paras get the default class "play" -->
<xsl:template match="d:chapter[@xml:id = 'play']/d:para" mode="class.attribute">
<xsl:attribute name="class">play</xsl:attribute>
</xsl:template>
更进一步的是,在调用这些模板的模板中包含<xsl:attribute>
,并在class.attribute
模板本身中仅具有所需的值。 像这样:
<xsl:template match="d:chapter[@xml:id = 'play']/d:para">
<p>
<xsl:attribute name="class">
<xsl:apply-templates select="." mode="class.attribute" />
</xsl:attribute>
...
</p>
</xsl:template>
<!-- Special handling for paras with one of the three roles -->
<xsl:template
match="d:chapter[@xml:id = 'play']/d:para[@role = 'line-verse' or @role = 'normal-play-para' or @role - 'line-indent']"
mode="class.attribute" >
<xsl:value-of select="@role" />
</xsl:template>
<!-- Other paras get the default class "play" -->
<xsl:template match="d:chapter[@xml:id = 'play']/d:para" mode="class.attribute">
<xsl:text>play</xsl:text>
</xsl:template>
为了具体回答您最初的问题,如果您确实需要一个专门匹配没有这些@role
值之一的模板para
,则可以在此 XPath 上进行匹配:
d:chapter[@xml:id = 'play']/d:para[not(@role = 'line-verse' or @role = 'normal-play-para' or @role - 'line-indent')]
但我认为我上面介绍的方法(para
将这些角色视为特例,并将其他所有角色视为默认值)是更好的方法。
一种可能的解决方案是:
<xsl:template mode="class.attribute" match=
"d:chapter[@xml:id = 'play']
/d:para[not(@role = 'line-verse'
or @role = 'no-indent'
or @role = 'normal-play-para'
)]" >
<xsl:attribute name="class">play</xsl:attribute>
</xsl:template>
但是,我会使用更灵活和可扩展的解决方案,它允许轻松修改"非播放"值:
<xsl:param name="pNonPlayVals">
<val>line-verse</val>
<val>no-indent</val>
<val>normal-play-para</val>
</xsl:param>
<xsl:template mode="class.attribute" match=
"d:chapter[@xml:id = 'play']/d:para
[not(@role = document('')/*/xsl:param[@name='pNonPlayVals']/val)]" >
<xsl:attribute name="class">play</xsl:attribute>
</xsl:template>