Разбор XML-файла с помощью дерева элементов

У меня есть большое количество файлов .xml (около 70), и мне нужно извлечь из них некоторые координаты. По-видимому, лучший способ сделать это - проанализировать файл xml с помощью дерева элементов. Я новичок в python (очень-очень новый!), и мне трудно понять всю документацию, которая поставляется с деревом элементов! Мне было интересно, есть ли у кого-нибудь код, в котором они использовали дерево элементов, или кто-нибудь мог бы объяснить мне, как это сделать. Спасибо!

Это образец из моего файла XML.

    <?xml version="1.0" encoding="UTF-8" ?> 
- <lev:Leveringsinformatie xmlns:lev="http://www.kadaster.nl/schemas/klic/20080722/leveringsinfo">
  <lev:Version>1.5</lev:Version> 
  <lev:Klicnummer>10G179900</lev:Klicnummer> 
  <lev:Ordernummer>0065491624</lev:Ordernummer> 
  <lev:RelatienummerGrondroerder>0000305605</lev:RelatienummerGrondroerder> 
  <lev:Leveringsvolgnummer>1</lev:Leveringsvolgnummer> 
  <lev:Meldingsoort>Graafmelding</lev:Meldingsoort> 
  <lev:DatumTijdAanvraag>2010-08-10T11:43:02.779+02:00</lev:DatumTijdAanvraag> 
  <lev:KlantReferentie>1207-0132-030 - 6</lev:KlantReferentie> 
- <lev:Locatie axisLabels="x y" srsDimension="2" srsName="epsg:28992" uomLabels="m m">
- <gml:exterior xmlns:gml="http://www.opengis.net/gml">
- <gml:LinearRing>
  <gml:posList>137800.0 484217.0 137796.0 484222.0 137832.0 483757.0 138178.0 483752.0 138174.0 484222.0 137800.0 484217.0</gml:posList> 
  </gml:LinearRing>
  </gml:exterior>
  </lev:Locatie>
- <lev:Pngformaat>
- <lev:OmsluitendeRechthoek xmlns:ns4="http://www.kadaster.nl/schemas/klic/20080722/madt" xmlns:bis="http://www.kadaster.nl/schemas/klic/20080722/klicnetbeheerdersinformatieservicetypes" xmlns:ns0="http://www.kadaster.nl/schemas/klic/20080722/gias" xmlns:ns7="http://www.kadaster.nl/schemas/klic/20080722/klicnetbeheerdersinformatieservicetypes" xmlns:madt="http://www.kadaster.nl/schemas/klic/20080722/madt" xmlns:gia="http://www.kadaster.nl/schemas/klic/20080722/gias" xmlns:klic="http://www.kadaster.nl/schemas/20080722/klic" xmlns:b="http://www.kadaster.nl/schemas/klic/20080722/bundelingtypes" xmlns:ns9="http://www.kadaster.nl/schemas/klic/20081010/bmkltypes" xmlns:gml="http://www.opengis.net/gml" xmlns:ns1="http://www.kadaster.nl/schemas/20080722/klic" xmlns:a="http://www.kadaster.nl/schemas/klic/20080722/bundelingservicetypes" xmlns:bmkl="http://www.kadaster.nl/schemas/klic/20081010/bmkltypes" xmlns:ns3="http://www.opengis.net/gml" xmlns:ns8="http://www.kadaster.nl/schemas/klic/20080722/knts">
- <gml:Envelope srsDimension="2" srsName="epsg:28992">
  <gml:lowerCorner>137796 483752</gml:lowerCorner> 
  <gml:upperCorner>138178 484222</gml:upperCorner> 
  </gml:Envelope>
  </lev:OmsluitendeRechthoek>
  <lev:PixelsBreed>5348</lev:PixelsBreed> 
  <lev:PixelsHoog>6580</lev:PixelsHoog> 
  </lev:Pngformaat>
- <lev:NetbeheerderLeveringen>
- <lev:NetbeheerderLevering>
  <lev:RelatienummerNetbeheerder>0000578695</lev:RelatienummerNetbeheerder> 
  <lev:Bedrijfsnaam>Gemeente Almere</lev:Bedrijfsnaam> 
  <lev:BedrijfsnaamAfkorting>Gemeente Almere</lev:BedrijfsnaamAfkorting> 

Мне нужно извлечь координаты нижнего и верхнего угла (lowerCorner/upperCorner)

Обновление: вот мой полный скрипт:

from xml.etree import ElementTree as ET
import sys, string, os, arcgisscripting
gp = arcgisscripting.create(9.3)

workspace = "D:/J040083"
gp.workspace = workspace

