2012-09-29 26 views
8

Supongamos que tenemos el archivo XML con la estructura de la siguiente manera.Analizar xml con lxml - extraer el valor del elemento

<?xml version="1.0" ?> 
<searchRetrieveResponse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.loc.gov/zing/srw/ http://www.loc.gov/standards/sru/sru1-1archive/xml-files/srw-types.xsd" xmlns="http://www.loc.gov/zing/srw/"> 
    <records xmlns:ns1="http://www.loc.gov/zing/srw/"> 
    <record> 
     <recordData> 
     <record xmlns=""> 
      <datafield tag="000"> 
      <subfield code="a">123</subfield> 
      <subfield code="b">456</subfield> 
      </datafield> 
      <datafield tag="001"> 
      <subfield code="a">789</subfield> 
      <subfield code="b">987</subfield> 
      </datafield> 
     </record> 
     </recordData> 
    </record> 
    <record> 
     <recordData> 
     <record xmlns=""> 
      <datafield tag="000"> 
      <subfield code="a">123</subfield> 
      <subfield code="b">456</subfield> 
      </datafield> 
      <datafield tag="001"> 
      <subfield code="a">789</subfield> 
      <subfield code="b">987</subfield> 
      </datafield> 
     </record> 
     </recordData> 
    </record> 
    </records> 
</searchRetrieveResponse> 

necesito para analizar a cabo:

  • El contenido de la "subcampo" (por ejemplo, 123 en el ejemplo anterior) y
  • valores de atributo (por ejemplo, 000 o 001)

Me pregunto cómo hacerlo usando lxml y XPath. Pegado a continuación está mi código inicial y amablemente le pido a alguien que me explique, cómo analizar los valores.

import urllib, urllib2 
from lxml import etree  

url = "https://dl.dropbox.com/u/540963/short_test.xml" 
fp = urllib2.urlopen(url) 
doc = etree.parse(fp) 
fp.close() 

ns = {'xsi':'http://www.loc.gov/zing/srw/'} 

for record in doc.xpath('//xsi:record', namespaces=ns): 
    print record.xpath("xsi:recordData/record/datafield[@tag='000']", namespaces=ns) 
+0

Está utilizando el prefijo 'xsi' para el espacio de nombres' http : // www.loc.gov/zing/srw/'- esto es válido, pero usualmente' xsi' se usa como un prefijo para el espacio de nombres estándar 'http: // www.w3.org/2001/XMLSchema-instance' . – MiMo

Respuesta

16

que habría más directa en su XPath: ir directamente a los elementos que desea, en este caso datafield.

>>> for df in doc.xpath('//datafield'): 
     # Iterate over attributes of datafield 
     for attrib_name in df.attrib: 
       print '@' + attrib_name + '=' + df.attrib[attrib_name] 

     # subfield is a child of datafield, and iterate 
     subfields = df.getchildren() 
     for subfield in subfields: 
       print 'subfield=' + subfield.text 

Además, parece que lxml le permite ignorar el espacio de nombres, ¿tal vez porque su ejemplo solo usa un espacio de nombres?

+0

Sí, tengo solo un espacio de nombre. – Andrej

6

Prueba el siguiente código de trabajo:

import urllib2 
from lxml import etree 

url = "https://dl.dropbox.com/u/540963/short_test.xml" 
fp = urllib2.urlopen(url) 
doc = etree.parse(fp) 
fp.close() 

for record in doc.xpath('//datafield'): 
    print record.xpath("./@tag")[0] 
    for x in record.xpath("./subfield/text()"): 
     print "\t", x 
+0

POST editado para mostrar solo datos y no listas. –

5

sólo iría con

for df in doc.xpath('//datafield'): 
    print df.attrib 
    for sf in df.getchildren(): 
     print sf.text 

también que no es necesario urllib, puede analizar directamente con XML HTTP

url = "http://dl.dropbox.com/u/540963/short_test.xml" #doesn't work with https though 
doc = etree.parse(url) 
Cuestiones relacionadas