Python:使用python-docx/lxml创建"目录"

Jos*_*nel 5 python docx wordml python-docx

我试图在python-docx(https://github.com/mikemaccana/python-docx)的帮助下自动创建.docx文件(WordML ).我当前的脚本使用以下循环手动创建ToC:

for chapter in myChapters:
    body.append(paragraph(chapter.text, style='ListNumber'))
Run Code Online (Sandbox Code Playgroud)

有没有人知道使用"内置单词"ToC功能的方法,它会自动添加索引并创建各个章节的段落链接?

非常感谢!

sca*_*nny 14

关键的挑战是渲染的ToC依赖于分页来知道每个标题要放置的页码.分页是布局引擎提供的功能,布局引擎是Word客户端内置的一个非常复杂的软件.用Python编写页面布局引擎可能不是一个好主意,绝对不是我计划在短期内进行的项目:)

ToC由两部分组成:

  1. 指定ToC放置的元素以及要包含的标题级别.
  2. 实际可见的ToC内容,标题和页码用虚线连接它们.

创建元素非常简单,而且工作量相对较低.创建实际的可见内容(至少如果您想要包含页码)需要Word布局引擎.

这些是选项:

  1. 只需添加标签和其他一些位来发信号通知ToC需要更新.首次打开文档时,会出现一个对话框,说明需要刷新链接.用户单击是,Bob是您的叔叔.如果用户单击否,则会显示ToC标题,其下方没有内容,并且可以手动更新ToC.

  2. 添加标记,然后通过C#或Visual Basic对Word自动化库使用Word客户端打开并保存文件; 所有字段(包括ToC字段)都会更新.

  3. 如果您有SharePoint实例或使用Word Automation Services可以执行此操作的任何内容,请执行相同的服务器端操作.

  4. 在文档中创建一个AutoOpen宏,在打开文档时自动运行字段更新.可能不会通过大量的病毒检查程序,也无法在公司环境中常见的锁定Windows版本上运行.

这是Eric White一套非常精彩的截屏视频,解释了所有毛茸茸的细节


小智 12

请参阅代码注释中的说明。

# First set directory where you want to save the file

import os
os.chdir("D:/")

# Now import required packages

import docx
from docx import Document
from docx.oxml.ns import qn
from docx.oxml import OxmlElement

# Initialising document to make word file using python

document = Document()

# Code for making Table of Contents

paragraph = document.add_paragraph()
run = paragraph.add_run()

fldChar = OxmlElement('w:fldChar')  # creates a new element
fldChar.set(qn('w:fldCharType'), 'begin')  # sets attribute on element

instrText = OxmlElement('w:instrText')
instrText.set(qn('xml:space'), 'preserve')  # sets attribute on element
instrText.text = 'TOC \\o "1-3" \\h \\z \\u'   # change 1-3 depending on heading levels you need

fldChar2 = OxmlElement('w:fldChar')
fldChar2.set(qn('w:fldCharType'), 'separate')

fldChar3 = OxmlElement('w:t')
fldChar3.text = "Right-click to update field."

fldChar2.append(fldChar3)

fldChar4 = OxmlElement('w:fldChar')
fldChar4.set(qn('w:fldCharType'), 'end')

r_element = run._r
r_element.append(fldChar)
r_element.append(instrText)
r_element.append(fldChar2)
r_element.append(fldChar4)

p_element = paragraph._p

# Giving headings that need to be included in Table of contents

document.add_heading("Network Connectivity")
document.add_heading("Weather Stations")

# Saving the word file by giving name to the file

name = "mdh2"
document.save(name+".docx")

# Now check word file which got created

# Select "Right-click to update field text"
# Now right click and then select update field option
# and then click on update entire table

# Now,You will find Automatic Table of Contents 
Run Code Online (Sandbox Code Playgroud)

  • 感谢您的代码片段,但是为什么我们必须手动更新目录。有没有办法在 python 脚本中自动执行此操作? (2认同)
  • 我想我找到了如何自动更新。为 fldChar3 添加这些代码行。fldChar3 = OxmlElement('w:updateFields') fldChar3.set(qn('w:val'), 'true') (2认同)
  • 当我打开word文档时,它说该文档链接到另一个文档。这是什么原因呢? (2认同)

Kos*_*vid 7

很抱歉在旧帖子中添加评论,但我认为这可能会有所帮助。这不是我的解决方案,但已在那里找到:https : //github.com/python-openxml/python-docx/issues/36 感谢https://github.com/mustashhttps://github。 com/scanny

    from docx.oxml.ns import qn
    from docx.oxml import OxmlElement

    paragraph = self.document.add_paragraph()
    run = paragraph.add_run()
    fldChar = OxmlElement('w:fldChar')  # creates a new element
    fldChar.set(qn('w:fldCharType'), 'begin')  # sets attribute on element
    instrText = OxmlElement('w:instrText')
    instrText.set(qn('xml:space'), 'preserve')  # sets attribute on element
    instrText.text = 'TOC \\o "1-3" \\h \\z \\u'   # change 1-3 depending on heading levels you need

    fldChar2 = OxmlElement('w:fldChar')
    fldChar2.set(qn('w:fldCharType'), 'separate')
    fldChar3 = OxmlElement('w:t')
    fldChar3.text = "Right-click to update field."
    fldChar2.append(fldChar3)

    fldChar4 = OxmlElement('w:fldChar')
    fldChar4.set(qn('w:fldCharType'), 'end')

    r_element = run._r
    r_element.append(fldChar)
    r_element.append(instrText)
    r_element.append(fldChar2)
    r_element.append(fldChar4)
    p_element = paragraph._p
Run Code Online (Sandbox Code Playgroud)


小智 5

@Mawg // 更新目录

有同样的问题来更新目录并用谷歌搜索它。不是我的代码,但它有效:

word = win32com.client.DispatchEx("Word.Application")
doc = word.Documents.Open(input_file_name)
doc.TablesOfContents(1).Update()
doc.Close(SaveChanges=True)
word.Quit()
Run Code Online (Sandbox Code Playgroud)

  • 这需要windows环境。/sf/ask/4351109171/ 将需要探索如何在 Ubuntu/Mac 环境中执行此步骤。 (3认同)