Здесь есть две проблемы:
Element.findall()
только с одним тэгом можно найти только direct children ;из соответствующей документации :
Element.findall()
находит только элементы с тегом, которые являются прямыми потомками текущего элемента.
Вы хотитеиспользуйте вместо этого XPath выражение ;префикс имени тега с .//
указывает API на поиск подэлементов на всех уровнях ниже текущего элемента .
В документе XML используются пространства имен XML;искомый элемент является частью пространства имен urn:iso:std:iso:20022:tech:xsd:auth.045.001.02
;это было установлено для родительского элемента Document
с атрибутом xmlns="..."
, который выглядит следующим образом (игнорируя другие атрибуты): атрибуты
<Document
xmlns="urn:iso:std:iso:20022:tech:xsd:auth.045.001.02"
>
xmlns
, с префиксом или без него (например, * 1035)*) применяются к элементу, для которого они определены, и ко всему поддереву, пока другой такой атрибут не переопределит настройку.
Обратите внимание, что префиксы, такие как xsi
, обычно являются локальными для документа, поэтому не имеет значения, чтопрефикс есть;это URI, который называет пространство имен.
Итак, вы хотите использовать пространство имен и вы хотите использовать выражение XPath. Проще всего использовать (свой) префикс, чтобы упростить написание выражений XPath. Это найдет ваши элементы:
namespace = 'urn:iso:std:iso:20022:tech:xsd:auth.045.001.02'
elems = tree.findall('.//ns:NonEqtyTrnsprncyData', {'ns': namespace})
Вы также можете использовать .//{urn:iso:std:iso:20022:tech:xsd:auth.045.001.02}NonEqtyTrnsprncyData
в качестве выражения и не использовать префикс пространства имен и карту, но это становится очень многословным при использовании более одного раза.
Вам также не нужно звонить tree.getroot()
;вы можете использовать tree.findall()
напрямую, потому что мы используем выражение XPath, которое в любом случае предназначено для поиска здесь всего дерева.
Демо:
>>> from xml.etree.ElementTree import parse
>>> tree = parse("FULNCR_20191005_D_1of10.xml")
>>> namespace = 'urn:iso:std:iso:20022:tech:xsd:auth.045.001.02'
>>> elems = tree.findall('.//ns:NonEqtyTrnsprncyData', {'ns': namespace})
>>> len(elems)
1
>>> elems[0]
<Element '{urn:iso:std:iso:20022:tech:xsd:auth.045.001.02}NonEqtyTrnsprncyData' at 0x109a84400>
>>> list(elems[0])
[<Element '{urn:iso:std:iso:20022:tech:xsd:auth.045.001.02}TechRcrdId' at 0x109a844a0>, <Element '{urn:iso:std:iso:20022:tech:xsd:auth.045.001.02}Id' at 0x109a84540>, <Element '{urn:iso:std:iso:20022:tech:xsd:auth.045.001.02}FinInstrmClssfctn' at 0x109a845e0>, <Element '{urn:iso:std:iso:20022:tech:xsd:auth.045.001.02}RptgPrd' at 0x109a84680>, <Element '{urn:iso:std:iso:20022:tech:xsd:auth.045.001.02}Lqdty' at 0x109a849a0>]
Обратите внимание, что все элементы, возвращаемыеAPI имеют полные имена ;если у вас есть документ с переменным набором пространств имен, вы можете проанализировать пространство имен из тэга:
>>> prefix, has_namespace, remainder = elems[0].tag.partition("}")
>>> if has_namespace:
... namespace, tag = prefix[1:], remainder
... else:
... namespace, tag = None, prefix
...
>>> namespace, tag
('urn:iso:std:iso:20022:tech:xsd:auth.045.001.02', 'NonEqtyTrnsprncyData')
Вы также можете посмотреть на lxml
проект , которыйпостроен на том же API ElementTree, но работает быстрее и предоставляет больше функций, таких как намного лучшая обработка пространства имен и полная поддержка XPath 1.0 (реализация ElementTree в стандартной библиотеке Python намного более ограничена).