Разбор XML в Python с использованием ElementTree

Ответы давались сотни раз, но решения так и не нашел. Я попробовал официальную документацию и ответы на stackoverflow.

У меня есть эта структура XML:

<?xml version="1.0" encoding="windows-1252"?>
<OpenShipments xmlns="x-schema:OpenShipments.xdr">
    <OpenShipment ProcessStatus="Processed" ShipmentOption="">
        <ShipTo>
            <CompanyOrName><![CDATA[xxx]]></CompanyOrName>
            <Attention><![CDATA[xxx]]></Attention>
            <Address1><![CDATA[xxx]]></Address1>
            <PostalCode><![CDATA[xxx]]></PostalCode>
            <CityOrTown><![CDATA[xxx]]></CityOrTown>
            <Telephone><![CDATA[xxx]]></Telephone>
            <EmailAddress><![CDATA[xxx]]></EmailAddress>
            <CountryTerritory><![CDATA[xxx]]></CountryTerritory>
        </ShipTo>
        <ShipmentInformation>
            <ServiceType>ST</ServiceType>
            <PackageType>CP</PackageType>
            <ShipmentActualWeight><![CDATA[XXX]]></ShipmentActualWeight>
            <QVNOption>
                <QVNRecipientAndNotificationTypes>
                    <CompanyOrName/>
                    <ContactName/>
                    <EMailAddress/>
                    <LabelCreation/>
                </QVNRecipientAndNotificationTypes>
                <ShipFromCompanyOrName>xxx</ShipFromCompanyOrName>
            </QVNOption>
        </ShipmentInformation>
        <ProcessMessage>

            <ShipmentRates>
                <ShipmentCharges>
                    <Rate>
                        <Published>XXX</Published>
                        <Negotiated>XXX</Negotiated>
                    </Rate>
                </ShipmentCharges>
                <ShipperCharges>
                    <Rate>
                        <Published>XXX</Published>
                        <Negotiated>XXX</Negotiated>
                    </Rate>
                </ShipperCharges>
                <ReceiverCharges>
                    <Rate>
                        <Published>0,00</Published>
                        <Negotiated>0,00</Negotiated>
                    </Rate>
                </ReceiverCharges>
                <QVN>
                    <Rate>
                        <Published>0,00</Published>
                        <Negotiated>0,00</Negotiated>
                    </Rate>
                </QVN>
                <PackageRates>
                    <PackageRate>
                        <TrackingNumber>TRACKING NUMBER</TrackingNumber>
                        <PackageCharges>
                            <Rate>
                            <Published>0,00</Published>
                            <Negotiated>0,00</Negotiated>
                            </Rate>
                        </PackageCharges>
                        <Delivery_AreaSurcharge>
                            <Rate>
                            <Published>0,00</Published>
                            <Negotiated>0,00</Negotiated>
                            </Rate>
                        </Delivery_AreaSurcharge>
                    </PackageRate>
                </PackageRates>
            </ShipmentRates>
            <TrackingNumbers>
                <TrackingNumber>TRACKING NUMBER</TrackingNumber>
            </TrackingNumbers>
            <ShipID>XXX</ShipID>
            <ImportID></ImportID>
            <Reference1></Reference1>
            <Reference2></Reference2>
        <ShipmentID></ShipmentID>
        <PRONumber></PRONumber>
        </ProcessMessage>
    </OpenShipment>
</OpenShipments>

Необходимо получить значение «TrackingNumber». Я пробовал функции findall() и find(), но безрезультатно.

import xml.etree.ElementTree as ET
import pprint

tree = ET.parse('file.out')
root = tree.getroot()

print root.findall('TrackingNumber')
# []
print root.find('TrackingNumber')
# None

ElementTree должен был сделать доступ к XML-элементам простым, но это оказалось для меня слишком сложным.


person user3041764    schedule 07.07.2016    source источник


Ответы (1)


Вам нужно сопоставление пространства имен :

from xml.etree import ElementTree as et

xm = et.fromstring(x)
ns = {"op": 'x-schema:OpenShipments.xdr'}
print(xm.findall('.//op:TrackingNumber',ns))

который даст вам что-то вроде:

[<Element '{x-schema:OpenShipments.xdr}TrackingNumber' at 0x7fa210579550>, <Element '{x-schema:OpenShipments.xdr}TrackingNumber' at 0x7fa210579910>]
person Padraic Cunningham    schedule 07.07.2016
comment
Это то, что мне нужно! - person user3041764; 07.07.2016
comment
Не беспокойтесь, вы также можете xm.findall('.//{x-schema:OpenShipments.xdr}TrackingNumber') , но это было бы красиво, если бы вы использовали несколько узлов в своем запросе xpath. - person Padraic Cunningham; 07.07.2016
comment
почему простой findall('TrackingNumber') не работает? - person user3041764; 07.07.2016
comment
@user3041764 user3041764, из-за пространства имен все в OpenShipments находится в пространстве имен x-schema:OpenShipments.xdr, поэтому к любым запросам нужно добавлять префикс ns, удалять xmlns="x-schema:OpenShipments.xdr" и использовать './/TrackingNumber', и вы увидите разницу - person Padraic Cunningham; 07.07.2016