lxml — Парсинг xml Python
Вопрос задан
Изменён 2 года 1 месяц назад
Просмотрен 300 раз
Есть файл xml, который нужно парсить на python, для нахождения тегов. Подскажите, как посчитать количество повторений этих тегов? Вывести в самом конце сам тег — количество. Вот файл xml:
<?xml version="1.0"?>
<catalog>
<book>
<author>Gambardella, Matthew</author>
<title>XML Developer's Guide</title>
<genre>Computer</genre>
<price>44.95</price>
<publish_date>2000-10-01</publish_date>
<description>An in-depth look at creating applications
with XML.
</description>
</book>
<book>
<author>Ralls, Kim</author>
<title>Midnight Rain</title>
<genre>Fantasy</genre>
<price>5.95</price>
<publish_date>2000-12-16</publish_date>
<description>A former architect battles corporate zombies,
an evil sorceress, and her own childhood to become queen
of the world.</description>
</book>
<book>
<author>Corets, Eva</author>
<title>Maeve Ascendant</title>
<genre>Fantasy</genre>
<price>5.95</price>
<publish_date>2000-11-17</publish_date>
<description>After the collapse of a nanotechnology
society in England, the young survivors lay the
foundation for a new society.</description>
</book>
</catalog>
Ниже код:
# -*- coding: utf-8 -*-
from lxml import etree
def parseBookXML(xmlFile):
with open(xmlFile) as fobj:
xml = fobj.
read()
root = etree.fromstring(xml)
book_dict = {}
books = []
for book in root.getchildren():
for elem in book.getchildren():
if not elem.text:
text = "None"
else:
text = elem.text
print(elem.tag + " => " + text)
book_dict[elem.tag] = text
if book.tag == "book":
books.append(book_dict)
book_dict = {}
return books
if __name__ == "__main__":
parseBookXML("books.xml")
- python
- lxml
Интересненько. Формализую задачу: вам нужно найти количество повторений тегов. Непонятно каких… Например для всех:
import re
from collections import Counter
def parseBookXML(xmlFile):
with open(xmlFile) as fobj:
xml = fobj.read()
# понимаю, что все тэги парные и смысла включать все нет смысла,
# буду забирать только открывающиеся
pattern = r"<\w{1,}"
how_many_tags = Counter(re.findall(pattern, k))
# что содержит how_many_tags
# Counter({'<book': 3, '<author': 3, '<title': 3, '<genre': 3, '<price': 3, '<publish_date': 3, '<description': 3, '<catalog': 1})
# если напрягают символы в начале ключей, то можно почистить
clear = {}
for i in how_many_tags:
key = i[1:]
clear[key] = how_many_tags[i]
# ну, и переменная clear {'catalog': 1, 'book': 3, 'author': 3, 'title': 3, 'genre': 3, 'price': 3, 'publish_date': 3, 'description': 3}
Если нужен подсчет вместе с закрывающими, то умножьте на 2 все значения и будет вам счастье.
Зарегистрируйтесь или войдите
Регистрация через Google Регистрация через Facebook Регистрация через почтуОтправить без регистрации
ПочтаНеобходима, но никому не показывается
Отправить без регистрации
ПочтаНеобходима, но никому не показывается
By clicking “Отправить ответ”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.
python — Парсинг XML файла таблицы с передачей в DataFrame
Воспользуйтесь данным решением (с) Austin Taylor:
import xml.etree.ElementTree as ET import pandas as pd class XML2DataFrame: def __init__(self, xml_data): self.root = ET.XML(xml_data) def parse_root(self, root): return [self.parse_element(child) for child in iter(root)] def parse_element(self, element, parsed=None): if parsed is None: parsed = dict() for key in element.keys(): parsed[key] = element.attrib.get(key) if element.text: parsed[element.tag] = element.text for child in list(element): self.parse_element(child, parsed) return parsed def process_data(self): structure_data = self.parse_root(self.root) return pd.DataFrame(structure_data) xml2df = XML2DataFrame(xml_data) df = xml2df.process_data()
Пример:
with open(r"D:\download\20200915_ED807_full.xml") as f:
xml_data = f.read()
xml2df = XML2DataFrame(xml_data)
df = xml2df.process_data()
результат:
In [32]: df
Out[32]:
BIC NameP CntrCd Rgn Ind .
.. SWBIC DefaultSWBIC \
0 041280103 УФК по Астраханской области RU 12 414056 ... NaN NaN
1 044525597 КУ "МИЛЛЕНИУМ БАНК" (ЗАО) - ГК "АСВ" RU 45 109240 ... NaN NaN
2 044525603 КУ ЗАО "ИПОТЕК БАНК" - ГК "АСВ" RU 45 109240 ... NaN NaN
3 044525608 КУ ООО КБ "ДОРИС БАНК" - ГК "АСВ" RU 45 109240 ... NaN NaN
4 044525652 КУ КБ "ПРИСКО КАПИТАЛ БАНК", АО - ГК... RU 45 109240 ... NaN NaN
... ... ... ... .. ... ... ... ...
2368 298003187 Департамент финансов г. Якутска RU 98 677000 ... NaN NaN
2369 015354008 УФК по Оренбургской области RU 53 460014 ... NaN NaN
2370 200000099 Территориальная избирательная комисс... RU 36 443110 ... NaN NaN
2371 200001413 Территориальная избирательная комисс.
.. RU 36 445011 ... NaN NaN
2372 047516949 БАНК "КУБ" (АО) RU 75 455044 ... CRDURU4CXXX 1
EnglName AccRstr AccRstrDate
0 NaN NaN NaN
1 NaN NaN NaN
2 NaN NaN NaN
3 NaN NaN NaN
4 NaN NaN NaN
... ... ... ...
2368 NaN NaN NaN
2369 NaN NaN NaN
2370 NaN NaN NaN
2371 NaN NaN NaN
2372 "Credit Ural Bank" Joint Stock Compa... NaN NaN
[2373 rows x 28 columns]
столбцы DataFrame:
In [33]: df.columns Out[33]: Index(['BIC', 'NameP', 'CntrCd', 'Rgn', 'Ind', 'Tnp', 'Nnp', 'Adr', 'DateIn', 'PtType', 'Srvcs', 'XchType', 'UID', 'ParticipantStatus', 'Account', 'RegulationAccountType', 'CK', 'AccountCBRBIC', 'AccountStatus', 'RegN', 'Rstr', 'RstrDate', 'PrntBIC', 'SWBIC', 'DefaultSWBIC', 'EnglName', 'AccRstr', 'AccRstrDate'], dtype='object')
все значения первой строки фрейма:
In [34]: pd.set_option("display.max_rows", 30)
In [35]: df.iloc[0]
Out[35]:
BIC 041280103
NameP УФК по Астраханской области
CntrCd RU
Rgn 12
Ind 414056
Tnp г
Nnp Астрахань
Adr ул Латышева, 6 Г
DateIn 2013-01-09
PtType 52
Srvcs 3
XchType 1
UID 1280002005
ParticipantStatus PSAC
Account 40116810600000010015
RegulationAccountType TRSA
CK 99
AccountCBRBIC 041280002
AccountStatus ACAC
RegN NaN
Rstr NaN
RstrDate NaN
PrntBIC NaN
SWBIC NaN
DefaultSWBIC NaN
EnglName NaN
AccRstr NaN
AccRstrDate NaN
Как разобрать файлы XML с помощью python? [Код включен]
От заказа продуктов через Instamart и покупки гардероба в Myntra до бронирования отпуска на MakemyTrip — в этом десятилетии веб-сайты стали незаменимыми! Вы когда-нибудь задумывались, как эти веб-сайты отображают информацию для клиентов в легко интерпретируемом виде, а также обрабатывают и взаимодействуют с данными в бэкэнде?
Существуют определенные форматы файлов, которые восполняют этот пробел, будучи интерпретируемыми как для машинного языка, так и для человека.
Одним из таких широко используемых форматов является XML, сокращение от Extensible Markup Language.
Что такое файлы XML и как их использовать?
Файлы XML используются для хранения и передачи данных между клиентами и серверами. Это позволяет нам определять данные в структурированном формате с помощью тегов, атрибутов и значений. Одним из основных преимуществ XML является его гибкость. Его можно использовать для представления данных во многих форматах и легко адаптировать для новых целей. Это делает его популярным выбором для таких приложений, как веб-службы, обмен данными и файлы конфигурации. В этой статье я познакомлю вас с различными методами Python для анализа XML-файла на практическом примере.
Вы ищете автоматизированный анализ XML? Попробуйте автоматизированные рабочие процессы Nanonets. Начните бесплатную пробную версию прямо сейчас.
Понимание структуры XML-файлов
Прежде чем мы углубимся в детали анализа XML-файлов, давайте сначала разберемся с различными частями XML-документа.
В XML элемент является фундаментальным строительным блоком документа, который представляет собой структурированную часть информации. Содержимое элемента всегда должно быть заключено между открывающим и закрывающим тегами, как показано ниже.
Я буду использовать пример файла «travel_pckgs.xml», который содержит сведения о различных турпакетах, предлагаемых компанией. Я буду продолжать использовать один и тот же файл в блоге для ясности.
<турпакеты> <пакет>Ощутите великолепную красоту Парижа и французскую культуру. Париж, Франция <цена>3000цена> <длительность>7длительность> <платеж>да <возврат>давозврат> платеж> пакет> <пакет>Отправляйтесь в захватывающее приключение на гавайских пляжах! описание> Гавайи, США <цена>4000цена> <длительность>10длительность> <платеж>нет <возврат>нетвозврат> платеж> пакет> <пакет>Побалуйте себя красотой и очарованием Италии и получите все- инклюзивный тур по настоящей итальянской кухне! Италия <цена>2000цена> <длительность>8длительность> <платеж>да <возврат>нетвозврат> платеж> пакет> <пакет>Ощутите красоту пляжей острова, включая подводное плавание. дайвинг и ночное плавание на байдарках по мангровым зарослям.
Андаманские и Никобарские острова <цена>800цена> <длительность>8длительность> <платеж>нет <возврат>давозврат> платеж> пакет> путешествия>
В файле содержатся данные о 4 турпакетах с подробной информацией о пункте назначения, описании, цене и способах оплаты, предоставленных агентством. Давайте посмотрим на разбивку различных частей приведенного выше XML:
- Корневой элемент: Элемент самого верхнего уровня называется корневым, который в нашем файле равен
. Он содержит все остальные элементы (предлагаются различные туры) - Атрибут: «id» — это атрибут каждого элемента
в нашем файле. Обратите внимание, что атрибут должен иметь уникальные значения («Отпуск в Париже», «Приключение на Гавайях» и т. д.) для каждого элемента.
Как видите, атрибут и его значение обычно упоминаются внутри начального тега. - Дочерние элементы : Элементы, завернутые в корень, являются дочерними элементами. В нашем случае все теги
являются дочерними элементами, каждый из которых хранит сведения о турпакете. - Подэлементы: Дочерний элемент может иметь больше подэлементов внутри своей структуры. Дочерний элемент
имеет подэлементы , и, , . Преимущество XML в том, что он позволяет хранить иерархическую информацию с помощью нескольких вложенных элементов. Подэлементдополнительно имеет подэлементы и , которые обозначают, есть ли у конкретного пакета варианты оплаты через EMI и возврата или нет.
Совет: Вы можете создать древовидное представление XML-файла, чтобы получить четкое представление об этом инструменте.
Посмотрите на иерархическое древовидное представление нашего XML-файла!
Отлично! Мы хотим читать данные, хранящиеся в этих полях, искать, обновлять и вносить изменения по мере необходимости для веб-сайта, верно? Это называется синтаксическим анализом, при котором XML-данные разбиваются на части и идентифицируются разные части.
Существует несколько способов анализа XML-файла в Python с помощью разных библиотек. Давайте погрузимся в первый метод!
Попробуйте Nanonets анализировать файлы XML. Начните бесплатную пробную версию без данных кредитной карты.
Использование Mini DOM для анализа XML-файлов
Я уверен, что вы сталкивались с DOM (Document Object Model), стандартным API для представления XML-файлов. Mini DOM — это встроенный модуль Python, который минимально реализует DOM.
Как работает мини-ДОМ?
Загружает входной XML-файл в память, создавая древовидную структуру «Дерево DOM» для хранения элементов, атрибутов и текстового содержимого.
Поскольку XML-файлы также по своей природе имеют иерархическую древовидную структуру, этот метод удобен для навигации и извлечения информации.
Давайте посмотрим, как импортировать пакет с помощью приведенного ниже кода. Вы можете проанализировать файл XML, используя функцию xml.dom.minidom.parse() , а также получить корневой элемент.
импорт xml.dom.minidom
# разбираем XML-файл
xml_doc = xml.dom.minidom.parse('travel_pckgs.xml')
# получить корневой элемент
корень = xml_doc.documentElement
print('Root is',root) Вывод, который я получил для приведенного выше кода:
>> Корень
Допустим, я хочу распечатать место, продолжительность и цена.
Функцию getAttribute() можно использовать для получения значения атрибута элемента.
Если вы хотите получить доступ ко всем элементам под определенным тегом, используйте метод getElementsByTagName() и укажите тег в качестве входных данных.
Самое приятное то, что getElementsByTagName() можно использовать рекурсивно для извлечения вложенных элементов.
# получить все элементы пакета
пакеты = xml_doc.getElementsByTagName («пакет»)
# перебираем пакеты и извлекаем данные
для пакета в пакетах:
package_id = package.getAttribute('id')
описание = package.getElementsByTagName('описание')[0].childNodes[0].data
цена = package.getElementsByTagName('price')[0].childNodes[0].data
продолжительность = package.getElementsByTagName('длительность')[0].childNodes[0].data
print('Идентификатор пакета:', package_id)
print('Описание:', описание)
print('Цена:', цена) Здесь показан вывод приведенного выше кода с извлеченными и напечатанными идентификатором, текстом описания и ценой каждого пакета.
Код пакета: Парижские каникулы Описание: Испытайте великолепную красоту Парижа и французскую культуру. Цена: 3000 ID пакета: Приключения на Гавайях Описание: Отправляйтесь в захватывающее приключение на гавайских пляжах! Цена: 4000 ID пакета: Бегство по-итальянски Описание: Насладитесь красотой и очарованием Италии и получите тур по итальянской кухне по системе «все включено»! Цена: 2000 ID пакета: Ретрит на Андаманских островах Описание: Испытайте красоту пляжей острова, включая подводное плавание.дайвинг и ночной каякинг через мангровые заросли. Цена: 800
Анализатор Minidom также позволяет нам перемещаться по дереву DOM от одного элемента к его родительскому элементу, его первому дочернему элементу, последнему дочернему элементу и так далее. Вы можете получить доступ к первому потомку элемента
# получить первый элемент пакета
paris_package = xml_doc.getElementsByTagName('пакет')[0]
# получить первый дочерний элемент пакета
first_child = париж_пакет.firstChild
#print(first_child)
>>
<Элемент DOM: описание по адресу 0x7f2e4800d9д0>
Имя узла: описание
Node Value: None Вы можете убедиться, что «описание» является первым дочерним элементом
Проверьте приведенный ниже пример и его вывод.
child_elements=paris_package.childNodes печать (дочерние_элементы) >> [<Элемент DOM: описание по адресу 0x7f057938e940>, <Элемент DOM: пункт назначения по адресу 0x7f057938e9d0>, <Элемент DOM: цена по адресу 0x7f057938ea60>, <Элемент DOM: продолжительность по адресу 0x7f057938eaf0>, <Элемент DOM: оплата по адресу 0x7f057938eb80>]
Подобно этому, minidom предоставляет больше способов обхода, таких как parentNode, lastChild nextSibling и т. д. Вы можете проверить все доступные функции библиотека здесь.
Но основным недостатком этого метода является дорогое использование памяти, так как весь файл загружается в память. Нецелесообразно использовать минидом для больших файлов.
Автоматизировать синтаксический анализ XML Nanonets. Начните бесплатную пробную версию сегодня. Кредитная карта не требуется.
Использование библиотеки ElementTree для анализа XML-файлов
ElementTree — это широко используемый встроенный анализатор Python, который предоставляет множество функций для чтения, обработки и изменения XML-файлов.
Этот синтаксический анализатор создает древовидную структуру для хранения данных в иерархическом формате.
Начнем с импорта библиотеки и вызова функции parse() нашего файла XML. Вы также можете предоставить входной файл в строковом формате и использовать функцию fromstring() . После того, как мы инициализируем проанализированное дерево, мы можем использовать получить root () функция для получения корневого тега, как показано ниже.
импортировать xml.etree.ElementTree как ET
дерево = ET.parse('travel_pkgs.xml')
#вызов корневого элемента
корень = дерево.getroot()
print("Корень есть",корень)
Выход:
>>
Корневой элемент Извлечен корневой тег ‘travelPackages’!
Допустим, теперь мы хотим получить доступ ко всем первым дочерним тегам корня. Мы можем использовать простой цикл for и перебирать его, печатая дочерние теги, такие как пункт назначения, цена и т.
д. Обратите внимание, что если бы мы указали значение атрибута внутри открывающего тега описания, круглые скобки не были бы пустыми. Посмотрите приведенный ниже фрагмент!
для x в корне[0]:
печать (x.tag, x.attrib)
Выход:
>>
описание {}
место назначения {}
цена {}
продолжительность {}
payment {} Кроме того, функция iter() может помочь вам найти любой интересующий элемент во всем дереве. Давайте используем это для извлечения описаний каждого пакета туров в нашем файле. Не забудьте использовать атрибут text для извлечения текста элемента.
Для x в root.iter('описание'):
печать (x.текст)
Выход:
>>
«Ощутите великолепную красоту Парижа и французскую культуру».
«Отправляйтесь в захватывающее приключение на пляжах Гавайев!»
"Побалуйте себя красотой и очарованием Италии и получите тур по итальянской кухне по системе "все включено"!"
«Насладитесь красотой пляжей острова, подводным плаванием с аквалангом и ночным каякингом через мангровые заросли.
При использовании ElementTree базовый цикл for достаточно эффективен для доступа к дочерним элементам. Посмотрим, как.
Анализ XML-файлов с помощью цикла for
Вы можете просто перебирать дочерние элементы с помощью цикла for, извлекая атрибуты, как показано ниже.
для тура в корень:
распечатать(тур.атриб)
Выход:
>>
{'id': 'Отпуск в Париже'}
{'id': 'Гавайские приключения'}
{'id': 'Побег из Италии'}
{'id': 'Andaman Island Retreat'} Для обработки сложных запросов и фильтрации ElementTee имеет метод findall() . Этот метод позволяет получить доступ ко всем дочерним элементам тега, переданным в качестве параметров. Допустим, вы хотите узнать о турпакетах стоимостью менее 4000 долларов, а также иметь EMIoption как «да». Проверьте фрагмент.
для пакета в root.findall('package'):
цена = int(package.find('price').text)
возврат = package.find('платеж/возврат').text.strip("'")
если цена < 4000 и возврат == 'да':
print(package.
attrib['id']) Мы в основном перебираем пакеты через root.findall(‘package’), а затем извлекаем цену и возмещение с помощью метод find() . После этого мы проверяем ограничения и отфильтровываем подходящие пакеты, которые напечатаны ниже.
Вывод:
>>
Отпуск в Париже
Отдых на Андаманских островах
Используя ElementTree, вы можете легко изменять и обновлять элементы и значения XML-файла, в отличие от miniDOM и SAX. Давайте проверим, как в следующем разделе.
Как изменить файлы XML с помощью ElementTree?
Допустим, пришло время рождественских каникул и агентство хочет удвоить стоимость пакета. ElementTree предоставляет set() функция, которую мы можем использовать для обновления значений элементов. В приведенном ниже коде я получил доступ к цене каждого пакета через функцию iter() и манипулировал ценами. Вы можете использовать функцию write() для записи нового XML-файла с обновленными элементами.
для цены в root.iter('price'):
новая_цена = интервал (цена.текст)*2
цена.текст = ул(новая_цена)
price.set('обновлено', 'да')
tree.write('christmas_packages.xml') Вы сможете найти выходной файл, подобный тому, что показан на изображении ниже. Если вы помните, цены на «Отпуск в Париже» и «Приключения на Гавайях» в исходном файле составляют 3000 и 4000 долларов.
Но что, если мы захотим добавить новый тег
ET.SubElement(корень[3], 'остаться')
для x в root.iter('оставаться'):
курорт = 'Частная вилла Премиум'
x.text = ул(курорт) Надеюсь, вы тоже получили результаты! Пакет также предоставляет функцию pop() , с помощью которой можно удалить атрибуты и подэлементы, если они не нужны.
Простой API для XML (SAX)
SAX — еще один синтаксический анализатор Python, который устраняет недостаток miniDOM за счет последовательного чтения документа. Он не загружает все дерево в свою память, а также позволяет отбрасывать элементы, уменьшая использование памяти.
Во-первых, давайте создадим объект парсера SAX и зарегистрируем функции обратного вызова для различных событий, которые вы хотите обрабатывать в XML-документе. Для этого я определяю собственный класс TravelPackageHandler, как показано ниже, путем подкласса ContentHandler SAX.
импорт xml.sax
# Определите собственный класс SAX ContentHandler для обработки событий
класс TravelPackageHandler (xml.sax.ContentHandler):
защита __init__(сам):
self.packages = []
self.current_package = {}
self.current_element = ""
self.current_payment = {}
def startElement (я, имя, атрибуты):
self.current_element = имя
если имя == "пакет":
self.current_package = {"id": attrs.getValue("id")}
символы определения (я, содержание):
если self.
current_element в ["описание", "назначение", "цена", "продолжительность", "вариант EMI", "возврат"]:
self.current_package[self.current_element] = content.strip()
если self.current_element == "оплата":
self.current_payment = {}
def endElement(я, имя):
если имя == "пакет":
self.current_package["платеж"] = self.current_payment
self.packages.append (self.current_package)
если имя == "оплата":
self.current_package["платеж"] = self.current_payment
def startElementNS(self, name, qname, attrs):
проходить
def endElementNS (я, имя, qname):
пройти В приведенном выше фрагменте используются методы startElement(), character(), и endElement() для извлечения данных из элементов и атрибутов XML. Когда синтаксический анализатор SAX читает документ, он запускает зарегистрированные функции обратного вызова для каждого встречающегося события. Например, если он встречает начало нового элемента, он вызывает функцию startElement(). Теперь давайте воспользуемся нашим настраиваемым обработчиком, чтобы получить различные идентификаторы пакетов, проанализировав XML-файл нашего примера.
# Создать объект парсера SAX
парсер = xml.sax.make_parser()
обработчик = TravelPackageHandler()
parser.setContentHandler(обработчик)
parser.parse ("путешествие_pckgs.xml")
для пакета в handler.packages:
print(f'Package: {package["id"]}') Output >>
Package: Paris Vacation
Package: Hawaii Adventure
Package: Italian Getaway
Package: Andaman Island Retreat
SAX can использоваться для больших файлов и потоковой передачи из-за его эффективности. Но это неудобно при работе с глубоко вложенными элементами. Что делать, если вы хотите получить доступ к любому произвольному узлу дерева? Поскольку он не поддерживает произвольный доступ, синтаксическому анализатору придется последовательно читать весь документ, чтобы получить доступ к определенному элементу.
Синхронизируйте все ваши двойные записи с Nanonets. Держите все свои счета сбалансированными, 24×7. Настройте процессы учета менее чем за 15 минут. Смотри как.
Потоковый синтаксический анализатор для XML
Это библиотека Python pulldom , которая предоставляет API потокового синтаксического анализатора с DOM-подобным интерфейсом.
Как это работает?
Обрабатывает XML-данные методом «вытягивания». То есть вы явно запрашиваете у синтаксического анализатора следующее событие (например, начальный элемент, конечный элемент, текст и т. д.) в данных XML.
Синтаксис знаком тому, что мы видели в предыдущих библиотеках. В приведенном ниже коде я демонстрирую, как импортировать библиотеку и использовать ее для печати туров продолжительностью 4 дня и более, а также обеспечить возврат средств при отмене.
из синтаксического анализа импорта xml.dom.pulldom
события = разбор ("travel_pkgs.xml")
для события, узел в событиях:
если событие == pulldom.START_ELEMENT и node.tagName == 'package':
продолжительность = int(node.getElementsByTagName('длительность')[0].
firstChild.data)
возврат = node.getElementsByTagName('refund')[0].firstChild.data.strip("'")
если продолжительность > 4 и возврат == 'да':
print(f"Пакет: {node.getAttribute('id')}")
print(f"Продолжительность: {длительность}")
print(f"Возврат: {возврат}") Вы должны получить результат вида:
Пакет: Парижские каникулы
Продолжительность: 7
Возврат: да
Пакет: Ретрит на Андаманских островах
Продолжительность: 8
Возврат: да 90 003
Проверьте результаты! Парсер pull сочетает в себе несколько функций miniDOM и SAX, что делает его относительно эффективным.
Резюме
Я уверен, что вы уже хорошо разбираетесь в различных парсерах, доступных в Python. Не менее важно знать, когда выбрать парсер, чтобы сэкономить время и ресурсы. Среди всех парсеров, которые мы видели, ElementTree обеспечивает максимальную совместимость с выражениями XPath, помогающими выполнять сложные запросы. Minidom имеет простой в использовании интерфейс и может быть выбран для работы с небольшими файлами, но он слишком медленный в случае больших файлов.
В то же время SAX используется в ситуациях, когда файл XML постоянно обновляется, как в случае машинного обучения в реальном времени.
Одной из альтернатив для анализа ваших файлов является использование инструментов автоматического анализа, таких как Nanonets. Наносети могут помочь вам извлечь данные из любого документа за считанные секунды, не написав ни одной строки кода.
O Оптимизируйте эффективность своего бизнеса, сократите расходы и ускорьте рост. Узнайте , как варианты использования Nanonets могут применяться к вашему продукту.
Разбор XML в Swift: Учебник с примерами
Поделиться
Ответить
- 0
Арджуна Скай Кок Подписаться Я инженер-программист, ютубер и писатель. Я создаю PredictSalary, SailorCoin и Pembangun.
7 минут чтения 2190 110
Хотя формат файла XML кажется устаревшим по сравнению с форматом файла JSON, XML жив. JSON может быть более популярен в веб-разработке, но у XML есть много функций, которых нет в JSON, например поддержка пространства имен, которая полезна, чтобы избежать конфликта имен для элементов и атрибутов. XML также имеет схему, которая может заставить XML-документ соответствовать определенному стандарту.
Вам не нужно искать стороннюю библиотеку для управления файлом XML с помощью Swift. В стандартной библиотеке Swift есть XMLParser для всех ваших XML-потребностей.
Перейти вперед:
- Настройка
XMLParserиXMLParserDelegate - Обработка элементов данных XML
- Обработка атрибутов элементов данных XML
- Обработка пространства имен в данных XML
- Получение текстового содержимого при разборе данных XML
- Обработка ошибок при анализе данных XML
Настройка
XMLParser и XMLParserDelegate Создайте проект Playground в XCode и назовите его XMLParsingPlayground .
Обратитесь к этой статье, чтобы узнать больше об этом шаге.
Чтобы проанализировать данные XML, необходимо преобразовать строку XML в Данные . Добавьте следующий код:
пусть xmlContent =
"""
<корень>
<статья>
Начало работы со Swift
статья>
<статья>
Как анализировать XML с помощью Rust
статья>
корень>
""";
пусть xmlData = данные (xmlContent.utf8)
В приведенном выше коде вы инициализировали экземпляр Data строкой XML. Теперь вам нужно инициализировать экземпляр XMLParser с помощью этого экземпляра Data :
пусть xmlParser = XMLParser (данные: xmlData)
XMLParser делегирует логику синтаксического анализа своему классу делегирования. Вам нужно будет реализовать этот класс, который наследует NSObject и XMLParserDelegate . Добавьте следующий код для создания класса и его экземпляра:
класс Parser1: NSObject, XMLParserDelegate {
func parserDidStartDocument(_ парсер: XMLParser) {
print("Начало документа")
print("Номер строки: \(parser.
lineNumber)")
}
func parserDidEndDocument(_ парсер: XMLParser) {
print("Конец документа")
print("Номер строки: \(parser.lineNumber)")
}
}
пусть парсер1 = парсер1()
В делегированном классе вы настроили логику, чтобы что-то делать, когда вы нажимаете начало документа и конец документа в процессе синтаксического анализа. Если вы столкнетесь с ними, вы напечатаете несколько строк и номер строки, где парсер сейчас находится. Оба метода принимают Экземпляр XMLParser в аргументах. Многие методы в делегированном классе принимают в качестве аргументов экземпляр XMLParser .
После завершения экземпляра делегирования синтаксического анализатора вы должны установить его как класс делегирования экземпляра XMLParser :
xmlParser.delegate = парсер1
Последний шаг — разобрать его:
xmlParser.parse()
Если вы скомпилировали и запустили программу, вы должны получить следующий вывод:
Начало документа Номер строки: 1 Конец документа Номер строки: 9
Код выше означает, что когда парсер встретил событие начала документа , он был в строке 1.
Затем он перешел к содержимому документа. Он прошел через элементы, но поскольку вы не реализовали методы для обработки этого, ничего не произошло. Наконец, когда он столкнулся с событием конца документа , он проинформировал нас через реализованный вами метод parserDidEndDocument .
Обработка элементов данных XML
При синтаксическом анализе XML вам необходимо реализовать методы для обработки интересующих вас узлов или событий. Если вас интересуют комментарии, вам необходимо реализовать метод, когда синтаксический анализатор встречает комментарии в данных XML.
Теперь вы хотите реализовать методы, когда синтаксический анализатор встречает такие элементы, как article и title . Метод, который вам нужно реализовать, — это метод парсера со следующей сигнатурой:
анализатор функций(
_ парсер: XMLParser,
didStartElement elementName: строка,
namespaceURI: Строка?,
квалифицированное имя qName: строка?,
атрибуты attributeDict: [String : String] = [:]
)
Создать новый делегированный класс парсера:
класс Parser2: NSObject, XMLParserDelegate {
анализатор функций(
_ парсер: XMLParser,
didStartElement elementName: строка,
namespaceURI: Строка?,
квалифицированное имя qName: строка?,
атрибуты attributeDict: [String : String] = [:]
) {
печать (имя элемента)
}
}
В новом делегированном классе вы не реализовали parserDidStartDocument и parserDidEndDocument , потому что вы сосредоточены только на разборе элементов.
Как обычно, вам нужно установить делегированный экземпляр класса нового экземпляра XMLParser и снова вызвать метод parse :
пусть парсер2 = парсер2() пусть xmlParser2 = XMLParser (данные: xmlData) xmlParser2.delegate = парсер2 xmlParser2.parse()
Скомпилируйте и запустите программу, она напечатает имена элементов:
корень статья заголовок статья заголовок
Как видите, элементов пять. Если вы хотите различать элементов заголовка , потому что их два, вам нужно добавить больше логики. Один из примеров — отследить, сколько элементов article встретилось при синтаксическом анализе.
Создать другой делегированный класс:
класс Parser3: NSObject, XMLParserDelegate {
переменная статьяNth = 0
анализатор функций(
_ парсер: XMLParser,
didStartElement elementName: строка,
namespaceURI: Строка?,
квалифицированное имя qName: строка?,
атрибуты attributeDict: [String : String] = [:]
) {
если (elementName=="статья") {
статьяNth += 1
} иначе если (elementName=="название") {
print("'\(elementName)' в номере элемента статьи \(articleNth)")
}
}
}
На этот раз вы отслеживали, сколько элементов статьи вы встретили, поэтому, когда вы встречаете элемент title , вы знаете, в каком элементе статьи вы находитесь.
Создайте новый экземпляр XMLParser и установите для делегированного класса значение Parser3 :
пусть парсер3 = парсер3() пусть xmlParser3 = XMLParser (данные: xmlData) xmlParser3.delegate = парсер3 xmlParser3.parse()
Если вы скомпилируете и запустите программу, вы должны увидеть этот вывод:
'заголовок' в элементе статьи номер 1 'заголовок' в элементе статьи номер 2
Обработка атрибутов элементов данных XML
Элементы данных XML также могут иметь атрибуты. Возможно, вы захотите запросить атрибуты. Недавно выполненный метод имеет еще один аргумент, который ссылается на атрибуты. Но сначала вам нужно создать другие XML-данные, потому что сейчас данные не имеют атрибутов:
. пусть xmlContent_attributes =
"""
<корень>
<тег статьи="быстро">
Начало работы со Swift
статья>
<тег статьи="ржавчина">
Как анализировать XML с помощью Rust
статья>
корень>
""";
пусть xmlData_attributes = данные (xmlContent_attributes.
utf8)
На этот раз вы добавили атрибуты к элементам статьи . Атрибуты id и tag .
Теперь вам нужно создать делегированный класс для обработки атрибутов:
класс Parser4: NSObject, XMLParserDelegate {
анализатор функций(
_ парсер: XMLParser,
didStartElement elementName: строка,
namespaceURI: Строка?,
квалифицированное имя qName: строка?,
атрибуты attributeDict: [String : String] = [:]
) {
for (attr_key, attr_val) в attributeDict {
print("Ключ: \(attr_key), значение: \(attr_val)")
}
}
}
Метод аналогичен ранее реализованному методу. Но на этот раз вы не проигнорировали аргумент attributeDict .
Более 200 000 разработчиков используют LogRocket для улучшения цифрового взаимодействия
Подробнее → Мы еще не закончили! Теперь вам нужно создать новый экземпляр XMLParser , который использует этот экземпляр делегированного класса:

