【问题标题】:Is there a way to force lxml to parse Unicode strings that specify an encoding in a tag?有没有办法强制 lxml 解析在标签中指定编码的 Unicode 字符串?
【发布时间】:2010-08-04 04:13:10
【问题描述】:

我有一个指定编码的 XML 文件,我使用 UnicodeDammit 将其转换为 unicode(出于存储原因,我不能将其存储为字符串)。我后来将它传递给 lxml 但它拒绝忽略文件中指定的编码并将其解析为 Unicode,并引发异常。

如何强制 lxml 解析文档?这种行为似乎过于严格。

【问题讨论】:

    标签: python lxml


    【解决方案1】:

    您不能从 unicode 字符串解析并且在字符串中有编码声明。 所以,要么你把它变成一个编码字符串(因为你显然不能将它存储为一个字符串,你必须在解析之前重新编码它。或者你自己用 lxml 将树序列化为 unicode:etree.tostring(tree, encoding=unicode),没有 xml声明。你可以很容易地用 etree.fromunicode 再次解析结果

    http://lxml.de/parsing.html#python-unicode-strings

    编辑:显然,如果您已经拥有 unicode 字符串,并且无法控制它是如何制作的。您必须再次对其进行编码,并向解析器提供您使用的编码:

    utf8_parser = etree.XMLParser(encoding='utf-8')
    
    def parse_from_unicode(unicode_str):
        s = unicode_str.encode('utf-8')
        return etree.fromstring(s, parser=utf8_parser)
    

    这将确保忽略 xml 声明中的任何内容,因为解析器将始终使用 utf-8。

    【讨论】:

    • 整个问题是我一开始就无法得到一棵树,如果可以的话,我不会有任何问题......
    • @Stavros Korokithakis,etree 是模块,而不是解析后的树。
    • @Daniel Kluev:是的,但是“树”是一棵树。
    • @Steven:关于您的编辑,应该可以,谢谢。最后,我从 lxml 中获取了编码检测正则表达式,并用它从文件中剥离了编码。既然失败早,我觉得应该是最快的。
    • 这个解决方案是错误的。不要盲目编码为 utf8。文档中的编码声明很可能是 utf16 或其他。解决方案是去掉不再需要的编码声明——你手头已经有了一个 unicode 字符串!
    【解决方案2】:

    基本上,解决办法是:

    if isinstance(mystring, unicode):
        mystring = mystring.encode("utf-8")
    

    说真的。干得好,lxml。

    编辑:事实证明,在这种情况下,lxml 自动检测编码不正确。看来我将不得不从页面中手动搜索并删除“charset”和“encoding”。

    【讨论】:

      【解决方案3】:

      解决方案不是重新编码字符串。字符串中的编码声明可以表示 UTF8 以外的内容。不要盲目地重新编码为 utf8 并期望它能一直工作。

      解决方案是去掉编码声明。你手头已经有一个 unicode 字符串,不再需要它了!

      # this is from lxml/apihelpers.pxi
      RE_XML_ENCODING = re.compile(
          ur'^(<\?xml[^>]+)\s+encoding\s*=\s*["\'][^"\']*["\'](\s*\?>|)', re.U)
      
      RE_XML_ENCODING.sub("", broken_xml_string, count=1)
      

      这里最坏的情况(没有找到 xml 编码声明)时间复杂度是 O(n),这非常糟糕(但仍然比盲目编码为二进制更好),所以我愿意接受这里的建议。

      PS:xml编码问题的一些有趣分析:

      default encoding for XML is UTF-8 or UTF-16?

      How default is the default encoding (UTF-8) in the XML Declaration?

      【讨论】:

      • 如果你给像 + 和 * 这样的匹配运算符一个限制,用 {,100} 替换它们,长字符串的最坏情况复杂度远小于 O(整个字符串长度)。然而,遇到最坏情况的几率确实很小!
      【解决方案4】:

      我有一个现有的实现,我需要树。 我也有一个 nbsp;元标记中的问题。将 resolve_entities 设置为 false 可以解决该问题。

          opener = urllib.request.build_opener()
          response = opener.open(url['url'])
          raw_page = response.read()
          response.close()
          parsed_page = raw_page.replace(b'encoding="UTF-8"',b'')
          parsed_page = StringIO(parsed_page.decode('ASCII'))
          parser = ET.XMLParser(resolve_entities = False, encoding="ASCII")
          tree = ET.parse(parsed_page, parser)
          root = tree.getroot()
      

      【讨论】:

        猜你喜欢
        • 2023-02-07
        • 2011-06-27
        • 1970-01-01
        • 2023-04-02
        • 2021-12-03
        • 2023-04-01
        • 1970-01-01
        • 1970-01-01
        • 2021-04-29
        相关资源
        最近更新 更多