Захватите все пути к элементам XML, используя xml.etree.ElementTree

avatar
gridiron
1 июля 2021 в 18:35
520
1
2

Используя python import lxml, я могу рекурсивно распечатать список путей для каждого элемента:

from lxml import etree
root = etree.parse(xml_file)
for e in root.iter():
    path = root.getelementpath(e)
    print(path)

Результаты:

TreatmentEpisodes
TreatmentEpisodes/TreatmentEpisode
TreatmentEpisodes/TreatmentEpisode/SourceRecordIdentifier
TreatmentEpisodes/TreatmentEpisode/FederalTaxIdentifier
TreatmentEpisodes/TreatmentEpisode/ClientSourceRecordIdentifier
etc.

Примечание. Я работаю с этим XSD: https://www.myflfamilies.com/service-programs/samh/155-2/155-2-v14/schemas/TreatmentEpisodeDataset.xsd

Я хочу сделать то же самое, используя импортировать xml.etree.ElementTree как ET ... но ElementTree, похоже, не имеет функции, эквивалентной lxml getelementpath().

Я прочитал документы. Я гуглил несколько дней. Я экспериментировал с XPath. Я догадался использовать iter() и пробовал "getpath()", "Element.getpath()" и т. д., надеясь обнаружить недокументированную функцию. Ошибка.

Возможно, я столкнулся с крайним случаем "ошибки пользователя", и, пожалуйста, простите меня, если это дубликат.

Я думал, что нашел ответ здесь: Получить Xpath динамически, используя ElementTree getpath(), но XPathEvaluator, похоже, работает только с «известным» элементом — у него нет опции «дайте мне все".

Вот что я пробовал:

import xml.etree.ElementTree as ET
tree = etree.parse(xml_file)
for entry in tree.xpath('//TreatmentEpisode'):
    print(entry)

Результаты:

<Element TreatmentEpisode at 0xffff8f8c8a00>

На что я надеялся:

TreatmentEpisodes/TreatmentEpisode

...однако, даже если я получил то, на что надеялся, я все еще не уверен, как получить полный путь для каждого элемента. Насколько я понимаю документы XPath, они работают только с «известными» именами элементов.

Источник
hc_dev
1 июля 2021 в 18:48
0

Похоже, вы провели исследование и попытались решить эту проблему с помощью кода ... теперь предоставьте хотя бы то, что вы «экспериментировали с XPath», ваш код - даже если это не удалось: минимальный воспроизводимый пример. Итак, мы видим, как приспособиться.

gridiron
1 июля 2021 в 18:52
1

Справедливо. Я могу сказать следующее: я думал, что нашел ответ здесь: coderhelper.com/questions/13136334/…, но XPathEvaluator, кажется, работает только с «известным» элементом — у него нет опции для "дай мне все". Тем не менее, я соберу больше примеров того, что я пробовал, и отредактирую свой вопрос.

gridiron
1 июля 2021 в 20:31
0

@hc_dev вопрос обновлен с попыткой примера.

DisappointedByUnaccountableMod
1 июля 2021 в 20:51
0

Не должно быть слишком сложно написать функцию для построения пути элемента. Вы пробовали это?

DisappointedByUnaccountableMod
1 июля 2021 в 21:05
0

Я беру это назад - не понял, что родительского атрибута нет :-( Однако это показывает способ создания дочернего-> родительского словаря, который может легко стать основой для получения пути к элементу coderhelper.com/ вопросы/2170610/…

gridiron
1 июля 2021 в 21:12
0

@barny - твой первый комментарий был уловкой. Я никогда не пробовал пример функции во второй половине ссылки SO, которую я цитировал в своем собственном вопросе! Определенно здесь происходит серьезная ошибка пользователя, поскольку я только что попробовал эту функцию по вашему предложению, и она сработала! Возможно, мои глаза отказали от чтения слишком большого количества форумов, но это был ответ прямо передо мной. Пост Давиде Брунато должен быть отмечен суперфлагом или что-то в этом роде.

DisappointedByUnaccountableMod
1 июля 2021 в 21:15
0

Вы, вероятно, должны проголосовать за этот ответ

gridiron
1 июля 2021 в 21:33
0

@барни пытался. Не пускает, пока у меня не будет "15 репутации". Я прятался здесь 15 лет - это был мой первый пост. :(

DisappointedByUnaccountableMod
1 июля 2021 в 21:34
0

Хорошо - постарайтесь не забыть проголосовать, как только у вас появится представитель

Ответы (1)

avatar
Valdi_Bo
3 июля 2021 в 19:42
2

Начать с:

import xml.etree.ElementTree as et

Интересным способом решения вашей проблемы является использование iterparse - итеративный синтаксический анализатор, содержащийся в ElementTree.

Он может сообщать, например. каждое событие start и end для каждого анализируемого элемента. Подробности ищите в Интернете документацию/примеры iterparse.

Идея состоит в следующем:

  1. Начать с пустого списка в качестве пути.
  2. В событии start добавьте имя элемента к path и напечатайте полный path собрано до сих пор.
  3. В событии end удалить последний элемент из path.

Вы даже можете обернуть этот код в функции генератора:

def pathGen(fn):
    path = []
    it = et.iterparse(fn, events=('start', 'end'))
    for evt, el in it:
        if evt == 'start':
            path.append(el.tag)
            yield '/'.join(path)
        else:
            path.pop()

Теперь при запуске:

for pth in pathGen('Input.xml'):
    print(pth)

вы получите распечатку полных путей всех элементов в вашем исходном файле что-то вроде:

TreatmentEpisodes
TreatmentEpisodes/TreatmentEpisode
TreatmentEpisodes/TreatmentEpisode/SourceRecordIdentifier
TreatmentEpisodes/TreatmentEpisode/FederalTaxIdentifier
TreatmentEpisodes/TreatmentEpisode/ClientSourceRecordIdentifier
TreatmentEpisodes/TreatmentEpisode
TreatmentEpisodes/TreatmentEpisode/SourceRecordIdentifier
TreatmentEpisodes/TreatmentEpisode/FederalTaxIdentifier
TreatmentEpisodes/TreatmentEpisode/ClientSourceRecordIdentifier
...
gridiron
9 октября 2021 в 14:47
0

Я бы проголосовал за ваш ответ, но у меня до сих пор нет минимальной репутации для этого!

gridiron
9 октября 2021 в 14:48
0

Для будущих читателей этого сообщения работает ответ Valdi_Bo, а также ответ Давиде Брунато в этом сообщении: coderhelper.com/questions/13136334/…