for root, dirs, filenames in os.walk(workspace): # returms root, dirs, and files
    for filename in filenames:
        filename_split = os.path.splitext(filename) # filename and extensionname (extension in [1])
        filename_zero = filename_split[0]
        extension = str.upper(filename_split[1])

        try:
            first_2_letters = str.upper(filename_zero[0] + filename_zero[1])
        except:
            first_2_letters = "XX"

        if first_2_letters == "LI" and extension == ".XML":
            tree = ET.parse(workspace)
            print tree.find('//{http://www.opengis.net/gml}lowerCorner').text
            print tree.find('//{http://www.opengis.net/gml}upperCorner').text

Теперь я получаю сообщение об ошибке:

Имя файла сообщения Положение строки
Трассировка
D:\J040083\TXT_EXTRACTION.py 32
разбор C:\Python25\Lib\xml\etree\ElementTree.py 862
разбор C:\Python25\Lib \xml\etree\ElementTree.py 579
IOError: [Errno 13] Отказано в доступе: 'D:/J040083'

и теперь я ДЕЙСТВИТЕЛЬНО запутался, потому что я могу получить доступ к этим файлам с другим скриптом, который почти точно такой же, как этот!!


person Alice Duff    schedule 18.01.2011    source источник
comment
Стыдно, да, я прочитал это! я просто не очень понимаю..   -  person Alice Duff    schedule 18.01.2011
comment
@Alice: я предлагаю вам опубликовать небольшой реалистичный фрагмент из XML-файла, который вы хотите проанализировать, и указать данные, которые вы хотите получить. Вы можете сделать это, отредактировав свой собственный пост.   -  person Eli Bendersky    schedule 18.01.2011
comment
Я пробовал это, но это просто отображается в моем вопросе не в правильном формате ... поэтому вместо комментариев у него были просто цифры!   -  person Alice Duff    schedule 18.01.2011
comment
@Alice: стоит потратить несколько минут на изучение правил форматирования SO. Обновите его, и, возможно, другой участник с большим опытом сможет исправить это для вас (позже вы сможете увидеть, как это делается).   -  person Eli Bendersky    schedule 18.01.2011
comment
хм.. я старался! Хотя, похоже, это не сработало! Я извиняюсь за свое невежество!   -  person Alice Duff    schedule 18.01.2011
comment
@Alice: это совсем не похоже на xml :) вставьте xml и отформатируйте его как код   -  person Eli Bendersky    schedule 18.01.2011
comment
ах да.. глупо! ну вот!   -  person Alice Duff    schedule 18.01.2011
comment
@Alice Duff - если вы собираетесь много работать с GML, я бы порекомендовал прочитать XML. GML может быть довольно сложным, и вы будете довольны тем, что разобрались с основами XML. Я не могу порекомендовать какие-либо учебные пособия, так как я давно их не просматривал, но избегайте W3Schools (НЕ связанных с W3, которые на самом деле пишут спецификацию!), Поскольку они часто неточны. Это первый результат, не принадлежащий W3Schools: learn-xml-tutorial.com   -  person James Walford    schedule 18.01.2011
comment
ГМЛ?! По сути, у меня есть сотни и сотни файлов .png, и мне нужно преобразовать их в формат, читаемый ArcMap (программа ГИС). Итак, я сделал скрипт, который преобразует их в шейп-файлы и загружает их в программу, но мне нужно написать еще один скрипт, который извлекает координаты из XML-файлов, которые идут с ними, чтобы поместить их в правильное место на странице. карту делаю!   -  person Alice Duff    schedule 18.01.2011
comment
@Alice Duff — ваш XML-файл — это GML opengeospatial.org/standards/gml XML-грамматика для выражающие географические особенности. Если вам нужно только извлечь координаты, все будет в порядке, но если вам нужны какие-либо другие манипуляции с XML, то GML может быть довольно сложным.   -  person James Walford    schedule 18.01.2011
comment
в порядке! Великолепно! Не могли бы вы указать мне направление любой документации/кода, который мог бы помочь мне извлечь эти координаты!   -  person Alice Duff    schedule 18.01.2011
comment
@Alice: это не полный образец XML (например, тег </lev:OmsluitendeRechthoek> не закрывает ничего, что я вижу в вашем образце). Пожалуйста, опубликуйте более полный образец   -  person Eli Bendersky    schedule 18.01.2011
comment
Вот и все — остальная часть кода после этого раздела — это просто имена людей, номера телефонов и т. д.!   -  person Alice Duff    schedule 18.01.2011
comment
@Alice, в вашем обновленном скрипте ошибка от tree = ET.parse(workspace). workspace — это просто имя каталога, а не имя файла.   -  person Mark Tolonen    schedule 21.01.2011


Ответы (2)


