如何添加w:altChunk及其与python-docx的关系
How to add w:altChunk and its relationship with python-docx
我有一个用例,它通过将 HTML 文件的(片段)作为备用块来使用 Word 文档中的 <w:altChunk/>
元素,并让 Word 在文件打开时执行此操作。当前的实现是使用 XML/XSL 编写 WordML XML、修改关系并手动完成所有打包工作,这真的很痛苦。
我想移动到 python-docx,但 API 不直接支持它。目前我找到了在文档 XML 中添加 <w:altChunk/>
的方法。但是仍然很难找到一种方法来将关系和相关文件添加到包中。
我想我应该制作一个兼容的部分并将其传递给 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')
注意:仅当使用 MS Word 打开文档时,altChunk 部分 work/appear
好吧,这里有一些提示。也许你可以 post 你的工作代码作为一个完整的 "answer":
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
中的一种。检查具有 altChunk 的 .docx 文件中的 [Content_Types].xml
部分以查看它们使用的内容。
一旦形成,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.
我有一个用例,它通过将 HTML 文件的(片段)作为备用块来使用 Word 文档中的 <w:altChunk/>
元素,并让 Word 在文件打开时执行此操作。当前的实现是使用 XML/XSL 编写 WordML XML、修改关系并手动完成所有打包工作,这真的很痛苦。
我想移动到 python-docx,但 API 不直接支持它。目前我找到了在文档 XML 中添加 <w:altChunk/>
的方法。但是仍然很难找到一种方法来将关系和相关文件添加到包中。
我想我应该制作一个兼容的部分并将其传递给 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')
注意:仅当使用 MS Word 打开文档时,altChunk 部分 work/appear
好吧,这里有一些提示。也许你可以 post 你的工作代码作为一个完整的 "answer":
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
中的一种。检查具有 altChunk 的 .docx 文件中的[Content_Types].xml
部分以查看它们使用的内容。
一旦形成,
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.