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