Tengo el siguiente XML que quiero analizar usando Python ElementTree
:
<rdf:RDF xml:base="http://dbpedia.org/ontology/"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:owl="http://www.w3.org/2002/07/owl#"
xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
xmlns="http://dbpedia.org/ontology/">
<owl:Class rdf:about="http://dbpedia.org/ontology/BasketballLeague">
<rdfs:label xml:lang="en">basketball league</rdfs:label>
<rdfs:comment xml:lang="en">
a group of sports teams that compete against each other
in Basketball
</rdfs:comment>
</owl:Class>
</rdf:RDF>
Quiero encontrar todas las owl:Class
etiquetas y luego extraer el valor de todas las rdfs:label
instancias dentro de ellas. Estoy usando el siguiente código:
tree = ET.parse("filename")
root = tree.getroot()
root.findall('owl:Class')
Debido al espacio de nombres, recibo el siguiente error.
SyntaxError: prefix 'owl' not found in prefix map
Intenté leer el documento en http://effbot.org/zone/element-namespaces.htm pero todavía no puedo hacer que esto funcione ya que el XML anterior tiene múltiples espacios de nombres anidados.
Por favor, hágame saber cómo cambiar el código para encontrar todas las owl:Class
etiquetas.
xmlns
atributos usted mismo; como se indica en la respuesta,lxml
hace esto por usted, elxml.etree.ElementTree
módulo no. Pero si está tratando de hacer coincidir un elemento específico (ya codificado), también está tratando de hacer coincidir un elemento específico en un espacio de nombres específico. Ese espacio de nombres no va a cambiar entre documentos más que el nombre del elemento. También puede codificar eso con el nombre del elemento.register_namespace
solo influye en la serialización, no en la búsqueda.cElementTree
lugar deElementTree
,findall
no tomará espacios de nombres como argumento de palabra clave, sino simplemente como un argumento normal, es decir, usoctree.findall('owl:Class', namespaces)
.findall
sin y luego con elnamespace
argumento, pero el argumento no se menciona como uno de los argumentos del método del método en la sección del objeto Elemento .Aquí le mostramos cómo hacer esto con lxml sin tener que codificar los espacios de nombres o escanear el texto en busca de ellos (como menciona Martijn Pieters):
ACTUALIZACIÓN :
5 años después todavía me encuentro con variaciones de este problema. lxml ayuda como mostré arriba, pero no en todos los casos. Los comentaristas pueden tener un punto válido con respecto a esta técnica cuando se trata de fusionar documentos, pero creo que la mayoría de las personas tienen dificultades simplemente buscando documentos.
Aquí hay otro caso y cómo lo manejé:
xmlns sin prefijo significa que las etiquetas no prefijadas obtienen este espacio de nombres predeterminado. Esto significa que cuando busca Tag2, debe incluir el espacio de nombres para encontrarlo. Sin embargo, lxml crea una entrada nsmap con None como clave, y no pude encontrar una manera de buscarla. Entonces, creé un nuevo diccionario de espacio de nombres como este
fuente
owl
) puede cambiar de un archivo a otro. Por lo tanto, hacer lo que sugiere esta respuesta es una muy mala idea.Nota : Esta es una respuesta útil para la biblioteca estándar ElementTree de Python sin usar espacios de nombres codificados.
Para extraer los prefijos y el URI del espacio de nombres de los datos XML, puede usar la
ElementTree.iterparse
función, analizando solo los eventos de inicio del espacio de nombres ( start-ns ):Luego, el diccionario se puede pasar como argumento a las funciones de búsqueda:
fuente
ValueError: write to closed
para esta líneafilemy_namespaces = dict([node for _, node in ET.iterparse(StringIO(my_schema), events=['start-ns'])])
. Alguna idea quiere mal?dict([...])
usted también puede usar la comprensión dict.StringIO(my_schema)
usted también puede poner el nombre del archivo XML.He estado usando un código similar a este y he descubierto que siempre vale la pena leer la documentación ... ¡como siempre!
findall () solo encontrará elementos que son hijos directos de la etiqueta actual . Entonces, no TODOS.
Puede valer la pena intentar que su código funcione con lo siguiente, especialmente si se trata de archivos xml grandes y complejos para que también se incluyan esos subelementos (etc.). Si sabes dónde están los elementos en tu xml, ¡entonces supongo que estará bien! Solo pensé que valía la pena recordarlo.
ref: https://docs.python.org/3/library/xml.etree.elementtree.html#finding-interesting-elements "Element.findall () encuentra solo elementos con una etiqueta que son hijos directos del elemento actual. Element.find () encuentra el primer elemento secundario con una etiqueta particular y Element.text accede al contenido de texto del elemento. Element.get () accede a los atributos del elemento: "
fuente
Para obtener el espacio de nombres en su formato de espacio de nombres, por ejemplo
{myNameSpace}
, puede hacer lo siguiente:De esta manera, puede usarlo más adelante en su código para buscar nodos, por ejemplo, usando la interpolación de cadenas (Python 3).
fuente
Mi solución se basa en el comentario de @Martijn Pieters:
Entonces, el truco aquí es usar diferentes diccionarios para la serialización y la búsqueda.
Ahora, registre todos los espacios de nombres para analizar y escribir:
Para buscar (
find()
,findall()
,iterfind()
) necesitamos un prefijo no vacío. Pase estas funciones a un diccionario modificado (aquí modifico el diccionario original, pero esto debe hacerse solo después de registrar los espacios de nombres).Ahora, las funciones de la
find()
familia se pueden usar con eldefault
prefijo:pero
no utiliza ningún prefijo para elementos en el espacio de nombres predeterminado.
fuente