25

我正在使用 knitr 和 pandoc 通过 markdown 生成一些 odt/docx 报告,现在我想知道您将如何格式化表格。我主要对添加规则感兴趣(至少顶部、底部和标题下方的规则,但能够在表格中添加任意规则也很好)。

通过 pandoc(没有任何特殊参数)从 pandoc 文档运行以下示例只会产生一个“普通”表,没有任何类型的规则/颜色/指南(在-t odt或中-t docx)。

+---------------+---------------+--------------------+
| Fruit         | Price         | Advantages         |
+===============+===============+====================+
| Bananas       | $1.34         | - built-in wrapper |
|               |               | - bright color     |
+---------------+---------------+--------------------+
| Oranges       | $2.10         | - cures scurvy     |
|               |               | - tasty            |
+---------------+---------------+--------------------+

我已经通过“样式”查看了在参考 .docx/.odt 中指定表格格式的可能性,但发现除了“表格标题”和“表格内容”样式之外没有任何明显的东西,这两种样式似乎都只涉及格式表中的文本。

由于对所见即所得风格的文档处理器相当不熟悉,我不知道如何继续。

4

6 回答 6

24

以下是我搜索如何执行此操作的方法:

在 Docx 中添加表格的方法是使用<w:tbl>标签。于是我在 github 存储库中搜索了这个,并在这个文件中找到了它(称为 Writers/Docx.hs,所以并不意外)

