Как добавить w: altChunk и его связь с python-docx - PullRequest
0 голосов
/ 07 марта 2019

У меня есть сценарий использования, который использует элемент <w:altChunk/> в документе Word путем внедрения (фрагмента) HTML-файла в качестве альтернативных фрагментов и позволяет Word сделать это, когда файл открывается. Текущая реализация использовала XML / XSL для составления WordML XML, изменения отношений и выполнения всех операций по упаковке вручную, что является настоящей болью.

Я хотел перейти на python-docx, но API не поддерживает это напрямую. В настоящее время я нашел способ добавить <w:altChunk/> в документ XML. Но все еще трудно найти способ добавить отношения и связанный файл в пакет.

Я думаю, что должен создать совместимую деталь и передать ее функции document.part.relate_to для выполнения своей работы. Но все еще не могу понять, как:

from docx import Document
from docx.oxml import OxmlElement, qn
from docx.opc.constants import RELATIONSHIP_TYPE as RT

def add_alt_chunk(doc: Document, chunk_part):
    ''' TODO: figuring how to add files and relationships'''
    r_id = doc.part.relate_to(chunk_part, RT.A_F_CHUNK)
    alt = OxmlElement('w:altChunk')
    alt.set(qn('r:id'), r_id)
    doc.element.body.sectPr.addprevious(alt)

Обновление:

Согласно совету Скани, ниже приведен мой рабочий код. Большое спасибо, Стив!

from docx import Document
from docx.oxml import OxmlElement
from docx.oxml.ns import qn
from docx.opc.part import Part
from docx.opc.constants import RELATIONSHIP_TYPE as RT


def add_alt_chunk(doc: Document, html: str):
    package = doc.part.package
    partname = package.next_partname('/word/altChunk%d.html')
    alt_part = Part(partname, 'text/html', html.encode(), package)
    r_id = doc.part.relate_to(alt_part, RT.A_F_CHUNK)
    alt_chunk = OxmlElement('w:altChunk')
    alt_chunk.set(qn('r:id'), r_id)
    doc.element.body.sectPr.addprevious(alt_chunk)


doc = Document()
doc.add_paragraph('Hello')
add_alt_chunk(doc, "<body><strong>I'm an altChunk</strong></body>")
doc.add_paragraph('Have a nice day!')
doc.save('test.docx')

Примечание : части altChunk работают / появляются только когда документ открыт с использованием MS Word

1 Ответ

1 голос
/ 07 марта 2019

Ну, некоторые подсказки здесь все равно.Возможно, вы можете опубликовать свой рабочий код в конце как полный «ответ»:

  1. Часть alt-chunk должна начать свою жизнь как docx.opc.part.Part объект.

    Аргумент blob должен быть байтами файла, который часто, но не всегда, представляет собой простой текст.Это должны быть байты, а не юникод (символы), поэтому любая кодировка должна выполняться перед вызовом Part().

    Я предполагаю, что вы можете использовать другие аргументы:

    • package - это общий пакет OPC, доступный в document.part.package.
    • . Вы можете использовать docx.opc.package.OpcPackage.next_partname() для получения доступного имени детали на основе корневого шаблона, такого как: "altChunk% s" для имени, такого как "altChunk3",Проверьте, какой префикс имени файла Word использует для них, возможно, с помощью unzip -l has-an-alt-chunk.docx;должно быть легко обнаружить.
    • Тип содержимого - один в docx.opc.constants.CONTENT_TYPE.Проверьте часть [Content_Types].xml в файле .docx, в котором есть altChunk, чтобы увидеть, что они используют.
  2. После формирования метод document_part.relate_to() создаст правильные отношения.Если существует более одного отношения (не часто), то вам нужно создать каждое отдельно.От конкретной части будет только одно отношение, только некоторые части связаны с несколькими другими частями.Проверьте отношения в существующем .docx, чтобы увидеть, но довольно неплохо догадаться, что в данном случае это только одно.

Таким образом, ваш код будет выглядеть примерно так:

package = document.part.package
partname = package.next_partname("altChunkySomethingPrefix")
content_type = docx.opc.constants.CONTENT_TYPE.THE_RIGHT_MIME_TYPE
blob = make_the_altChunk_file_bytes()

alt_chunk_part = Part(partname, content_type, blob, package)

rId = document.part.relate_to(alt_chunk_part, RT.A_F_CHUNK)
etc.
...