пусть парсер4 = парсер4() пусть xmlParser4 = XMLParser (данные: xmlData_attributes) xmlParser4.delegate = парсер4 xmlParser4.parse()
Если вы скомпилировали и запустили программу, вы увидите следующие атрибуты:
Ключ: идентификатор, значение: 1 Ключ: тег, значение: swift Ключ: идентификатор, значение: 2 Ключ: тег, значение: ржавчина
Обработка пространства имен в данных XML
Теперь есть два аргумента, которые вы не рассмотрели в методе синтаксического анализатора . Это namespaceURI и qName , которые связаны друг с другом.
Во-первых, вам нужно добавить пространства имен в данные XML:
пусть xmlContent_namespace =
"""
<корневой xmlns:t="http://logrocket.com/tech" xmlns:m="http://logrocket.com/marketing">
Начало работы со Swift
Как анализировать XML с помощью Rust
корень>
""";
пусть xmlData_namespace = данные (xmlContent_namespace.
utf8)
В этих XML-данных есть два пространства имен: http://logrocket.com/tech и http://logrocket.com/marketing . Элементы внутри корневого элемента используют пространства имен. Это уже не артикул , а т:артикул или м:артикул .
t ссылается на xmlns:t , который имеет значение http://logrocket.com/tech . m относится к xmlns:m , имеющему значение http://logrocket.com/marketing .
Затем вам нужно создать делегированный класс для обработки пространства имен:
класс Parser5: NSObject, XMLParserDelegate {
анализатор функций(
_ парсер: XMLParser,
didStartElement elementName: строка,
namespaceURI: Строка?,
квалифицированное имя qName: строка?,
атрибуты attributeDict: [String : String] = [:]
) {
print("URI пространства имен: \(URI пространства имен!), полное имя: \(qName!)")
}
}
Чтобы получить URI пространства имен, например, http://logrocket., вы можете использовать
com/tech namespaceURI аргумент. Чтобы получить полное имя, например, t:article , можно использовать аргумент qName .
Следующий важный шаг. Создайте новый экземпляр XMLParser для обработки пространства имен:
пусть парсер5 = парсер5() пусть xmlParser5 = XMLParser (данные: xmlData_namespace) xmlParser5.delegate = парсер5 xmlParser5.shouldProcessNamespaces = истина xmlParser5.parse()
Прежде чем скомпилировать и запустить программу, обратите внимание на строку, которая указывает синтаксическому анализатору обрабатывать пространство имен. Чтобы включить пространство имен в данных XML, вам нужно установить shouldProcessNamespaces свойство синтаксического анализатора на true . В противном случае пространства имен будут игнорироваться.
Скомпилируйте и запустите программу. Затем вы получите URI пространства имен и полные имена:
.
URI пространства имен: полное имя: корень URI пространства имен: http://logrocket.com/tech, полное имя: t:article URI пространства имен: http://logrocket.com/tech, полное имя: t:title URI пространства имен: http://logrocket.com/marketing, полное имя: m:article URI пространства имен: http://logrocket.com/marketing, полное имя: m:title
Получение текстового содержимого при разборе данных XML
Теперь пришло время получить текстовое содержимое из данных XML. Метод, который вам нужно реализовать, — это метод парсера со следующей сигнатурой:
анализатор функций(
_ парсер: XMLParser,
строка foundCharacters: строка
)
Добавьте следующие данные XML:
пусть xmlContent_text =
"""
<корень>
<статья>
Начало работы со Swift
<опубликовано>правдаопубликовано>
статья>
<статья>
Как анализировать XML с помощью Rust
<опубликовано>ложьопубликовано>
статья>
корень>
""";
пусть xmlData_text = данные (xmlContent_text.
utf8)
Затем вам нужно реализовать делегированный класс, у которого есть метод для обработки текстового содержимого:
класс Parser6: NSObject, XMLParserDelegate {
анализатор функций(
_ парсер: XMLParser,
строка foundCharacters: строка
) {
если (string.trimmingCharacters(in: .whitespacesAndNewlines) != "") {
печать (строка)
}
}
}
Вас интересует только текстовое содержимое, содержащее несколько символов. Если бы вы не реализовали фильтр, это привело бы к большому количеству пустого текстового контента. Текстовый контекст определяется как текст между узлами элемента. Это включает в себя пустой текст между артикул элемент и заголовок элемент а также:
<артикул>
Как анализировать XML с помощью Rust
Это не просто пробелы, между статья и заголовок есть новая строка. Вот почему вы сначала обрезали его, а затем проверили, пустая это строка или нет.
Наконец, создайте экземпляр XMLParser для обработки текстового содержимого:
пусть парсер6 = парсер6() пусть xmlParser6 = XMLParser (данные: xmlData_text) xmlParser6.delegate = парсер6 xmlParser6.parse()
Если вы скомпилировали и запустили программу, вы должны получить следующее текстовое содержимое:
Начало работы со Swift истинный Как парсить XML с помощью Rust ЛОЖЬ
Обработка ошибок при анализе данных XML
Жизнь не идеальна. Иногда вы получаете несовершенные данные XML, и данные повреждены. Но не волнуйтесь! Вы можете обрабатывать ошибки с помощью метода парсера со следующей сигнатурой:
анализатор функций(
_ парсер: XMLParser,
parseErrorOccurred parseError: Ошибка
)
Но сначала вам нужно записать поврежденные данные XML:
пусть xmlContent_corrupted =
"""
<корень>
<статья>
Начало работы со Swift
статья>
<статья>
Как анализировать XML с помощью Rust
статья>
корень>
""";
пусть xmlData_corrupted = данные (xmlContent_corrupted.
utf8)
Обратите внимание, что отсутствует закрывающий заголовок тег.
Затем создайте делегированный класс для обработки ошибки:
класс Parser7: NSObject, XMLParserDelegate {
анализатор функций(
_ парсер: XMLParser,
parseErrorOccurred parseError: Ошибка
) {
печать (parseError)
}
}
Этот метод выдал аргумент parseError , содержащий информацию об ошибке. В этом случае вы напечатали саму ошибку.
Как выглядит ошибка? Вам нужно создать XMLParser экземпляр, чтобы взять этот делегированный класс:
пусть парсер7 = парсер7() пусть xmlParser7 = XMLParser (данные: xmlData_corrupted) xmlParser7.delegate = парсер7 xmlParser7.parse()
Если вы скомпилировали и запустили программу, вы должны увидеть ошибку:
Error Domain=NSXMLParserErrorDomain Code=76 "(null)" UserInfo={NSXMLParserErrorColumn=15, NSXMLParserErrorLineNumber=8, NSXMLParserErrorMessage=Открывающий и закрывающий теги не совпадают: строка заголовка 7 и статья
}
Вы получили номер строки и номер столбца, где произошла ошибка.
Вы также получили сообщение об ошибке, в котором говорилось, что открывающий и закрывающий теги не совпадают.
Заключение
В этой статье вы узнали, как анализировать XML-данные. Вы начали с создания экземпляра XMLParser . Затем вы создали делегированный класс XMLParserDelegate для обработки логики процесса синтаксического анализа. Оттуда вы обрабатывали элементы, атрибуты и текстовое содержимое. Вы также устранили ошибку в процессе синтаксического анализа и настроили синтаксический анализатор для обработки пространства имен.
Другие замечательные статьи от LogRocket:
- Не упустите момент с The Replay, кураторским информационным бюллетенем от LogRocket
- Узнайте, как Galileo компании LogRocket преодолевает шум, чтобы заблаговременно решать проблемы в вашем приложении
- Используйте useEffect React для оптимизации производительности вашего приложения
- Переключение между несколькими версиями узла
- Узнайте, как анимировать приложение React с помощью AnimXYZ
- Изучите Tauri, новую платформу для создания двоичных файлов
- Консультативные советы предназначены не только для руководителей.