ElementTree может быть сложным, когда задействованы пространства имен. Искомый элемент называется <gml:lowerCorner> и <gml:upperCorner>. При поиске выше в данных XML gml определяется как пространство имен XML: xmlns:gml="http://www.opengis.net/gml". Способ найти подэлемент XML-дерева следующий:

from xml.etree import ElementTree as ET
tree = ET.parse('file.xml')
print tree.find('//{http://www.opengis.net/gml}lowerCorner').text
print tree.find('//{http://www.opengis.net/gml}upperCorner').text

Вывод

137796 483752
138178 484222

Объяснение

Используя поддержку ElementTree XPath, // выбирает все подэлементы на всех уровнях дерева. ElementTree использует нотацию {url}tag для тега в определенном пространстве имен. URL-адрес gml: http://www.opengis.net/gml. .text извлекает данные в элементе.

Обратите внимание, что // — это ярлык для поиска вложенного узла. Полный путь upperCorner в синтаксисе ElementTree на самом деле:

{http://www.kadaster.nl/schemas/klic/20080722/leveringsinfo}Pngformaat/{http://www.kadaster.nl/schemas/klic/20080722/leveringsinfo}OmsluitendeRechthoek/{http://www.opengis.net/gml}Envelope/{http://www.opengis.net/gml}upperCorner
person Mark Tolonen    schedule 18.01.2011
comment
+1 за хорошее объяснение. Единственное, в чем я не уверен, так это в том, что если на документ приходится не более 1 gml:Envelope, возможно, Алиса сможет прокомментировать? - person James Walford; 18.01.2011
comment
о ура ура!! Оно работает!! Остальная часть XML - это просто имена людей и адреса электронной почты - так что я думаю, что раздел, который я вам показал, единственный gml - если это то, что вы имеете в виду, джеймс? Теперь мне нужно сохранить вывод в предопределенном файле Excel! Большое спасибо всем вам! - person Alice Duff; 19.01.2011
comment
Если ответ приемлем, отметьте его как принятый. Рад помочь. :) - person Mark Tolonen; 19.01.2011
comment
Привет Марк! Мне пришлось снять отметку с вашего ответа, потому что у меня есть новый вопрос, или я должен просто опубликовать его как новый вопрос? - person Alice Duff; 19.01.2011

Использовать ElementTree очень просто, в основном вы создаете объект из файла, находите элементы по имени или пути и получаете их текст или атрибут.

В вашем случае это немного сложнее, потому что в вашем файле есть пространства имен, поэтому нам нужно преобразовать путь из формы ns:tag в форму {uri}tag. Это цель функции transform_path

NS_MAP = {
    'http://www.kadaster.nl/schemas/klic/20080722/leveringsinfo' : 'lev',
    'http://www.opengis.net/gml' : 'gml',
}
INV_NS_MAP = {v:k for k, v in NS_MAP.items()} #inverse ns_map 
#for python2: INV_NS_MAP = dict((v,k) for k, v in NS_MAP.iteritems())

#ElementTree expect tags in form {uri}tag, but it would be a pain to have complete uri for eache tag
def transform_path (path):
    res = ''
    tags = path.split('/')
    for tag in tags:
      ns, tag = tag.split(':')
      res += "{"+INV_NS_MAP[ns]+"}"+tag+'/'
    return res

import xml.etree.ElementTree as ET
tree = ET.parse('test.xml')
doc = tree.getroot()

lowerCorner = doc.find(transform_path("lev:Pngformaat/lev:OmsluitendeRechthoek/gml:Envelope/gml:lowerCorner"))
upperCorner = doc.find(transform_path("lev:Pngformaat/lev:OmsluitendeRechthoek/gml:Envelope/gml:upperCorner"))
print (lowerCorner.text)         # Print coordinates
print (upperCorner.text)         # Print coordinates

#for python2: print elem.text

Запуск скрипта с вашим файлом даст следующий результат:

137796 483752
138178 484222
person CharlesB    schedule 18.01.2011
comment
Спасибо, Чарльз, я пытаюсь запустить ваш код, но он продолжает выдавать ошибку «Недопустимый синтаксис» для последней строки! - person Alice Duff; 18.01.2011
comment
У меня возникли проблемы с работой этого скрипта. Теперь я получаю ошибку Invalid Syntax для второй с последней строки..? - person Alice Duff; 18.01.2011
comment
Я думаю, что это должно работать, я просто не понимаю, как заставить его работать с моими данными - я попытаюсь провести некоторое исследование и, надеюсь, пойму!! - person Alice Duff; 18.01.2011
comment
Сделал небольшой скрипт, который считывает координаты вашего файла - person CharlesB; 18.01.2011