有没有办法使用xpath来过滤/处理文字结果元素?

时间:2015-03-30 20:23:24

标签: xslt xslt-2.0 xsl-fo

我正在使用样式表来转换类似于IETF(即xhtml)表的表,但是面向列的表转换为xsl-fo。

最初的步骤之一是转换< col />标签到< fo:table-column />标签。 不幸的是,出于某种原因,XSL 1.1规范的作者没有提供一种从< fo:table-column />自动传输所有属性的方法。在相应列中的表格单元格中,属性(宽度除外)也不会自动应用(在我看来,真的是愚蠢的设计决策 - here is one of the Antenna House developers complaining about the same thing in 2001!)。继承不适用于< fo:table-column />没有孩子。

这使我的任务是找出为每列设置的格式化属性,并手动将它们应用到适当的表格单元格。但是如何最好地做到这一点?我有一个想法是放置所有< fo:table-column />将节点转换为变量,但那我将如何使用xpath处理这些节点?另一个想法是必须有一种方法来使用临时结果树来做到这一点,但从来没有使用过这样的东西,并且对于这是否可行是无能为力的,如果是,那么如何使用临时结果树。我是用标签XSLT 1.0和XSLT 2.0发布这个问题,只是为了看的答案,但我真的不得不使用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>

然而,这有一个问题,即&lt; table-column /&gt;中没有任何属性。自动应用于相应列中的表格单元格,除非您明确要求使用 from-table-colum()函数调用它们( 的宽度除外) >自动应用)。因此,例如,对于表格 3rd 列中的表格单元格,我需要像这样输出fo:

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

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

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

问题是你如何知道在特定列中寻找表格单元的属性?

2 个答案:

答案 0 :(得分:1)

对于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"/>

答案 1 :(得分: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>

这假设表格单元本身没有跨度;否则这会变得复杂得多。