Точнее и надежнее извлекать данные позволяют более полноценные инструменты анализа XML, имеющиеся в языке Python. Так, в примере 19.10 представлена реализация процедуры анализа на основе модели SAX: представленный класс реализует методы обратного вызова, которые будут вызываться в процессе анализа, а программный код на верхнем уровне создает и запускает парсер.
Пример 19.10. PP4E\Lang\Xml\saxbook.py
Анализ XML: SAX — это прикладной интерфейс на основе методов обратного вызова, перехватывающих события, возникающие в процессе разбора документа import xml.sax, xml.sax.handler, pprint
class BookHandler(xml.sax.handler.ContentHandler):
def __init__(self):
self.inTitle = False # обрабатывает события парсера XML
self.mapping = {} # модель конечного автомата
def startElement(self, name, attributes):
if name == "book": # если встречен открывающий тег book,
self.buffer = "" # сохранить ISBN в ключе словаря
self.isbn = attributes["isbn"]
elif name == "title": # если встречен открывающий тег title,
self.inTitle = True # установить флаг нахождения в теге title
def characters(self, data):
if self.inTitle: # вызывается при получении текста из тега
self.buffer += data # если тег title, добавить текст в буфер
def endElement(self, name):
if name == "title":
self.inTitle = False # закрывающий тег title
self.mapping[self.isbn] = self.buffer # сохранить текст в словаре
parser = xml.sax.make_parser()
handler = BookHandler()
parser.setContentHandler(handler)
parser.parse(‘books.xml’)
pprint.pprint(handler.mapping)
Модель SAX является наиболее эффективной, но малопонятной на первый взгляд, потому что класс должен запоминать, анализ какого участка выполняется в текущий момент. Например, когда обнаруживается открывающий тег title, мы устанавливаем флаг состояния и инициализируем буфер — при обнаружении каждого символа внутри тега title мы добавляем его в буфер, пока не будет встречен закрывающий тег title. В результате содержимое тега title сохраняется в виде строки. Сама модель очень проста, но управлять ею иногда бывает очень сложно. Например, когда могут встречаться произвольно вложенные теги, информацию о состоянии, возвращаемую методами, вызываемыми при обработке вложенных тегов, может потребоваться сохранять в стеке.
Перед началом синтаксического анализа мы создаем объект парсера parser, устанавливаем экземпляр нашего класса как обработчик событий и запускаем анализ. По мере просмотра содержимого файла XML при встрече различных компонентов автоматически будут вызываться методы нашего класса. По завершении анализа мы снова используем модуль Python pprint для вывода результатов — объект mapping словаря находится в экземпляре обработчика. Результат получился практически точно такой же, но обратите внимание, что мнемоника, обозначающая символ «&», на этот раз была корректно преобразована — парсер SAX действительно выполняет анализ XML, а не отыскивает совпадения в тексте:
C:\…\PP4E\Lang\Xml> python saxbook.py |
|
{‘0-596-00128-2’ |
: ‘Python & XML’, |
‘0-596-00797-3’ |
: ‘Python Cookbook, 2nd Edition’, |
‘0-596-10046-9’ |
: ‘Python in a Nutshell, 2nd Edition’, |
‘0-596-15806-8’ |
: ‘Learning Python, 4th Edition’, |
‘0-596-15808-4’ |
: ‘Python Pocket Reference, 4th Edition |
‘0-596-15810-6’ |
: ‘Programming Python, 4th Edition’} |
Использованная литература:
Марк Лутц — Программирование на Python, 4-е издание, II том, 2011