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 состоит из двух частей:
- элемент, который определяет размещение ToC и такие вещи, как уровни заголовков для включения.
- фактический видимый контент ToC, заголовки и номера страниц с пунктирными линиями, соединяющими их.
Создать элемент довольно просто и сравнительно легко. Создание фактического видимого содержимого, по крайней мере, если вы хотите, чтобы номера страниц были включены, требует механизма компоновки Word.
Это варианты:
Просто добавьте тег и несколько других битов, чтобы сообщить Word о необходимости обновления ToC. Когда документ открывается впервые, появляется диалоговое окно с сообщением о необходимости обновления ссылок. Пользователь нажимает Да, и Боб твой дядя. Если пользователь нажимает Нет, заголовок ToC появляется без содержимого под ним, и ToC можно обновить вручную.
Добавьте тег, а затем подключите клиент Word с помощью C# или Visual Basic к библиотеке Word Automation, чтобы открыть и сохранить файл; все поля (включая поле ToC) обновляются.
Сделайте то же самое на стороне сервера, если у вас есть экземпляр SharePoint или что-то еще, что может сделать это с Word Automation Services.
Создайте макрос 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
это код, который автоматически генерирует оглавление.
но у меня есть сомнения, как можно создать страницу списка рисунков, содержащую все подписи к рисункам и поле переключения номера страницы.