CFA LogoCFA Logo Computer
Новости Статьи Магазин Драйвера Контакты
Новости
RSS канал новостей
В конце марта компания ASRock анонсировала фирменную линейку графических ускорителей Phantom Gaming. ...
Компания Huawei продолжает заниматься расширением фирменной линейки смартфонов Y Series. Очередное ...
Компания Antec в своем очередном пресс-релизе анонсировала поставки фирменной серии блоков питания ...
Компания Thermalright отчиталась о готовности нового высокопроизводительного процессорного кулера ...
Компания Biostar сообщает в официальном пресс-релизе о готовности флагманской материнской платы ...
Самое интересное
Программаторы 25 SPI FLASH Адаптеры Optibay HDD Caddy Драйвера nVidia GeForce Драйвера AMD Radeon HD Игры на DVD Сравнение видеокарт Сравнение процессоров

АРХИВ СТАТЕЙ ЖУРНАЛА «МОЙ КОМПЬЮТЕР» ЗА 2003 ГОД

Хранитель МногоLикий

(c)Петр 'Roxton' СЕМИЛЕТОВ

Эта статья должна послужить маяком на берегу XML, чтобы программеры на Delphi устремили к нему свои корабли — простите, компиляторы — и узнали, какая это гибкая, универсальная технология.Я покажу всю мощь XML в несколько нетрадиционном ключе. Обычно XML используется для представления иерархичных структур данных. Однако XML пригоден для хранения и предоставления доступа к вообще любой информации. Что я хочу сказать?

Итак, жизнь программиста до и после XML. Сначала — до. Предположим, вы делаете браузер. У него есть закладки, история, список открытых окон — продолжите сами. Все это надо как-то хранить. Причем, закладки и историю надо еще сохранять загружать. То есть, нужны свои форматы файлов. Как они будут реализованы внутри — дело ваше, это могут быть ini'шки, или же формат, основанный на чтении/записи переменных-record'ов. Если посмотреть на все это со стороны, то видятся хаос и анархия. Но мало того, что придется делать свои процедуры ввода/вывода информации. Надо будет писать и классы, которые представляют эту информацию внутри программы. Специальный класс для закладок, класс для истории и так далее. Код раздувается, раздувается и лопается.

Теперь — время XML. Тезис первый — в формате XML вы можете хранить данные любого типа. Будь то числа или строки. Тезис второй — один XML-класс может инкапсулировать в себе как средства ввода/вывода, так и являться контейнером для информации, к каковой предоставляет очень простой доступ.

Давайте на реальном примере разберем, как все это работает. Нам понадобится замечательная библиотека XMLWorks. Ее можно скачать с http://www.delphihome.com/xml. XMLWorks совершенно бесплатна и распространяется с исходным кодом. Я успешно компилировал с ней программы в Delphi версий пятой и последней седьмой. Кроме того, нужна библиотека FastStrings (http://www.droopyeyes.com/bin/faststrings.zip, 15 Кб), тоже бесплатная и с открытым кодом.

В состав XMLWorks входит несколько библиотек, однако нас будет интересовать основная, которая заключена в модуле XMLWorks2.pas. Главная идея XMLWorks заключается в том, чтобы генерировать XML-структуры на основе полей, объявленных в классах. Понимаете, к чему я? Любое поле класса может быть сохранено в XML-файл и считано оттуда. Звучит прозаично, однако на деле оборачивается большой выгодой и экономией как времени, так и кода.

Прежде чем перейти к конкретному примеру, давайте поговорим о некоторых аспектах применения XML-парадигмы.

Традиционно при сохранении опций программисты используют ini-файл и некую структуру, поля которой отражают содержимое ini-файла. Получается какая-то дуальная природа внутреннего представления этих опций — надо каждую отдельно читать, записывать, привлекать к этому делу класс для работы с ini-файлами. При использовании Реестра — то же самое, тот же дуализм. Не говоря уже о том, что возникает трудность с сохранением строковых ключей, которые содержат в себе многострочные значения (разделенные символом перевода строки) — обычный TIniFile с этим не справляется. На помощь приходит XMLWorks. Ему по плечу и многострочные поля, и автоматическая загрузка/сохранение значений в соответствующие поля.

Далее. XMLWorks идеально подходит в тех случаях, когда есть необходимость работать с данными, организованными как записи (records) или классы. Вместо создания, скажем, экземпляра TList с кучей объектов внутри него, вы можете использовать XML-структуру, которая умеет сохранять и загружать информацию.

Как все это реализовано на уровне XMLWorks? Существует класс TXMLCollection, который порожден он стандартного TCollection. TXMLCollection хранит в себе коллекцию (список), состоящую из экземпляров класса, который вы произведете от класса TXMLCollectionItem. TXMLCollectionItem — это базовый класс, на его основе вы должны строить свои собственные классы, в которых и задаются нужные вам поля. Обратите внимание на имена классов! Для корректной работы XMLWorks необходимо, чтобы соблюдались два правила:

1. Имя потомка TXMLCollection должно начинаться с T и завершаться словом Collection. Например, TXMLPlaylistCollection.

2. Имя потомка TXMLCollectionItem должно соответствовать тому же условию. Например, TXMLPlaylistCollectionItem.

Давайте приведу немного кода, чтобы легче было объяснять. Сначала сформулируем задачу. Надо сделать плейлист. Который может читаться из файла и записываться в него. Кроме того, нам понадобятся методы доступа к каждому элементу плейлиста и некие утилитные процедуры, например, по заполнению экземпляра TStrings названиями песен.

