J'ai le XML suivant que je veux analyser en utilisant 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>
Je veux trouver toutes les owl:Class
balises, puis extraire la valeur de toutes les rdfs:label
instances qu'elles contiennent. J'utilise le code suivant:
tree = ET.parse("filename")
root = tree.getroot()
root.findall('owl:Class')
En raison de l'espace de noms, j'obtiens l'erreur suivante.
SyntaxError: prefix 'owl' not found in prefix map
J'ai essayé de lire le document à http://effbot.org/zone/element-namespaces.htm mais je ne suis toujours pas en mesure de faire fonctionner cela car le XML ci-dessus a plusieurs espaces de noms imbriqués.
Veuillez me faire savoir comment modifier le code pour trouver toutes les owl:Class
balises.
xmlns
attributs; comme indiqué dans la réponse, lelxml
fait pour vous, lexml.etree.ElementTree
module ne le fait pas. Mais si vous essayez de faire correspondre un élément spécifique (déjà codé en dur), vous essayez également de faire correspondre un élément spécifique dans un espace de noms spécifique. Cet espace de noms ne changera pas plus entre les documents que le nom de l'élément. Vous pouvez également coder en dur avec le nom de l'élément.register_namespace
que la sérialisation, pas la recherche.cElementTree
place deElementTree
,findall
ne prendra pas les espaces de noms comme argument mot-clé, mais plutôt simplement comme argument normal, c'est-à-dire usectree.findall('owl:Class', namespaces)
.findall
sans et ensuite avec l'namespace
argument, mais l'argument n'est pas mentionné comme l'un des arguments de la méthode méthode dans la section Objet élément .Voici comment faire cela avec lxml sans avoir à coder en dur les espaces de noms ou à analyser le texte pour eux (comme le mentionne Martijn Pieters):
MISE À JOUR :
5 ans plus tard, je rencontre toujours des variantes de ce problème. lxml aide comme je l'ai montré ci-dessus, mais pas dans tous les cas. Les commentateurs ont peut-être un point valable concernant cette technique lorsqu'il s'agit de fusionner des documents, mais je pense que la plupart des gens ont du mal à simplement rechercher des documents.
Voici un autre cas et comment je l'ai géré:
xmlns sans préfixe signifie que les balises sans préfixe obtiennent cet espace de noms par défaut. Cela signifie que lorsque vous recherchez Tag2, vous devez inclure l'espace de noms pour le trouver. Cependant, lxml crée une entrée nsmap avec Aucun comme clé, et je n'ai pas trouvé de moyen de la rechercher. J'ai donc créé un nouveau dictionnaire d'espaces de noms comme celui-ci
la source
owl
) peut changer de fichier en fichier. Par conséquent, faire ce que cette réponse suggère est une très mauvaise idée.Remarque : Ceci est une réponse utile pour la bibliothèque standard ElementTree de Python sans utiliser d'espaces de noms codés en dur.
Pour extraire les préfixes et l'URI de l'espace de noms des données XML, vous pouvez utiliser la
ElementTree.iterparse
fonction, en analysant uniquement les événements de démarrage de l'espace de noms ( start-ns ):Ensuite, le dictionnaire peut être passé en argument aux fonctions de recherche:
la source
ValueError: write to closed
pour cette lignefilemy_namespaces = dict([node for _, node in ET.iterparse(StringIO(my_schema), events=['start-ns'])])
. Une idée veut mal?dict([...])
vous pouvez également utiliser la compréhension de dict.StringIO(my_schema)
vous pouvez également mettre le nom de fichier du fichier XML.J'ai utilisé un code similaire à celui-ci et j'ai trouvé qu'il valait toujours la peine de lire la documentation ... comme d'habitude!
findall () ne trouvera que les éléments qui sont des enfants directs de la balise courante . Donc, pas vraiment TOUS.
Cela peut valoir la peine d'essayer de faire fonctionner votre code avec les éléments suivants, surtout si vous avez affaire à des fichiers XML volumineux et complexes afin que ces sous-sous-éléments (etc.) soient également inclus. Si vous savez vous-même où se trouvent les éléments dans votre xml, alors je suppose que ça ira! Je pensais juste que cela valait la peine de se souvenir.
ref: https://docs.python.org/3/library/xml.etree.elementtree.html#finding-interesting-elements "Element.findall () ne trouve que les éléments avec une balise qui sont des enfants directs de l'élément courant. Element.find () trouve le premier enfant avec une balise particulière, et Element.text accède au contenu texte de l'élément. Element.get () accède aux attributs de l'élément: "
la source
Pour obtenir l'espace de noms dans son format d'espace de noms, par exemple
{myNameSpace}
, vous pouvez faire ce qui suit:De cette façon, vous pouvez l'utiliser plus tard dans votre code pour trouver des nœuds, par exemple en utilisant une interpolation de chaîne (Python 3).
la source
Ma solution est basée sur le commentaire de @Martijn Pieters:
L'astuce ici est donc d'utiliser différents dictionnaires pour la sérialisation et la recherche.
Maintenant, enregistrez tous les espaces de noms pour l'analyse et l'écriture:
Pour la recherche (
find()
,findall()
,iterfind()
) nous avons besoin d' un préfixe non vide. Passez à ces fonctions un dictionnaire modifié (ici je modifie le dictionnaire original, mais cela ne doit être fait qu'après l'enregistrement des espaces de noms).Désormais, les fonctions de la
find()
famille peuvent être utilisées avec ledefault
préfixe:mais
n'utilise aucun préfixe pour les éléments de l'espace de noms par défaut.
la source