blockToOpenXML opts (Table caption aligns widths headers rows) = do
  let captionStr = stringify caption
  caption' <- if null caption
                 then return []
                 else withParaProp (pStyle "TableCaption")
                      $ blockToOpenXML opts (Para caption)
  let alignmentFor al = mknode "w:jc" [("w:val",alignmentToString al)] ()
  let cellToOpenXML (al, cell) = withParaProp (alignmentFor al)
                                    $ blocksToOpenXML opts cell
  headers' <- mapM cellToOpenXML $ zip aligns headers
  rows' <- mapM (\cells -> mapM cellToOpenXML $ zip aligns cells)
           $ rows
  let borderProps = mknode "w:tcPr" []
                    [ mknode "w:tcBorders" []
                      $ mknode "w:bottom" [("w:val","single")] ()
                    , mknode "w:vAlign" [("w:val","bottom")] () ]
  let mkcell border contents = mknode "w:tc" []
                            $ [ borderProps | border ] ++
                            if null contents
                               then [mknode "w:p" [] ()]
                               else contents
  let mkrow border cells = mknode "w:tr" [] $ map (mkcell border) cells
  let textwidth = 7920  -- 5.5 in in twips, 1/20 pt
  let mkgridcol w = mknode "w:gridCol"
                       [("w:w", show $ (floor (textwidth * w) :: Integer))] ()
  return $
    [ mknode "w:tbl" []
      ( mknode "w:tblPr" []
        ( [ mknode "w:tblStyle" [("w:val","TableNormal")] () ] ++
          [ mknode "w:tblCaption" [("w:val", captionStr)] ()
          | not (null caption) ] )
      : mknode "w:tblGrid" []
        (if all (==0) widths
            then []
            else map mkgridcol widths)
      : [ mkrow True headers' | not (all null headers) ] ++
      map (mkrow False) rows'
      )
    ] ++ caption'

我对 Haskell 完全不熟悉,但我可以看到边框样式是硬编码的,因为其中没有变量:

let borderProps = mknode "w:tcPr" []
                    [ mknode "w:tcBorders" []
                      $ mknode "w:bottom" [("w:val","single")] ()
                    , mknode "w:vAlign" [("w:val","bottom")] () ]

这意味着什么 ?

这意味着您无法使用当前版本的 PanDoc 更改 docx 表的样式。但是,有一种方法可以让您拥有自己的风格。

如何获得自己的风格?

  1. 在表格上创建具有您想要的样式的 Docx 文档(通过创建该表格)
  2. 更改该文件的扩展名并解压缩
  3. 打开word/document.xml并搜索<w:tbl>
  4. 尝试找出您的样式在 XML 中的转换方式,并根据您所看到的更改borderProps。

这是我创建的带有边框样式的测试: 自定义边框样式

这是相应的 XML:

<w:tblBorders>
  <w:top w:val="dotted" w:sz="18" w:space="0" w:color="C0504D" w:themeColor="accent2"/>
  <w:left w:val="dotted" w:sz="18" w:space="0" w:color="C0504D" w:themeColor="accent2"/>
  <w:bottom w:val="dotted" w:sz="18" w:space="0" w:color="C0504D" w:themeColor="accent2"/>
  <w:right w:val="dotted" w:sz="18" w:space="0" w:color="C0504D" w:themeColor="accent2"/>
  <w:insideH w:val="dotted" w:sz="18" w:space="0" w:color="C0504D" w:themeColor="accent2"/>
  <w:insideV w:val="dotted" w:sz="18" w:space="0" w:color="C0504D" w:themeColor="accent2"/>
</w:tblBorders>

odt 呢?

我还没看,请问你自己用类似的方法没有找到。

希望这会有所帮助,并毫不犹豫地提出更多问题

于 2013-07-25T16:13:16.647 回答
10

与 edi9999 相同的建议:破解转换后的 docx 的 xml 内容。以下是我的 R 代码。

tblPr变量包含要添加到 docx 中的表格的样式定义。您可以修改字符串以满足您自己的需要。

require(XML)

docx.file <- "report.docx"
tblPr <- '<w:tblPr xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"><w:tblStyle w:val="a8"/><w:tblW w:w="0" w:type="auto"/><w:tblBorders><w:top w:val="single" w:sz="4" w:space="0" w:color="000000" w:themeColor="text1"/><w:left w:val="single" w:sz="4" w:space="0" w:color="000000" w:themeColor="text1"/><w:bottom w:val="single" w:sz="4" w:space="0" w:color="000000" w:themeColor="text1"/><w:right w:val="single" w:sz="4" w:space="0" w:color="000000" w:themeColor="text1"/><w:insideH w:val="single" w:sz="4" w:space="0" w:color="000000" w:themeColor="text1"/><w:insideV w:val="single" w:sz="4" w:space="0" w:color="000000" w:themeColor="text1"/></w:tblBorders><w:jc w:val="center"/></w:tblPr>'

## unzip the docx converted by Pandoc
system(paste("unzip", docx.file, "-d temp_dir"))
document.xml <- "temp_dir/word/document.xml"

doc <- xmlParse(document.xml)
tbl <- getNodeSet(xmlRoot(doc), "//w:tbl")
tblPr.node <- lapply(1:length(tbl), function (i)
                   xmlRoot(xmlParse(tblPr)))
added.Pr <- names(xmlChildren(tblPr.node[[1]]))
for (i in 1:length(tbl)) {
    tbl.node <- tbl[[i]]
    if ('tblPr' %in% names(xmlChildren(tbl.node))) {
        children.Pr <- xmlChildren(xmlChildren(tbl.node)$tblPr)
        for (j in length(added.Pr):1) {
            if (added.Pr[j] %in% names(children.Pr)) {
                replaceNodes(children.Pr[[added.Pr[j]]],
                             xmlChildren(tblPr.node[[i]])[[added.Pr[j]]])
            } else {
                ## first.child <- children.Pr[[1]]
                addSibling(children.Pr[['tblStyle']],
                           xmlChildren(tblPr.node[[i]])[[added.Pr[j]]],
                           after=TRUE)
            }
        }
    } else {
        addSibling(xmlChildren(tbl.node)[[1]], tblPr.node[[i]], after=FALSE)
    }
}

## save hacked xml back to docx
saveXML(doc, document.xml, indent = F)
setwd("temp_dir")
system(paste("zip -r ../", docx.file, " *", sep=""))
setwd("..")
system("rm -fr temp_dir")
于 2013-07-25T16:38:15.963 回答
4

edi9999 有最好的答案,但这是我所做的:

创建 docx 时,请使用参考 docx 来获取样式。该引用将包含一堆其他样式,这些样式不被 Pandoc 用来创建,但它们仍然存在。通常,您将获得默认设置,但您也可以添加新的表格样式。

然后,您只需要更新 word\document.xml 文件以引用新的表格样式,您可以通过编程方式(通过解压缩、运行 sed 和更新 docx 存档)来执行此操作,例如:

7z.exe x mydoc.docx word\document.xml
sed "s/<w:tblStyle w:val=\"TableNormal\"/<w:tblStyle w:val=\"NewTableStyle\"/g" word\document.xml > word\document2.xml
copy word\document2.xml word\document.xml /y
7z.exe u mydoc.docx word\document.xml
于 2015-06-18T14:04:32.703 回答
4

reference.docx.

于 2015-12-08T04:39:15.230 回答
2

使用参考 docx 文件,然后 python-docx 很容易完成这项工作:

https://python-docx.readthedocs.io/

首先将您的文档转换为 docx :

重击:

pandoc --standalone --data-dir=/path/to/reference/ --output=/tmp/xxx.docx input_file.md

备注:

  • /path/to/reference/指向包含的文件夹reference.docx
  • reference.docx是一个包含 docx 元素所需样式的文件

然后为您的文档表格提供您想要使用的样式:

Python :

import docx
document = docx.Document('/tmp/xxx.docx')
for table in document.tables:
    table.style = document.styles['custom_style'] # custom_style must exist in your reference.docx file
于 2018-11-30T16:23:05.840 回答
1

只需在参考文档文件中添加一个您想要的表格样式,称为“表格”。并将 pandoc 更新为最新。

于 2018-03-02T11:08:01.557 回答