Чтение онлайн

ЖАНРЫ

Программирование на языке Ruby
Шрифт:

</book>

<book isbn="074325631X">

<title>First Man: The Life of Neil A. Armstrong</title>

<author>James R. Hansen</author>

<description>Definitive biography of the first man on

the moon. </description>

</book>

 </section>

</library>

15.1.1. Древовидное

представление

Сначала покажем, как работать с ХМL-документом, представленным в виде дерева. Для начала затребуем библиотеку

rexml/document
; обычно для удобства мы включаем также директиву
include rexml
, чтобы импортировать все необходимое в пространство имен верхнего уровня. В листинге 15.2 продемонстрировано несколько полезных приемов.

Листинг 15.2. Разбор документа с применением DOM

require 'rexml/document'

include REXML

input = File.new("books.xml")

doc = Document.new(input)

root = doc.root

puts root.attributes["shelf"] # Недавние приобретения

doc.elements.each("library/section") { |e| puts e.attributes["name"] }

# Выводится:

# Ruby

# Space

doc.elements.each("*/section/book") { |e| puts e.attributes["isbn"] }

# Выводится:

# 0672328844

# 0321445619

# 0684835509

# 074325631X

sec2 = root.elements[2]

author = sec2.elements[1].elements["author"].text # Robert Zubrin

Обратите внимание: атрибуты представляются в виде хэша. Обращаться к элементам можно либо по пути, либо по номеру. В последнем случае учтите, что согласно спецификации XML индексация элементов начинается с 1, а не с 0, как в Ruby.

15.1.2. Потоковый разбор

А теперь попробуем разобрать тот же самый файл в потоковом стиле (на практике это вряд ли понадобилось бы, потому что размер файла невелик). У этого подхода несколько вариантов, в листинге 15.3 показан один из них. Идея в том, чтобы определить класс слушателя, методы которого анализатор будет вызывать для обработки событий.

Листинг 15.3. SAX-разбор

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*$/ # Ничего, кроме пропусков.

abbrev = data[0..40] + (data.length > 40 ? "..." : "")

puts " text : #{abbrev.inspect}"

 end

end

list = MyListener.new

source = File.new "books.xml"

Document.parse_stream(source, list)

В

этом нам поможет класс
StreamListener
; сам по себе он содержит только заглушки, то есть пустые методы обратного вызова. Вы должны переопределить их в своем подклассе. Когда анализатор встречает открывающий тег, он вызывает метод
tag_open
. Можете считать это чем-то вроде метода
method_missing
, которому в качестве параметра передается имя тега (и все его атрибуты в форме хэша). Аналогично работает метод
text
; о других методах вы можете прочитать в документации на сайтеили в каком-нибудь другом месте.

Программа в листинге 15.3 протоколирует обнаружение каждого открывающего и каждого закрывающего тега. Результат работы показан в листинге 15.4 (для краткости текст приведен не полностью).

Листинг 15.4. Результат работы программы потокового разбора

tag_start: "library", {"shelf"=>"Recent Acquisitions"}

tag_start: "section", {"name"=>"Ruby"}

tag_start: "book", {"isbn"=>"0672328844"}

tag_start: "title", {}

text : "The Ruby Way"

tag_start: "author", {}

text : "Hal Fulton"

tag_start: "description", {}

text : "Second edition. The book you are now read..."

tag_start: "section", {"name"=>"Space"}

tag_start: "book", {"isbn"=>"0684835509"}

tag_start: "title", {}

text : "The Case for Mars"

tag_start: "author", {}

text : "Robert Zubrin"

tag_start: "description", {}

text : "Pushing toward a second home for the huma..."

tag_start: "book", {"isbn"=>"074325631X"}

tag_start: "title", {}

text : "First Man: The Life of Neil A. Armstrong"

tag_start: "author", {}

text : "James R. Hansen"

tag_start: "description", {}

text : "Definitive biography of the first man on ..."

15.1.3. XPath и другие интерфейсы

Альтернативным способом работы с ХМL-документом является язык XPath, с помощью которого описывается, как обратиться к конкретным элементам и атрибутам XML-документа.

Библиотека REXML поддерживает XPath с помощью класса XPath. Предполагается, что документ представлен в виде DOM (см. выше листинг 15.2). Рассмотрим следующий код:

Поделиться с друзьями: