【问题标题】:Python: Unicode and ElementTree.parsePython:Unicode 和 ElementTree.parse
【发布时间】:2011-03-25 23:59:04
【问题描述】:

我正在尝试迁移到 Python 2.7,由于 Unicode 在那里很重要,我会尝试使用 XML 文件和文本处理它们,并使用 xml.etree.cElementTree 库解析它们。但是我遇到了这个错误:

>>> import xml.etree.cElementTree as ET
>>> from io import StringIO
>>> source = """\
... <?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
... <root>
...   <Parent>
...     <Child>
...       <Element>Text</Element>
...     </Child>
...   </Parent>
... </root>
... """
>>> srcbuf = StringIO(source.decode('utf-8'))
>>> doc = ET.parse(srcbuf)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 56, in parse
  File "<string>", line 35, in parse
cElementTree.ParseError: no element found: line 1, column 0

使用io.open('filename.xml', encoding='utf-8') 传递给ET.parse 也会发生同样的事情:

>>> with io.open('test.xml', mode='w', encoding='utf-8') as fp:
...     fp.write(source.decode('utf-8'))
...
150L
>>> with io.open('test.xml', mode='r', encoding='utf-8') as fp:
...     fp.read()
...
u'<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>\n<root>\n  <Parent>\n
    <Child>\n      <Element>Text</Element>\n    </Child>\n  </Parent>\n</root>\n
'
>>> with io.open('test.xml', mode='r', encoding='utf-8') as fp:
...     ET.parse(fp)
...
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "<string>", line 56, in parse
  File "<string>", line 35, in parse
cElementTree.ParseError: no element found: line 1, column 0

我在这里缺少关于 unicode 和 ET 解析的内容吗?

edit:显然,ET 解析器不能很好地处理 unicode 输入流?以下作品:

>>> with io.open('test.xml', mode='rb') as fp:
...     ET.parse(fp)
...
<ElementTree object at 0x0180BC10>

但这也意味着如果我想解析内存中的文本,我不能使用io.StringIO,除非我先将它编码到内存缓冲区中?

【问题讨论】:

    标签: python xml unicode python-3.x


    【解决方案1】:

    您的问题是您提供 ElementTree unicode,但它更喜欢消耗字节。在任何情况下,它都会为您提供 unicode。

    在 Python 2.x 中,它只能消耗字节。你可以告诉它这些字节的编码是什么,但就是这样。因此,如果您确实必须使用表示 文本文件 的对象,例如 io.StringIO,首先您需要将其转换为其他内容。

    如果您从字面上开始以 UTF-8 编码的 2.x-str (AKA bytes) 开头,那么在内存中,如您的示例所示,使用 xml.etree.cElementTree.XML 一举将其解析为 XML不要担心这些:-)。

    如果您想要一个可以处理从文件中增量读取的数据的接口,请使用 xml.etree.cElementTree.parseio.BytesIO 将其转换为内存中的字节流,而不是内存中的字符串。如果您想使用io.open,请将其与b 标志一起使用,以便获得字节流。

    在 Python 3.x 中,您可以将 unicode 直接传递给 ElementTree,这更方便一些,并且可以说,新版本的 ElementTree 更正确地允许这样做。但是,您可能仍然不想这样做,Python 3 的版本仍然接受字节作为输入。无论如何,您总是从字节开始:通过将它们直接从输入源传递到 ElementTree,您可以让它在 XML 解析引擎内智能地进行编码或解码,以及对编码声明进行动态检测在输入流中,您可以使用 XML,但不能使用任意文本数据。因此,让 XML 解析器完成解码工作是承担该责任的正确位置。

    【讨论】:

      【解决方案2】:

      我在 Python 2.6 中遇到了和你一样的问题。

      Python 2.x 和 3.x 版本中 cElementTree.parse 的“utf-8”编码似乎不同。在 Python 2.x 中,我们可以使用 XMLParser 对 unicode 进行编码。例如:

      import xml.etree.cElementTree as etree
      
      parser = etree.XMLParser(encoding="utf-8")
      targetTree = etree.parse( "./targetPageID.xml", parser=parser )
      pageIds = targetTree.find("categorymembers")
      print "pageIds:",etree.tostring(pageIds)
      

      XMLParser方法可以参考这个页面(“XMLParser”部分):http://effbot.org/zone/elementtree-13-intro.htm

      虽然以下方法适用于 Python 3.x 版本:

      import xml.etree.cElementTree as etree
      import codecs
      
      target_file = codecs.open("./targetPageID.xml",mode='r',encoding='utf-8')
      
      targetTree = etree.parse( target_file )
      pageIds = targetTree.find("categorymembers")
      print "pageIds:",etree.tostring(pageIds)
      

      希望对你有帮助。

      【讨论】:

      • 这有点对,但是 Python 2 和 Python 3 之间的 ElementTree 版本比你认为的更相似。我想我会写一个不同的答案。
      【解决方案3】:

      你不能用吗

      doc = ET.fromstring(source)
      

      在你的第一个例子中?

      【讨论】:

      • 我没有意识到这个功能的存在。小问题:fromstring 返回 Element,而 parse 返回 ElementTree
      • 这个函数也被称为它的别名,XML,即from xml.etree.cElementTree import XML。如果您的代码中有一个 XML 常量,这个别名就可以很好地阅读;你可以做fooDocument = XML(""" ... """)
      • xml.etree.cElementTree 模块自 python 3.3 起已弃用。见docs.python.org/3/library/xml.etree.elementtree.html
      猜你喜欢
      • 2017-12-05
      • 1970-01-01
      • 2017-11-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-23
      • 1970-01-01
      • 2013-12-13
      相关资源
      最近更新 更多