33

我从可能包含未经处理的用户贡献内容的外部源接收 xml 字符串。

以下 xml 字符串在中给出了 ParseError cElementTree

>>> print repr(s)
'<Comment>dddddddd\x08\x08\x08\x08\x08\x08_____</Comment>'
>>> import xml.etree.cElementTree as ET
>>> ET.XML(s)

Traceback (most recent call last):
  File "<pyshell#4>", line 1, in <module>
    ET.XML(s)
  File "<string>", line 106, in XML
ParseError: not well-formed (invalid token): line 1, column 17

有没有办法让 cElementTree 不抱怨?

4

13 回答 13

34

它似乎在抱怨\x08你需要逃避它。

编辑:

或者您可以让解析器使用忽略错误recover

from lxml import etree
parser = etree.XMLParser(recover=True)
etree.fromstring(xmlstring, parser=parser)
于 2012-10-24T09:25:11.857 回答
27

我遇到了同样的错误(使用 ElementTree)。在我的情况下,这是因为编码,我能够解决它而无需使用外部库。希望这有助于其他人根据标题找到这个问题。(参考

import xml.etree.ElementTree as ET
parser = ET.XMLParser(encoding="utf-8")
tree = ET.fromstring(xmlstring, parser=parser)

编辑:根据评论,这个答案可能已经过时了。但是,当它被回答时,这确实起作用了......

于 2013-11-25T22:24:57.473 回答
7

请参阅另一个问题的答案以及 XML 规范的相应部分

退格U+0008是 XML 文档中的无效字符。它必须表示为转义的实体&#8;,并且不能简单地出现。

如果您需要处理此 XML 片段,则必须在将其输入 XML 解析器之前替换\x08in 。s

于 2012-10-24T09:35:26.873 回答
7

上述修复均不适合我。唯一有效的是使用BeautifulSoup而不是ElementTree如下:

from bs4 import BeautifulSoup

with open("data/myfile.xml") as fp:
    soup = BeautifulSoup(fp, 'xml')

然后你可以搜索树:

soup.find_all('mytag')
于 2018-05-08T10:56:24.530 回答
4

这个代码片段对我有用。我在解析一批 XML 文件时遇到问题。我不得不将它们编码为“iso-8859-5”

import xml.etree.ElementTree as ET

tree = ET.parse(filename, parser = ET.XMLParser(encoding = 'iso-8859-5'))
于 2020-02-25T19:24:18.050 回答
3

这很可能是编码错误。例如,我有一个以 UTF-8-BOM 编码的 xml 文件(从 Notepad++ 编码菜单中检查)并收到类似的错误消息。

解决方法(Python 3.6)

import io
from xml.etree import ElementTree as ET

with io.open(file, 'r', encoding='utf-8-sig') as f:
    contents = f.read()
    tree = ET.fromstring(contents)

检查 xml 文件的编码。如果它使用不同的编码,请相应地更改“utf-8-sig”。

于 2018-02-13T14:29:09.520 回答
3

使用 Python 的 ElementTree 为我提供了一个解决方案...这有无效的令牌错误:

# -*- coding: utf-8 -*-
import xml.etree.ElementTree as ET

xml = u"""<?xml version='1.0' encoding='utf8'?>
<osm generator="pycrocosm server" version="0.6"><changeset created_at="2017-09-06T19:26:50.302136+00:00" id="273" max_lat="0.0" max_lon="0.0" min_lat="0.0" min_lon="0.0" open="true" uid="345" user="john"><tag k="test" v="Съешь же ещё этих мягких французских булок да выпей чаю" /><tag k="foo" v="bar" /><discussion><comment data="2015-01-01T18:56:48Z" uid="1841" user="metaodi"><text>Did you verify those street names?</text></comment></discussion></changeset></osm>"""

xmltest = ET.fromstring(xml.encode("utf-8"))

但是,它可以在编码类型中添加连字符:

<?xml version='1.0' encoding='utf-8'?>

最奇怪的。有人在python 文档中发现了这个脚注:

XML 输出中包含的编码字符串应符合适当的标准。例如,“UTF-8”有效,但“UTF8”无效。

于 2017-09-06T19:35:48.897 回答
2

在整个 WWW 中进行了大量搜索后,我才发现如果您希望 XML 解析器正常工作,您必须转义某些字符!以下是我如何做到并为我工作的:

escape_illegal_xml_characters = lambda x: re.sub(u'[\x00-\x08\x0b\x0c\x0e-\x1F\uD800-\uDFFF\uFFFE\uFFFF]', '', x)

并像往常一样使用它:

ET.XML(escape_illegal_xml_characters(my_xml_string)) #instead of ET.XML(my_xml_string)
于 2019-12-13T09:57:01.700 回答
1

我一直陷入类似的问题。终于弄清楚了在我的特殊情况下的根本原因是什么。如果您从位于同一文件夹中的多个 XML 文件中读取数据,您还将解析 .DS_Store 文件。在解析之前添加这个条件

for file in files:
    if file.endswith('.xml'):
       run_your_code...

这个技巧也帮助了我

于 2017-06-23T19:38:21.527 回答
1

在我的情况下,lxml 解决了这个问题

from lxml import etree

for _, elein etree.iterparse(xml_file, tag='tag_i_wanted', unicode='utf-8'):
    print(ele.tag, ele.text)  

在另一种情况下,

parser = etree.XMLParser(recover=True)
tree = etree.parse(xml_file, parser=parser)
tags_needed = tree.iter('TAG NAME')

感谢东海岸西

蟒蛇 2.7

于 2019-10-24T05:49:26.527 回答
0

唯一对我有用的是我必须在打开文件时添加模式和编码,如下所示:

with open(filenames[0], mode='r',encoding='utf-8') as f:
     readFile()

否则,如果我只是这样做,每次都会失败并出现无效令牌错误:

 f = open(filenames[0], 'r')
 readFile()
于 2019-08-29T18:28:44.573 回答
0

帮助我解决这个错误的是 Juan 的回答 - https://stackoverflow.com/a/20204635/4433222 但还不够 - 经过努力,我发现需要使用 UTF-8 保存 XML 文件,而不需要 BOM 编码。

该解决方案不适用于“普通”UTF-8。

于 2016-02-05T10:20:02.003 回答
-1

我在这里的答案中尝试了其他解决方案,但没有运气。由于我只需要从单个 xml 节点中提取值,因此我放弃并编写了我的函数来执行此操作:

def ParseXmlTagContents(source, tag, tagContentsRegex):
    openTagString = "<"+tag+">"
    closeTagString = "</"+tag+">"
    found = re.search(openTagString + tagContentsRegex + closeTagString, source)
    if found:   
        start = found.regs[0][0]
        end = found.regs[0][1]
        return source[start+len(openTagString):end-len(closeTagString)]
    return ""

示例用法是:

<?xml version="1.0" encoding="utf-16"?>
<parentNode>
    <childNode>123</childNode>
</parentNode>

ParseXmlTagContents(xmlString, "childNode", "[0-9]+")
于 2018-09-06T13:36:28.190 回答