Python: создайте "оглавление" с помощью python-docx/lxml

Я пытаюсь автоматизировать создание файлов.docx (WordML) с помощью python-docx ( https://github.com/mikemaccana/python-docx). Мой текущий скрипт создает ToC вручную с помощью следующего цикла:

for chapter in myChapters:
    body.append(paragraph(chapter.text, style='ListNumber'))

Кто-нибудь знает способ использования "встроенной в слово" ToC-функции, которая автоматически добавляет индекс, а также создает ссылки на абзацы для отдельных глав?

Большое спасибо!

5 ответов

Решение

Основная проблема заключается в том, что визуализированный ToC зависит от нумерации страниц, чтобы узнать, какой номер страницы нужно разместить для каждого заголовка. Разбиение на страницы - это функция, предоставляемая механизмом компоновки, очень сложным программным обеспечением, встроенным в клиент Word. Написание движка макета страницы на Python, вероятно, не очень хорошая идея, определенно не тот проект, который я планирую предпринять в ближайшее время:)

ToC состоит из двух частей:

  1. элемент, который определяет размещение ToC и такие вещи, как уровни заголовков для включения.
  2. фактический видимый контент ToC, заголовки и номера страниц с пунктирными линиями, соединяющими их.

Создать элемент довольно просто и сравнительно легко. Создание фактического видимого содержимого, по крайней мере, если вы хотите, чтобы номера страниц были включены, требует механизма компоновки Word.

Это варианты:

  1. Просто добавьте тег и несколько других битов, чтобы сообщить Word о необходимости обновления ToC. Когда документ открывается впервые, появляется диалоговое окно с сообщением о необходимости обновления ссылок. Пользователь нажимает Да, и Боб твой дядя. Если пользователь нажимает Нет, заголовок ToC появляется без содержимого под ним, и ToC можно обновить вручную.

  2. Добавьте тег, а затем подключите клиент Word с помощью C# или Visual Basic к библиотеке Word Automation, чтобы открыть и сохранить файл; все поля (включая поле ToC) обновляются.

  3. Сделайте то же самое на стороне сервера, если у вас есть экземпляр SharePoint или что-то еще, что может сделать это с Word Automation Services.

  4. Создайте макрос AutoOpen в документе, который автоматически запускает обновление поля при открытии документа. Вероятно, не пройдет много проверок на вирусы и не будет работать с заблокированными сборками Windows, обычными в корпоративной среде.

Вот очень хороший набор скринкастов Эрика Уайта, которые объясняют все волосатые детали

Извините за добавление комментариев к старому сообщению, но я думаю, что это может быть полезно. Это не мое решение, но оно было найдено там: https://github.com/python-openxml/python-docx/issues/36 Благодаря https://github.com/mustash и https://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

Для создания автоматического оглавления в Word с помощью python:

#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 

#Спасибо

@Mawg // Обновление ToC

Имел ту же проблему, чтобы обновить ToC и гуглил для него. Не мой код, но он работает:

word = win32com.client.DispatchEx("Word.Application")
doc = word.Documents.Open(input_file_name)
doc.TablesOfContents(1).Update()
doc.Close(SaveChanges=True)
word.Quit()
      def fields(self,new_doc):
    para = new_doc.add_paragraph("Table of Content")
    para.alignment = WD_ALIGN_PARAGRAPH.CENTER 
    for run in para.runs:
        run.font.name = 'Arial'
        run.font.size = Pt(14)
        run.bold = True
        run.underline = True
    paragraph = new_doc.add_paragraph()
    paragraph.paragraph_format.space_before = Inches(0)
    paragraph.paragraph_format.space_after = Inches(0)
    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."
    fldChar3 = OxmlElement('w:updateFields') 
    fldChar3.set(qn('w:val'), 'true') 
    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

это код, который автоматически генерирует оглавление.

но у меня есть сомнения, как можно создать страницу списка рисунков, содержащую все подписи к рисункам и поле переключения номера страницы.

Другие вопросы по тегам