C++. Сборник рецептов - [187]

Шрифт
Интервал

Проектирование парсера, использующего функции обратного вызова, имеет несколько важных преимуществ. Например, можно выполнять синтаксический анализ очень больших документов, которые не помещаются в памяти. Кроме того, это может сэкономить процессорное время, потому что не надо выполнять многочисленные операции динамического выделения памяти, необходимые для конструирования узлов внутреннего представления документа XML, и потому что пользователь может создавать свое представление данных документа непосредственно, а не во время прохождения дерева документа, как я это делал в примере 14.3.

Пример 14.8 достаточно простой: я получаю парсер SAX2, регистрирую >ContentHandler и >ErrorHandler, анализирую документ >animals.xml и печатаю список объектов >Animal, заполненный обработчиком >ContentHandler. Следует отметить два интересных момента: во-первых, функция >XMLReaderFactory::createXMLReader() возвращает экземпляр >SAX2XMLReader, память под который выделяется динамически и должна освобождаться пользователем в явной форме; для этой цели я использую >std::auto_ptr, чтобы обеспечить удаление парсера даже в случае возникновения исключения. Во-вторых, среда Xerces должна быть инициализирована, используя >xercesc::XMLPlatformUtils::Initialize(), и очищена при помощи >xercesc::XMLPlatformUtils::Terminate(). Я инкапсулирую эту инициализацию и очистку в классе >XercesInitializer, который вызывает >XMLPlatformUtils::Initialize() в своем конструкторе и >XMLPlatformUtils::Terminate() в своем деструкторе. Это гарантирует вызов >Terminate(), даже если выбрасывается исключение. Это пример метода захвата ресурса при инициализации (Resource Acquisition Is Initialization — RAII), который был продемонстрирован в примере 8.3.

Давайте теперь посмотрим, как класс >CircusContentHandler из примера 14.6 реализует интерфейс SAX2 >ContentHandler. Парсер SAX 2 вызывает метод >startElement() при каждой встрече открывающего тега элемента. Если элементу приписано пространство имен, первый аргумент, >uri, будет содержать URI пространства имен элемента, а второй аргумент, >localname, будет содержать ту часть имени тега элемента, которая идет за префиксом пространства имен. Если элемент не имеет пространства имен, эти два аргумента будут иметь пустые строки. Третий аргумент содержит имя тега элемента, если с элементом не связывается пространство имен; в противном случае этот аргумент может содержать либо имя тега элемента в том виде, в каком оно встречается в анализируемом документе, либо пустую строку. Четвертым аргументом является экземпляр класса >Attributes, представляющего набор атрибутов элемента.

В приведенной в примере 14.6 реализации >startElement() я игнорирую элемент >animalList. Когда я встречаю элемент >animal, я добавляю новый объект >Animal в список животных; назовем его текущим объектом >Animal и предоставим право установки свойств этого >Animal обработчикам других элементов. Когда я встречаю элемент >veterinarian или >trainer, я вызываю функцию >contactFromAttributes для конструирования экземпляра >Contact из набора атрибутов элемента и затем использую этот объект >Contact для установки свойств ветеринара и дрессировщика в текущем элементе >Animal. Когда я встречаю элемент name, >species или >dateOfBirth, я очищаю переменную-член >currentText_, которая будет использоваться для хранения текстового содержимого этого элемента.

Парсер SAX2 вызывает метод >characters() для передачи символьных данных, содержащихся в элементе. Этот парсер может передавать символы элемента с помощью нескольких вызовов метода >characters(); пока не встретится закрывающий тег, нельзя быть уверенным в передаче всех символьных данных. Поэтому в реализации >characters() я просто добавляю полученные символы в конец переменной-члена >currentText_, которую я использую для установки клички, вида и даты рождения >Animal сразу после встречи закрывающего тега для элемента >name, >species или >dateOfBirth.

Парсер SAX2 вызывает метод >endElement() при выходе из каждого элемента. Его аргументы имеют тот же смысл, который имеют первые три аргумента метода >startElement(). В реализации >endElement(), приведенной в примере 14.6, я игнорирую все элементы, отличные от >name, >species и >dateOfBirth. Когда происходит обратный вызов, соответствующий одному из этих элементов, сигнализирующий о сделанном только что выходе парсера из элемента, я использую символьные данные, сохраненные в >currentText_ для установки клички, вида и даты рождения текущего объекта >Animal.

