Обработка XML, XPath и XSL трансформации в Ruby

Изучая новую технологию всегда хочется применить её для решения текущих задач. А одна из основных задач современного программиста - это составление программ, которые собирают данные из нескольких систем, обрабатывают их и выдают результат. Это напоминает сборку модели из готовых деталей конструктора, где роль крупных блоков играют, например, базы данных, а в качестве соединительных деталей используется простой и гибкий язык программирования.

Основными источниками данных в современном программировании являются текстовые файлы, базы данных и файлы в 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 и тому подобное получаем совсем небольшой список:

* libgdome-ruby (beta): http://raa.ruby-lang.org/project/libgdome-ruby/
* libxml (production quality): http://raa.ruby-lang.org/project/libxml/
* libxslt (working): http://raa.ruby-lang.org/project/libxslt/

Я попробую сравнить найденные библиотеки между собой в решении простой задачи.
Постановка задачи

Программа 1. Генерация XML документа (generateXml.rb)

puts '<nodes>'
1000.times {|i| puts '<node sum="1" avg="' + i.to_s + '">Node sample text</node>'}
puts '</nodes>'


Задача


В сгенерированном программой 1 XML документе пройтись по всем узлам, посчитать сумму атрибутов sum и найти среднее значение атрибута avg.

Решение задачи методами rexml


Удобный API компенсируется недостатком производительности. Дело в том, что библиотека rexml написана на самом Ruby, производительность которого относительно C/C++ не велика. Также можно отметить, что XSL трансформацию библиотека rexml не поддерживает.

Программа 2. Решение задачи (parseXml_2.rb)

require "rexml/document"
include REXML

xmlStr = ''

ARGF.each {|line| xmlStr << line}

doc = Document.new xmlStr
sum = avgSum = count = 0
doc.elements.each('/nodes/node') { |e|
        count += 1
        sum += e.attributes['sum'].to_i
        avgSum += e.attributes['avg'].to_i
}
puts "count(node): #{count}, sum(sum): #{sum}, avg(avg): #{avgSum/count}"

Определение времени выполнения и результат

$ time ruby generateXml.rb | ruby parseXml_2.rb
count(node): 1000, sum(sum): 1000, avg(avg): 499

real    0m6.035s
user    0m5.450s
sys     0m0.590s

Итого - 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)

require "gdome"

xmlStr = ''
ARGF.each {|line| xmlStr << line}

domImpl = Dom::implementation
doc = domImpl.createDocFromMemory(xmlStr, 0)

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:

$ time ruby generateXml.rb | ruby parseXml_3.rb
count(node): 1000, sum(sum): 1000, avg(avg): 499

real    0m0.334s
user    0m0.300s
sys     0m0.030s


Победитель - Оболочка для libxml


Заявленая автором оболочки поддержка 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

sum = avgSum = count = 0
doc.find('/nodes/node').each { |e|
    count += 1
    sum += e['sum'].to_i
    avgSum += e['avg'].to_i
}
puts "count(node): #{count}, sum(sum): #{sum}, avg(avg): #{avgSum/count}"

Традиционный замер времени выполнения:

$ time ruby generateXml.rb | ruby parseXml_4.rb
count(node): 1000, sum(sum): 1000, avg(avg): 499

real    0m0.210s
user    0m0.180s
sys     0m0.030s

Можно сказать только одно: Кубок победителю :-) 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.

XSL файл для трансформации (filesToHtml.xsl):

<?xml version="1.0" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<html><body><ul>
<xsl:for-each select="/files/file">
    <li><xsl:value-of select="."/></li>
</xsl:for-each>
</ul></body></html>
</xsl:template>
</xsl:stylesheet>

Ruby скрипт, осуществляющий трансформацию (buildFileList.rb):

require 'xml/libxml'
require 'xml/libxslt'

xslt = XML::XSLT.file('filesToHtml.xsl')

xp = XML::Parser.new

# замечатальный пример компакности 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 трансформаций. Он соединяет лучшее, что было сделано в программировании - удобный синтаксис языка вместе с использованием существующих библиотек. Полученное в результате решение отличается простотой и легкостью в изучении, что делает его эффективным инструментом для программистов.

Обсуждение

Re: Обработка XML, XPath и XSL трансформации в Ruby

odds of winning at blackjack online

casino empire cheat world poker finals at foxwoods
casino desktop wallpaper michigan fantasy 5 lotto
poker travel kit makeover and dressup games
driving game red game
gamehouse poker treasure bay casino biloxi mississippi
free atv game 3d willy wonka game
tightpoker let it ride poker sahara casino
casino fx royale trailer computer game clock tower
probability of rolling a certain number on two dice littlewoods poker uk
free monopoly game download gambling dictionary
poker playing dogs painting riverboat gambling kentucky
sands convention center las vegas slot a heatsinks
grand yavuz hotel old cigarette slot machines
port 1025 blackjack online army games
money making secret a crazy game of poker mp3
loose slots vegas club penguin the ds game
make your own clay poker chips wynn hotel and casino home
lottosouth.+com board game blank
harrah's rincon casino 50 let go poker tip hosting spider's web online
49 6 7 loto super florida lotto payoff
casino casino online poker slot yourbestonlinecasino.com strategy for texas hold em poker
game of dГ©sire mickleson gambling
how to make a roulette wheel pokerroom reviews
latex game free video 2006 blog casino cialis spam viagra
casinos gaming harrah's casino rincon
casino fife loch sport poker run
no deposit casino redeem coupon caesars poker chips
niagara casino hotel pacific poker com multi
boonville capri casino isle mo governor of poker descargar
online blackjack game freed slot car gears
pokerstars signup best casino promotions
game massive online rune scape las vegas court
des francaise jeux loto freeaddicting games
pokerstars problems irish lottery results
casino online rated top poker games free online
bravo poker tv telecharger strip poker
lottery gambling 1109 gambling nokey
las vegas car for sale draw odds poker
high roller online casino car games mcqueen
blotto pathological gambling addiction

Read Amazed

Many of us know you are right, but unfortunately few of us will say it aloud. where to buy cialis