Саммерфилд - Программирование на Python 3 (1077331), страница 82
Текст из файла (страница 82)
Работа с файлами Получив дерево элементов, можно приступать к выполнению итераций по всем элементам <!пс!Оепт> с использованием метода хв1. етгее. Е1евептТгее. Г! 00з11( ). Информация о каждом инциденте возвращается в виде объекта хв1, е! гее, Е)евепт. Здесь используется та же методика обработки атрибутов элемента, что и в разделе с описанием метода тврогт техт гезех(), — сначала все значения сохраняются в словаре бата, а затем выполняется преобразование таких данных, как даты, числа и логические значения, в соответствующие типы данных.
Для извлечения элементов <а! г рог!> и <паггаттзе> и чтения их атрибутов техт используется метод хв1. етгее. Е1евеп!. Г!00(). Если текстовый элемент не содержит текст, его атрибут техт будет иметь значение ))опе, поэтому нам необходимо учитывать это обстоятельство при чтении текстового элемента комментария, который может оказаться пустым. Во всех случаях возвращаемые значения атрибутов и текст не содержат экранированных последовательностей ХМЬ, потому что они автоматически преобразуются в соответствующие символы. При использовании парсеров ХМЬ для обработки данных об авиационных инцидентах, как и любых других парсеров, будут возбуждаться исключения: в случае отсутствия элементов с названием аэропорта или с комментарием, в случае ошибки при выполнении какого-либо преобразования или при выходе любого числового значения за границы допустимого диапазона — этим гарантируется, что ошибочные данные будут приводить к прекращению анализа файла и к выводу сообщения об ошибке.
Программный код в конце метода, создающий и сохраняющий инциденты, а также программный код обработки исключений остался тем же, что мы уже видели ранее, ООМ (0осител1 ОЬ1ес1 Моде! — объектная модель документа) Модель 1)ОМ вЂ” это стандартный АР1 представления и манипулирования документами ХМЬ в памяти. Программный код создания и записи 1)ОМ в файл и анализа файла ХМЬ с применением модели 1)ОМ по своей структуре близко напоминает программный код, работающий с деревом элементов, только немного длиннее. Мы рассмотрим метод ехрогт хв1 0ов(), разделив его на две части.
Работа этого метода делится на два этапа: сначала создается дерево 1)ОМ, отражающее данные об инцидентах, а потом оно записывается в файл. Как и в случае с деревом элементов, существуют программы, которые используют дерево 1)ОМ в качестве основной структуры для хранения своих данных, и в этой ситуации существующие данные просто записываются в файл, минуя первый этап. Сет ехрогт хв! Сов(эе!Г. Гт1епаве): пов = хв1.сов,в!птссв.цет00И!вр!евешаттоп() тгее = сов.сгеатероспвепт(моле, "тле!сел!э", лопе) Запись и синтаксический анализ файлов ХМЬ 369 гоос = сгее.босовепсе1еаепс гог 1пссбепс 1п эе1г.ча1оее(): е1евепс = сгее.сгеасее1еаепс("Спс1бепс") Гаг аССг!Ьотс, ча1пе 1п ( ("герогС !б", спс!бепт.герогт 1б), (" басе", шс1бепс.басе.сэогогвас()), ("асгсгагс !б", 1пссбепс.асгсгагс Сб), ("а!гога(с суре", Спс1бепс.а1гсгагс суре), ("р11ос регсепс Ьоогэ оп Суре", эсг(1пс1бепс.р!1ос регсеы почте оп туре)), ("р11ос Соса1 Посте", есг(спс1бепс.рс1ос соса1 ьооге)), ("в!батс", эсг(спс(спссбепс.в!ба!с)))): е1еаепс.эесяссг1ьосе(ассгсьосе, ча1ье) Гог паве, Сехт !и (("а1грогс", !пошел!.а1грогс), ("паггас1че", спссбепс.паггас1че)): сехс е!евеш = сгее.сгеасетехсиобе(секс) паве е!евепс = сгее.сгеасее1евепс(паве) паве е1евепс.аррепбсьс1б(секс е1еаепс) е1евепт.аррепбСЬС1б(паве е1евепс) гооС аррепбСЬ!1б(е1евепс) Метод начинается с того, что получает реализацию РОМ.
По умолчанию реализация предоставляется парсером ехра С. Модуль ха1. сов. в1п1- боа предоставляет более простую и более легковесную реализацию 1)ОМ по сравнению с той, что предоставляется модулем ха1. бов, хотя и использует объекты, которые определяются в модуле ха1. бов. После получения реализации 1)ОМ можно приступать к созданию документа. Первый аргумент метода ха1.боа.00И1ар1евепсас(оп.сгеасе0осоаепс()— это Е)В1 пространства имен, но в нашем случае он не требуется, поэтому мы передаем значение Нэпе. Второй аргумент — это квалифицированное имя (имя тега корневого элемента) и третий аргумент — это тип документа, в нем мы также передаем значение йопе, так как у нас отсутствует тип документа.
Создав дерево, представляющее документ, мы получаем корневой элемент и в цикле заполняем его информацией об инцидентах. Для каждого инцидента создается элемент <1пссбепС>, а для создания каждого атрибута этого элемента вызывается метод ее!Асс гСЬосе(), которому передаются имя атрибута и значение. Так же как и в случае с деревом элементов, нам не нужно беспокоиться об экранировании символов «ос», «<» и «>» (так же, как и о кавычках в значениях атрибутов). Для текстовых данных с названием аэропорта и комментариями необходимо создать текстовые элементы, которые будут хранить сам текст, и обычные элементы (с соответствующим именем тега), которые будут играть роль родительских элементов, после чего обычные элементы (и содержащиеся в нем текстовые элементы) добавляются в текущий элемент <1пссбепс>. Как только элемент с информацией об инциденте будет заполнен, он добавляется в корневой элемент. 370 Глаза 7. Работа с файлами тп = лопе 1гу: ТП = орел(тыепвве, "и", епсод(пд="от(8") тгее.иг1(ехмц ТП, ЕПСОдвпд="ОТР-8") гетогп Тгое Импортирование документа в виде дерева РОМ напоминает импортирование в дерево элементов, но, как и при экспортировании, для реализации импортирования требуется больший объем программного кода.
Мы рассмотрим функцию тмрогт хв1 дав(), разделив ее на три части, и начнем со строки с инструкцией деу и определения вложенной функциидет Техт(). де( тврогт хи1 дои(ве1(, 111епаэе); де( дет техт(поде 11вт): техт = [) тог поде 1п поде 11вт: 1( поде.подеТуре == поде. ТЕХТ КООЕ: техт.вррепд(паде.дота) гетогп "".)о(п(техт).втг)р() Функция де( техт() выполняет обход списка узлов (то есть дочерних узлов заданного узла) и из каждого текстового узла извлекает его текст и добавляет в конец списка текстов. В конце функция возвращает весь извлеченный текст, объединенный в одну строку, попутно удалив пробельные символы в начале и в конце строки.
тгу: дои = хм1.дов.втптдом.рагве(111опаие) ехсерт (ЕпувгопвептЕггог, хи1,рвгвегв.ехрат,Ехра(Еггог) ав егг: рг)ш("(О): 1ирогт еггог; (т)Г,тогиат( ов.рвто.оавепаие(вув.агду(О)), егг)) гетогп Еа1ве Преобразование содержимого файла ХМ1 в дерево РОМ выполняется достаточно просто, потому что модуль всю основную работу берет на себя, но мы должны быть готовы обработать ошибки парсера ехрат, потому что этот парсер ХМ1, как и в случае с деревом элементов, по умолчанию используется классами 17ОМ. ве1(.с1еаг() гог е1овопт 1п дов.дете1еиептвдутадиаие("1пстдопт"): а Кодировки символов в файлах ХМЦ стр. 366 Мы опустили блоки ехсерт и т1па11у, так как они ничем не отличаются от тех, что мы уже видели.
Этот фрагмент наглядно демонстрирует различия между строками с именами кодировок, используемыми при работе со встроенной функцией орел(), и строками с именами кодировок, используемыми для файлов ХМЬ, о чем уже говорилось выше. Запись и синтаксический анализ файлов ХМь 371 Сгу: баса = () тот а1сг1ьисе сп ("герогс Сб", "басе", "а1гсгат1 1б", "асгсгатс суре", "рс1ос регсепс поигв оп Суре", "рс1ЬС 1оса1 Поигв", "в1ба1г"): ба1а[ас1гсьисе] = е1еаеп1.десА11г1ьи1е(ас1ыьисе) баса[ "басе" ] = ба1еСсве.басе11ве.в1гр11ае( баса[ "ба1е" ], "%у-%в-%б" ) .
ба1е() баСа[ "рс1о1 регсепт Поигв оп Суре" ] = ( 11оа1(баса[ "р11ос регсепс поцгв оп суре" ])) баСа["рыос СоСа1 Поигв"] = СпС( бата["рс1о1 Соса1 Поигв"]) ба1а["асбасг"] = ьоо1(спс(баса["ппба1г"])) асгрогс = е1евеп1,цесе1евеп1вВутадйаае("а1грогс")[О] баса["а!грот!"] = дес сех1(асгрогс.сьс1бйобев) паггатсне = е1еаепс.цеСЕ1еаепсвВуТадйаве( "пагга1сне")[О) баса["паггассие"] = дес секс(паггассце.сп11бйобав) спспбепС = 1пс1бепс( "ба1а) ве1([тпссбепс.герогс 1б] = 1псшепс ехсер1 (Уа1иеЕггог, СоайирЕггог, 1пспбепсЕггог) ав егг: рг1пс("(О): ппрогс еггог: (т)".Соппас( ов.раСП.Ьавепаае(вув.аг9ч[0]), егг)) гесцгп Ра1ве гесцгп Тгце о Локальные функцнн, стр.
409 ветствующие ится сообще- После создания дерева ]ЗОМ производится очистка словаря с инцидентами и выполняются итерации по всем тегам <спс! беп1>. Из каждого тега инцидента извлекаются его атрибуты, и затем даты, числа и логические значения преобразовываются в соответствующие типы данных тем же способом, который применялся при работе с деревом элементов. Единственное существенное отличие между деревом РОМ и деревом элементов состоит атом, как обрабатываются текстовые узлы.
Сначала с помощью метода хв1. бов. Е1евепс. цеСЕ1евепсвВуТадйаве() извлекаются дочерние элементы с заданными именами тегов, в данном случае это <аз грог1> и <пагга11ие>, которые, как мы знаем, всегда присутствуют в единственном экземпляре, поэтому мы извлекаем первый [и только первый) дочерний элемент каждого из этих двух типов. Затем с помощью вложенной функции выполняются итерации по всем дочерним узлам этих тегов, чтобы извлечь текст, находящийся в них. Как обычно, если возникают какие-либо ошибки, соот исключения перехватываются, для пользователя вывод ние и вызывающей программе возвращается Ра1ве. Глаза?.
Работа с файлами Различия между подходами с использованием БОМ и дерева элементов невелики, и, поскольку в обоих случаях в конечном итоге используется парсер ехрат, оба они обладают неплохой производительностью. Запись файла ХМЕ вручную Запись в файл уже существующего дерева элементов или дерева РОМ может быть реализована единственным вызовом метода. Но если данные еще не представлены в какой-либо из этих форм, то сначала будет необходимо создать дерево элементов или дерево БОМ, хотя иногда может оказаться гораздо удобнее просто записать данные в файл, минуя этот этап. При создании файлов ХМЬ, чтобы получить правильно оформленный документ ХМЬ, необходимо гарантировать корректное экранирование служебных символов в тексте и в значениях атрибутов. Ниже приводится программный код метода ехрогт ха1 аапоа1(), выполняющий запись данных об инцидентах в файл ХМ1л бе( ехрогт ха1 аапча1(ве1(, тт1епаае): тп = зобе тгу; гп = преп(гт1епаае, "и", епсоб!по="от(8") гп.иг!те('<?ха1 чегыоп="1.0" епсоб!псх"ОТЕ-8"?>1п') Го.чг!те("<тпс!беата>1п") тог 1псюепт !и ве1Ь ча1чев(): тп.чг!те('<!пс!беат герогт !б=(герогг 1б) 'бате="(О.бате!в)" 'а!гога(т !б=(а!гога(! тб) ' 'а!гсгатт туре=(а!гсгатт туре) 'р11о! регсепт Поогв оп туре=' '"(О.р>1от регсепт Поогв оп туре)" 'р!1от тота1 поогв="(О.р11от тота1 паств)" 'а!ба!г="(О.а!ба!г:б)">1п' '<а!грог!>(а!грот()</а!грогт>1п' '<паггаттче>1п(паггаттче)1п</паггаттче>тп' '</!по!беат>1п'.(огаат(!пс!беат, герогт !б=ха1.вах.вахе!>1в.оиотеаттг( тпс1бепт.