Ich möchte die Methode "findall" verwenden, um einige Elemente der XML-Quelldatei im ElementTree-Modul zu finden.
Die XML-Quelldatei (test.xml) hat jedoch einen Namespace. Ich schneide einen Teil der XML-Datei als Beispiel ab:
<?xml version="1.0" encoding="iso-8859-1"?>
<XML_HEADER xmlns="http://www.test.com">
<TYPE>Updates</TYPE>
<DATE>9/26/2012 10:30:34 AM</DATE>
<COPYRIGHT_NOTICE>All Rights Reserved.</COPYRIGHT_NOTICE>
<LICENSE>newlicense.htm</LICENSE>
<DEAL_LEVEL>
<PAID_OFF>N</PAID_OFF>
</DEAL_LEVEL>
</XML_HEADER>
Der Beispiel-Python-Code ist unten:
from xml.etree import ElementTree as ET
tree = ET.parse(r"test.xml")
el1 = tree.findall("DEAL_LEVEL/PAID_OFF") # Return None
el2 = tree.findall("{http://www.test.com}DEAL_LEVEL/{http://www.test.com}PAID_OFF") # Return <Element '{http://www.test.com}DEAL_LEVEL/PAID_OFF' at 0xb78b90>
Obwohl dies funktionieren kann, ist es sehr unpraktisch, vor jedem Tag einen Namespace hinzuzufügen, da ein Namespace "{http://www.test.com}" vorhanden ist.
Wie kann ich den Namespace ignorieren, wenn ich die Methoden "find", "findall" usw. verwende?
python
namespaces
find
elementtree
findall
KevinLeng
quelle
quelle
tree.findall("xmlns:DEAL_LEVEL/xmlns:PAID_OFF", namespaces={'xmlns': 'http://www.test.com'})
bequem genug?tree.findall("{0}DEAL_LEVEL/{0}PAID_OFF".format('{http://www.test.com}'))
Antworten:
Anstatt das XML-Dokument selbst zu ändern, ist es am besten, es zu analysieren und dann die Tags im Ergebnis zu ändern. Auf diese Weise können Sie mehrere Namespaces und Namespace-Aliase verarbeiten:
Dies basiert auf der Diskussion hier: http://bugs.python.org/issue18304
Update:
rpartition
Stattpartition
sicherzustellen, dass Sie den Tag-Namenpostfix
auch dann erhalten, wenn kein Namespace vorhanden ist. So könnte man es verdichten:quelle
et.findall('{*}sometag')
. Außerdem wird der Elementbaum selbst entstellt, nicht nur "die Suche wird durchgeführt, wobei Namespaces nur dieses Mal ignoriert werden, ohne das Dokument usw. erneut zu analysieren und die Namespace-Informationen beizubehalten". In diesem Fall müssen Sie den Baum beobachten und selbst sehen, ob der Knoten Ihren Wünschen entspricht, nachdem Sie den Namespace entfernt haben.Wenn Sie das xmlns-Attribut vor dem Parsen aus der xml entfernen, wird nicht jedem Tag im Baum ein Namespace vorangestellt.
quelle
=
Gleichheitszeichen.Die bisherigen Antworten haben den Namespace-Wert explizit in das Skript eingefügt. Für eine allgemeinere Lösung würde ich lieber den Namespace aus der XML extrahieren:
Und verwenden Sie es in der Suchmethode:
quelle
namespace
Hier ist eine Erweiterung der Antwort von nonagon, mit der auch Namespaces von Attributen entfernt werden:
UPDATE: hinzugefügt,
list()
damit der Iterator funktioniert (wird für Python 3 benötigt)quelle
Verbesserung der Antwort von ericspod:
Anstatt den Analysemodus global zu ändern, können wir dies in ein Objekt einschließen, das das with-Konstrukt unterstützt.
Dies kann dann wie folgt verwendet werden
Das Schöne an dieser Art ist, dass sie kein Verhalten für nicht verwandten Code außerhalb des with-Blocks ändert. Ich habe dies erstellt, nachdem ich Fehler in nicht verwandten Bibliotheken erhalten hatte, nachdem ich die Version von ericspod verwendet hatte, die auch expat verwendete.
quelle
xml.etree.ElementTree.XMLParser
irgendwie optimiert ist und das Patchen von Affenexpat
absolut keine Wirkung hat.Sie können auch das elegante Konstrukt zur Zeichenfolgenformatierung verwenden:
oder, wenn Sie sicher sind, dass PAID_OFF nur in einer Ebene im Baum angezeigt wird :
quelle
Wenn Sie verwenden
ElementTree
und nichtcElementTree
, können Sie Expat zwingen, die Namespace-Verarbeitung zu ignorieren, indem Sie Folgendes ersetzenParserCreate()
:ElementTree
versucht, Expat durch Aufrufen zu verwendenParserCreate()
, bietet jedoch keine Option, keine Namespace-Trennzeichenfolge anzugeben. Der obige Code führt dazu, dass es ignoriert wird. Es wird jedoch gewarnt, dass dies andere Probleme verursachen kann.quelle
ElementTree.fromstring(s, parser=None)
ich versuche Parser an ihn zu übergeben.Ich könnte zu spät kommen, aber ich denke nicht, dass dies
re.sub
eine gute Lösung ist.Das Umschreiben
xml.parsers.expat
funktioniert jedoch nicht für Python 3.x-Versionen.Der Hauptschuldige ist das
xml/etree/ElementTree.py
siehe unten im QuellcodeWelches ist ein bisschen traurig.
Die Lösung besteht darin, es zuerst loszuwerden.
Getestet auf Python 3.6.
Die Try-
try
Anweisung ist nützlich, wenn Sie irgendwo in Ihrem Code ein Modul zweimal neu laden oder importieren und dabei seltsame Fehler wie zÜbrigens sieht der etree-Quellcode wirklich chaotisch aus.
quelle
Kombinieren wir die Antwort von nonagon mit der Antwort von mzjn auf eine verwandte Frage :
Mit dieser Funktion können wir:
Erstellen Sie einen Iterator, um sowohl Namespaces als auch ein analysiertes Baumobjekt abzurufen .
Iterate über die erstellte Iterator bekommen die Namensräume dict , dass wir später in jedem passieren können
find()
oderfindall()
Anruf als von iMom0 sugested .Ich denke, dies ist der beste Ansatz, da weder eine Quell-XML noch die daraus resultierende analysierte
xml.etree.ElementTree
Ausgabe manipuliert werden kann.Ich möchte auch der Antwort von barny die Bereitstellung eines wesentlichen Teils dieses Puzzles zuschreiben (dass Sie die analysierte Wurzel vom Iterator erhalten können). Bis dahin habe ich den XML-Baum in meiner Anwendung tatsächlich zweimal durchlaufen (einmal, um Namespaces zu erhalten, zweitens für einen Stamm).
quelle
find()
und abzufragenfindall()
. Sie füttern diese Methoden einfach mit dem Diktat der Namespacesparse_xml()
und verwenden das Präfix des Namespaces in Ihren Abfragen. ZB:et_element.findall(".//some_ns_prefix:some_xml_tag", namespaces=xml_namespaces)