首页 > 解决方案 > 如何添加 w:altChunk 及其与 python-docx 的关系

问题描述

我有一个用例,它<w:altChunk/>通过将 HTML 文件注入(片段)作为备用块来使用 Word 文档中的元素,并在文件打开时让 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)

更新:

根据scanny的建议,以下是我的工作代码。非常感谢史蒂夫!

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 打开文档时工作/出现

标签: python-docx

解决方案


好吧,无论如何这里有一些提示。也许您可以在最后发布您的工作代码作为完整的“答案”:

  1. alt-chunk 部分需要作为一个docx.opc.part.Part对象开始它的生命。

    参数应该是文件的blob字节,通常但不总是纯文本。它必须是字节,而不是 unicode(字符),所以任何编码都必须在调用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具有 altChunk 的 .docx 文件中的部分以查看它们使用的内容。
  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.

推荐阅读