2011-03-22 26 views
12

Necesito comprobar si existe cierta etiqueta en un archivo xml.Python Lxml (objectify): Comprobando si existe una etiqueta

Por ejemplo, quiero ver si existe la etiqueta en este fragmento:

<main> 
     <elem1/> 
     <elem2>Hi</elem2> 
     <elem3/> 
     ... 
</main> 

Actualmente, estoy usando un truco feo, con la comprobación de errores, así:

try: 
    if root.elem1.tag: 
     foo = elem1 
except AttributeError: 
    foo = "error finding elem1" 

también desea personalizar la cadena si no puede encontrar el nodo (es decir, "no se puede encontrar -tagname-").

Tengo que verificar una larga lista de variables, y no quiero repetir el código 100 veces.

¿Alguna sugerencia?

Editar:

Aquí está un recorte del archivo XML real:

<main> 
<asset name="Virtual Dvaered Unpresence"> 
    <virtual/> 
    <presence> 
    <faction>Dvaered</faction> 
    <value>-1000.000000</value> 
    <range>0</range> 
    </presence> 
</asset> 
<asset name="Virtual Empire Small"> 
    <virtual/> 
    <presence> 
    <faction>Empire</faction> 
    <value>100.000000</value> 
    <range>2</range> 
    </presence> 
</asset> 
</main> 

Quiero comprobar si existe o no la etiqueta, y si es así, para obtener el contenido.

Editar edición: Bien, voy a combinar dos de las respuestas, pero solo puedo votar por una. Lo siento.

Datos 3: pregunta sobre XPath aquí: Python lxml (objectify): Xpath troubles

Respuesta

5

supuesto de que desea obtener el valor de elem2, puede utilizar XPath para encontrarlo.

tree = etree.parse(StringIO(htmlString), etree.HTMLParser()).getroot() 
youWantValue = tree.xpath('/main/elem2')[0].text 
+0

¿Qué pasa si el nodo no existe? ¿Da un error, o simplemente un valor en blanco? – Biosci3c

+0

@ Biosci3c ese ejemplo específico da un error, debido al '[0]' tratando de eliminar la referencia del primer valor devuelto por la llamada 'xpath'. Si comprobó si la lista estaba vacía antes de eliminar la referencia, por el contrario, tendría una prueba sin error. Con esa corrección hecho, por cierto, creo que esta es la respuesta de mejores prácticas entre las dadas. –

+0

Ok, me gusta la sugerencia de XPATH, así que la usaré también. Por cierto, creo que te falta un paréntesis de cierre al final de la parte superior línea – Biosci3c

1

Si el documento tiende a ser relativamente corto se puede iterar sobre todos los hijos de <main> buscar etiquetas que coincidan con su conjunto de nombres de variables:

tree = lxml.etree.fromstring(DATA) 
NAMES = set(['elem1', 'elem3']) 
for node in tree.iterchildren(): 
    if node.tag in NAMES: 
     print 'found', node.tag 

O puede buscar el nombre de cada variable de uno a la vez:

for tag in ('elem1', 'elem3'): 
    if tree.find(tag) is not None: 
     print 'found', tag 
+0

El documento que estoy trabajando es bastante largo. Voy a poner un fragmento de esto en la pregunta. – Biosci3c

+0

Además, ¿la primera línea establece los límites para buscar? – Biosci3c

6

Editar: respuesta actualizada para el archivo de muestra.

Supongo que desea buscar cada activo para ciertas etiquetas. Si es así, los siguientes trabajó para mí:

import lxml.objectify 

# Parse the file. 
tree = lxml.objectify.parse('sample.xml') 
root = tree.getroot() 

# Which elements to find. 
to_find = set(['presence/faction', 'presence/value', 'fake']) 

# Go through each asset in the document. 
for asset in root.findall('asset'): 
    # Check for each element. 
    for name in to_find: 
     node = asset.find(name) 
     if node is not None: 
      print 'Found %s, its value is %s' % (name, node) 
     else: 
      print 'Unable to find %s' % name 

La salida fue:

Found presence/value, its value is -1000.0 
Found presence/faction, its value is Dvaered 
Unable to find fake 
Found presence/value, its value is 100.0 
Found presence/faction, its value is Empire 
Unable to find fake 
+0

Parece que funcionará de maravilla. Lo intentaré cuando tenga la oportunidad. Solo para aclarar, ¿estás usando set() con una lista como argumento? – Biosci3c

+0

Sí. El constructor toma un iterable para dar las entradas iniciales en el conjunto. Ver [los documentos] (http://docs.python.org/library/stdtypes.html#set) para más detalles. – Blair

+0

Bien, un problema. ¿Cómo puedo hacer que esto asigne valores a variables particulares (es decir, var_fac = presencia/facción, var_value = presencia/valor? – Biosci3c

23

hasattr() trabajos para esto:

if hasattr(root, 'elem1'): 
    foo = root.elem1 
+2

Esta es la respuesta que me gusta. Todavía es feo, pero eso es culpa de Python, no del póster. Solo quiero verificar la existencia de un niño, no patear un procesador xpath de fuerza completa. – odigity

+1

Tenga en cuenta que internamente hasattr funciona llamando a getattr y atrapando excepciones, por lo que es tan feo por dentro como por fuera (al menos fue la última vez que lo comprobé) :) –

Cuestiones relacionadas