Mam następujący kod XML, który chcę przeanalizować za pomocą Pythona 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>
Chcę znaleźć wszystkie owl:Class
tagi, a następnie wyodrębnić wartość wszystkich rdfs:label
wystąpień w nich. Używam następującego kodu:
tree = ET.parse("filename")
root = tree.getroot()
root.findall('owl:Class')
Z powodu przestrzeni nazw pojawia się następujący błąd.
SyntaxError: prefix 'owl' not found in prefix map
Próbowałem czytać dokument pod adresem http://effbot.org/zone/element-namespaces.htm, ale nadal nie mogę tego uruchomić, ponieważ powyższy kod XML ma wiele zagnieżdżonych przestrzeni nazw.
Uprzejmie daj mi znać, jak zmienić kod, aby znaleźć wszystkie owl:Class
tagi.
xmlns
atrybutów; jak podano w odpowiedzi,lxml
robi to za Ciebie,xml.etree.ElementTree
moduł nie. Ale jeśli próbujesz dopasować określony (już zakodowany) element, próbujesz również dopasować określony element w określonej przestrzeni nazw. Ta przestrzeń nazw nie zmieni się między dokumentami bardziej niż nazwa elementu. Równie dobrze możesz zakodować to na stałe z nazwą elementu.register_namespace
wpływa tylko na serializację, a nie na wyszukiwanie.cElementTree
zamiastElementTree
,findall
nie będzie traktować przestrzeni nazw jako argumentu słowa kluczowego, ale raczej jako zwykły argument, tjctree.findall('owl:Class', namespaces)
. Use .findall
bez, a następnie znamespace
argumentem, ale argument nie jest wymieniony jako jeden z argumentów metody metody w sekcji obiektu Element .Oto jak to zrobić za pomocą lxml bez konieczności kodowania przestrzeni nazw lub skanowania ich tekstu (jak wspomina Martijn Pieters):
AKTUALIZACJA :
5 lat później wciąż napotykam różne odmiany tego problemu. lxml pomaga, jak pokazałem powyżej, ale nie w każdym przypadku. Komentatorzy mogą mieć rację co do tej techniki, jeśli chodzi o scalanie dokumentów, ale myślę, że większość ludzi ma trudności z prostym wyszukiwaniem dokumentów.
Oto inny przypadek i jak sobie z tym poradziłem:
xmlns bez prefiksu oznacza, że tagi bez prefiksu otrzymują tę domyślną przestrzeń nazw. Oznacza to, że kiedy szukasz Tag2, musisz uwzględnić przestrzeń nazw, aby ją znaleźć. Jednak lxml tworzy wpis nsmap z None jako kluczem i nie mogłem znaleźć sposobu, aby go wyszukać. Dlatego utworzyłem nowy słownik przestrzeni nazw, taki jak ten
źródło
owl
) może zmieniać się z pliku na plik. Dlatego robienie tego, co sugeruje ta odpowiedź, jest naprawdę złym pomysłem.Uwaga : jest to odpowiedź przydatna w przypadku standardowej biblioteki Pythona ElementTree bez używania zakodowanych na stałe przestrzeni nazw.
Aby wyodrębnić prefiksy i URI przestrzeni nazw z danych XML, możesz użyć
ElementTree.iterparse
funkcji, analizując tylko zdarzenia początkowe przestrzeni nazw ( start-ns ):Następnie słownik można przekazać jako argument do funkcji wyszukiwania:
źródło
ValueError: write to closed
dla tej liniifilemy_namespaces = dict([node for _, node in ET.iterparse(StringIO(my_schema), events=['start-ns'])])
. Każdy pomysł chce źle?dict([...])
ciebie możesz też użyć dyktowania ze zrozumieniem.StringIO(my_schema)
ciebie możesz też podać nazwę pliku XML.Używałem podobnego kodu do tego i stwierdziłem, że zawsze warto przeczytać dokumentację ... jak zwykle!
findall () znajdzie tylko elementy, które są bezpośrednimi dziećmi bieżącego znacznika . Więc nie do końca WSZYSTKIE.
Może warto spróbować, aby Twój kod działał z następującymi elementami, zwłaszcza jeśli masz do czynienia z dużymi i złożonymi plikami xml, tak aby uwzględnione były również elementy podrzędne (itp.). Jeśli wiesz, gdzie znajdują się elementy w Twoim xml, to chyba będzie dobrze! Pomyślałem, że warto o tym pamiętać.
ref: https://docs.python.org/3/library/xml.etree.elementtree.html#finding-interesting-elements "Element.findall () wyszukuje tylko elementy z tagiem, które są bezpośrednimi potomkami bieżącego elementu. Element.find () znajduje pierwsze dziecko z określonym znacznikiem, a Element.text uzyskuje dostęp do zawartości tekstowej elementu. Element.get () uzyskuje dostęp do atrybutów elementu: "
źródło
Aby uzyskać przestrzeń nazw w formacie przestrzeni nazw
{myNameSpace}
, możesz na przykład wykonać następujące czynności:W ten sposób możesz użyć go później w kodzie, aby znaleźć węzły, np. Za pomocą interpolacji ciągów (Python 3).
źródło
Moje rozwiązanie bazuje na komentarzu @Martijn Pieters:
Tak więc sztuczka polega na użyciu różnych słowników do serializacji i wyszukiwania.
Teraz zarejestruj wszystkie przestrzenie nazw do analizowania i pisania:
Do przeszukiwania (
find()
,findall()
,iterfind()
) musimy niepusty prefiks. Przekaż tym funkcjom zmodyfikowany słownik (tutaj modyfikuję oryginalny słownik, ale trzeba to zrobić dopiero po zarejestrowaniu przestrzeni nazw).Teraz funkcje z
find()
rodziny mogą być używane zdefault
przedrostkiem:ale
nie używa żadnych przedrostków dla elementów w domyślnej przestrzeni nazw.
źródło