【问题标题】:Problems extracting the XML from a Word document in French with Python: illegal characters generated使用 Python 从法语 Word 文档中提取 XML 的问题:生成的非法字符
【发布时间】:2016-10-31 22:11:29
【问题描述】:

在过去的几天里,我一直在尝试创建一个脚本,该脚本将 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)

getXmldocxFilename 中提取 XML 作为字符串。 createNewDocx 获取原始 Word 文档并将其 XML 替换为 xmlString,这是原始 XML 的修改版本,并将生成的 Word 文档保存为 newFilename

为了检查脚本是否按预期工作,我首先创建了一个测试文档(“test.docx”)并运行createNewDocx("test.docx",getXml("test.docx"),"test2.docx")。如果一切都按预期工作,这应该创建一个相同的 test.docx 副本,另存为 test2.docx。确实如此。

然后我使测试文档更加详细,并尝试修改它。而且脚本仍然有效!

然后我自信地将我的脚本应用到我真正有兴趣修改的 Word 文档:template.docx。我运行createNewDocx("template.docx",getXml("template.docx"),"template2.docx"),期望脚本会生成一个相同的template.docx 副本,但命名为template2.docx。不幸的是,新的 Word 文档无法打开;显然 XML 中有一个非法字符。

我真的不明白为什么我的代码适用于我的测试文档而不适用于我的实际文档。我会发布 template.docx 的 XML,但它包含个人信息。 test.docx 和 template.docx 之间的一个重要区别是 template.docx 是用法语编写的,因此包含重音等特殊字符,而且撇号看起来也不同。我不知道这是否是造成我麻烦的原因,但我没有其他想法。

【问题讨论】:

  • 打开 template2.docx 时遇到的实际错误是什么?
  • 非法 xml 字符。位置:部分:/word/document.xml,行:3,列:921
  • 你能在word/document.xmltemplate.docxtemplate2.docx 中加入第3 行吗?
  • 我仍然怀疑这是一个编码问题。 import locale; print(locale.getpreferredencoding(False)) 带给你什么?
  • @cpburnz 运行您建议的代码会得到 cp1252。如何找到 word/document.xml 的第三行?如果我将getXml("template.docx") 复制/粘贴到文本文件中,该文件的第三行是否与xml 文件的第三行相同?

标签: python xml character-encoding docx


【解决方案1】:

问题是您不小心更改了word/document.xmltemplate2.docx 的编码。 word/document.xml(来自 template.docx)最初被编码为 UTF-8(这是 XML 文档的默认编码)。

xmlString = zip.read("word/document.xml").decode("utf-8")

但是,当您为template2.docx 复制它时,您将编码更改为CP-1252。根据open(file, "w") 的文档,

在文本模式下,如果未指定编码,则使用的编码取决于平台:调用 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)

【讨论】:

  • 谢谢。有没有办法将编码更改为 UTF-8?我想我应该做类似open(file, "w", encoding="utf-8).
  • @AlessandroPower 就是这样。我将其添加到我的答案中。
  • 感谢您的好回答。就我而言,我阅读了 docx-xml 并对其进行了修改,因此我也必须将编码添加到 read-file-open 中:with open(text_xml, encoding="utf-8") as text
猜你喜欢
  • 2015-02-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多