2009-12-23 17 views
14

¿Cómo se puede acceder a los atributos NS mediante ElementTree?¿Accediendo al atributo XMLNS con Python Elementree?

Con el siguiente:

<data xmlns="http://www.foo.net/a" xmlns:a="http://www.foo.net/a" book="1" category="ABS" date="2009-12-22"> 

Cuando intento root.get ('xmlns') regrese Ninguno, categoría y fecha están muy bien, .. Cualquier ayuda apreciada

+3

No puedo responder a su pregunta, pero después de haber luchado contra esta deficiencia durante un par de días, estoy dispuesto a afirmar que no es posible utilizarla con la API actual de ElementTree. En mi aplicación, necesitaba detectar si ya existía un atributo xmlns: xlink en el elemento raíz, y si no, agregarlo. No es posible probar si ya existe un atributo xmlns y, lo que es más, ElementTree se complace en agregarlo dos veces si lo intentas. Dado que cero o dos atributos xmlns idénticos en el mismo elemento causan un error en la mayoría de los consumidores XML, esto hace que ElementTree sea muy difícil de usar. –

Respuesta

14

creo element.tag es lo que estás buscando. Tenga en cuenta que su ejemplo no tiene una barra inclinada, por lo que está desequilibrado y no se analizará. He agregado uno en mi ejemplo.

>>> from xml.etree import ElementTree as ET 
>>> data = '''<data xmlns="http://www.foo.net/a" 
...     xmlns:a="http://www.foo.net/a" 
...     book="1" category="ABS" date="2009-12-22"/>''' 
>>> element = ET.fromstring(data) 
>>> element 
<Element {http://www.foo.net/a}data at 1013b74d0> 
>>> element.tag 
'{http://www.foo.net/a}data' 
>>> element.attrib 
{'category': 'ABS', 'date': '2009-12-22', 'book': '1'} 

Si lo que desea es conocer las xmlns URI, puede dividir a cabo con una función como:

def tag_uri_and_name(elem): 
    if elem.tag[0] == "{": 
     uri, ignore, tag = elem.tag[1:].partition("}") 
    else: 
     uri = None 
     tag = elem.tag 
    return uri, tag 

Para mucho más en espacios de nombres y nombres cualificados en elementtree, ver effbot's examples.

+11

¿Por qué no hay una función como esta en la biblioteca? Parece que todo archivo xml con un espacio de nombres lo necesitaría. ¿Lo estoy perdiendo? – Clutch

+0

@clutch Me pregunto lo mismo. Alguien sabe una razón por qué? – Santa

+0

@rednaw, no estoy convencido de que la división sea mejor. Se garantiza que la partición devolverá una tupla de exactamente tres elementos, dividir puede devolver una cantidad arbitraria de elementos. En la práctica, sería sintácticamente inválido tener todo menos una llave de cierre, pero aún así. Creo que la partición es mejor. –

7

Mire la documentación/ejemplos de los espacios de nombres de effbot; específicamente la función parse_map. Le muestra cómo agregar un atributo * ns_map * a cada elemento que contiene el mapeo de prefijo/URI que se aplica a ese elemento específico.

Sin embargo, eso agrega el atributo ns_map a todos los elementos. Para mis necesidades, descubrí que quería un mapa global de todos los espacios de nombres utilizados para hacer que la búsqueda de elementos fuera más fácil y no codificada.

Esto es lo que ocurrió:

import elementtree.ElementTree as ET 

def parse_and_get_ns(file): 
    events = "start", "start-ns" 
    root = None 
    ns = {} 
    for event, elem in ET.iterparse(file, events): 
     if event == "start-ns": 
      if elem[0] in ns and ns[elem[0]] != elem[1]: 
       # NOTE: It is perfectly valid to have the same prefix refer 
       #  to different URI namespaces in different parts of the 
       #  document. This exception serves as a reminder that this 
       #  solution is not robust. Use at your own peril. 
       raise KeyError("Duplicate prefix with different URI found.") 
      ns[elem[0]] = "{%s}" % elem[1] 
     elif event == "start": 
      if root is None: 
       root = elem 
    return ET.ElementTree(root), ns 

Con esto se puede analizar un archivo XML y obtener un diccionario con las asignaciones de espacio de nombres. Por lo tanto, si usted tiene un archivo XML como el siguiente ("my.xml"):

<?xml version="1.0" encoding="UTF-8" ?> 
<rss version="2.0" 
xmlns:content="http://purl.org/rss/1.0/modules/content/" 
xmlns:dc="http://purl.org/dc/elements/1.1/"\ 
> 
<feed> 
    <item> 
    <title>Foo</title> 
    <dc:creator>Joe McGroin</dc:creator> 
    <description>etc...</description> 
    </item> 
</feed> 
</rss> 

usted será capaz de utilizar las namepaces XML y obtener información para elementos como dc: creator:

>>> tree, ns = parse_and_get_ns("my.xml") 
>>> ns 
{u'content': '{http://purl.org/rss/1.0/modules/content/}', 
u'dc': '{http://purl.org/dc/elements/1.1/}'} 
>>> item = tree.find("/feed/item") 
>>> item.findtext(ns['dc']+"creator") 
'Joe McGroin' 
+0

Respondió mi publicación en http://stackoverflow.com/questions/13018024/converting-my-python-script-from-lxml-to-xml-etree/13019393#13019393 –

Cuestiones relacionadas