Я использую встроенный модуль Python ElementTree. Получить доступ к дочерним узлам просто, но как насчет родительских или одноуровневых узлов? - можно ли это сделать эффективно, не обходя все дерево?
доступ к родительскому узлу узла ElementTree
Ответы (10)
Прямой поддержки в виде атрибута parent
нет, но, возможно, вы можете использовать шаблоны, описанные здесь. для достижения желаемого эффекта. Предлагается следующая однострочная строка (обновленная из сообщения со ссылкой на Python 3.8) для создания сопоставления дочерних и родительских элементов для всего дерева с использованием метода xml.etree.ElementTree.Element.iter
:
parent_map = {c: p for p in tree.iter() for c in p}
parent_map = {(c,p) for p in tree.iter( ) for c in p}
- person gerardw; 08.09.2017
parent_map = {c:p for p in root.iter( ) for c in p}
- person gerardw; 08.09.2017
Ответ Виная все еще должен работать, но для Python 2.7+ и 3.2+ рекомендуется следующее:
parent_map = {c:p for p in tree.iter() for c in p}
getiterator()
устарел в пользу iter()
, и приятно использовать новый конструктор понимания списка dict
.
Во-вторых, при создании XML-документа возможно, что у дочернего элемента будет несколько родителей, хотя это удаляется после сериализации документа. Если это имеет значение, вы можете попробовать следующее:
parent_map = {}
for p in tree.iter():
for c in p:
if c in parent_map:
parent_map[c].append(p)
# Or raise, if you don't want to allow this.
else:
parent_map[c] = [p]
# Or parent_map[c] = p if you don't want to allow this
.find()
.
- person supergra; 28.07.2015
.find()
в качестве примера функции, которая просто возвращает элемент
- person Brett; 30.07.2015
Вы можете использовать нотацию xpath ...
в ElementTree.
<parent>
<child id="123">data1</child>
</parent>
xml.findall('.//child[@id="123"]...')
>> [<Element 'parent'>]
root.find(".//*[@testname='generated_sql']...")
- person Bostone; 08.09.2017
...
XPath. Что оно делает? Документы на него есть?
- person raphinesse; 23.05.2018
...
взято из XPath 1.0. Библиотека Python Std имеет ограниченную поддержку выражений XPath, lxml имеет большую поддержку.
- person josven; 22.08.2018
id
?
- person Ioannis Filippidis; 16.09.2020
xml.findall('.//child...')
Какой-то другой атрибут: xml.findall('.//child[@other="123"]...')
- person josven; 17.09.2020
.
(выбрать текущий узел) и ..
(получить родителя).
- person Nat Riddle; 20.05.2021
Как указано в Получить родительский элемент после использования метода поиска (xml .etree.ElementTree) вам придется выполнить непрямой поиск родителя. Имея xml:
<a>
<b>
<c>data</c>
<d>data</d>
</b>
</a>
Предполагая, что вы создали элемент etree в переменной xml
, вы можете использовать:
In[1] parent = xml.find('.//c/..')
In[2] child = parent.find('./c')
В результате чего:
Out[1]: <Element 'b' at 0x00XXXXXX>
Out[2]: <Element 'c' at 0x00XXXXXX>
Родитель более высокого уровня будет найден как: secondparent=xml.find('.//c/../..')
являющийся <Element 'a' at 0x00XXXXXX>
Селектор XPath '..' нельзя использовать для извлечения родительского узла в 3.5.3 или 3.6.1 (по крайней мере, в OSX), например, в интерактивном режиме:
import xml.etree.ElementTree as ET
root = ET.fromstring('<parent><child></child></parent>')
child = root.find('child')
parent = child.find('..') # retrieve the parent
parent is None # unexpected answer True
Последний ответ разбивает все надежды...
Вставка сюда моего ответа из https://stackoverflow.com/a/54943960/492336:
У меня была аналогичная проблема, и я немного креативил. Оказывается, ничто не мешает нам самим добавить информацию о происхождении. Мы можем позже раздеть его, как только он нам больше не понадобится.
def addParentInfo(et):
for child in et:
child.attrib['__my_parent__'] = et
addParentInfo(child)
def stripParentInfo(et):
for child in et:
child.attrib.pop('__my_parent__', 'None')
stripParentInfo(child)
def getParent(et):
if '__my_parent__' in et.attrib:
return et.attrib['__my_parent__']
else:
return None
# Example usage
tree = ...
addParentInfo(tree.getroot())
el = tree.findall(...)[0]
parent = getParent(el)
while parent:
doSomethingWith(parent)
parent = getParent(parent)
stripParentInfo(tree.getroot())
Получил ответ от
https://towardsdatascience.com/processing-xml-in-python-elementtree-c8992941efd2
Совет: используйте '...' внутри XPath, чтобы вернуть родительский элемент текущего элемента.
for object_book in root.findall('.//*[@name="The Hunger Games"]...'):
print(object_book)
Если вы используете lxml, я смог получить родительский элемент следующим образом:
parent_node = next(child_node.iterancestors())
Это вызовет исключение StopIteration
, если у элемента нет предков, поэтому будьте готовы поймать его, если вы можете столкнуться с таким сценарием.
Другой способ, если вам просто нужен родительский элемент одного подэлемента, а также известный xpath подэлемента.
parentElement = subElement.find(xpath+"/..")
subElement.find('..')
.
- person damian; 21.01.2015
xpath
уже существует, поэтому большинству пользователей она бесполезна.
- person ArtOfWarfare; 22.05.2020
Посмотрите на 19.7.2.2. раздел: Поддерживаемый синтаксис XPath ...
Найдите родителя узла, используя путь:
parent_node = node.find('..')
None
, если путь пытается достичь предков начального элемента (вызван элемент find
). (docs.python.org/3/library /а>).
- person mzjn; 14.12.2017