oga/lib/oga/xml/tree_builder.rb

135 lines
3.0 KiB
Ruby
Raw Normal View History

module Oga
module XML
##
# The TreeBuilder class turns an AST into a DOM tree. This DOM tree can be
# traversed by requesting child elements, parent elements, etc.
#
# Basic usage:
#
# builder = Oga::XML::TreeBuilder.new
# ast = s(:element, ...)
#
# builder.process(ast) # => #<Oga::XML::Document ...>
#
class TreeBuilder < ::AST::Processor
##
# @param [Oga::AST::Node] node
# @return [Oga::XML::Document]
#
2014-03-28 07:59:48 +00:00
def on_document(node)
document = Document.new
document.children = process_all(node)
document.children.each do |child|
child.parent = document
end
return document
end
##
# @param [Oga::AST::Node] node
# @return [Oga::XML::Comment]
#
2014-03-28 07:59:48 +00:00
def on_comment(node)
return Comment.new(:text => node.children[0])
end
##
# Processes an `(element)` node and its child elements.
#
# An element can have a parent, previous and next element as well as a
# number of child elements.
#
# @param [Oga::AST::Node] node
# @return [Oga::XML::Element]
#
def on_element(node)
2014-03-28 07:59:48 +00:00
ns, name, attr, *children = *node
if attr
attr = process(attr)
end
if children
children = process_all(children.compact)
2014-03-28 07:59:48 +00:00
end
element = Element.new(
:name => name,
:namespace => ns,
:attributes => attr,
:children => children
)
process_children(element)
2014-03-28 07:59:48 +00:00
return element
end
##
# @param [Oga::AST::Node] node
# @return [Oga::XML::Text]
#
def on_text(node)
2014-03-28 07:59:48 +00:00
return Text.new(:text => node.children[0])
end
##
# @param [Oga::AST::Node] node
# @return [Oga::XML::Cdata]
#
def on_cdata(node)
return Cdata.new(:text => node.children[0])
end
2014-03-28 07:59:48 +00:00
##
# Converts a `(attributes)` node into a Hash.
#
# @param [Oga::AST::Node] node
# @return [Hash]
#
2014-03-28 07:59:48 +00:00
def on_attributes(node)
pairs = process_all(node)
return Hash[pairs]
end
##
# @param [Oga::AST::Node] node
# @return [Array]
#
2014-03-28 07:59:48 +00:00
def on_attribute(node)
return *node
end
private
##
# Iterates over the child elements of an element and assigns the parent,
# previous and next elements. The supplied object is modified in place.
#
# @param [Oga::XML::Element] element
#
def process_children(element)
amount = element.children.length
element.children.each_with_index do |child, index|
prev_index = index - 1
next_index = index + 1
if index > 0
child.previous = element.children[prev_index]
end
if next_index <= amount
child.next = element.children[next_index]
end
child.parent = element
end
end
end # TreeBuilder
end # XML
end # Oga