ParseError:使用cElementTree格式不正确(无效令牌)

时间:2012-10-24 09:18:52

标签: python parsing elementtree

我从外部源接收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不抱怨?

13 个答案:

答案 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文档中的无效字符。它必须表示为转义实体&#8;,并且不能明确地发生。

如果您需要处理此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'?>

最奇怪的。 Someonepython 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')

感谢theeastcoastwest

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]+")