【问题标题】:Error 'failed to load external entity' when using Python lxml使用 Python lxml 时出现错误“无法加载外部实体”
【发布时间】:2012-05-14 12:19:44
【问题描述】:

我正在尝试解析从 Web 检索到的 XML 文档,但在解析后出现以下错误时崩溃:

': failed to load external entity "<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="GreenButtonDataStyleSheet.xslt"?>

这是下载的 XML 中的第二行。有没有办法阻止解析器尝试加载外部实体,或者有其他方法来解决这个问题?这是我到目前为止的代码:

import urllib2
import lxml.etree as etree

file = urllib2.urlopen("http://www.greenbuttondata.org/data/15MinLP_15Days.xml")
data = file.read()
file.close()

tree = etree.parse(data)

【问题讨论】:

    标签: python xml lxml elementtree


    【解决方案1】:

    您收到该错误是因为您正在加载的 XML 引用了外部资源:

    <?xml-stylesheet type="text/xsl" href="GreenButtonDataStyleSheet.xslt"?>
    

    LXML 不知道如何解析GreenButtonDataStyleSheet.xslt。您和我可能都意识到,相对于您的原始 URL http://www.greenbuttondata.org/data/15MinLP_15Days.xml,它是可用的...诀窍是告诉 lxml 如何加载它。

    lxml documentation 包含一个标题为“Document loading and URL resolving”的部分,其中包含您需要的所有信息。

    【讨论】:

    • 你知道是否可以关闭加载所有外部资源吗?我查看了文档,但找不到任何东西。
    • "您收到该错误是因为您正在加载的 XML 引用了外部资源"。不,这不是您收到错误的原因。请看我的回答。
    【解决方案2】:

    etree.parse(source) 期望 source 是其中之一

    • 文件名/路径
    • 一个文件对象
    • 类似文件的对象
    • 使用 HTTP 或 FTP 协议的 URL

    问题在于您将 XML 内容作为字符串提供。

    你也可以不用urllib2.urlopen()。只需使用

    tree = etree.parse("http://www.greenbuttondata.org/data/15MinLP_15Days.xml")
    

    演示(使用 lxml 2.3.4):

    >>> from lxml import etree
    >>> tree = etree.parse("http://www.greenbuttondata.org/data/15MinLP_15Days.xml")
    >>> tree.getroot()
    <Element {http://www.w3.org/2005/Atom}feed at 0xedaa08>
    >>>   
    

    在一个competing answer中,提示lxml失败是因为文档中的处理指令引用的样式表。但这不是这里的问题。 lxml 不会尝试加载样式表,如果您按照上述方式进行,则 XML 文档会被解析得很好。

    如果您想实际加载样式表,则必须明确说明。需要这样的东西:

    from lxml import etree
    
    tree = etree.parse("http://www.greenbuttondata.org/data/15MinLP_15Days.xml")
    
    # Create an _XSLTProcessingInstruction object
    pi = tree.xpath("//processing-instruction()")[0] 
    
    # Parse the stylesheet and return an ElementTree
    xsl = pi.parseXSL()   
    

    【讨论】:

    • @Duke:谢谢!很高兴终于得到了一些积极的反馈。
    • 我在解析 URL 时遇到此错误。知道如何禁用加载那些“外部实体”吗?我对样式表不感兴趣,只想解析页面中的锚点。
    • @MightyPork:这个问题并不是关于“外部实体”;错误信息具有误导性。这里的问题是 OP 在字符串对象上使用etree.parse(),这是行不通的。如果您有相关问题,我认为您应该提出一个新问题。
    • @mzjn 我确实问过,但我得到的所有建议都是使用不同的库来获取 url。我认为您对问题有更深入的了解并且可以提供帮助。
    • 在我的例子中,我得到了错误,因为我试图用解析打开一个 https url。
    【解决方案3】:

    与 mzjn 所说的一致,如果您确实想将字符串传递给 etree.parse(),只需将其包装在 StringIO 对象中即可。

    例子:

    from lxml import etree
    from StringIO import StringIO
    
    myString = "<html><p>blah blah blah</p></html>"
    
    tree = etree.parse(StringIO(myString))
    

    此方法用于lxml documentation。

    【讨论】:

    • 对于python3:from io import StringIO
    【解决方案4】:

    用于解析的 lxml 文档说 要从字符串解析,请改用 fromstring() 函数。

    parse(...)
        parse(source, parser=None, base_url=None)
    
        Return an ElementTree object loaded with source elements.  If no parser
        is provided as second argument, the default parser is used.
    
        The ``source`` can be any of the following:
    
        - a file name/path
        - a file object
        - a file-like object
        - a URL using the HTTP or FTP protocol
    
        To parse from a string, use the ``fromstring()`` function instead.
    
        Note that it is generally faster to parse from a file path or URL
        than from an open file object or file-like object.  Transparent
        decompression from gzip compressed sources is supported (unless
        explicitly disabled in libxml2).
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-19
      • 2013-08-10
      相关资源
      最近更新 更多