使用XSLT将XHTML表转换为LaTeX

时间:2021-08-03 14:16:21

I'm new in XSLT (v1.0) and I can't convert complex XHTML tables to LaTeX using XSLT.

我是XSLT (v1.0)的新手,不能使用XSLT将复杂的XHTML表转换为LaTeX。

What I mean when I said complex tables, are tables with rows with different number of columns. In other words, td with colspan.

当我说复杂表格时,我指的是列数不同的表格。换句话说,td与colspan。

i.e. (xhtml table)

例如(xhtml表)

<table border="1" cellspacing="0" cellpadding="0">
    <tr>
        <td valign="top" width="68" colspan="3"> <p>Values</p> </td>
    </tr> 
    <tr> 
        <td valign="top" width="68"> <p>95</p> </td> 
        <td valign="top" width="68"> <p>169</p> <p> </p> </td> 
        <td valign="top" width="68"> <p>180</p> <p> </p> </td>
    </tr>
</table>

What I'm doing in the XSL file is:

我在XSL文件中所做的是:

<xsl:template match="xhtml:table[@border='1']">
    <xsl:text>\begin{center}</xsl:text>
    <xsl:text>\begin{tabular}{</xsl:text>

    <xsl:for-each select="xhtml:tr[1]/*">
        <xsl:text>c</xsl:text>
        <xsl:if test="position() = last()">
            <xsl:text>}&#10;</xsl:text>
        </xsl:if>
    </xsl:for-each>

    <xsl:text>\toprule&#10;</xsl:text>
    <xsl:for-each select="xhtml:tr">
        <xsl:if test="position() != 1">
            <xsl:text>\midrule&#10;</xsl:text>
        </xsl:if>

        <xsl:if test="position() = 2">
            <xsl:text>\midrule&#10;</xsl:text>
        </xsl:if>

        <xsl:for-each select="xhtml:td|xhtml:th">
            <xsl:if test="name() = 'th'">{\bf </xsl:if>
            <xsl:apply-templates />
            <xsl:if test="name() = 'th'">}</xsl:if>

            <xsl:if test="position() != last()">
            <xsl:text>&amp;</xsl:text>
            </xsl:if>
        </xsl:for-each>

        <xsl:text> \\&#10;</xsl:text>
    </xsl:for-each>

    <xsl:text>\bottomrule&#10;</xsl:text>

    <xsl:text>\end{tabular}&#10;</xsl:text>
    <xsl:text>\end{center}&#10;</xsl:text>
</xsl:template>

But as you can see, this code just works for simple tables, without the colspan attribute. The code loops around the first tr, and for each td, it writes an "c". So, in the case above, it will only create a one column table.

但是正如您所看到的,这段代码只适用于简单的表,没有colspan属性。代码围绕第一个tr循环,对于每个td,它都写一个“c”。因此,在上面的例子中,它只会创建一个列表。

What I want to do is count the number of td, and the number of colspans if it exists, to create a correct table, with 3 columns.

我要做的是计算td的数量,如果存在的话,计算colspan的数量,以创建一个包含3列的正确表。

Does anyone knows how to do this? Thanks in advance.

有人知道怎么做吗?提前谢谢。

1 个解决方案

#1


6  

This is easier in XSLT2 but you can use the (//*)[position() &lt;= n] idiom in XSLT 1 to iterate n times. I also fixed up your TeX a bit: \bf has been deprecated since latex2e released in back in 1993:-)

在XSLT2中这更容易,但是您可以使用XSLT 1中的(/ *)[position() <= n]习语来迭代n次。我也修正了你的TeX:自1993年latex2e发布以来,\bf已经被弃用:-)


<table  xmlns="http://www.w3.org/1999/xhtml"
    border="1" cellspacing="0" cellpadding="0">
    <tr>
        <td valign="top" width="68" colspan="3"> <p>Values</p> </td>
    </tr> 
    <tr> 
        <td valign="top" width="68"> <p>95</p> </td> 
        <td valign="top" width="68"> <p>169</p> <p> </p> </td> 
        <td valign="top" width="68"> <p>180</p> <p> </p> </td>
    </tr>
</table>

<xsl:stylesheet version="1.0"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xhtml="http://www.w3.org/1999/xhtml">

<xsl:output method="text"/>

