Python Docx 目录

介绍

在处理文档时,往往需要生成一个目录来帮助读者快速导航到特定的章节或内容。Python Docx 是一个强大的 Python 库,可以用来创建和修改 Microsoft Word 文档。本文将介绍如何使用该库生成目录,并提供一些代码示例。

安装

首先,我们需要安装 Python Docx 库。可以使用 pip 包管理器进行安装:

pip install python-docx

创建一个简单的 Word 文档

在生成目录之前,我们先来了解一下如何创建一个简单的 Word 文档。以下代码演示了如何创建一个包含标题和正文的文档:

import docx

# 创建一个新的文档
doc = docx.Document()

# 添加标题
doc.add_heading('My Document', 0)

# 添加正文内容
doc.add_paragraph('This is the first paragraph.')
doc.add_paragraph('This is the second paragraph.')

# 保存文档
doc.save('my_document.docx')

运行上述代码后,将生成一个名为 my_document.docx 的 Word 文档,并包含标题和两个段落。

生成目录

现在,我们来看看如何生成一个带有目录的 Word 文档。Python Docx 提供了 docx.oxml 模块,可以用来操作文档的 XML 内容。我们可以使用该模块来插入目录。

以下是一个生成目录的示例代码:

from docx import Document
from docx.oxml.ns import nsdecls
from docx.oxml import parse_xml
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT


def add_table_of_contents(doc):
    # 获取文档的主要部分
    main_part = doc.part

    # 创建一个新的 XML 元素来表示目录
    toc = parse_xml(r'<w:sdt xmlns:w="
                    '<w:sdtPr><w:docPartObj><w:docPartGallery w:val="Table of Contents"/></w:docPartObj>'
                    '<w:text/></w:sdtPr><w:sdtContent/></w:sdt>')

    # 查找文档中的标题和段落
    headings = []
    paragraphs = []
    for element in doc.element.body.iter():
        if element.tag.endswith('heading'):
            headings.append(element)
        elif element.tag.endswith('p'):
            paragraphs.append(element)

    # 添加目录标题
    title = doc.add_heading('Table of Contents', level=1)
    title.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER

    # 创建目录项
    for heading in headings:
        # 获取标题的级别
        level = int(heading.tag[-1])

        # 创建目录项的 XML 元素
        toc_entry = parse_xml(f'<w:p xmlns:w="{nsdecls("w")}"><w:r><w:fldSimple w:instr=" PAGEREF _Toc{n}" />'
                              f'<w:r><w:fldSimple w:instr=" TOC \o \h \z \u" /><w:t></w:t></w:r></w:p>')

        # 插入目录项
        main_part.element.body.insert(0, toc_entry)

        # 更新目录项的页码
        toc_start = main_part.element.body.index(toc_entry) + 1
        toc_end = toc_start + 1
        toc_entry[0][0].attrib[f'{nsdecls("w")}fldSimpleData'] = f' {toc_start}-{toc_end} '

        # 更新目录项的样式
        toc_entry[0][0][0].attrib[f'{nsdecls("w")}fldSimpleData'] = f' PAGEREF _Toc{n} '
        toc_entry[0][1][0].attrib[f'{nsdecls("w")}fldSimpleData'] = f' TOC \o \h \z \u '
        toc_entry[0][1][1].text = heading.text

    # 添加目录到文档
    main_part.element.body.insert(0, toc)


# 创建一个新的文档
doc = Document()

# 添加标题和内容
doc.add_heading('Chapter 1', level=1)
doc.add_paragraph('This is chapter 1.')

doc.add_heading('Section 1.1', level=2)
doc.add_paragraph('This is section 1.1.')

doc.add_heading('Section 1.2', level=2)
doc.add_paragraph('This is section 1.2.')

doc.add_heading('Chapter 2', level=1)
doc.add_paragraph('This is chapter 2.')

# 生成目