Несколько важных особенностей SAX2 не проиллюстрировано в примерах 14.6, 14.7 и 14.8. Например, класс >SAX2XMLReader содержит перегрузку метода >parse(), которая принимает в качестве аргумента экземпляр >xercesc::InputSource вместо строки в С-стиле. >InputSource является абстрактным классом, инкапсулирующим источник символьных данных; конкретные его подклассы, в том числе >xercesc::MemBufInputSource и >xercesc::URLInputSource, позволяют парсеру SAX2 анализировать документ XML, который находится не в локальной файловой системе.

Более того, интерфейс >ContentHandler содержит много дополнительных методов, например


Рекомендуем почитать
Изучаем Java EE 7

Java Enterprise Edition (Java EE) остается одной из ведущих технологий и платформ на основе Java. Данная книга представляет собой логичное пошаговое руководство, в котором подробно описаны многие спецификации и эталонные реализации Java EE 7. Работа с ними продемонстрирована на практических примерах. В этом фундаментальном издании также используется новейшая версия инструмента GlassFish, предназначенного для развертывания и администрирования примеров кода. Книга написана ведущим специалистом по обработке запросов на спецификацию Java EE, членом наблюдательного совета организации Java Community Process (JCP)


Pro Git

Разработчику часто требуется много сторонних инструментов, чтобы создавать и поддерживать проект. Система Git — один из таких инструментов и используется для контроля промежуточных версий вашего приложения, позволяя вам исправлять ошибки, откатывать к старой версии, разрабатывать проект в команде и сливать его потом. В книге вы узнаете об основах работы с Git: установка, ключевые команды, gitHub и многое другое.В книге рассматриваются следующие темы:основы Git;ветвление в Git;Git на сервере;распределённый Git;GitHub;инструменты Git;настройка Git;Git и другие системы контроля версий.


Java 7

Рассмотрено все необходимое для разработки, компиляции, отладки и запуска приложений Java. Изложены практические приемы использования как традиционных, так и новейших конструкций объектно-ориентированного языка Java, графической библиотеки классов Swing, расширенной библиотеки Java 2D, работа со звуком, печать, способы русификации программ. Приведено полное описание нововведений Java SE 7: двоичная запись чисел, строковые варианты разветвлений, "ромбовидный оператор", NIO2, новые средства многопоточности и др.


Фундаментальные алгоритмы и структуры данных в Delphi

Книга "Фундаментальные алгоритмы и структуры данных в Delphi" представляет собой уникальное учебное и справочное пособие по наиболее распространенным алгоритмам манипулирования данными, которые зарекомендовали себя как надежные и проверенные многими поколениями программистов. По данным журнала "Delphi Informant" за 2002 год, эта книга была признана сообществом разработчиков прикладных приложений на Delphi как «самая лучшая книга по практическому применению всех версий Delphi».В книге подробно рассматриваются базовые понятия алгоритмов и основополагающие структуры данных, алгоритмы сортировки, поиска, хеширования, синтаксического разбора, сжатия данных, а также многие другие темы, тесно связанные с прикладным программированием.


Питон — модули, пакеты, классы, экземпляры

Python - объектно-ориентированный язык сверхвысокого уровня. Python, в отличии от Java, не требует исключительно объектной ориентированности, но классы в Python так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.


Как пасти котов. Наставление для программистов, руководящих другими программистами

«Как пасти котов» – это книга о лидерстве и руководстве, о том, как первое совмещать со вторым. Это, если хотите, словарь трудных случаев управления IT-проектами. Программист подобен кошке, которая гуляет сама по себе. Так уж исторически сложилось. Именно поэтому так непросто быть руководителем команды разработчиков. Даже если вы еще месяц назад были блестящим и дисциплинированным программистом и вдруг оказались в роли менеджера, вряд ли вы знаете, с чего надо начать, какой выбрать стиль руководства, как нанимать и увольнять сотрудников, проводить совещания, добиваться своевременного выполнения задач.