【问题标题】:Add styling rules in pandoc tables for odt/docx output (table borders)在 pandoc 表格中添加样式规则以用于 odt/docx 输出(表格边框)
【发布时间】:2013-07-25 12:53:31
【问题描述】:

我正在使用 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 中指定表格格式的可能性,但发现除了“表格标题”和“表格内容”样式之外没有任何明显的东西,这两者似乎都只关心表格中文本的格式。

由于对所见即所得式文档处理器相当陌生,我不知道如何继续。

【问题讨论】:

    标签: docx pandoc odt


    【解决方案1】:

    这是我搜索如何做到这一点的方法:

    在Docx中添加表格的方法是使用<w:tbl>标签。于是我在github仓库中搜索了这个,找到了in this file(叫做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并搜索&lt;w:tbl&gt;
    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 呢?

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

    希望这会有所帮助,不要犹豫,问更多问题

    【讨论】:

    • 我会接受这个,因为它是第一个。我什至没有想过简单地检查代码(或者也许我太懒了,更喜欢让其他人去做;))!谢谢!
    • 当您不熟悉背后发生的事情时,检查代码并不总是那么容易,例如文档的结构,表格在docx中的表示方式。所以这很正常。
    • 谢谢!看看我的 docx 开源项目,也许你也需要:github.com/edi9999/docxtemplater
    【解决方案2】:

    与 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")
    

    【讨论】:

      【解决方案3】:

      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
      

      【讨论】:

      • 这个答案加上 --reference-docx= 选项是一个杀手!
      【解决方案4】:

      reference.docx 中添加一个名为“TableNormal”的表格样式。

      【讨论】:

      • 这对我不起作用,因为 Word (2010) 抱怨保留了这种样式。
      • 实际上,当添加一个名为“Table”的表格样式时,它对我有用
      • Table 或 TableNormal 是内置在 sytle 中的,只需修改即可。
      【解决方案5】:

      使用参考 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
      

      【讨论】:

      • 那个包是pydocx 还是python-docx?它可以在 Windows 之外运行吗?该类docx.Document 的文档在哪里?
      • python-docx。是的,它可以在窗户外工作。还有docx.Document 文档:python-docx.readthedocs.io/en/latest/api/… 虽然它仍然有一些限制,但它是我发现的用于构建 docx 文件的最完整的工具。
      • python 的建议太棒了!我只想补充一点,document.save("target.docx") 是必需的,或者对document 所做的更改似乎不会保留在磁盘上。
      【解决方案6】:

      只需在reference-doc文件中添加一个你想要的名为“Table”的表格样式。并将pandoc更新为最新的。

      【讨论】:

        猜你喜欢
        • 2020-05-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多