【问题标题】:Is there any way to use xpath to filter/process literal result elements?有没有办法使用 xpath 来过滤/处理文字结果元素?
【发布时间】:2015-03-30 20:23:23
【问题描述】:

我正在开发一个样式表,以将类似于 IETF(即 xhtml)表格但面向列的表格转换为 xsl-fo。

第一步是将

标签转换为 标签。 不幸的是,由于某种原因,XSL 1.1 规范的作者没有提供一种方法来自动将所有属性从 传输到相应列中的表格单元格,以及属性(宽度除外) 也不会自动应用(在我看来,这真是愚蠢的设计决定——here is one of the Antenna House developers complaining about the same thing in 2001!)。继承也不适用,因为 没有任何子节点。

这让我的任务是弄清楚为每一列设置了哪些格式属性,并手动将它们应用到适当的表格单元格中。但是,如何最好地做到这一点?我的一个想法是将所有 节点放入一个变量中,但是我将如何使用 xpath 来处理这些节点?另一种想法是必须有一种方法可以使用临时结果树来做到这一点,但从未使用过这样的东西,并且对于这是否可能以及如何使用临时结果树一无所知。我发布这个带有标签 XSLT 1.0 和 XSLT 2.0 的问题只是为了看看是否有 is 答案,但我真的受限于使用 XSLT 1.0 来解决这个问题。

编辑:有人要求举个具体的例子。源文档片段可能如下所示:

<table>
  <col width="33%" font-weight="bold" border="1pt solid black"/>
  <col width="34%" span="2" color="red" background-color="gray"/>
  <col font-style="italic" align="center" background-color="yellow"/>
  <tr><td>A</td><td>B</td><td>C</td><td>D</td></tr>
  <tr><td>dog</td><td>cat</td><td>mouse</td><td>elephant</td></tr>
  ...
</table>

即一个标准的 xhtml 表,除了一些通常使用 style 属性表示的属性。

那么自然翻译就是

<table> -->  <fo:table>
<col/>  -->  <fo:table-column/>
<tr>    -->  <fo:table-row>
<td>    -->  <fo:table-cell>

但是,这样做有一个问题,即 中的任何属性都不会自动应用于相应列中的表格单元格,除非您特别要求使用 from- 调用它们table-colum() 函数(宽度除外, 自动应用)。因此,例如,对于表格的 3rd 列中的表格单元格,我需要像这样输出 fo:

<fo:table-cell color="from-table-column()" background-color="from-table-column()>

对于 第 4 列中的表格单元格,我需要输出

<fo:table-cell font-style="from-table-column()" align="from-table-column()" background-color="from-table-column()>

问题是您如何知道在特定列中查找表格单元格的哪些属性?

【问题讨论】:

  • 输入和请求输出的一个小例子在这里真的很有帮助,恕我直言。特别是 WRT 到“没有提供自动传输所有属性的方法”。
  • 我不确定我是否理解您的问题......这个answer of yours 解释了from-table-column() 函数的工作原理;你不能把格式属性放在fo:table-column上,然后在单元格中用from-table-column()引用那些值吗?
  • @michael.hor257k -- 我添加了一个具体的例子。
  • @lfurini -- 是的,您可以将所有格式属性放在fo:table-column 中。问题是一旦您在处理表格单元格的模板中,如何确定其中哪些适用于特定的

标签: xslt xslt-2.0 xsl-fo


【解决方案1】:

警告:我对 XSL-FO 一无所知;这只是您的起点。

按照我理解您的问题的方式,您希望每个表格单元格具有与源文档中对应的col 相同的属性列表。这很容易通过查看当前处理的td 的位置并使用它在相同的相对位置查找col 来完成。但是,由于某些col 元素具有span 属性,所以这并不那么容易。

我建议的解决方案是从“枚举”col 元素开始,这样它们的数量就与列的数量一样多。有了这些,我们就可以按计划进行。

