1require 'rexml/xmltokens' 2 3# [ :element, parent, name, attributes, children* ] 4 # a = Node.new 5 # a << "B" # => <a>B</a> 6 # a.b # => <a>B<b/></a> 7 # a.b[1] # => <a>B<b/><b/><a> 8 # a.b[1]["x"] = "y" # => <a>B<b/><b x="y"/></a> 9 # a.b[0].c # => <a>B<b><c/></b><b x="y"/></a> 10 # a.b.c << "D" # => <a>B<b><c>D</c></b><b x="y"/></a> 11module REXML 12 module Light 13 # Represents a tagged XML element. Elements are characterized by 14 # having children, attributes, and names, and can themselves be 15 # children. 16 class Node 17 NAMESPLIT = /^(?:(#{XMLTokens::NCNAME_STR}):)?(#{XMLTokens::NCNAME_STR})/u 18 PARENTS = [ :element, :document, :doctype ] 19 # Create a new element. 20 def initialize node=nil 21 @node = node 22 if node.kind_of? String 23 node = [ :text, node ] 24 elsif node.nil? 25 node = [ :document, nil, nil ] 26 elsif node[0] == :start_element 27 node[0] = :element 28 elsif node[0] == :start_doctype 29 node[0] = :doctype 30 elsif node[0] == :start_document 31 node[0] = :document 32 end 33 end 34 35 def size 36 if PARENTS.include? @node[0] 37 @node[-1].size 38 else 39 0 40 end 41 end 42 43 def each 44 size.times { |x| yield( at(x+4) ) } 45 end 46 47 def name 48 at(2) 49 end 50 51 def name=( name_str, ns=nil ) 52 pfx = '' 53 pfx = "#{prefix(ns)}:" if ns 54 _old_put(2, "#{pfx}#{name_str}") 55 end 56 57 def parent=( node ) 58 _old_put(1,node) 59 end 60 61 def local_name 62 namesplit 63 @name 64 end 65 66 def local_name=( name_str ) 67 _old_put( 1, "#@prefix:#{name_str}" ) 68 end 69 70 def prefix( namespace=nil ) 71 prefix_of( self, namespace ) 72 end 73 74 def namespace( prefix=prefix() ) 75 namespace_of( self, prefix ) 76 end 77 78 def namespace=( namespace ) 79 @prefix = prefix( namespace ) 80 pfx = '' 81 pfx = "#@prefix:" if @prefix.size > 0 82 _old_put(1, "#{pfx}#@name") 83 end 84 85 def []( reference, ns=nil ) 86 if reference.kind_of? String 87 pfx = '' 88 pfx = "#{prefix(ns)}:" if ns 89 at(3)["#{pfx}#{reference}"] 90 elsif reference.kind_of? Range 91 _old_get( Range.new(4+reference.begin, reference.end, reference.exclude_end?) ) 92 else 93 _old_get( 4+reference ) 94 end 95 end 96 97 def =~( path ) 98 XPath.match( self, path ) 99 end 100 101 # Doesn't handle namespaces yet 102 def []=( reference, ns, value=nil ) 103 if reference.kind_of? String 104 value = ns unless value 105 at( 3 )[reference] = value 106 elsif reference.kind_of? Range 107 _old_put( Range.new(3+reference.begin, reference.end, reference.exclude_end?), ns ) 108 else 109 if value 110 _old_put( 4+reference, ns, value ) 111 else 112 _old_put( 4+reference, ns ) 113 end 114 end 115 end 116 117 # Append a child to this element, optionally under a provided namespace. 118 # The namespace argument is ignored if the element argument is an Element 119 # object. Otherwise, the element argument is a string, the namespace (if 120 # provided) is the namespace the element is created in. 121 def << element 122 if node_type() == :text 123 at(-1) << element 124 else 125 newnode = Node.new( element ) 126 newnode.parent = self 127 self.push( newnode ) 128 end 129 at(-1) 130 end 131 132 def node_type 133 _old_get(0) 134 end 135 136 def text=( foo ) 137 replace = at(4).kind_of?(String)? 1 : 0 138 self._old_put(4,replace, normalizefoo) 139 end 140 141 def root 142 context = self 143 context = context.at(1) while context.at(1) 144 end 145 146 def has_name?( name, namespace = '' ) 147 at(3) == name and namespace() == namespace 148 end 149 150 def children 151 self 152 end 153 154 def parent 155 at(1) 156 end 157 158 def to_s 159 160 end 161 162 private 163 164 def namesplit 165 return if @name.defined? 166 at(2) =~ NAMESPLIT 167 @prefix = '' || $1 168 @name = $2 169 end 170 171 def namespace_of( node, prefix=nil ) 172 if not prefix 173 name = at(2) 174 name =~ NAMESPLIT 175 prefix = $1 176 end 177 to_find = 'xmlns' 178 to_find = "xmlns:#{prefix}" if not prefix.nil? 179 ns = at(3)[ to_find ] 180 ns ? ns : namespace_of( @node[0], prefix ) 181 end 182 183 def prefix_of( node, namespace=nil ) 184 if not namespace 185 name = node.name 186 name =~ NAMESPLIT 187 $1 188 else 189 ns = at(3).find { |k,v| v == namespace } 190 ns ? ns : prefix_of( node.parent, namespace ) 191 end 192 end 193 end 194 end 195end 196