2012-05-04 7 views
14

Sto cercando di analizzare un documento XML a recuperare dal web, ma si blocca dopo l'analisi con questo errore:Errore 'riuscito a caricare un'entità esterna' quando si usa Python lxml

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

Questo è il secondo linea nell'XML che viene scaricato. C'è un modo per impedire al parser di provare a caricare l'entità esterna o un altro modo per risolverlo? Questo è il codice che ho finora:

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) 

risposta

0

Stai diventando che errore perché il codice XML che si desidera caricare riferimenti una risorsa esterna:

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

LXML non sa come risolvere GreenButtonDataStyleSheet.xslt . Probabilmente tu e io ci rendiamo conto che sarà disponibile in relazione al tuo URL originale, http://www.greenbuttondata.org/data/15MinLP_15Days.xml ... il trucco è dire a lxml come fare per caricarlo.

Il lxml documentation include una sezione intitolata "Document loading and URL resolving", che contiene quasi tutte le informazioni necessarie.

+0

Sai se è possibile disattivare il caricamento di tutte le risorse esterne? Ho cercato nella documentazione ma non ho trovato nulla. – daveeloo

+1

"* Stai ricevendo quell'errore perché l'XML che stai caricando fa riferimento a una risorsa esterna *". No. Non è questo il motivo per cui ottieni l'errore. Per favore vedi la mia risposta. – mzjn

9

etree.parse(source) aspetta source di essere uno dei

  • un nome di file/percorso
  • un oggetto file
  • un oggetto simile a file
  • un URL utilizzando il protocollo HTTP o FTP protocollo

Il problema è che si fornisce il contenuto XML come una stringa.

Si può anche fare senza urllib2.urlopen(). Basta usare

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

dimostrazione (utilizzando 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> 
>>> 

In un competing answer, si suggerisce che lxml non riesce a causa del foglio di stile a cui fa riferimento l'istruzione di elaborazione del documento . Ma questo non è il problema qui. lxml non tenta di caricare il foglio di stile e il documento XML viene analizzato bene se si fa come descritto sopra.

Se si desidera caricare effettivamente il foglio di stile, è necessario esserne espliciti. C'è bisogno di qualcosa di simile:

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() 
+0

Downvoter: per favore spiega cosa c'è di sbagliato in questa risposta. – mzjn

+0

grazie mzjn. hai ragione! upvoted. – Duke

+0

@Duke: Grazie! È bello avere finalmente un feedback positivo. – mzjn

18

In concerto con quello mzjn Detto questo, se si vuole passare una stringa a etree.parse(), basta avvolgerlo in un oggetto StringIO.

Esempio:

from lxml import etree 
from StringIO import StringIO 

myString = "<html><p>blah blah blah</p></html>" 

tree = etree.parse(StringIO(myString)) 

Questo metodo è utilizzato nel lxml documentation.

+3

Per python3: 'da io import StringIO' – Adversus

1

lxml docs per parse dice Per analizzare da una stringa, utilizzare invece la funzione 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). 
Problemi correlati