以下样式表:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:variable name="columns">
    <xsl:for-each select="/table/col">
        <xsl:call-template name="replicate">
            <xsl:with-param name="n">
                <xsl:choose>
                    <xsl:when test="@span">
                        <xsl:value-of select="@span"/>
                    </xsl:when>
                    <xsl:otherwise>1</xsl:otherwise>
                </xsl:choose>
            </xsl:with-param>
        </xsl:call-template>
    </xsl:for-each>
</xsl:variable>

<xsl:template match="/table">
    <fo:table>
        <xsl:apply-templates/>  
    </fo:table>
</xsl:template>

<xsl:template match="tr">
    <fo:table-row>
        <xsl:apply-templates select="td"/>
    </fo:table-row>
</xsl:template>

<xsl:template match="td">
    <xsl:variable name="i" select="position()" />
    <fo:table-cell>
        <xsl:for-each select="exsl:node-set($columns)/col[$i]/@*[not(name()='width' or name()='span')]">
            <xsl:attribute name="{name()}">from-table-column()</xsl:attribute>
        </xsl:for-each>
        <xsl:apply-templates/>  
    </fo:table-cell>
</xsl:template>

<xsl:template name="replicate">
    <xsl:param name="n"/>
    <xsl:if test="$n">
        <xsl:copy-of select="."/>
        <xsl:call-template name="replicate">
            <xsl:with-param name="n" select="$n - 1"/>
        </xsl:call-template>        
    </xsl:if>
</xsl:template>

</xsl:stylesheet>

当应用于您的输入示例时,将产生以下结果

<?xml version="1.0" encoding="utf-8"?>
<fo:table xmlns:fo="http://www.w3.org/1999/XSL/Format">
   <fo:table-row>
      <fo:table-cell font-weight="from-table-column()" border="from-table-column()">A</fo:table-cell>
      <fo:table-cell color="from-table-column()" background-color="from-table-column()">B</fo:table-cell>
      <fo:table-cell color="from-table-column()" background-color="from-table-column()">C</fo:table-cell>
      <fo:table-cell font-style="from-table-column()" align="from-table-column()" background-color="from-table-column()">D</fo:table-cell>
   </fo:table-row>
   <fo:table-row>
      <fo:table-cell font-weight="from-table-column()" border="from-table-column()">dog</fo:table-cell>
      <fo:table-cell color="from-table-column()" background-color="from-table-column()">cat</fo:table-cell>
      <fo:table-cell color="from-table-column()" background-color="from-table-column()">mouse</fo:table-cell>
      <fo:table-cell font-style="from-table-column()" align="from-table-column()" background-color="from-table-column()">elephant</fo:table-cell>
   </fo:table-row>
</fo:table>

这是假设表格单元格本身没有跨度;否则这可能会变得更加复杂。

【讨论】:

  • 太棒了!我曾想过这样的解决方案,但不知道如何使用 exslt。谢谢你的例子!
【解决方案2】:

在 XSLT 1.0 中,包含结果节点的变量是结果树片段,将其转换为节点集以应用 XPath 或进一步处理节点,您可以使用 exsl:node-set 或类似的方法,例如

<xsl:variable name="v1-rtf">
  <fo:table-column>...</fo:table:column>
</xsl:variable>

<xsl:variable name="v1-ns" xmlns:exsl="http://exslt.org/common" select="exsl:node-set($v1-rtf)"/>

<xsl:apply-templates select="$v1-ns/fo:table-column"/>

XSLT 2.0 的唯一区别是您不需要exsl:node-set 函数及其转换操作,您可以直接使用任何带有临时树的变量,例如

<xsl:variable name="v1">
  <fo:table-column>...</fo:table:column>
</xsl:variable>

<xsl:apply-templates select="$v1/fo:table-column"/>

【讨论】:

    猜你喜欢
    • 2015-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-02
    • 1970-01-01
    • 2017-02-14
    • 2015-01-26
    相关资源
    最近更新 更多