Python: анализ файлов XML ESMA (европейский финансовый орган) - PullRequest
0 голосов
/ 11 октября 2019

Я попытался проанализировать найденные здесь XML-файлы:

https://registers.esma.europa.eu/publication/searchRegister?core=esma_registers_fitrs_files

с использованием xml.etree.ElementTree.parse()

Эти файлы содержат ISIN-коды безопасности и данные об объеме торговли, введенные MiFIRправила отчетности.

Я не смог найти ничего с помощью findall () или find (). Цикл по дочерним элементам и внукам, кажется, работает, но глубина дерева сумасшедшая.

Я хочу извлечь ISIN и данные для каждого узла NonEqtyTrnsprncyData. Я пытался

from xml.etree.ElementTree import parse
tree = parse("FULNCR_20191005_D_1of10.xml")
root = tree.getroot()
elems = root.findall('NonEqtyTrnsprncyData')

только дать мне [] в элементах.

Использование той же логики для образца базы данных mondial-3.0.xml сработало безошибочно в моих первых усилиях.

Кто-нибудь здесь успешно проанализировал XML-файлы ESMA и может повысить мою кривую обучения?

Короткая версия XML-файла:

<?xml version="1.0" encoding="UTF-8"?>
<BizData
    xsi:schemaLocation="urn:iso:std:iso:20022:tech:xsd:head.003.001.01 head.003.001.01.xsd"
    xmlns="urn:iso:std:iso:20022:tech:xsd:head.003.001.01" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <Hdr>
        <AppHdr
            xsi:schemaLocation="urn:iso:std:iso:20022:tech:xsd:head.001.001.01 head.001.001.01_ESMAUG_1.0.0.xsd"
            xmlns="urn:iso:std:iso:20022:tech:xsd:head.001.001.01" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <Fr>
                <OrgId>
                    <Id>
                        <OrgId>
                            <Othr>
                                <Id>EU</Id>
                            </Othr>
                        </OrgId>
                    </Id>
                </OrgId>
            </Fr>
            <To>
                <OrgId>
                    <Id>
                        <OrgId>
                            <Othr>
                                <Id>Public</Id>
                            </Othr>
                        </OrgId>
                    </Id>
                </OrgId>
            </To>
            <BizMsgIdr>FULNCR_20191005_D_3of10</BizMsgIdr>
            <MsgDefIdr>auth.045.001.02</MsgDefIdr>
            <CreDt>2019-10-05T13:00:01Z</CreDt>
        </AppHdr>
    </Hdr>
    <Pyld>
        <Document
            xsi:schemaLocation="urn:iso:std:iso:20022:tech:xsd:auth.045.001.02 auth.045.001.02_ESMAUG_DATNCR_1.1.0.xsd"
            xmlns="urn:iso:std:iso:20022:tech:xsd:auth.045.001.02" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <FinInstrmRptgNonEqtyTradgActvtyRslt>
                <RptHdr>
                    <RptgNtty>
                        <NtlCmptntAuthrty>EU</NtlCmptntAuthrty>
                    </RptgNtty>
                    <RptgPrd>
                        <FrDtToDt>
                            <FrDt>2019-10-05</FrDt>
                            <ToDt>2019-10-11</ToDt>
                        </FrDtToDt>
                    </RptgPrd>
                </RptHdr>
                <NonEqtyTrnsprncyData>
                    <TechRcrdId>1</TechRcrdId>
                    <Id>CH0110680714</Id>
                    <FinInstrmClssfctn>BOND</FinInstrmClssfctn>
                    <RptgPrd>
                        <FrDtToDt>
                            <FrDt>2018-01-01</FrDt>
                            <ToDt>2018-03-31</ToDt>
                        </FrDtToDt>
                    </RptgPrd>
                    <Lqdty>false</Lqdty>
                </NonEqtyTrnsprncyData>
            </FinInstrmRptgNonEqtyTradgActvtyRslt>
        </Document>
    </Pyld>
</BizData>

, где я удаляю все элементы NonEqtyTrnsprncyData, кроме одного.

1 Ответ

0 голосов
/ 11 октября 2019

Здесь есть две проблемы:

  • 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 намного более ограничена).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...