mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
233 lines
4.5 KiB
Ruby
233 lines
4.5 KiB
Ruby
|
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 = [ :start_document, nil, nil ]
|
||
|
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
|
||
|
|
||
|
# 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 text?
|
||
|
at(-1) << element
|
||
|
else
|
||
|
newnode = Node.new( element )
|
||
|
newnode.parent = self
|
||
|
self.push( newnode )
|
||
|
end
|
||
|
at(-1)
|
||
|
end
|
||
|
|
||
|
def node_type
|
||
|
self[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 element?
|
||
|
at(0) == :start_element
|
||
|
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 text?
|
||
|
at(0) == :text
|
||
|
end
|
||
|
|
||
|
def to_s
|
||
|
|
||
|
end
|
||
|
|
||
|
def el!
|
||
|
if text?()
|
||
|
_old_put( 0, :start_element )
|
||
|
push({})
|
||
|
end
|
||
|
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
|