Ruby - Руководство по XML, XSLT и XPath
Что такое XML?
Extensible Markup Language (XML) - это язык разметки, очень похожий на HTML или SGML. Это рекомендовано Консорциумом World Wide Web и доступно в качестве открытого стандарта.
XML - это переносимый язык с открытым исходным кодом, который позволяет программистам разрабатывать приложения, которые могут быть прочитаны другими приложениями, независимо от операционной системы и / или языка разработки.
XML чрезвычайно полезен для отслеживания небольших и средних объемов данных, не требуя магистрали на основе SQL.
Архитектуры синтаксического анализатора XML и API
Для парсеров XML доступны два разных варианта:
SAX-like (Stream interfaces)- Здесь вы регистрируете обратные вызовы для интересующих событий, а затем позволяете синтаксическому анализатору продолжить работу с документом. Это полезно, когда ваши документы большие или у вас есть ограничения памяти, он анализирует файл при чтении его с диска, и весь файл никогда не сохраняется в памяти.
DOM-like (Object tree interfaces) - Это рекомендация Консорциума World Wide Web, согласно которой весь файл считывается в память и сохраняется в иерархической (древовидной) форме для представления всех функций XML-документа.
Очевидно, что SAX не может обрабатывать информацию так быстро, как DOM, при работе с большими файлами. С другой стороны, использование исключительно DOM может действительно убить ваши ресурсы, особенно при использовании большого количества небольших файлов.
SAX доступен только для чтения, в то время как DOM позволяет вносить изменения в XML-файл. Поскольку эти два разных API буквально дополняют друг друга, нет причин, по которым вы не можете использовать их оба для больших проектов.
Разбор и создание XML с помощью Ruby
Самый распространенный способ манипулирования XML - это библиотека REXML Шона Рассела. С 2002 года REXML является частью стандартного дистрибутива Ruby.
REXML - это XML-процессор на чистом Ruby, соответствующий стандарту XML 1.0. Это непроверяющий процессор, прошедший все не подтверждающие тесты соответствия OASIS.
Парсер REXML имеет следующие преимущества перед другими доступными парсерами:
- Он на 100% написан на Ruby.
- Его можно использовать как для синтаксического анализа SAX, так и для DOM.
- Это легкий, менее 2000 строк кода.
- Методы и классы действительно просты для понимания.
- API на основе SAX2 и полная поддержка XPath.
- Поставляется с установкой Ruby, отдельная установка не требуется.
Для всех наших примеров кода XML давайте использовать в качестве входных данных простой файл XML -
<collection shelf = "New Arrivals">
<movie title = "Enemy Behind">
<type>War, Thriller</type>
<format>DVD</format>
<year>2003</year>
<rating>PG</rating>
<stars>10</stars>
<description>Talk about a US-Japan war</description>
</movie>
<movie title = "Transformers">
<type>Anime, Science Fiction</type>
<format>DVD</format>
<year>1989</year>
<rating>R</rating>
<stars>8</stars>
<description>A schientific fiction</description>
</movie>
<movie title = "Trigun">
<type>Anime, Action</type>
<format>DVD</format>
<episodes>4</episodes>
<rating>PG</rating>
<stars>10</stars>
<description>Vash the Stampede!</description>
</movie>
<movie title = "Ishtar">
<type>Comedy</type>
<format>VHS</format>
<rating>PG</rating>
<stars>2</stars>
<description>Viewable boredom</description>
</movie>
</collection>
DOM-подобный парсинг
Давайте сначала проанализируем наши XML-данные в виде дерева . Начнем с требованияrexml/documentбиблиотека; часто мы включаем REXML для импорта в пространство имен верхнего уровня для удобства.
#!/usr/bin/ruby -w
require 'rexml/document'
include REXML
xmlfile = File.new("movies.xml")
xmldoc = Document.new(xmlfile)
# Now get the root element
root = xmldoc.root
puts "Root element : " + root.attributes["shelf"]
# This will output all the movie titles.
xmldoc.elements.each("collection/movie"){
|e| puts "Movie Title : " + e.attributes["title"]
}
# This will output all the movie types.
xmldoc.elements.each("collection/movie/type") {
|e| puts "Movie Type : " + e.text
}
# This will output all the movie description.
xmldoc.elements.each("collection/movie/description") {
|e| puts "Movie Description : " + e.text
}
Это даст следующий результат -
Root element : New Arrivals
Movie Title : Enemy Behind
Movie Title : Transformers
Movie Title : Trigun
Movie Title : Ishtar
Movie Type : War, Thriller
Movie Type : Anime, Science Fiction
Movie Type : Anime, Action
Movie Type : Comedy
Movie Description : Talk about a US-Japan war
Movie Description : A schientific fiction
Movie Description : Vash the Stampede!
Movie Description : Viewable boredom
SAX-подобный синтаксический анализ
Чтобы обработать те же данные, файл movies.xml , в потоковом режиме, мы определим класс слушателя , методы которого будут целью обратных вызовов от парсера.
NOTE - Не рекомендуется использовать SAX-подобный синтаксический анализ для небольшого файла, это просто демонстрационный пример.
#!/usr/bin/ruby -w
require 'rexml/document'
require 'rexml/streamlistener'
include REXML
class MyListener
include REXML::StreamListener
def tag_start(*args)
puts "tag_start: #{args.map {|x| x.inspect}.join(', ')}"
end
def text(data)
return if data =~ /^\w*$/ # whitespace only
abbrev = data[0..40] + (data.length > 40 ? "..." : "")
puts " text : #{abbrev.inspect}"
end
end
list = MyListener.new
xmlfile = File.new("movies.xml")
Document.parse_stream(xmlfile, list)
Это даст следующий результат -
tag_start: "collection", {"shelf"=>"New Arrivals"}
tag_start: "movie", {"title"=>"Enemy Behind"}
tag_start: "type", {}
text : "War, Thriller"
tag_start: "format", {}
tag_start: "year", {}
tag_start: "rating", {}
tag_start: "stars", {}
tag_start: "description", {}
text : "Talk about a US-Japan war"
tag_start: "movie", {"title"=>"Transformers"}
tag_start: "type", {}
text : "Anime, Science Fiction"
tag_start: "format", {}
tag_start: "year", {}
tag_start: "rating", {}
tag_start: "stars", {}
tag_start: "description", {}
text : "A schientific fiction"
tag_start: "movie", {"title"=>"Trigun"}
tag_start: "type", {}
text : "Anime, Action"
tag_start: "format", {}
tag_start: "episodes", {}
tag_start: "rating", {}
tag_start: "stars", {}
tag_start: "description", {}
text : "Vash the Stampede!"
tag_start: "movie", {"title"=>"Ishtar"}
tag_start: "type", {}
tag_start: "format", {}
tag_start: "rating", {}
tag_start: "stars", {}
tag_start: "description", {}
text : "Viewable boredom"
XPath и Ruby
Альтернативный способ просмотра XML - XPath. Это своего рода псевдоязык, который описывает, как найти определенные элементы и атрибуты в XML-документе, рассматривая этот документ как логически упорядоченное дерево.
REXML поддерживает XPath через класс XPath . Он предполагает синтаксический анализ на основе дерева (объектная модель документа), как мы видели выше.
#!/usr/bin/ruby -w
require 'rexml/document'
include REXML
xmlfile = File.new("movies.xml")
xmldoc = Document.new(xmlfile)
# Info for the first movie found
movie = XPath.first(xmldoc, "//movie")
p movie
# Print out all the movie types
XPath.each(xmldoc, "//type") { |e| puts e.text }
# Get an array of all of the movie formats.
names = XPath.match(xmldoc, "//format").map {|x| x.text }
p names
Это даст следующий результат -
<movie title = 'Enemy Behind'> ... </>
War, Thriller
Anime, Science Fiction
Anime, Action
Comedy
["DVD", "DVD", "DVD", "VHS"]
XSLT и Ruby
Доступны два парсера XSLT, которые может использовать Ruby. Здесь приводится краткое описание каждого из них.
Рубин-Саблотрон
Этот синтаксический анализатор написан и поддерживается Масаёши Такахаши. Это написано в основном для ОС Linux и требует следующих библиотек:
- Sablot
- Iconv
- Expat
Вы можете найти этот модуль на Ruby-Sablotron.
XSLT4R
XSLT4R написан Майклом Нойманом, его можно найти в RAA в разделе «Библиотека» в разделе XML. XSLT4R использует простой интерфейс командной строки, хотя в качестве альтернативы его можно использовать в стороннем приложении для преобразования XML-документа.
XSLT4R требует для работы XMLScan, который включен в архив XSLT4R и также является полностью модулем Ruby. Эти модули могут быть установлены с использованием стандартного метода установки Ruby (например, ruby install.rb).
XSLT4R имеет следующий синтаксис -
ruby xslt.rb stylesheet.xsl document.xml [arguments]
Если вы хотите использовать XSLT4R из приложения, вы можете включить XSLT и ввести необходимые параметры. Вот пример -
require "xslt"
stylesheet = File.readlines("stylesheet.xsl").to_s
xml_doc = File.readlines("document.xml").to_s
arguments = { 'image_dir' => '/....' }
sheet = XSLT::Stylesheet.new( stylesheet, arguments )
# output to StdOut
sheet.apply( xml_doc )
# output to 'str'
str = ""
sheet.output = [ str ]
sheet.apply( xml_doc )
Дальнейшее чтение
Для получения полной информации о парсере REXML, пожалуйста, обратитесь к стандартной документации по REXML Parser Documentation .
Вы можете загрузить XSLT4R из репозитория RAA .