У меня есть следующий XML, который я хочу проанализировать с помощью 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>
Я хочу найти все owl:Class
теги, а затем извлечь значение всех rdfs:label
экземпляров внутри них. Я использую следующий код:
tree = ET.parse("filename")
root = tree.getroot()
root.findall('owl:Class')
Из-за пространства имен я получаю следующую ошибку.
SyntaxError: prefix 'owl' not found in prefix map
Я попытался прочитать документ по адресу http://effbot.org/zone/element-namespaces.htm, но я до сих пор не могу заставить это работать, так как вышеупомянутый XML имеет несколько вложенных пространств имен.
Пожалуйста, дайте мне знать, как изменить код, чтобы найти все owl:Class
теги.
xmlns
атрибутов; как указано в ответе,lxml
делает это для вас,xml.etree.ElementTree
модуль не делает. Но если вы пытаетесь сопоставить определенный (уже жестко закодированный) элемент, то вы также пытаетесь сопоставить конкретный элемент в определенном пространстве имен. Это пространство имен не будет меняться между документами так же, как имя элемента. Вы можете также жестко закодировать это с именем элемента.register_namespace
влияет только на сериализацию, а не на поиск.cElementTree
вместоElementTree
,findall
не будет принимать пространства имен в качестве аргумента ключевого слова, а скорее просто как обычный аргумент, то есть использоватьctree.findall('owl:Class', namespaces)
.findall
без, а затем сnamespace
аргументом, но этот аргумент не упоминается в качестве одного из аргументов метода метода в разделе объекта Element .Вот как это сделать с помощью lxml без необходимости жесткого кодирования пространств имен или сканирования их текста (как упоминает Мартейн Питерс):
ОБНОВЛЕНИЕ :
Спустя 5 лет я все еще сталкиваюсь с вариантами этой проблемы. lxml помогает, как я показал выше, но не в каждом случае. Комментаторы могут иметь правильное мнение об этой технике, когда речь идет о слиянии документов, но я думаю, что большинство людей испытывают трудности с простым поиском документов.
Вот еще один случай и как я с этим справился:
xmlns без префикса означает, что теги без префиксов получают это пространство имен по умолчанию. Это означает, что при поиске Tag2 вам необходимо включить пространство имен, чтобы найти его. Однако lxml создает запись nsmap с ключом None, и я не смог найти способ найти его. Итак, я создал новый словарь пространства имен, как это
источник
owl
) может меняться от файла к файлу. Поэтому делать то, что предлагает этот ответ, действительно плохая идея.Примечание . Этот ответ полезен для стандартной библиотеки Python ElementTree без использования жестко заданных пространств имен.
Для извлечения префиксов пространства имен и URI из данных XML вы можете использовать
ElementTree.iterparse
функцию, анализирующую только события запуска пространства имен ( start-ns ):Затем словарь можно передать в качестве аргумента функциям поиска:
источник
ValueError: write to closed
для этой строкиfilemy_namespaces = dict([node for _, node in ET.iterparse(StringIO(my_schema), events=['start-ns'])])
. Любая идея хочет неправильно?dict([...])
вы также можете использовать диктовку понимания.StringIO(my_schema)
вы также можете указать имя файла XML.Я использовал подобный код для этого и обнаружил, что всегда стоит прочитать документацию ... как обычно!
findall () найдет только элементы, которые являются прямыми потомками текущего тега . Так что не совсем ВСЕ.
Возможно, стоит попытаться заставить ваш код работать со следующим, особенно если вы имеете дело с большими и сложными XML-файлами, чтобы эти подэлементы (и т. Д.) Также были включены. Если вы сами знаете, где находятся элементы в вашем xml, тогда, я думаю, все будет хорошо! Просто подумал, что это стоит запомнить.
ref: https://docs.python.org/3/library/xml.etree.elementtree.html#finding-interesting-elements "Element.findall () находит только элементы с тегом, которые являются прямыми потомками текущего элемента. Element.find () находит первого потомка с определенным тегом, а Element.text обращается к текстовому содержимому элемента. Element.get () обращается к атрибутам элемента: "
источник
Чтобы получить пространство имен в его формате, например
{myNameSpace}
, вы можете сделать следующее:Таким образом, вы можете использовать его позже в своем коде для поиска узлов, например, используя интерполяцию строк (Python 3).
источник
Мое решение основано на комментарии @Martijn Pieters:
Так что хитрость здесь заключается в том, чтобы использовать разные словари для сериализации и поиска.
Теперь зарегистрируйте все пространства имен для анализа и записи:
Для поиска (
find()
,findall()
,iterfind()
), нужно непустой префикс. Передайте этим функциям измененный словарь (здесь я изменяю исходный словарь, но это должно быть сделано только после того, как пространства имен зарегистрированы).Теперь функции из
find()
семейства можно использовать сdefault
префиксом:но
не использует префиксы для элементов в пространстве имен по умолчанию.
источник