在过去的几天里,我一直在尝试创建一个脚本,该脚本将1)从Word文档中提取XML,2)修改该XML,以及3)使用新的XML来创建和保存新的Word文档。在许多stackoverflow用户的帮助下,我最终能够找到看起来很有前途的代码。这是:
import zipfile
import os
import tempfile
import shutil
def getXml(docxFilename):
zip = zipfile.ZipFile(open(docxFilename,"rb"))
xmlString= zip.read("word/document.xml").decode("utf-8")
return xmlString
def createNewDocx(originalDocx,xmlString,newFilename):
tmpDir = tempfile.mkdtemp()
zip = zipfile.ZipFile(open(originalDocx,"rb"))
zip.extractall(tmpDir)
with open(os.path.join(tmpDir,"word/document.xml"),"w") as f:
f.write(xmlString)
filenames = zip.namelist()
zipCopyFilename = newFilename
with zipfile.ZipFile(zipCopyFilename,"w") as docx:
for filename in filenames:
docx.write(os.path.join(tmpDir,filename),filename)
shutil.rmtree(tmpDir)
getXml
从docxFilename
中提取XML作为字符串。 createNewDocx
获取原始Word文档,并使用xmlString
替换其XML,newFilename
是原始XML的修改版本,并将生成的Word文档保存为createNewDocx("test.docx",getXml("test.docx"),"test2.docx")
。
要检查脚本是否按预期工作,我首先创建了一个测试文档(" test.docx")并运行template.docx
。如果一切按预期工作,则应该创建保存为test2.docx的test.docx的相同副本。的确,情况确实如此。
然后,我使测试文档更加精细,并进行了修改实验。脚本仍然有效!
然后我自信地将我的脚本应用于我真正感兴趣修改的Word文档:createNewDocx("template.docx",getXml("template.docx"),"template2.docx")
。我运行{{1}},期望该脚本生成一个相同的template.docx副本,但名为template2.docx。不幸的是,新的Word文档无法打开;显然XML中存在非法字符。
我真的不明白为什么我的代码适用于我的测试文档但不适用于我的实际文档。我会发布template.docx的XML,但它包含个人信息。 test.docx和template.docx之间的一个重要区别是template.docx是用法语编写的,因此包含特殊字符(如重音符号),并且撇号看起来也不同。我不知道这是不是造成我的麻烦,但我没有其他想法。
答案 0 :(得分:2)
问题在于您无意中更改了word/document.xml
中template2.docx
的编码。 word/document.xml
(来自template.docx
)最初编码为UTF-8(这是XML文档的默认编码)。
xmlString = zip.read("word/document.xml").decode("utf-8")
但是,当您为template2.docx
复制时,您正在将编码更改为 CP-1252 。根据{{3}}的文档,
在文本模式下,如果未指定编码,则使用的编码与平台相关:调用locale.getpreferredencoding(False)以获取当前的语言环境编码。
您表示调用locale.getpreferredencoding(False)
会为您cp1252
提供正在编写的编码word/document.xml
。
由于您没有明确地将<?xml version="1.0" encoding="cp1252"?>
添加到word/document.xml
的开头,因此Word(或任何其他XML阅读器)会将其读作 UTF-8 而不是 CP-1252 这就是为您提供非法的XML字符错误。
因此,您希望在使用encoding
参数open()
进行书写时将编码指定为 UTF-8 :
with open(os.path.join(tmpDir, "word/document.xml"), "w", encoding="UTF-8") as f:
f.write(xmlString)