Одна из проблем, с которой вы столкнулись, заключается в том, что когда вы делаете for x in y
, вы выполняете итерацию всех дочерних элементов текущего элемента.
Итак, когда вы делаете это:
for Folder in Document:
...
вы не просто перебираете Folder
элементов; Вы также перебираете name
, open
, Schema
, Style
и StyleMap
(пока исключено пространство имен).
Вы можете по-прежнему получать то, что вы хотите, протестировав значение атрибута name
и затем вернув текст элементов ...
for Document in root:
for Folder in Document:
for Placemark in Folder:
for ExtendedData in Placemark:
for SchemaData in ExtendedData:
for SimpleData in SchemaData:
if SimpleData.get("name") == "ID":
print(SimpleData.text)
но я бы не советовал.
Вместо этого рассмотрите возможность использования XPath 1.0 с функцией lxml xpath()
.
Это позволит вам нацеливаться на интересующие вас элементы.
В этом примере я собираюсь использовать полный путь вместо //
сокращенного синтаксиса . Я также буду использовать предикат для проверки значения атрибута.
На первый взгляд вы можете подумать, что XPath для всех элементов SimpleData
со значением атрибута name
«ID» будет:
/kml/Document/Folder/Placemark/ExtendedData/SchemaData/SimpleData[@name='ID']
но это не тот случай. Если вы заметили, что в корневом элементе (kml
) есть xmlns="http://www.opengis.net/kml/2.2"
. Это означает, что этот элемент и все его дочерние элементы находятся в пространстве имен по умолчанию http://www.opengis.net/kml/2.2
(если в этих элементах не указано иное).
Для иллюстрации, если вы добавили print(f"In Folder element \"{Folder.tag}\"...")
в цикл for Folder in Document
, вы увидите:
In Folder element "{http://www.opengis.net/kml/2.2}name"...
In Folder element "{http://www.opengis.net/kml/2.2}open"...
In Folder element "{http://www.opengis.net/kml/2.2}Schema"...
In Folder element "{http://www.opengis.net/kml/2.2}Style"...
In Folder element "{http://www.opengis.net/kml/2.2}StyleMap"...
In Folder element "{http://www.opengis.net/kml/2.2}Style"...
In Folder element "{http://www.opengis.net/kml/2.2}Folder"...
Существует несколько способов обработки пространств имен в lxml , но я предпочитаю объявлять их в словаре и передавать их с аргументом namespaces
.
Вот полный пример ...
from lxml import etree
ns = {"kml": "http://www.opengis.net/kml/2.2"}
tree = etree.parse("test.kml")
for simple_data in tree.xpath("/kml:kml/kml:Document/kml:Folder/kml:Placemark/kml:ExtendedData/kml:SchemaData/kml:SimpleData[@name='ID']", namespaces=ns):
print(simple_data.text)
Вывод на печать ...
FM2
FM3