XML表格转换为LaTeX

5
假设我有一个如下形式的XML表格:
<table>
  <tr>
    <td>First Name:</td>
    <td>Bill Gates</td>
  </tr>
  <tr>
    <td rowspan="2">Telephone:</td>
    <td>555 77 854</td>
  </tr>
  <tr>
    <td>555 77 855</td>
  </tr>
</table>

我希望用XSLT将其转换为LaTeX(我从其他地方偷了这个例子)。 我想要的结果是

\documentclass{memoir}
\usepackage{multirow}
\begin{document}
\begin{tabular}{*{10}{c}}
 First name & Bill Gates &\\
 \multirow{2}{*}{Telephone:}
   & 555 77 854 &\\
   & 555 77 855 &
\end{tabular}
\end{document}

在大多数情况下,这两种表格格式之间存在着相当的一对一对应关系。因此,在大多数情况下,这样做效果非常好:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" omit-xml-declaration="yes" encoding="UTF-8"/>

<xsl:template match="/">

\documentclass{memoir}
\usepackage{multirow}
\begin{document}

<xsl:apply-templates/>

\end{document}

</xsl:template>

<xsl:template match="table">
\begin{tabular}{*{10}{c}}
<xsl:apply-templates/>
\end{tabular}
</xsl:template>

<xsl:template match="tr">
<xsl:apply-templates />\\
</xsl:template>

<xsl:template match="td[not(@rowspan) and not(@colspan)]">
<xsl:apply-templates/> &amp;
</xsl:template>

<xsl:template match="td[not(@colspoan)]">
\multirow{<xsl:value-of select="@colspan"/>}{*}{<xsl:apply-templates/>} &amp;
</xsl:template>

<xsl:template match="td[not(@rowspan)]">
\multicolumn{<xsl:value-of select="@colspan"/>}{l}{<xsl:apply-templates/>} &amp;
</xsl:template>

<xsl:template match="td">
\multirow{<xsl:value-of select="@rowspan"/>}{*}{\multicolumn{<xsl:value-of select="@colspan"/>}}{l}{<xsl:apply-templates/>} &amp;
</xsl:template>
</xsl:stylesheet>

问题在于&amp;(输出时变为&)。在LaTeX中,您需要在跨越单元格的第三行开头使用它。但在XML表格中不是这种情况。如何解决这个问题?

你的问题中的XSLT是否完全代表了你所面临的问题?只是其中一个模板输出文本\multicolumn,但在你的预期输出中实际上并没有显示出来。此外,XSLT引用了一个no函数,我认为应该实际上是not。还有一些语法错误。在匹配table的模板中缺少一个",在匹配td[no(@rowspan)的模板中缺少一个]。如果你能纠正所有这些,那将会非常有帮助。谢谢! - Tim C
不,有时候也会使用\multicolumn。但是大多数情况下都是\multirow引起了问题。我为这个问题专门制作了一个简化版本。我会尝试纠正你提到的错误。 - Gaussler
为什么在 LaTeX 中加入 \cr?(这不是 LaTeX 命令)我想你本意是 &,因为你在每个 td 中都添加了它们。 - David Carlisle
你在提问过程中改变了问题。你最初的问题是如何转义 &,但现在你想做复杂的 rowspan/colspan 操作。即使你开始给出奖励,这也会让回答者感到沮丧。更好的方法是针对新问题提出新的问题。 - flup
我没有改变问题的一点。你所说的是同一件事情的两种不同表述。问题在于LaTeX和我的XML文档处理colspan和rowspan的方式不同。问题是如何编写一个代码来在这两个系统之间进行翻译。这一直是重点。 - Gaussler
显示剩余2条评论
1个回答

9

enter image description here

<xsl:stylesheet version="2.0"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema">

<xsl:output method="text"/>

<xsl:template match="/">
\documentclass{memoir}
\usepackage{multirow}
\begin{document}
<xsl:apply-templates/>
\end{document}
</xsl:template>

<xsl:template match="table">
<xsl:variable name="noc" select="max(tr/sum(td/(@colspan/number(.),1)[1]))"/>
<xsl:text>\begin{tabular}{*{</xsl:text>
<xsl:value-of select="$noc"/>
<xsl:text>}{l}}&#10;</xsl:text>
<xsl:apply-templates select="tr[1]">
 <xsl:with-param name="rspans" select="for $i in 1 to xs:integer($noc) return 0"/>
</xsl:apply-templates>
<xsl:text>\end{tabular}</xsl:text>
</xsl:template>

<xsl:template match="tr">
 <xsl:param name="rspans"/>
<xsl:text/>% [<xsl:value-of select="$rspans"/>]
 <xsl:variable name="tr" select="."/>
 <xsl:for-each select="$rspans">
  <xsl:variable name="c" select="position()"/>
  <xsl:variable name="td" select="$tr/td[count($rspans[position() &lt;=$c][.=0])]"/>
  <xsl:if test=".=0">
   <xsl:if test="$td/@rowspan[. &gt; 1]">
    <xsl:text>\multirow{</xsl:text>
    <xsl:value-of select="$td/@rowspan"/>
    <xsl:text>}{*}{</xsl:text>
   </xsl:if>
   <xsl:apply-templates select="$td"/>
   <xsl:if test="$td/@rowspan[. &gt; 1]">}</xsl:if>
  </xsl:if>
  <xsl:choose>
   <xsl:when test=". &gt;1 and position()=last()">&amp;\\&#10;</xsl:when>
   <xsl:when test="position()=last()">\\&#10;</xsl:when>
   <xsl:otherwise>&amp;</xsl:otherwise>  
  </xsl:choose>
 </xsl:for-each>
 <xsl:apply-templates select="following-sibling::tr[1]">
  <xsl:with-param name="rspans" select="for $c in 1 to count($rspans)
   return
   ($rspans[$c] +
   td[count($rspans[position() &lt;=$c][.=0])]/(@rowspan,1)[1]
   -1)"/>
 </xsl:apply-templates>
</xsl:template>

</xsl:stylesheet>

非常感谢您的精彩回答,@DavidCarlisle。我目前正在尝试使用它,但是似乎没有支持多个\multirow列并排放置的功能。此外,也没有\multicolumn支持。这两个问题要如何解决呢?是否困难重重? - Gaussler
2
@Gaussler 多行应该是完全支持的,如果不是的话,我以后可能会再看一下。这里不支持多列,我计划把它留给读者练习(这并不难,你只需要在 rowspan 参数中传播 colspan 条目而不仅仅是 1)。我可能会留下一些多列提示或在修复 multispan 的同时完成它,可能需要到周末... - David Carlisle
我确实知道如何在这种情况下使用\multicolumn;我主要是这么说是想问一下是否有特定的原因你没有包含它。看起来并非如此。 - Gaussler
@DavidCarlisle,修复有问题了吗? :-) - Gaussler
@Gaussler 不好意思,很奇怪我居然忘了你 :-) 稍后会查看。 - David Carlisle
显示剩余8条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接