2

这是一个通用的 XSLT 1.0 问题,我需要知道它来编写用于处理 docbook xml 文件的 XSLT 语句。在我的 docbook XML 中,我试图在 XSLT 1.0 中编写一个复合 xpath 语句,它说,为 html 输出中的 p 标签硬编码一个新属性“class =”play”。

我希望对没有这些属性的每个标签都执行此操作 <para>

  1. 角色=“正常播放段落”和
  2. 角色=“无缩进”和
  3. “角色=”行诗“

这是我的 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>

在 Docbook XSLT 处理之后,我希望 HTML 输出看起来像这样:

<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> 

docbook xslt 有 2 种机制在起作用,您并不需要真正了解它们。

首先,在<para role="">元素中,角色的值变成了p的类。这是默认行为。其次,我使用一种特殊模式将 a 硬编码"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>    

但我需要的不止这些。我不仅要排除 role="line-verse",还要排除 role="no-indent" 和 role="normal-play-para"。

所以我必须更改 match 属性中 xpath 语句的值,使其排除三个属性值。我不知道该怎么做。有人知道吗?谢谢。

关于答案的更新:

首先,我要感谢大家花时间理解我的问题并制定答案。我应该提一下,我还是这个东西的新手,而且,我的问题有点不公平,因为我使用的是一些复杂/复杂的 Docbook XSL。因此,我需要一个不会与 Docbook XSL 样式表发生冲突的答案。另外,我意识到如果我没有同时导入 docbook xsl,您编写的转换可能是生成 html 输出的完全有效的答案。

我在这里选择为“最佳”的答案可能不是最优雅的,而只是在我导入 epub3 docbook-ns 样式表时对我有用的答案。因此,Rishe 先生的单行答案实际上完全符合我的需要,即使它不那么优雅。

我真的不知道在我开始的这个定制中发生了什么:

<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

另一件事。Dimitre Novatchev 的 2 个答案看起来好像可行。顺便说一句,您忘记包含该 <xsl:param name="class" select="local-name(.)"/>语句(很容易修复)并且该解决方案有效。

但是,Dimitre,我还有一个问题。您给出的第二个答案使用了变量,看起来简单而实用。如果我尝试一下,我的 Saxon 6.5 解析器会给出验证错误。(E [Saxon6.5.5] xsl:template 中的匹配模式可能不包含对变量的引用)。也许这很简单,比如一个错字。但是有没有可能在 XSLT 1.0 模板匹配中不允许使用变量?

4

2 回答 2

2

你可以试试这个:

<!-- 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>

要专门回答您的原始问题,如果您确实需要一个专门匹配具有这些值之一的paras的模板,您可以在此 XPath 上进行匹配:@role

d:chapter[@xml:id = 'play']/d:para[not(@role = 'line-verse' or @role = 'normal-play-para' or @role - 'line-indent')]

但我认为我上面介绍的方法(将para这些角色视为特例,并将其他所有内容视为默认值)是更好的方法。

于 2013-01-21T07:22:43.610 回答
1

一种可能的解决方案是

  <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>
于 2013-01-21T13:31:44.100 回答