我从外部源接收xml字符串,其中包含未经过授权的用户贡献内容。
以下xml字符串在cElementTree
中给出了ParseError:
>>> 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不抱怨?
答案 0 :(得分:23)
似乎抱怨\x08
你需要逃避它。
修改:
或者您可以让解析器使用recover
from lxml import etree
parser = etree.XMLParser(recover=True)
etree.fromstring(xmlstring, parser=parser)
答案 1 :(得分:22)
我遇到了同样的错误(使用ElementTree)。在我的情况下,这是因为编码,我能够解决它而无需使用外部库。希望这有助于其他人根据标题找到这个问题。 (reference)
import xml.etree.ElementTree as ET
parser = ET.XMLParser(encoding="utf-8")
tree = ET.fromstring(xmlstring, parser=parser)
编辑:根据评论,此答案可能已过时。但是当它被回答时,这确实起作用了......
答案 2 :(得分:6)
请参阅this answer另一个问题以及XML规范的according part。
退格U+0008是XML文档中的无效字符。它必须表示为转义实体
,并且不能明确地发生。
如果您需要处理此XML代码段,则必须先替换\x08
中的s
,然后再将其提供给XML解析器。
答案 3 :(得分:1)
我一直陷入类似的问题。最后想出了我特定情况下的根本原因。如果您从位于同一文件夹中的多个XML文件中读取数据,您还将解析.DS_Store文件。 在解析之前添加此条件
for file in files:
if file.endswith('.xml'):
run_your_code...
这个技巧也帮助了我
答案 4 :(得分:1)
使用Python的ElementTree为我提供gottcha的解决方案...这有无效的令牌错误:
# -*- 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'?>
最奇怪的。 Someone在python docs:
中找到了这个脚注XML输出中包含的编码字符串应符合 适当的标准。例如,“UTF-8”有效,但“UTF8”有效 不
答案 5 :(得分:1)
上述修复都不适合我。唯一有效的方法是使用BeautifulSoup
代替ElementTree
,如下所示:
from bs4 import BeautifulSoup
with open("data/myfile.xml") as fp:
soup = BeautifulSoup(fp, 'xml')
然后你可以搜索树:
soup.find_all('mytag')
答案 6 :(得分:1)
此代码段对我有用。我在解析一批XML文件时遇到问题。我不得不将它们编码为'iso-8859-5'
import xml.etree.ElementTree as ET
tree = ET.parse(filename, parser = ET.XMLParser(encoding = 'iso-8859-5'))
答案 7 :(得分:0)
帮助我解决这个错误的是Juan的回答 - https://stackoverflow.com/a/20204635/4433222 但还不够 - 经过努力,我发现需要使用UTF-8保存XML文件而不进行BOM编码。
该解决方案不适用于“普通”UTF-8。
答案 8 :(得分:0)
这很可能是编码错误。例如,我有一个以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”。
答案 9 :(得分:0)
对我唯一有用的是我在打开文件时必须添加模式和编码,如下所示:
with open(filenames[0], mode='r',encoding='utf-8') as f:
readFile()
否则,如果我只是这样做,每次都会因无效的令牌错误而失败:
f = open(filenames[0], 'r')
readFile()
答案 10 :(得分:0)
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')
Python 2.7
答案 11 :(得分:0)
经过整个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)
答案 12 :(得分:-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]+")