XML для розробників Perl Частина 2
Огляд парсингу дерева та парсингу, керованого подіями

Серія контенту:
Цей контент є частиною # із серії # статей: XML для розробників Perl
Цей контент є частиною серії: XML для розробників Perl
Слідкуйте за виходом нових статей цієї серії.
Для дуже великої кількості Perl-додатків як інструмент для роботи з XML достатньо XML::Simple , який розглядався в частині 1 цієї серії статей (див. Ресурси). XML::Simple вміє перетворювати вхідні XML-файли в структури даних Perl, що легко обробляються, і назад перетворювати такі структури даних в XML. Однак треба пам'ятати, що цей метод працює не завжди.
XML::Simple - не найкраще рішення, коли вам потрібно створити подання XML-документа в пам'яті, а потім виконати пошук по ньому або перетворити складним і непередбачуваним чином. У таких ситуаціях застосовується парсинг дерева. Якщо XML-документ не міститься в пам'яті або є потоком невідомої довжини, використовувати XML::Simple також не можна. І тут слід використовувати парсер, керований подіями. Парсери, керовані подіями, спочатку здаються дещо незвичайними, але коли ви почнете використовувати цей тип парсингу, SAX може стати вашим улюбленим інструментом.
Початок роботи
Щоб йти за викладом у статті, вам знадобиться кілька модулів Perl з відкритим вихідним кодом. Ви можете отримати їх одним із двох способів: якщо у вас Windows, використовуйте ppm; якщо UNIX® або Linux™ - зверніться до CPAN (див. Ресурси). Якщо ви не знаєте про ці архіви, прочитайте про них у частині 1 цієї серії статей.
У лістингу 1 показано, як можна керувати модулями наUNIX/Linux. Звичайно, краще працювати як користувач root, щоб модулі були доступні всім користувачам в системі. У цих модулів є залежності, деякі з яких можуть бути відсутніми у вашій системі. Якщо cpan налаштований правильно (follow=yes), залежність буде встановлено автоматично.
Лістинг 1. Отримання модулів, що використовуються в цій статті за допомогою CPAN
Як видно з лістингу 2, Windows це навіть простіше. Знову ж таки встановлювати все краще з правами адміністратора.
Лістинг 2. Отримання модулів PPM
Парсинг дерева
Для багатьох програмістів може виявитися дуже зручним відображати XML у вигляді деревоподібної структури. Таке уявлення XML було формалізоване як об'єктна модель документа (Document Object Model – DOM), і використовується вже багато років; DOM Level 3 вийшла у 2002 році.
DOM представляє XML-документ як дерево двонаправлених вузлів, де перший нащадок на кожному рівні приєднується до свого батька та паралельно до братів. У дереві визначено великий набір функцій, реалізованих усіма основними мовами програмування.
Посилання на специфікацію DOM і докладніші введення в специфікацію DOM, XPath та суміжні протоколи ви знайдете в розділі Ресурси.
Багато модуль Perl можуть розбирати XML-документи в дерева DOM. Одним із найкращих є XML::LibXML Петра Паяса (див. Ресурси). Він є оболонкою для libxml2 проекту Gnome - багатофункціонального пакета, що включає парсер DOM, часткову реалізацію XPath та реалізацію SAX2 (описується нижче).
У лістингу 3 показаний файл, з яким ви працювали в частині 1 (див. Ресурси), де його розбирали з XML::Simple , змінювали подання на структуру даних Perl і після цього використовували XML::Simple , щоб перетворити його назадXML у текстовій формі.
Лістинг 3. Зоомагазин Розі, pets.xml
Цей файл легко розібрати за допомогою XML::LibXML (див. листинг 4 і результат програми в лістингу 5). Проста команда $parser->parse_file створює деревоподібну структуру XML для моделі DOM. Ми визначаємо просту підпрограму на Perl для додавання поделемента до вузла в дереві і потім використовуємо це для створення піддерева, що представляє окрему тварину. Далі ми за допомогою підпрограми addPet() додаємо до нашого асортименту пару нових тварин: піщанку та хом'яка.
Лістинг 4. Розбір асортименту магазину Розі за допомогою XML :: LibXML
Щоб показати свою майстерність у DOM, ми отримуємо список посилань на вузли цін у дереві і збільшуємо кожну ціну на 20%. Оскільки текст (ціна) всередині елемента може бути представлена більш ніж одним текстовим вузлом, найпростіший спосіб зробити це – витягти ціну з вузла, збільшити та переформатувати її і після цього повністю замінити початковий вузол замість того, щоб змінювати його на місці. Це, звичайно, значно складніше, ніж таке перетворення в коді Perl в першій частині.
Лістинг 5. Упорядковані вихідні дані парсера дерева
Це традиційний підхід, коли ви працюєте з XML, використовуючи стандартний дерево парсер. Вихідний варіант у вигляді тексту в форматі XML перетворюється на дерево DOM. Щоб переміщатися по дереву та обходити вузли, можна йти за зв'язками від одного вузла до іншого або використовувати команди типу XPath для отримання наборів посилань на вузли. Далі вузли можна редагувати за допомогою цих посилань. Після цього можна записати дерево на диск або просто роздрукувати.
Для невеликих і нескладних дерев використання XML::Simple зазвичай дешевше у плані витрат на розробку. Однак якщо XML-документ трохи складний, наявність таких методів як getElementsByTagName , схиляє чашу ваг на бік XML::LibXML . Хоча цей метод може працювати повільніше, ніж добре зроблений Perl і XML::Simple, він не вимагає написання та налагодження коду.
Парсинг на основі подій: SAX
Простий програмний інтерфейс програми для XML (Simple API for XML - SAX) підходить до питання парсингу зовсім інакше. Цей метод спочатку передбачає вищі непродуктивні витрати. SAX представляє документ як серію подій і вимагає, щоб ви вказали, як на кожне з них реагувати. До таких подій входять start_document , end_document , start_element , end_element і символи . Повний список наведено у документі "Зв'язування Perl SAX 2.1" у розділі Ресурси. Для будь-якого документа програміст Perl повинен надати набір методів-обробників, по одному для кожного типу подій.
Хоча цей підхід може здаватися стомлюючим і вимагатиме багаторазових повторень, насправді він ефективно працює, що ви незабаром побачите.
Хоча XML::LibXML і має інтерфейс SAX, він залишається парсером DOM, отже, зчитує весь документ на згадку і потім надає йому інтерфейс, орієнтований на події. Найчастіше це може бути зручно, проте він не працює з документами, які не містяться в пам'яті або є потоками XML, як Jabber/XMPP. Тому ми використовуватимемо XML::SAX::ExpatXS . Цей модуль є оболонкою для випробуваного парсера expat, написаного Джеймсом Кларком, та працює дуже надійно та швидко.
Припустимо, що ми маємо новий зоомагазин, схожий на той, що був розглянутий у частині 1. У лістингу 6 представлена частина інвентарної книги магазину.
Лістинг 6. Великий зоомагазин Ліззі, pets2.xml
Щоб розібрати цей файл за допомогою SAX2, нам потрібно щось для обробки подій, породжених парсером. Найпростіший обробник подій – це програма запису, яка виводить якийсь текст для кожної події. Код у лістингу 7 розбирає наш новий XML.
Лістинг 7. Розбір pets2.xml за допомогою SAX
Після цього XML видає результат, показаний у лістингу 8.
Лістинг 8. Результати парсера SAX
Декілька моментів, на які слід звертати увагу, використовуючи ExpatXS:
- Переконайтеся, що всі ваші інструментальні засоби - це SAX або SAX2: не намагайтеся використовувати їх разом. Якщо ви використовуєте XML::Handler::YAWriter замість XML::SAX::Writer у лістингу 7, то ви не отримуватимете жодних повідомлень про помилку, але результатом буде здебільшого сміття. Оскільки ExpatXS - це парсер SAX2, з ним потрібно використовувати записуючу програму SAX2.
- Щоб перевірити парсер на помилки, покладіть парсер в оболонку eval і перевірте $@, а не $! .
- Перш ніж використовувати оброблювачі, їх потрібно створити. Важливо розуміти, що хоча з погляду програміста SAX-парсер є конвеєром (це питання докладніше розглядається нижче), ), що рухається зліва направо, ініціалізація проводиться справа наліво. Тобто конвеєр виглядає як P> W, тому ініціалізувати потрібно у зворотному порядку: спочатку W, потім P.
Драйвери та фільтри
Саме тут входить у гру SAX. SAX визначає потік подій: парсер створює послідовність подій і передає кожну з них обробнику. Уявіть абстрактний модуль, який може працювати як парсер та/або як обробник. Як і парсер, він може створювати події SAX. Але він також є обробником, який можевзаємодіяти з будь-якою стандартною подією SAX, просто "переодягнувши капелюх"; потім він може взяти роль парсера та відправити подію наступному обробнику. Тобто він визначає набір за замовчуванням методів, які тільки передають події. Модуль, що обробляє ці методи, - це XML::SAX::Base .
Більше того, цей підхід можна застосувати на обох кінцях каналу. На одному кінці каналу генератором є парсер SAX2, який приймає XML-документ та створює події. Насправді генератор може бути будь-яке джерело подій SAX. Наприклад, можна створити модуль, який зчитує таблицю в базі даних і виводить потік подій SAX. (Це реалізовано в XML::Generator::DBI .)
Інший кінець каналу зазвичай отримує події SAX та створює документ. XML::SAX::Writer якраз це робить. Однак обробник може так само вводити інформацію до бази даних ( XML::SAX::DBI ).
Все це дає дві великі переваги. По-перше, це стимулює створення обробників SAX, які виконують прості перетворення потоку подій. Це спрацювало; вже зараз існує сотні модулів Perl з відкритим кодом, що реалізують зв'язування SAX 2.1 (див. ресурси). По-друге, це означає, що розробникам достатньо створити обробники, які забезпечують той мінімум функціональних можливостей, який потрібен для вирішення конкретного завдання, але відсутній у існуючих обробниках. Обидві переваги фактично замінюють дорогі часи програмістів замінюють дешевими машинними ресурсами.
Розробка обробників за допомогою XML::SAX::Base Кіпа Хемптона складається з двох простих етапів. По-перше, обробник має розширити базовий клас. По-друге, якщо є потреба, програміст повинен перевизначити базові методи. При цьому можна або скасувати подію, або викликати метод,перевизначений у базовому класі. Важливо, щоб обробник викликав методи суперкласу, а не методи в перевизначальному модулі (див. листинг 9).
Лістинг 9. Використання XML::SAX::Base
Висновок
У цій статті (другий із трьох у серії) я представив короткий огляд дуже складного світу парсингу XML.
Спочатку я показав, як перетворювати XML-документ на дерево об'єктів у пам'яті. Спочатку більшість програмістів вважають цей підхід більш природним, і це справді у багатьох відношеннях зручніше за умови, що дані вміщатимуться в пам'яті.
Після цього я представив SAX і парсинг на основі подій - метод, який вам слід застосовувати у випадку, якщо ваш документ XML занадто великий або є безперервним потоком. З'ясовується, що інструментальні засоби, розроблені для роботи в таких умовах, ведуть до абсолютно іншого стилю програмування, дуже плідного конвеєру SAX.
З наступної статті серії ви дізнаєтеся, як можна використовувати обидва ці підходи, DOM-і SAX-парсинг, в більш складних додатках.