基于Expat的XML解析脚本在Linux上不工作,Windows上正常

1 投票
2 回答
5153 浏览
提问于 2025-04-16 12:15

我正在用Python写一套工具,从一些由交通模拟软件生成的XML文件中提取数据。因为生成的文件可能会很大,所以我使用了xml.parsers.expat来解析这些文件。

问题是,当我在工作时的Windows XP机器上运行我的脚本时,一切都很顺利,但在家里的Ubuntu 10.10上,处理同一个文件时却出现了以下错误:
ExpatError: not well-formed (invalid token): line 1, column 0

这个文件最初是用utf-8编码的,但在标签中声明的编码是ascii,所以我尝试把它改成utf-8(或者UTF8或utf8),但都没有成功。因为文件没有BOM(字节顺序标记),我尝试添加它,但还是不行。我还尝试把Windows的换行符(CR/LF)替换成Unix的换行符(CR),但也没有成功。

另外,我工作时用的Python版本是2.7.1,而我在Ubuntu上用的是2.6.6,但我觉得这和我的问题没有关系:几周前我把工作电脑上的Python从2.6升级到2.7时没有遇到任何问题。

因为我不是专家,现在快想不出办法了,有什么建议吗?

编辑:
经过进一步调查(现在我头疼,真讨厌与Unicode相关的问题),看起来问题是通过正确设置系统环境变量LANG、LC_ALL和LANGUAGE解决的(在我这个情况下是“fr_FR.utf-8”)。我不明白为什么一开始它们没有设置好,也不明白为什么现在就能工作了……

谢谢大家的帮助!

2 个回答

3

我也遇到过同样的问题。与其直接像这样解析文件:

document = xmltodict.parse("myfile.xml") # Parse the read document string

我选择先通过一个对象打开这个xml文档,然后再进行解析,像这样:

document_file = open("myfile.xml", "r") # Open a file in read-only mode
original_doc = document_file.read() # read the file object
document = xmltodict.parse(original_doc) # Parse the read document string

这样做就成功了。

3

以下是文档中的一些摘录:

xml.parsers.expat.XML_ERROR_INVALID_TOKEN
当输入的字节无法正确对应到一个字符时,就会出现这个错误;比如在UTF-8输入流中出现了一个NUL字节(值为0)。

ExpatError.lineno
错误被发现的行号。第一行的编号是1。

ExpatError.offset
错误发生在该行的字符偏移量。第一列的编号是0。

以上信息通常表明你的文件的第一个字节有问题。

从原始文件开始,也就是那个在Windows上能正常工作的文件。请编辑你的问题,展示一下这样做的结果:

python -c "print repr(open('win_ok_file.xml', 'rb').read(200))"

这将清楚地显示你文件中前200个字节的内容。

另外,请给我们看一个简化版的代码,确保它在Windows上能正常工作并且能绕过最初的错误,但在Linux上会重现问题。

一些声明,供你参考:

  • “文件最初是用utf-8编码的,但在标签中声明的编码是ascii”... 如果XML声明中的编码是“ascii”,但文件中有非ASCII字符,合规的解析器应该会抛出异常。你确定你报告的信息是正确的吗?

  • XML文档的默认编码是UTF-8。换句话说,如果在XML声明中没有提到编码,或者根本没有XML声明,解析器就必须使用UTF-8进行解码。

  • 在开头放一个UTF-8 BOM(字节顺序标记)更可能会造成麻烦,而不是帮助。

  • XML标准要求解析器接受CR作为XML文档中的有效字节,然后立即假装它不存在(除了在有xmlns:space="preserve"的元素中)。将CR LF改为LF并不是个好主意。

还有一些问题:一个“相当大的”文件有多少字节?你考虑过使用iterparse()来自xml.etree.cElementTreelxml吗?

撰写回答