Pregunta

Necesito obtener una lista de valores de atributos de elementos secundarios en Python.

Es más fácil de explicar con un ejemplo.

Dado un XML como este:

<elements>
    <parent name="CategoryA">
        <child value="a1"/>
        <child value="a2"/>
        <child value="a3"/>
    </parent>
    <parent name="CategoryB">
        <child value="b1"/>
        <child value="b2"/>
        <child value="b3"/>
    </parent>
</elements>

Quiero poder hacer algo como:

>>> getValues("CategoryA")
['a1', 'a2', 'a3']
>>> getValues("CategoryB")
['b1', 'b2', 'b3']

Parece un trabajo para XPath pero estoy abierto a todas las recomendaciones.También me gustaría conocer sus bibliotecas XML de Python favoritas.

¿Fue útil?

Solución

Realmente no soy un experto en Python, pero aquí hay una solución XPath que usa libxml2.

import libxml2

DOC = """<elements>
    <parent name="CategoryA">
        <child value="a1"/>
        <child value="a2"/>
        <child value="a3"/>
    </parent>
    <parent name="CategoryB">
        <child value="b1"/>
        <child value="b2"/>
        <child value="b3"/>
    </parent>
</elements>"""

doc = libxml2.parseDoc(DOC)

def getValues(cat):
    return [attr.content for attr in doc.xpathEval("/elements/parent[@name='%s']/child/@value" % (cat))]

print getValues("CategoryA")

Con resultado...

['a1', 'a2', 'a3']

Otros consejos

Árbol de elementos 1.3 (desafortunadamente no 1.2, que es el que se incluye con Python) soporta XPath como esto:

import elementtree.ElementTree as xml

def getValues(tree, category):
    parent = tree.find(".//parent[@name='%s']" % category)
    return [child.get('value') for child in parent]

Entonces puedes hacer

>>> tree = xml.parse('data.xml')
>>> getValues(tree, 'CategoryA')
['a1', 'a2', 'a3']
>>> getValues(tree, 'CategoryB')
['b1', 'b2', 'b3']

lxml.etree (que también proporciona la interfaz ElementTree) también funcionará de la misma manera.

Usando un DOM W3 estándar como el minidom de stdlib o pxdom:

def getValues(category):
    for parent in document.getElementsByTagName('parent'):
        if parent.getAttribute('name')==category:
            return [
                el.getAttribute('value')
                for el in parent.getElementsByTagName('child')
            ]
    raise ValueError('parent not found')

Debo admitir que soy fan de xmltramp debido a su facilidad de uso.

Accediendo a lo anterior se convierte en:

  import xmltramp

  values = xmltramp.parse('''...''')

  def getValues( values, category ):
    cat = [ parent for parent in values['parent':] if parent(name) == category ]
    cat_values = [ child(value) for child in parent['child':] for parent in cat ]
    return cat_values

  getValues( values, "CategoryA" )
  getValues( values, "CategoryB" )

Puedes hacer esto con hermosasopa

>>> from BeautifulSoup import BeautifulStoneSoup
>>> soup = BeautifulStoneSoup(xml)
>>> def getValues(name):
. . .      return [child['value'] for child in soup.find('parent', attrs={'name': name}).findAll('child')]

Si está trabajando con HTML/XML, le recomendaría que eche un vistazo a BeautifulSoup.Es similar al árbol DOM pero contiene más funciones.

Mi biblioteca xml de Python preferida es lxml , que envuelve libxml2.
XPath parece el camino a seguir aquí, así que escribiría esto como algo como:

from lxml import etree

def getValues(xml, category):
    return [x.attrib['value'] for x in 
            xml.findall('/parent[@name="%s"]/*' % category)]

xml = etree.parse(open('filename.xml'))

>>> print getValues(xml, 'CategoryA')
['a1', 'a2', 'a3']
>>> print getValues(xml, 'CategoryB')
['b1', 'b2', 'b3]

En Python 3.x, obtener una lista de atributos es una tarea sencilla que consiste en utilizar el miembro items()

Utilizando el ElementTree, el siguiente fragmento muestra una forma de obtener la lista de atributos.TENGA EN CUENTA que este ejemplo no considera los espacios de nombres, que, si están presentes, deberán contabilizarse.

    import xml.etree.ElementTree as ET

    flName = 'test.xml'
    tree = ET.parse(flName)
    root = tree.getroot()
    for element in root.findall('<child-node-of-root>'):
        attrList = element.items()
        print(len(attrList), " : [", attrList, "]" )

REFERENCIA:

Elemento.elementos()
Devuelve los atributos del elemento como una secuencia de pares (nombre, valor).
Los atributos se devuelven en un orden arbitrario.

manual de pitón

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top