ruby--ruby/lib/rexml/light/node.rb

232 lines
4.6 KiB
Ruby
Raw Normal View History

require 'rexml/xmltokens'
require 'rexml/light/node'
# Development model
# document = Node.new
# Add an element "foo" to the document
# foo = document << "foo"
# # Set attribute "attr" on foo
# foo["attr"] = "la"
# # Set another attribute in a different namespace
# foo["attr", "namespace"] = "too"
# # Swap foo into another namespace
# foo.namespace = "blah"
# # Add a couple of element nodes to foo
# foo << "a"
# foo << "b"
# # Access the children of foo in various ways
# a = foo[0]
# foo.each { |child|
# #...
# }
# # Add text to foo
# # Add instruction
# # Add comment
# # Get the root of the document
# document == a.root
# # Write the document out
# puts document.to_s
module REXML
module Light
# Represents a tagged XML element. Elements are characterized by
# having children, attributes, and names, and can themselves be
# children.
class Node < Array
alias :_old_get :[]
alias :_old_put :[]=
NAMESPLIT = /^(?:(#{XMLTokens::NCNAME_STR}):)?(#{XMLTokens::NCNAME_STR})/u
# Create a new element.
def initialize node=nil
if node.kind_of? String
node = [ :text, node ]
elsif node.nil?
node = [ :document, nil, nil ]
elsif node[0] == :start_element
node[0] = :element
end
replace( node )
_old_put( 1, 0, 1 )
_old_put( 1, nil )
end
def size
el!()
super-4
end
def each( &block )
el!()
size.times { |x| yield( at(x+4) ) }
end
def name
el!()
at(2)
end
def name=( name_str, ns=nil )
el!()
pfx = ''
pfx = "#{prefix(ns)}:" if ns
_old_put(1, "#{pfx}#{name_str}")
end
def parent=( node )
_old_put(1,node)
end
def local_name
el!()
namesplit
@name
end
def local_name=( name_str )
el!()
_old_put( 1, "#@prefix:#{name_str}" )
end
def prefix( namespace=nil )
el!()
prefix_of( self, namespace )
end
def namespace( prefix=prefix() )
el!()
namespace_of( self, prefix )
end
def namespace=( namespace )
el!()
@prefix = prefix( namespace )
pfx = ''
pfx = "#@prefix:" if @prefix.size > 0
_old_put(1, "#{pfx}#@name")
end
def []( reference, ns=nil )
el!()
if reference.kind_of? String
pfx = ''
pfx = "#{prefix(ns)}:" if ns
at(3)["#{pfx}#{reference}"]
elsif reference.kind_of? Range
_old_get( Range.new(4+reference.begin, reference.end, reference.exclude_end?) )
else
_old_get( 4+reference )
end
end
def =~( path )
XPath.match( self, path )
end
# Doesn't handle namespaces yet
def []=( reference, ns, value=nil )
el!()
if reference.kind_of? String
value = ns unless value
at( 3 )[reference] = value
elsif reference.kind_of? Range
_old_put( Range.new(3+reference.begin, reference.end, reference.exclude_end?), ns )
else
if value
_old_put( 4+reference, ns, value )
else
_old_put( 4+reference, ns )
end
end
end
# Append a child to this element, optionally under a provided namespace.
# The namespace argument is ignored if the element argument is an Element
# object. Otherwise, the element argument is a string, the namespace (if
# provided) is the namespace the element is created in.
def << element
if node_type() == :text
at(-1) << element
else
newnode = Node.new( element )
newnode.parent = self
self.push( newnode )
end
at(-1)
end
def node_type
_old_get(0)
end
def text=( foo )
replace = at(4).kind_of? String ? 1 : 0
self._old_put(4,replace, normalizefoo)
end
def root
context = self
context = context.at(1) while context.at(1)
end
def has_name?( name, namespace = '' )
el!()
at(3) == name and namespace() == namespace
end
def children
el!()
self
end
def parent
at(1)
end
def to_s
end
def el!
if node_type() != :element and node_type() != :document
_old_put( 0, :element )
push({})
end
self
end
private
def namesplit
return if @name.defined?
at(2) =~ NAMESPLIT
@prefix = '' || $1
@name = $2
end
def namespace_of( node, prefix=nil )
if not prefix
name = at(2)
name =~ NAMESPLIT
prefix = $1
end
to_find = 'xmlns'
to_find = "xmlns:#{prefix}" if not prefix.nil?
ns = at(3)[ to_find ]
ns ? ns : namespace_of( @node[0], prefix )
end
def prefix_of( node, namespace=nil )
if not namespace
name = node.name
name =~ NAMESPLIT
$1
else
ns = at(3).find { |k,v| v == namespace }
ns ? ns : prefix_of( node.parent, namespace )
end
end
end
end
end