read()
root = etree.fromstring(xml)
book_dict = {}
books = []
for book in root.getchildren():
for elem in book.getchildren():
if not elem.text:
text = "None"
else:
text = elem.text
print(elem.tag + " => " + text)
book_dict[elem.tag] = text
if book.tag == "book":
books.append(book_dict)
book_dict = {}
return books
if __name__ == "__main__":
parseBookXML("books.xml")
etree.ElementTree as ET
import pandas as pd
class XML2DataFrame:
def __init__(self, xml_data):
self.root = ET.XML(xml_data)
def parse_root(self, root):
return [self.parse_element(child) for child in iter(root)]
def parse_element(self, element, parsed=None):
if parsed is None:
parsed = dict()
for key in element.keys():
parsed[key] = element.attrib.get(key)
if element.text:
parsed[element.tag] = element.text
for child in list(element):
self.parse_element(child, parsed)
return parsed
def process_data(self):
structure_data = self.parse_root(self.root)
return pd.DataFrame(structure_data)
xml2df = XML2DataFrame(xml_data)
df = xml2df.process_data()
.. SWBIC DefaultSWBIC \
0 041280103 УФК по Астраханской области RU 12 414056 ... NaN NaN
1 044525597 КУ "МИЛЛЕНИУМ БАНК" (ЗАО) - ГК "АСВ" RU 45 109240 ... NaN NaN
2 044525603 КУ ЗАО "ИПОТЕК БАНК" - ГК "АСВ" RU 45 109240 ... NaN NaN
3 044525608 КУ ООО КБ "ДОРИС БАНК" - ГК "АСВ" RU 45 109240 ... NaN NaN
4 044525652 КУ КБ "ПРИСКО КАПИТАЛ БАНК", АО - ГК... RU 45 109240 ... NaN NaN
... ... ... ... .. ... ... ... ...
2368 298003187 Департамент финансов г. Якутска RU 98 677000 ... NaN NaN
2369 015354008 УФК по Оренбургской области RU 53 460014 ... NaN NaN
2370 200000099 Территориальная избирательная комисс... RU 36 443110 ... NaN NaN
2371 200001413 Территориальная избирательная комисс.
columns
Out[33]:
Index(['BIC', 'NameP', 'CntrCd', 'Rgn', 'Ind', 'Tnp', 'Nnp', 'Adr', 'DateIn', 'PtType', 'Srvcs', 'XchType', 'UID',
'ParticipantStatus', 'Account', 'RegulationAccountType', 'CK', 'AccountCBRBIC', 'AccountStatus', 'RegN', 'Rstr',
'RstrDate', 'PrntBIC', 'SWBIC', 'DefaultSWBIC', 'EnglName', 'AccRstr', 'AccRstrDate'],
dtype='object')
дайвинг и ночное плавание на байдарках по мангровым зарослям.
Как видите, атрибут и его значение обычно упоминаются внутри начального тега.
дайвинг и ночной каякинг через мангровые заросли.
Цена: 800
attrib['id'])
current_element в ["описание", "назначение", "цена", "продолжительность", "вариант EMI", "возврат"]:
self.current_package[self.current_element] = content.strip()
если self.current_element == "оплата":
self.current_payment = {}
def endElement(я, имя):
если имя == "пакет":
self.current_package["платеж"] = self.current_payment
self.packages.append (self.current_package)
если имя == "оплата":
self.current_package["платеж"] = self.current_payment
def startElementNS(self, name, qname, attrs):
проходить
def endElementNS (я, имя, qname):
пройти
firstChild.data)
возврат = node.getElementsByTagName('refund')[0].firstChild.data.strip("'")
если продолжительность > 4 и возврат == 'да':
print(f"Пакет: {node.getAttribute('id')}")
print(f"Продолжительность: {длительность}")
print(f"Возврат: {возврат}")
lineNumber)")
}
func parserDidEndDocument(_ парсер: XMLParser) {
print("Конец документа")
print("Номер строки: \(parser.lineNumber)")
}
}
пусть парсер1 = парсер1()
utf8)
utf8)
utf8)
utf8)
