- Введение
- Обработка XML
- Постановка задачи
- Решение задачи методами rexml
- Решение задачи c помощью libgdome-ruby
- Победитель - Оболочка для libxml
- Вкусность на последок: XSL трансформация с использованием libxslt.
- Заключение
Введение
Изучая новую технологию всегда хочется применить её для решения
текущих задач. А одна из основных задач современного программиста -
это составление программ, которые собирают данные из нескольких
систем, обрабатывают их и выдают результат. Это напоминает сборку
модели из готовых деталей конструктора, где роль крупных блоков
играют, например, базы данных, а в качестве соединительных деталей
используется простой и гибкий язык программирования.
Основными источниками данных в современном программировании являются
текстовые файлы, базы данных и файлы в XML формате. А обрабатывать и
соединять их друг с другом попробуем с помощью скриптового языка
программирования Ruby.
Обработка текстовых файлов не представляет особой сложности, поскольку
возможности Ruby в области поддержки регулярных выражений делают
разбор любого текстового файла не очень сложной задачей. А вот
обработку XML документов можно рассмотреть подробнее.
Обработка XML
Для обработки XML существует как стандартное решение в виде rexml
библиотеки, которая входит в Ruby 1.8, так и альтернативные варианты,
которые в большинстве случаев представляют собой обертки (wrappers)
вокруг С библиотек libxml2 и производных от неё.
Поиск расширений Ruby для обработки XML документов
(http://raa.ruby-lang.org/search.rhtml?search=xml и на
http://libxml.org) приводит к множеству библиотек. Но отбросив все
alpha, unstable, experimental и тому подобное получаем совсем
небольшой список:
В сгенерированном программой 1 XML документе пройтись по всем узлам,
посчитать сумму атрибутов sum и найти среднее значение атрибута avg.
Решение задачи методами rexml
Удобный API компенсируется недостатком производительности. Дело в том,
что библиотека rexml написана на самом Ruby, производительность
которого относительно C/C++ не велика. Также можно отметить, что XSL
трансформацию библиотека rexml не поддерживает.
Итого - 6 секунд длился разбор документа на моем компьютере.
model name : Celeron (Mendocino)
cpu MHz : 534.552
cache size : 128 KB
bogomips : 1064.96
Решение задачи c помощью libgdome-ruby
libgdome-ruby-0.3.tar.bz2 представляет собой оболочку вокруг Gdome2
библиотеки. Gdome2 - это реализация W3C DOM Level2 на C. Поэтому для
установки libgdome-ruby надо сначала установить Gdome2 библиотеку.
Тут и пригодится Portage от Gentoo Linux:
$ emerge dev-libs/gdome2
Для ручной установки замечу, что Gdome2 зависит от библиотек libxml2
(http://xmlsoft.org/) и glib (http://www.gtk.org/). Сам Gdome2
можно скачать с сайта http://phd.cs.unibo.it/gdome2/
Далее переходим к установке Ruby расширения libgdome-ruby:
$ tar -xjf libgdome-ruby-0.3.tar.bz2
$ cd libgdome-ruby-0.3
$ ruby extconf.rb
$ make
$ make install
Программа 3. Решение задачи с использованием Gdome2 (parseXml_3.rb)
sum = avgSum = count = 0
children = doc.documentElement.childNodes
(0...children.length).each{ |i|
el = children.item(i)
if (el.kind_of?(Dom::Element))
count += 1
sum += el.getAttribute('sum').to_i
avgSum += el.getAttribute('avg').to_i
end
}
puts "count(node): #{count}, sum(sum): #{sum}, avg(avg): #{avgSum/count}"
Можно задать резонный вопрос: почему я не использовал XPath, для
выборки узлов /Nodes/Node. Отвечаю - в библиотеке libgdome-ruby XPath
не реализовали, хотя в самой Gnome2 XPath присутствует в полной мере.
Отметим, что XSL трансформация не реализована в Gdom2 и, как
следствие, в libgdome-ruby тоже.
Время выполнения задачи с использованием gdome значительно лучше, чем
с rexml:
Заявленая автором оболочки поддержка XPath и простые и напоминающие
rexml интерфейсы весьма привлекательны. Библиотека зависит от libm
(математические функции), libz (zlib), libiconv и, естественно, от
libxml2. Как правило, все эти библиотеки в современных дистрибутивах
есть, поэтому переходим без лишних слов к установке и реализации нашей
задачи:
Устанавливаем скачаный файл libxml-0.3.4.tar.gz:
$ tar -xzf libxml-0.3.4.tar.gz
$ cd libxml-0.3.4
$ ruby extconf.rb
$ make && make install
Программа 4. Решение задачи с использованием libxml (parseXml_4.rb)
require 'xml/libxml'
xmlStr = ''
ARGF.each {|line| xmlStr << line}
xp = XML::Parser.new()
xp.string = xmlStr
doc = xp.parse
Можно сказать только одно: Кубок победителю :-) Ruby libxml extention
показал лучший результат по эффективности и удобству интерфейсов.
Вкусность на последок: XSL трансформация с использованием libxslt.
Для установки libxslt требуется, что бы libxml уже было установлено и
header файлы находились в директории ../libxml относительно директории
с libxslt.
$ ln -s libxml-0.3.4 libxml
$ tar -xzf libxslt-0.3.4.tar.gz
$ cd libxslt-0.3.4
$ ruby extconf.rb
$ make && make install
Для примера предположим, что нам надо вывести список файлов в
директории. Довольно простая задача, но при этом требуется разделить
данные от представления. Это может понадобится, например, если дизайн
представления будет менятся.
Примерная реализация: получаем список файлов в директории, строим из
списка файлов XML и трансформируем его в HTML при помощи XSL.
# замечатальный пример компакности Ruby - выполнение shell комманды,
# проход по строкам её результата и составление XML в одной строке :-)
xp.string = `ls`.inject('<files>') { |xml, file|
xml << '<file>' << file.chomp << '</file>' } + '</files>'
xslt.doc = xp.parse
s = xslt.parse
s.apply
s.print
Проверяем производительность:
$ time ruby buildFileList.rb
... результат трансформации пропущен ...
real 0m0.064s
user 0m0.030s
sys 0m0.030s
Заключение
Резюмируя, можно сказать, что Ruby на данный момент обладает
достаточными средствами для обработки XML документов и выполнения XSL
трансформаций. Он соединяет лучшее, что было сделано в
программировании - удобный синтаксис языка вместе с использованием
существующих библиотек. Полученное в результате решение отличается
простотой и легкостью в изучении, что делает его эффективным
инструментом для программистов.