<xsl:template match="xhtml:table[@border='1']">
 <xsl:text>\begin{center}&#10;</xsl:text>
 <xsl:text>\begin{tabular}{</xsl:text>

 <xsl:for-each select="xhtml:tr[1]/*">
  <xsl:choose>
   <xsl:when test="@colspan">
    <xsl:for-each select="(//*)[position()&lt;=current()/@colspan]">c</xsl:for-each>
   </xsl:when>
   <xsl:otherwise>c</xsl:otherwise>
  </xsl:choose>
 </xsl:for-each>
 <xsl:text>}&#10;</xsl:text>

 <xsl:text>\toprule&#10;</xsl:text>
 <xsl:for-each select="xhtml:tr">
  <xsl:if test="position() != 1">
   <xsl:text>\midrule&#10;</xsl:text>
  </xsl:if>

  <xsl:if test="position() = 2">
   <xsl:text>\midrule&#10;</xsl:text>
  </xsl:if>

  <xsl:for-each select="xhtml:td|xhtml:th">
   <xsl:if test="self::xhtml:th">\bfseries </xsl:if>
   <xsl:apply-templates />
   <xsl:if test="position() != last()">
    <xsl:text>&amp;</xsl:text>
   </xsl:if>
  </xsl:for-each>

  <xsl:if test="position()!=last()"> \\&#10;</xsl:if>
 </xsl:for-each>

 <xsl:text>\end{tabular}&#10;</xsl:text>
 <xsl:text>\end{center}</xsl:text>

</xsl:template>
</xsl:stylesheet>

\begin{center}
\begin{tabular}{ccc}
\toprule
 Values  \\
\midrule
\midrule
 95 & 169   & 180   \end{tabular}
\end{center}

#1


6  

This is easier in XSLT2 but you can use the (//*)[position() &lt;= n] idiom in XSLT 1 to iterate n times. I also fixed up your TeX a bit: \bf has been deprecated since latex2e released in back in 1993:-)

在XSLT2中这更容易,但是您可以使用XSLT 1中的(/ *)[position() <= n]习语来迭代n次。我也修正了你的TeX:自1993年latex2e发布以来,\bf已经被弃用:-)


<table  xmlns="http://www.w3.org/1999/xhtml"
    border="1" cellspacing="0" cellpadding="0">
    <tr>
        <td valign="top" width="68" colspan="3"> <p>Values</p> </td>
    </tr> 
    <tr> 
        <td valign="top" width="68"> <p>95</p> </td> 
        <td valign="top" width="68"> <p>169</p> <p> </p> </td> 
        <td valign="top" width="68"> <p>180</p> <p> </p> </td>
    </tr>
</table>

<xsl:stylesheet version="1.0"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xhtml="http://www.w3.org/1999/xhtml">

<xsl:output method="text"/>

<xsl:template match="xhtml:table[@border='1']">
 <xsl:text>\begin{center}&#10;</xsl:text>
 <xsl:text>\begin{tabular}{</xsl:text>

 <xsl:for-each select="xhtml:tr[1]/*">
  <xsl:choose>
   <xsl:when test="@colspan">
    <xsl:for-each select="(//*)[position()&lt;=current()/@colspan]">c</xsl:for-each>
   </xsl:when>
   <xsl:otherwise>c</xsl:otherwise>
  </xsl:choose>
 </xsl:for-each>
 <xsl:text>}&#10;</xsl:text>

 <xsl:text>\toprule&#10;</xsl:text>
 <xsl:for-each select="xhtml:tr">
  <xsl:if test="position() != 1">
   <xsl:text>\midrule&#10;</xsl:text>
  </xsl:if>

  <xsl:if test="position() = 2">
   <xsl:text>\midrule&#10;</xsl:text>
  </xsl:if>

  <xsl:for-each select="xhtml:td|xhtml:th">
   <xsl:if test="self::xhtml:th">\bfseries </xsl:if>
   <xsl:apply-templates />
   <xsl:if test="position() != last()">
    <xsl:text>&amp;</xsl:text>
   </xsl:if>
  </xsl:for-each>

  <xsl:if test="position()!=last()"> \\&#10;</xsl:if>
 </xsl:for-each>

 <xsl:text>\end{tabular}&#10;</xsl:text>
 <xsl:text>\end{center}</xsl:text>

</xsl:template>
</xsl:stylesheet>

\begin{center}
\begin{tabular}{ccc}
\toprule
 Values  \\
\midrule
\midrule
 95 & 169   & 180   \end{tabular}
\end{center}