Каждый элемент плейлиста можно представить в виде класса:

На всякий пожарный прокомментирую — поле artist хранит в себе имя исполнителя или название группы, songname — название песни, а time — ее длину, время. Поле filename для экономии места в статье пропускаем. Это ведь демо, а не реальный проект.

Теперь опишем класс-коллекцию, в которой будем хранить элементы плейлиста, то есть экземпляры класса TPlaylistCollectionItem. Вот эта коллекция:

Как видите, она содержит в себе ряд функций и процедур. Зачем они?

AddNewItem — добавляет в коллекцию новый элемент и сразу заполняет его поля значениями, которые вы передадите в параметрах.

GetSongsNames — заполняет s:TStrings названиями песен, содержащихся в плейлисте.

GetItemByIndex — возвращает элемент плейлиста по его индексу (номеру).

GetItemBySongName — возвращает элемент плейлиста, но уже находя его по названию песни (то есть, смотря в поле songname).

Реализация этих функций позволит мне проиллюстрировать основные методы работы с XMLWorks. Первой идет у нас процедура AddNewItem. Я написал два ее варианта, длинный, для чайников :-), и лаконичный, но чуть более сложный.

Вот для чайников:

Вначале мы объявляем переменную new_item, затем на ее основе создаем экземпляр класса TPlaylistCollectionItem с помощью метода (функции) Add, которой обладает класс TXMLCollection и его потомки, в нашем случае это TPlayListCollection. Затем, уже имея на руках созданный новый элемент new_item, мы заполняем его поля теми значениями, что переданы в параметрах.

А вот более краткая реализация этой же процедуры:

Здесь мы обходимся без «промежуточной» переменной, неявно создавая экземпляр TPlaylistCollectionItem и используя его в конструкции with. Как видите, более лаконичный код :-). Перейдем к следующей процедуре:

Сначала мы узнаем количество элементов в коллекции. Мы читаем его в переменную c (от «count») и отнимаем единицу. Затем сравниваем, и если c равна -1, то выходим из процедуры. Зачем отнимаем единицу, и зачем вся эта возня, не проще ли оперировать сразу с count? На самом деле описанный мною подход — очень правильный, оптимальный. Переменная c служит нам верхней границей в цикле. Если мы будем использовать свойство TPlayListCollection.count, нам придется в цикле каждый раз отнимать от него единицу, потому что count выводит количество элементов, нумерация которых начинается с единицы. А при обращении к элементу коллекции по индексу нумерация идет с нуля.

Следовательно, чтобы не отнимать единицу каждый раз при очередной итерации цикла, мы делаем это всего один раз и используем вместо count переменную c.

Далее, мы очищаем список строк s —s.clear, и начинаем заполнять его названиями песен. Для этого мы в цикле прогоняем все элементы коллекции и для каждого из них используем операцию приведения к типу (typecast). Наверное, стоит чуть подробнее. Вот:

Мы берем items[i], то бишь элемент коллекции, имеющий номер i. Для получения доступа к полю songname нам нужно привести этот элемент к типу (классу) TPlaylistCollectionItem. Потому что в items по определению хранятся экземпляры отнюдь не TPlaylistCollectionItem, а TXMLCollectionItem! И лишь механизм полиморфизма позволяет нам интерпретировать элемент items не как TXMLCollectionItem, но как TPlaylistCollectionItem, получив доступ к его полю songname.

Далее, совсем простая функция:

Здесь мы получаем элемент плейлиста по его индексу и приводим его к типу TPlaylistCollectionItem. Далее:

А эта функция показывает, как можно найти элемент по некоему критерию: в нашем случае — по полю songname. Мы в цикле прогоняем всю коллекцию и сравниваем поле songname каждого элемента с параметром a_songname, полученным функцией. Первый же элемент с полем songname, равным a_songname, будет возвращен в качестве результата функции. Иначе возвращается nil. Сразу после нахождения идет прерывание цикла, потому что элемент уже найден и дальше искать нет смысла.

Все. Теперь посмотрим, как это работает на деле. Создаем экземпляр нашей коллекции:

Обратите внимание, что в качестве параметра для конструктора мы передаем тот класс, который будем хранить в коллекции. Экземпляр создан, добавим несколько элементов:

Сохраним этот плейлист в XML-файл:

Загрузим из файла:

Изменим значение некоторых полей для элемента коллекции №2:

Заполним TListBox названиями песен:

Вот, пожалуй, и все — мы рассмотрели основные приемы работы с XML-коллекцией. Разумеется, я немного упростил алгоритмы в плане их функциональности. Например, вместо процедуры GetNames следовало написать другую, которой передавался бы дополнительный параметр вроде format:string и где задавался бы формат, согласно которому информация выводилась бы в список — те же Winamp'овские макросы вроде %7, %8...

Чтобы у вас был уже набранный, в электронном виде код, выкладываю по адресу http://www.roxton.kiev.ua/db/mk_xmlplaylist_demo.zipдвухкилобайтный исходник того, о чем я сегодня рассказал — такая небольшая демка под Delphi 7, но заработает и в пятой, и в шестой версиях.

Рекомендуем ещё прочитать:






Данную страницу никто не комментировал. Вы можете стать первым.

Ваше имя:
Ваша почта:

RSS
Комментарий:
Введите символы или вычислите пример: *
captcha
Обновить





Хостинг на серверах в Украине, США и Германии. © sector.biz.ua 2006-2015 design by Vadim Popov