xmlparser 0.6.81
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/MANIFEST +112 -0
- data/README +697 -0
- data/README.ja +789 -0
- data/Rakefile +34 -0
- data/ext/encoding.h +91 -0
- data/ext/xmlparser/mkrf_conf.rb +28 -0
- data/ext/xmlparser/xmlparser.c +2226 -0
- data/lib/sax.rb +1 -0
- data/lib/saxdriver.rb +1 -0
- data/lib/wget.rb +47 -0
- data/lib/xml/dom/builder-ja.rb +58 -0
- data/lib/xml/dom/builder.rb +310 -0
- data/lib/xml/dom/core.rb +3276 -0
- data/lib/xml/dom/digest.rb +94 -0
- data/lib/xml/dom/visitor.rb +182 -0
- data/lib/xml/dom2/attr.rb +213 -0
- data/lib/xml/dom2/cdatasection.rb +76 -0
- data/lib/xml/dom2/characterdata.rb +177 -0
- data/lib/xml/dom2/comment.rb +81 -0
- data/lib/xml/dom2/core.rb +19 -0
- data/lib/xml/dom2/document.rb +317 -0
- data/lib/xml/dom2/documentfragment.rb +82 -0
- data/lib/xml/dom2/documenttype.rb +102 -0
- data/lib/xml/dom2/dombuilder.rb +277 -0
- data/lib/xml/dom2/dombuilderfilter.rb +12 -0
- data/lib/xml/dom2/domentityresolver.rb +13 -0
- data/lib/xml/dom2/domentityresolverimpl.rb +37 -0
- data/lib/xml/dom2/domexception.rb +95 -0
- data/lib/xml/dom2/domimplementation.rb +61 -0
- data/lib/xml/dom2/dominputsource.rb +29 -0
- data/lib/xml/dom2/element.rb +533 -0
- data/lib/xml/dom2/entity.rb +110 -0
- data/lib/xml/dom2/entityreference.rb +107 -0
- data/lib/xml/dom2/namednodemap.rb +138 -0
- data/lib/xml/dom2/node.rb +587 -0
- data/lib/xml/dom2/nodelist.rb +231 -0
- data/lib/xml/dom2/notation.rb +86 -0
- data/lib/xml/dom2/processinginstruction.rb +155 -0
- data/lib/xml/dom2/text.rb +128 -0
- data/lib/xml/dom2/xpath.rb +398 -0
- data/lib/xml/encoding-ja.rb +42 -0
- data/lib/xml/parser.rb +13 -0
- data/lib/xml/parserns.rb +236 -0
- data/lib/xml/sax.rb +353 -0
- data/lib/xml/saxdriver.rb +370 -0
- data/lib/xml/xpath.rb +3284 -0
- data/lib/xml/xpath.ry +2352 -0
- data/lib/xmldigest.rb +1 -0
- data/lib/xmltree.rb +1 -0
- data/lib/xmltreebuilder.rb +1 -0
- data/lib/xmltreevisitor.rb +1 -0
- metadata +111 -0
data/lib/sax.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'xml/sax'
|
data/lib/saxdriver.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'xml/saxdriver'
|
data/lib/wget.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
## -*- Ruby -*-
|
2
|
+
## URLopen
|
3
|
+
## 1999 by yoshidam
|
4
|
+
##
|
5
|
+
## TODO: This module should be writen by Ruby instead of wget/lynx.
|
6
|
+
|
7
|
+
module WGET
|
8
|
+
PARAM = {
|
9
|
+
'wget' => nil,
|
10
|
+
'opts' => nil,
|
11
|
+
'http_proxy' => nil,
|
12
|
+
'ftp_proxy' => nil
|
13
|
+
}
|
14
|
+
|
15
|
+
def open(url, *rest)
|
16
|
+
raise TypeError.new("wrong argument type #{url.inspect}" +
|
17
|
+
" (expected String)") if url.class != String
|
18
|
+
|
19
|
+
if url =~ /^\/|^\./ || (url !~ /^http:|^ftp:/ && FileTest.exist?(url))
|
20
|
+
File::open(url, *rest)
|
21
|
+
else
|
22
|
+
ENV['http_proxy'] = PARAM['http_proxy'] if PARAM['http_proxy']
|
23
|
+
ENV['ftp_proxy'] = PARAM['ftp_proxy'] if PARAM['ftp_proxy']
|
24
|
+
IO::popen(PARAM['wget'] + ' ' + PARAM['opts'] + ' ' + url)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
module_function :open
|
28
|
+
end
|
29
|
+
|
30
|
+
[ '/usr/local/bin/wget', '/usr/bin/wget',
|
31
|
+
'/usr/local/bin/lynx', '/usr/bin/lynx',
|
32
|
+
'/usr/local/bin/lwp-request', '/usr/bin/lwp-request' ].each do |p|
|
33
|
+
if FileTest.executable?(p)
|
34
|
+
WGET::PARAM['wget'] = p
|
35
|
+
case p
|
36
|
+
when /wget$/
|
37
|
+
WGET::PARAM['opts'] = '-q -O -'
|
38
|
+
when /lynx$/
|
39
|
+
WGET::PARAM['opts'] = '-source'
|
40
|
+
when /lwp-request$/
|
41
|
+
WGET::PARAM['opts'] = '-m GET'
|
42
|
+
end
|
43
|
+
break
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
raise "wget not found" if !WGET::PARAM['wget']
|
@@ -0,0 +1,58 @@
|
|
1
|
+
## -*- Ruby -*-
|
2
|
+
## Tree builder class for Japanese encoding
|
3
|
+
## 1998 by yoshidam
|
4
|
+
|
5
|
+
require 'xml/dom/builder'
|
6
|
+
|
7
|
+
module XML
|
8
|
+
module DOM
|
9
|
+
class JapaneseBuilder<Builder
|
10
|
+
require 'kconv'
|
11
|
+
include Kconv
|
12
|
+
require 'uconv'
|
13
|
+
include Uconv
|
14
|
+
|
15
|
+
def nameConverter(str)
|
16
|
+
u8toeuc(str)
|
17
|
+
end
|
18
|
+
def cdataConverter(str)
|
19
|
+
u8toeuc(str)
|
20
|
+
end
|
21
|
+
|
22
|
+
def parseStream(stream, trim = false)
|
23
|
+
## empty file
|
24
|
+
if ((xml = stream.gets).nil?); exit 1; end
|
25
|
+
## rewrite encoding in XML decl.
|
26
|
+
if xml =~ /^<\?xml\sversion=.+\sencoding=.EUC-JP./i
|
27
|
+
xml.sub!(/EUC-JP/i, "UTF-8")
|
28
|
+
encoding = 'EUC-JP'
|
29
|
+
elsif xml =~ /^<\?xml\sversion=.+\sencoding=.Shift_JIS./i
|
30
|
+
xml.sub!(/Shift_JIS/i, "UTF-8")
|
31
|
+
encoding = "Shift_JIS"
|
32
|
+
elsif xml =~ /^<\?xml\sversion=.+\sencoding=.ISO-2022-JP./i
|
33
|
+
xml.sub!(/ISO-2022-JP/i, "UTF-8")
|
34
|
+
encoding = "ISO-2022-JP"
|
35
|
+
end
|
36
|
+
|
37
|
+
## read body
|
38
|
+
xml += String(stream.read)
|
39
|
+
|
40
|
+
## convert body encoding
|
41
|
+
if encoding == "EUC-JP"
|
42
|
+
xml = euctou8(xml)
|
43
|
+
elsif encoding == "Shift_JIS"
|
44
|
+
xml = euctou8(kconv(xml, EUC, SJIS))
|
45
|
+
elsif encoding == "ISO-2022-JP"
|
46
|
+
xml = euctou8(kconv(xml, EUC, JIS))
|
47
|
+
end
|
48
|
+
|
49
|
+
return parse(xml, trim)
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
def Uconv.unknown_unicode_handler(u)
|
54
|
+
return '®'
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,310 @@
|
|
1
|
+
## -*- Ruby -*-
|
2
|
+
## XML::DOM::Builder
|
3
|
+
## 1999 by yoshidam
|
4
|
+
|
5
|
+
require 'xml/parser'
|
6
|
+
require 'xml/dom/core'
|
7
|
+
|
8
|
+
=begin
|
9
|
+
= XML::DOM::Builder
|
10
|
+
|
11
|
+
== Module XML
|
12
|
+
|
13
|
+
=end
|
14
|
+
module XML
|
15
|
+
module DOM
|
16
|
+
|
17
|
+
=begin
|
18
|
+
== Class XML::DOM::Builder (XML::SimpleTreeBuilder)
|
19
|
+
|
20
|
+
=== superclass
|
21
|
+
XML::Parser
|
22
|
+
|
23
|
+
=end
|
24
|
+
class Builder<Parser
|
25
|
+
include XML::DOM
|
26
|
+
|
27
|
+
attr :createCDATASection, true
|
28
|
+
attr :createEntityReference, true
|
29
|
+
|
30
|
+
## replace 'open' by WGET::open
|
31
|
+
begin
|
32
|
+
require 'wget'
|
33
|
+
include WGET
|
34
|
+
rescue
|
35
|
+
## ignore
|
36
|
+
end
|
37
|
+
|
38
|
+
=begin
|
39
|
+
=== Class Methods
|
40
|
+
|
41
|
+
--- DOM::Builder.new(level = 0, *args)
|
42
|
+
|
43
|
+
Constructor of DOM builder.
|
44
|
+
|
45
|
+
usage:
|
46
|
+
parser = XML::SimpleTreeBuilder.new(level)
|
47
|
+
|
48
|
+
level: 0 -- ignore default events (defualt)
|
49
|
+
1 -- catch default events and create the Comment,
|
50
|
+
the EntityReference, the XML declaration (as PI) and
|
51
|
+
the non-DOM-compliant DocumentType nodes.
|
52
|
+
|
53
|
+
=end
|
54
|
+
|
55
|
+
def self.new(level = 0, *args)
|
56
|
+
document = Document.new
|
57
|
+
ret = super(*args)
|
58
|
+
external = false
|
59
|
+
external = true if args[0].is_a?(SimpleTreeBuilder)
|
60
|
+
ret.__initialize__(level, document, external)
|
61
|
+
ret
|
62
|
+
end
|
63
|
+
|
64
|
+
## Constructor
|
65
|
+
## parser = XML::SimpleTreeBuilder.new(level)
|
66
|
+
## level: 0 -- ignore default events (defualt)
|
67
|
+
## 1 -- catch default events and create the Comment,
|
68
|
+
## the EntityReference, the XML declaration (as PI) and
|
69
|
+
## the non-DOM-compliant DocumentType nodes.
|
70
|
+
def __initialize__(level, document, external)
|
71
|
+
@tree = nil
|
72
|
+
@level = level
|
73
|
+
@document = document
|
74
|
+
@external = external
|
75
|
+
@createCDATASection = false
|
76
|
+
@createEntityReference = false
|
77
|
+
if @level > 0
|
78
|
+
@createCDATASection = true
|
79
|
+
@createEntityReference = true
|
80
|
+
def self.default(data); defaultHandler(data); end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
=begin
|
85
|
+
=== Methods
|
86
|
+
|
87
|
+
--- Builder#nameConverter(str)
|
88
|
+
|
89
|
+
User redefinable name encoding converter
|
90
|
+
|
91
|
+
=end
|
92
|
+
## User redefinable name encoding converter
|
93
|
+
def nameConverter(str)
|
94
|
+
str
|
95
|
+
end
|
96
|
+
|
97
|
+
=begin
|
98
|
+
--- Builder#cdataConverter(str)
|
99
|
+
|
100
|
+
User redefinable cdata encoding converter
|
101
|
+
|
102
|
+
=end
|
103
|
+
## User redefinable cdata encoding converter
|
104
|
+
def cdataConverter(str)
|
105
|
+
str
|
106
|
+
end
|
107
|
+
|
108
|
+
=begin
|
109
|
+
=== Methods
|
110
|
+
--- Builder#parse(xml, parse_ext = false)
|
111
|
+
|
112
|
+
parse string or stream of XML contents.
|
113
|
+
|
114
|
+
xml: string or stream of XML contents
|
115
|
+
parse_ext: flag whether parse external entities or not
|
116
|
+
|
117
|
+
ex. doctree = parser.parse(xml, parse_ext)
|
118
|
+
|
119
|
+
=end
|
120
|
+
## Parse
|
121
|
+
## doctree = parser.parse(xml, parse_ext)
|
122
|
+
## xml: string or stream of XML contents
|
123
|
+
## parse_ext: flag whether parse external entities or not
|
124
|
+
def parse(xml, parse_ext = false)
|
125
|
+
if @external
|
126
|
+
@tree = @document.createDocumentFragment
|
127
|
+
else
|
128
|
+
@tree = @document
|
129
|
+
end
|
130
|
+
@parse_ext = parse_ext
|
131
|
+
@current = @tree
|
132
|
+
@inDocDecl = 0
|
133
|
+
@decl = ""
|
134
|
+
@inDecl = 0
|
135
|
+
@idRest = 0
|
136
|
+
@extID = nil
|
137
|
+
@cdata_f = false
|
138
|
+
@cdata_buf = ''
|
139
|
+
super(xml)
|
140
|
+
@tree
|
141
|
+
end
|
142
|
+
|
143
|
+
def text
|
144
|
+
return if @cdata_buf == ''
|
145
|
+
textnode = @document.createTextNode(cdataConverter(@cdata_buf))
|
146
|
+
@current.appendChild(textnode)
|
147
|
+
@cdata_buf = ''
|
148
|
+
end
|
149
|
+
|
150
|
+
def startElement(name, data)
|
151
|
+
text
|
152
|
+
elem = @document.createElement(nameConverter(name))
|
153
|
+
data.each do |key, value|
|
154
|
+
attr = @document.createAttribute(nameConverter(key))
|
155
|
+
attr.appendChild(@document.createTextNode(cdataConverter(value)))
|
156
|
+
elem.setAttributeNode(attr)
|
157
|
+
end
|
158
|
+
@current.appendChild(elem)
|
159
|
+
@current = elem
|
160
|
+
end
|
161
|
+
|
162
|
+
def endElement(name)
|
163
|
+
text
|
164
|
+
@current = @current.parentNode
|
165
|
+
end
|
166
|
+
|
167
|
+
def character(data)
|
168
|
+
@cdata_buf << data
|
169
|
+
end
|
170
|
+
|
171
|
+
def processingInstruction(name, data)
|
172
|
+
text
|
173
|
+
pi = @document.createProcessingInstruction(nameConverter(name),
|
174
|
+
cdataConverter(data))
|
175
|
+
## PI data should not be converted
|
176
|
+
@current.appendChild(pi)
|
177
|
+
end
|
178
|
+
|
179
|
+
def externalEntityRef(context, base, systemId, publicId)
|
180
|
+
text
|
181
|
+
tree = nil
|
182
|
+
if @parse_ext
|
183
|
+
extp = self.class.new(@level, self, context)
|
184
|
+
extp.setBase(base) if base
|
185
|
+
file = systemId
|
186
|
+
if systemId !~ /^\/|^\.|^http:|^ftp:/ && !base.nil?
|
187
|
+
file = base + systemId
|
188
|
+
end
|
189
|
+
begin
|
190
|
+
tree = extp.parse(open(file).read, @parse_ext)
|
191
|
+
rescue XML::ParserError
|
192
|
+
raise XML::ParserError.new("#{systemId}(#{extp.line}): #{$!}")
|
193
|
+
rescue Errno::ENOENT
|
194
|
+
raise Errno::ENOENT.new("#{$!}")
|
195
|
+
end
|
196
|
+
extp.done
|
197
|
+
end
|
198
|
+
if @createEntityReference
|
199
|
+
entref = @document.createEntityReference(nameConverter(context))
|
200
|
+
@current.appendChild(entref)
|
201
|
+
entref.appendChild(tree) if tree
|
202
|
+
else
|
203
|
+
@current.appendChild(tree) if tree
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
def startCdata
|
208
|
+
return unless @createCDATASection
|
209
|
+
text
|
210
|
+
@cdata_f = true
|
211
|
+
end
|
212
|
+
|
213
|
+
def endCdata
|
214
|
+
return unless @createCDATASection
|
215
|
+
cdata = @document.createCDATASection(cdataConverter(@cdata_buf))
|
216
|
+
@current.appendChild(cdata)
|
217
|
+
@cdata_buf = ''
|
218
|
+
@cdata_f = false
|
219
|
+
end
|
220
|
+
|
221
|
+
def comment(data)
|
222
|
+
text
|
223
|
+
comment = @document.createComment(cdataConverter(data))
|
224
|
+
## Comment should not be converted
|
225
|
+
@current.appendChild(comment)
|
226
|
+
end
|
227
|
+
|
228
|
+
def defaultHandler(data)
|
229
|
+
if data =~ /^\&(.+);$/
|
230
|
+
eref = @document.createEntityReference(nameConverter($1))
|
231
|
+
@current.appendChild(eref)
|
232
|
+
elsif data =~ /^<\?xml\s*([\s\S]*)\?>$/
|
233
|
+
## XML declaration should not be a PI.
|
234
|
+
pi = @document.createProcessingInstruction("xml",
|
235
|
+
cdataConverter($1))
|
236
|
+
@current.appendChild(pi)
|
237
|
+
elsif @inDocDecl == 0 && data =~ /^<\!DOCTYPE$/
|
238
|
+
@inDocDecl = 1
|
239
|
+
@inDecl = 0
|
240
|
+
@idRest = 0
|
241
|
+
@extID = nil
|
242
|
+
elsif @inDocDecl == 1
|
243
|
+
if data == "["
|
244
|
+
@inDocDecl = 2
|
245
|
+
elsif data == ">"
|
246
|
+
if !@extID.nil?
|
247
|
+
## @current.nodeValue = @extID
|
248
|
+
end
|
249
|
+
@inDocDecl = 0
|
250
|
+
## @current = @current.parentNode
|
251
|
+
elsif data == "SYSTEM"
|
252
|
+
@idRest = 1
|
253
|
+
@extID = data
|
254
|
+
elsif data == "PUBLIC"
|
255
|
+
@idRest = 2
|
256
|
+
@extID = data
|
257
|
+
elsif data !~ /^\s+$/
|
258
|
+
if @idRest > 0
|
259
|
+
## SysID or PubID
|
260
|
+
@extID <<= " " + data
|
261
|
+
@idRest -= 1
|
262
|
+
else
|
263
|
+
## Root Element Type
|
264
|
+
docType = data
|
265
|
+
## doctype = DocumentType.new(nameConverter(docType))
|
266
|
+
## @current.appendChild(doctype)
|
267
|
+
## @current = doctype
|
268
|
+
end
|
269
|
+
end
|
270
|
+
elsif @inDocDecl == 2
|
271
|
+
if @inDecl == 0
|
272
|
+
if data == "]"
|
273
|
+
@inDocDecl = 1
|
274
|
+
elsif data =~ /^<\!/
|
275
|
+
@decl = data
|
276
|
+
@inDecl = 1
|
277
|
+
elsif data =~ /^%(.+);$/
|
278
|
+
## PERef
|
279
|
+
## cdata = @document.createTextNode(nameConverter(data))
|
280
|
+
## @current.appendChild(cdata)
|
281
|
+
else
|
282
|
+
## WHITESPCAE
|
283
|
+
end
|
284
|
+
else ## inDecl == 1
|
285
|
+
if data == ">"
|
286
|
+
@decl <<= data
|
287
|
+
@inDecl = 0
|
288
|
+
## Markup Decl
|
289
|
+
## cdata = @document.createTextNode(cdataConverter(@decl))
|
290
|
+
## Markup decl should not be converted
|
291
|
+
## @current.appendChild(cdata)
|
292
|
+
elsif data =~ /^\s+$/
|
293
|
+
## WHITESPACE
|
294
|
+
@decl << " "
|
295
|
+
else
|
296
|
+
@decl << data
|
297
|
+
end
|
298
|
+
end
|
299
|
+
else
|
300
|
+
## maybe WHITESPACE
|
301
|
+
## cdata = @document.createTextNode(cdataConverter(data))
|
302
|
+
## @current.appendChild(cdata)
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
SimpleTreeBuilder = DOM::Builder
|
310
|
+
end
|
data/lib/xml/dom/core.rb
ADDED
@@ -0,0 +1,3276 @@
|
|
1
|
+
## -*- Ruby -*-
|
2
|
+
## XML::SimpleTree
|
3
|
+
## 1998-2000 by yoshidam
|
4
|
+
##
|
5
|
+
## XPointer support is contributed by Masaki Fukushima
|
6
|
+
## <fukusima@goto.info.waseda.ac.jp>
|
7
|
+
##
|
8
|
+
|
9
|
+
require 'singleton'
|
10
|
+
|
11
|
+
=begin
|
12
|
+
|
13
|
+
= XML::DOM (XML::SimpleTree)
|
14
|
+
|
15
|
+
=end
|
16
|
+
|
17
|
+
|
18
|
+
=begin
|
19
|
+
|
20
|
+
== Module XML
|
21
|
+
|
22
|
+
=end
|
23
|
+
|
24
|
+
module XML
|
25
|
+
|
26
|
+
=begin
|
27
|
+
=== Class Methods
|
28
|
+
|
29
|
+
--- XML.charRef(s)
|
30
|
+
|
31
|
+
replace character '&','<','>',"'",'"' in string s to character reference.
|
32
|
+
=end
|
33
|
+
|
34
|
+
def XML.charRef(s)
|
35
|
+
str = s.dup
|
36
|
+
str.gsub!("&", "&")
|
37
|
+
str.gsub!("<", "<")
|
38
|
+
str.gsub!(">", ">")
|
39
|
+
str.gsub!("'", "'")
|
40
|
+
str.gsub!('"', """)
|
41
|
+
str
|
42
|
+
end
|
43
|
+
|
44
|
+
=begin
|
45
|
+
|
46
|
+
== Module XML::Spec
|
47
|
+
|
48
|
+
Constants related to XML Specification.
|
49
|
+
|
50
|
+
=end
|
51
|
+
## [Masaki Fukushima]
|
52
|
+
module Spec
|
53
|
+
## Constants related to XML Specification
|
54
|
+
## (W3C Recommendation or Working Draft)
|
55
|
+
|
56
|
+
# XML
|
57
|
+
Letter_s = '[a-zA-Z]'
|
58
|
+
Digit_s = '\d'
|
59
|
+
NameChar_s = "(#{Letter_s}|#{Digit_s}|[\\.\\-_:])"
|
60
|
+
Name_s = "(#{Letter_s}|[_:])#{NameChar_s}*"
|
61
|
+
SkipLit_s = "(\"[^\"]*\"|'[^']*')"
|
62
|
+
Name = /^#{Name_s}$/o
|
63
|
+
SkipList = /^#{SkipLit_s}$/o
|
64
|
+
|
65
|
+
# XPointer
|
66
|
+
Instance_s = "(\\+|-)?[1-9]#{Digit_s}*"
|
67
|
+
Instance = /^#{Instance_s}$/o
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
=begin
|
72
|
+
|
73
|
+
== Module XML::DOM (XML::SimpleTree)
|
74
|
+
|
75
|
+
DOM-like APIs module.
|
76
|
+
|
77
|
+
=end
|
78
|
+
|
79
|
+
module DOM
|
80
|
+
|
81
|
+
## Fundamental Interfaces
|
82
|
+
|
83
|
+
=begin
|
84
|
+
|
85
|
+
== Class XML::DOM::DOMException
|
86
|
+
|
87
|
+
=== superclass
|
88
|
+
Exception
|
89
|
+
|
90
|
+
DOM exception.
|
91
|
+
=end
|
92
|
+
|
93
|
+
class DOMException<Exception
|
94
|
+
INDEX_SIZE_ERR = 1
|
95
|
+
WSTRING_SIZE_ERR = 2
|
96
|
+
HIERARCHY_REQUEST_ERR = 3
|
97
|
+
WRONG_DOCUMENT_ERR = 4
|
98
|
+
INVALID_NAME_ERR = 5
|
99
|
+
NO_DATA_ALLOWED_ERR = 6
|
100
|
+
NO_MODIFICATION_ALLOWED_ERR = 7
|
101
|
+
NOT_FOUND_ERR = 8
|
102
|
+
NOT_SUPPORTED_ERR = 9
|
103
|
+
INUSE_ATTRIBUTE_ERR = 10
|
104
|
+
ERRMSG = [
|
105
|
+
"no error",
|
106
|
+
"index size",
|
107
|
+
"wstring size",
|
108
|
+
"hierarchy request",
|
109
|
+
"wrong document",
|
110
|
+
"invalid name",
|
111
|
+
"no data allowed",
|
112
|
+
"no modification allowed",
|
113
|
+
"not found",
|
114
|
+
"not supported",
|
115
|
+
"inuse attribute"
|
116
|
+
]
|
117
|
+
|
118
|
+
=begin
|
119
|
+
=== Class Methods
|
120
|
+
|
121
|
+
--- DOMException.new(code = 0)
|
122
|
+
|
123
|
+
generate DOM exception.
|
124
|
+
=end
|
125
|
+
|
126
|
+
def initialize(code = 0)
|
127
|
+
@code = code
|
128
|
+
end
|
129
|
+
|
130
|
+
=begin
|
131
|
+
=== Methods
|
132
|
+
|
133
|
+
--- DOMException#code()
|
134
|
+
|
135
|
+
return code of exception.
|
136
|
+
|
137
|
+
=end
|
138
|
+
def code
|
139
|
+
@code
|
140
|
+
end
|
141
|
+
|
142
|
+
=begin
|
143
|
+
|
144
|
+
--- DOMException#to_s()
|
145
|
+
|
146
|
+
return the string representation of the error.
|
147
|
+
|
148
|
+
=end
|
149
|
+
def to_s
|
150
|
+
ERRMSG[@code]
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
=begin
|
155
|
+
== Class XML::DOM::DOMImplementation
|
156
|
+
|
157
|
+
=end
|
158
|
+
class DOMImplementation
|
159
|
+
include Singleton
|
160
|
+
|
161
|
+
=begin
|
162
|
+
--- DOMImplementation#hasFeature(feature, version)
|
163
|
+
|
164
|
+
test if DOM implementation has correct feature and version.
|
165
|
+
|
166
|
+
=end
|
167
|
+
def hasFeature(feature, version)
|
168
|
+
if feature =~ /^XML$/i && (version.nil? || version == "1.0")
|
169
|
+
return true
|
170
|
+
end
|
171
|
+
false
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
=begin
|
176
|
+
== Class XML::DOM::Node
|
177
|
+
|
178
|
+
=end
|
179
|
+
class Node
|
180
|
+
## [DOM]
|
181
|
+
NODE_NODE = 0
|
182
|
+
ELEMENT_NODE = 1
|
183
|
+
ATTRIBUTE_NODE = 2
|
184
|
+
TEXT_NODE = 3
|
185
|
+
CDATA_SECTION_NODE = 4
|
186
|
+
ENTITY_REFERENCE_NODE = 5
|
187
|
+
ENTITY_NODE = 6
|
188
|
+
PROCESSING_INSTRUCTION_NODE = 7
|
189
|
+
COMMENT_NODE = 8
|
190
|
+
DOCUMENT_NODE = 9
|
191
|
+
DOCUMENT_TYPE_NODE = 10
|
192
|
+
DOCUMENT_FRAGMENT_NODE = 11
|
193
|
+
NOTATION_NODE = 12
|
194
|
+
|
195
|
+
## non-DOM
|
196
|
+
# NODE = 0
|
197
|
+
# ELEMENT = 1
|
198
|
+
# ATTRIBUTE = 2
|
199
|
+
# TEXT = 3
|
200
|
+
# CDATA_SECTION = 4
|
201
|
+
# ENTITY_REFERENCE = 5
|
202
|
+
# ENTITY = 6
|
203
|
+
# PI = 7
|
204
|
+
# PROCESSING_INSTRUCTION = 7
|
205
|
+
# COMMENT = 8
|
206
|
+
# DOCUMENT = 9
|
207
|
+
# DOCUMENT_TYPE = 10
|
208
|
+
# DOCUMENT_FRAGMENT = 11
|
209
|
+
# NOTATION = 12
|
210
|
+
|
211
|
+
=begin
|
212
|
+
=== Class Methods
|
213
|
+
|
214
|
+
--- Node.new(*children)
|
215
|
+
|
216
|
+
make a Node.
|
217
|
+
children is a Array of child, or sequence of child.
|
218
|
+
child is a String or Node.
|
219
|
+
|
220
|
+
=end
|
221
|
+
## new([child1, child2, ...]) or
|
222
|
+
## new(child1, child2, ...)
|
223
|
+
## child?: String or Node
|
224
|
+
def initialize(*children)
|
225
|
+
@parent = nil
|
226
|
+
@children = nil
|
227
|
+
self.childNodes = children if children.length > 0
|
228
|
+
end
|
229
|
+
|
230
|
+
=begin
|
231
|
+
=== Methods
|
232
|
+
|
233
|
+
--- Node#parentNode
|
234
|
+
|
235
|
+
[DOM]
|
236
|
+
return parent node.
|
237
|
+
|
238
|
+
=end
|
239
|
+
## [DOM]
|
240
|
+
def parentNode
|
241
|
+
@parent
|
242
|
+
end
|
243
|
+
|
244
|
+
=begin
|
245
|
+
--- Node#parentNode=(p)
|
246
|
+
|
247
|
+
set node p as parent.
|
248
|
+
=end
|
249
|
+
|
250
|
+
def parentNode=(p)
|
251
|
+
@parent = p
|
252
|
+
end
|
253
|
+
|
254
|
+
=begin
|
255
|
+
--- Node#nodeType
|
256
|
+
|
257
|
+
[DOM]
|
258
|
+
return nodetype.
|
259
|
+
|
260
|
+
=end
|
261
|
+
## [DOM]
|
262
|
+
def nodeType
|
263
|
+
NODE_NODE
|
264
|
+
end
|
265
|
+
|
266
|
+
=begin
|
267
|
+
--- Node#nodeName
|
268
|
+
|
269
|
+
[DOM]
|
270
|
+
return nodename.
|
271
|
+
|
272
|
+
=end
|
273
|
+
## [DOM]
|
274
|
+
def nodeName
|
275
|
+
"#node"
|
276
|
+
end
|
277
|
+
|
278
|
+
# def nodeName=(p)
|
279
|
+
# @name = p
|
280
|
+
# end
|
281
|
+
|
282
|
+
=begin
|
283
|
+
--- Node#nodeValue
|
284
|
+
|
285
|
+
[DOM]
|
286
|
+
return nodevalue.
|
287
|
+
|
288
|
+
=end
|
289
|
+
## [DOM]
|
290
|
+
def nodeValue; nil; end
|
291
|
+
|
292
|
+
=begin
|
293
|
+
--- Node#nodeValue=(p)
|
294
|
+
|
295
|
+
[DOM]
|
296
|
+
set nodevalue as p.
|
297
|
+
=end
|
298
|
+
## [DOM]
|
299
|
+
def nodeValue=(p)
|
300
|
+
## no effect
|
301
|
+
end
|
302
|
+
|
303
|
+
=begin
|
304
|
+
--- Node#childNodes()
|
305
|
+
|
306
|
+
[DOM]
|
307
|
+
if method has block, apply block for children nodes.
|
308
|
+
without block, return children nodelist.
|
309
|
+
=end
|
310
|
+
## [DOM]
|
311
|
+
def childNodes
|
312
|
+
if iterator?
|
313
|
+
@children.each do |child|
|
314
|
+
yield(child)
|
315
|
+
end if @children
|
316
|
+
else
|
317
|
+
return @children if !@children.nil?
|
318
|
+
@children = NodeList.new
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
|
323
|
+
=begin
|
324
|
+
--- Node#childNodes=(p)
|
325
|
+
|
326
|
+
set child node as p.
|
327
|
+
=end
|
328
|
+
def childNodes=(p)
|
329
|
+
if @children.nil?
|
330
|
+
@children = NodeList.new
|
331
|
+
else
|
332
|
+
@children.to_a.clear
|
333
|
+
end
|
334
|
+
if p.nil? || (p.is_a?(Array) && p.length == 0)
|
335
|
+
return
|
336
|
+
end
|
337
|
+
p.flatten!
|
338
|
+
p.each do |child|
|
339
|
+
if child.is_a?(String)
|
340
|
+
c = Text.new(child)
|
341
|
+
@children.push(c)
|
342
|
+
c.parentNode = self
|
343
|
+
elsif child.is_a?(Node)
|
344
|
+
@children.push(child)
|
345
|
+
child.parentNode = self
|
346
|
+
else
|
347
|
+
raise "parameter error"
|
348
|
+
end
|
349
|
+
end if p
|
350
|
+
end
|
351
|
+
|
352
|
+
=begin
|
353
|
+
--- Node#attributes
|
354
|
+
|
355
|
+
[DOM]
|
356
|
+
return attributes of node(but always return nil?).
|
357
|
+
=end
|
358
|
+
## [DOM]
|
359
|
+
def attributes
|
360
|
+
nil
|
361
|
+
end
|
362
|
+
|
363
|
+
## proper parameter type?
|
364
|
+
# def attributes=(p)
|
365
|
+
# end
|
366
|
+
|
367
|
+
=begin
|
368
|
+
--- Node#[]=(index, nodes)
|
369
|
+
|
370
|
+
set children node as nodes with []-style.
|
371
|
+
=end
|
372
|
+
def []=(index, nodes)
|
373
|
+
@children[index..index] = nodes
|
374
|
+
@children.each do |child|
|
375
|
+
child.parentNode = self
|
376
|
+
end if @children
|
377
|
+
end
|
378
|
+
|
379
|
+
=begin
|
380
|
+
--- Node#[](index)
|
381
|
+
|
382
|
+
get children node with []-style.
|
383
|
+
=end
|
384
|
+
def [](index)
|
385
|
+
@children[index]
|
386
|
+
end
|
387
|
+
|
388
|
+
=begin
|
389
|
+
--- Node#+(node)
|
390
|
+
|
391
|
+
concat node to Node.
|
392
|
+
=end
|
393
|
+
def +(node)
|
394
|
+
[self, node]
|
395
|
+
end
|
396
|
+
|
397
|
+
=begin
|
398
|
+
--- Node#to_s
|
399
|
+
|
400
|
+
returns the string representation of the Node.
|
401
|
+
=end
|
402
|
+
def to_s
|
403
|
+
@children.to_s
|
404
|
+
end
|
405
|
+
|
406
|
+
=begin
|
407
|
+
--- Node#dump(depth = 0)
|
408
|
+
|
409
|
+
dump the Node.
|
410
|
+
=end
|
411
|
+
def dump(depth = 0)
|
412
|
+
print ' ' * depth * 2
|
413
|
+
print nodeName + "\n"
|
414
|
+
@children.each do |child|
|
415
|
+
child.dump(depth + 1)
|
416
|
+
end if @children
|
417
|
+
end
|
418
|
+
|
419
|
+
=begin
|
420
|
+
--- Node#inspect()
|
421
|
+
|
422
|
+
returns the human-readable string representation.
|
423
|
+
=end
|
424
|
+
def inspect
|
425
|
+
"#<#{self.class}: #{self.nodeName}>"
|
426
|
+
end
|
427
|
+
|
428
|
+
=begin
|
429
|
+
--- Node#firstChild()
|
430
|
+
|
431
|
+
[DOM]
|
432
|
+
return the first child node.
|
433
|
+
=end
|
434
|
+
## [DOM]
|
435
|
+
def firstChild
|
436
|
+
return nil if !@children || @children.length == 0
|
437
|
+
return @children[0]
|
438
|
+
end
|
439
|
+
|
440
|
+
=begin
|
441
|
+
--- Node#lastChild()
|
442
|
+
|
443
|
+
[DOM]
|
444
|
+
return the last child node.
|
445
|
+
=end
|
446
|
+
## [DOM]
|
447
|
+
def lastChild
|
448
|
+
return nil if !@children || @children.length == 0
|
449
|
+
return @children[-1]
|
450
|
+
end
|
451
|
+
|
452
|
+
=begin
|
453
|
+
--- Node#previousSibling()
|
454
|
+
|
455
|
+
[DOM]
|
456
|
+
return the previous sibling node.
|
457
|
+
=end
|
458
|
+
## [DOM]
|
459
|
+
def previousSibling
|
460
|
+
return nil if !@parent
|
461
|
+
prev = nil
|
462
|
+
@parent.childNodes do |child|
|
463
|
+
return prev if child == self
|
464
|
+
prev = child
|
465
|
+
end
|
466
|
+
nil
|
467
|
+
end
|
468
|
+
|
469
|
+
=begin
|
470
|
+
--- Node#nextSibling()
|
471
|
+
|
472
|
+
[DOM]
|
473
|
+
return the next sibling node.
|
474
|
+
=end
|
475
|
+
## [DOM]
|
476
|
+
def nextSibling
|
477
|
+
return nil if !@parent
|
478
|
+
nexts = nil
|
479
|
+
@parent.childNodes.reverse.each do |child|
|
480
|
+
return nexts if child == self
|
481
|
+
nexts = child
|
482
|
+
end
|
483
|
+
nil
|
484
|
+
end
|
485
|
+
|
486
|
+
def _getChildIndex(node)
|
487
|
+
index = 0
|
488
|
+
@children.each do |child|
|
489
|
+
if child == node
|
490
|
+
return index
|
491
|
+
end
|
492
|
+
index += 1
|
493
|
+
end
|
494
|
+
nil
|
495
|
+
end
|
496
|
+
|
497
|
+
def _removeFromTree
|
498
|
+
parent = parentNode
|
499
|
+
if parent
|
500
|
+
parent.removeChild(self)
|
501
|
+
end
|
502
|
+
end
|
503
|
+
|
504
|
+
def _checkNode(node)
|
505
|
+
raise DOMException.new(DOMException::HIERARCHY_REQUEST_ERR)
|
506
|
+
end
|
507
|
+
|
508
|
+
def _insertNodes(index, node)
|
509
|
+
if node.nodeType == DOCUMENT_FRAGMENT_NODE
|
510
|
+
|
511
|
+
node.childNodes.to_a.each_with_index do |n, i|
|
512
|
+
if index == -1
|
513
|
+
_insertNodes(-1, n)
|
514
|
+
else
|
515
|
+
_insertNodes(index + i, n)
|
516
|
+
end
|
517
|
+
end
|
518
|
+
elsif node.is_a?(Node)
|
519
|
+
## to be checked
|
520
|
+
_checkNode(node)
|
521
|
+
node._removeFromTree
|
522
|
+
if index == -1
|
523
|
+
@children.push(node)
|
524
|
+
else
|
525
|
+
@children[index, 0] = node
|
526
|
+
end
|
527
|
+
node.parentNode = self
|
528
|
+
else
|
529
|
+
raise ArgumentError, "invalid value for Node"
|
530
|
+
end
|
531
|
+
end
|
532
|
+
|
533
|
+
def _removeNode(index, node)
|
534
|
+
@children[index, 1] = nil
|
535
|
+
node.parentNode = nil
|
536
|
+
end
|
537
|
+
|
538
|
+
# =begin
|
539
|
+
# --- Node#insertAfter(newChild, refChild)
|
540
|
+
#
|
541
|
+
# insert newChild into the node after refChild.
|
542
|
+
# =end
|
543
|
+
# def insertAfter(newChild, refChild)
|
544
|
+
# if @children.nil? || @children.length == 0
|
545
|
+
# raise DOMException.new(DOMException::NOT_FOUND_ERR)
|
546
|
+
# end
|
547
|
+
# index = _getChildIndex(refChild)
|
548
|
+
# raise DOMException.new(DOMException::NOT_FOUND_ERR) if index.nil?
|
549
|
+
# _insertNodes(index, newChild)
|
550
|
+
# end
|
551
|
+
|
552
|
+
=begin
|
553
|
+
--- Node#insertBefore(newChild, refChild)
|
554
|
+
|
555
|
+
[DOM]
|
556
|
+
insert newChild into the node before refChild.
|
557
|
+
=end
|
558
|
+
## [DOM]
|
559
|
+
def insertBefore(newChild, refChild)
|
560
|
+
if @children.nil? || @children.length == 0
|
561
|
+
raise DOMException.new(DOMException::NOT_FOUND_ERR)
|
562
|
+
end
|
563
|
+
index = _getChildIndex(refChild)
|
564
|
+
raise DOMException.new(DOMException::NOT_FOUND_ERR) if !index
|
565
|
+
_insertNodes(index, newChild)
|
566
|
+
end
|
567
|
+
|
568
|
+
=begin
|
569
|
+
--- Node#replaceChild(newChild, oldChild)
|
570
|
+
|
571
|
+
[DOM]
|
572
|
+
replace the child node oldChild with newChild.
|
573
|
+
=end
|
574
|
+
## [DOM]
|
575
|
+
def replaceChild(newChild, oldChild)
|
576
|
+
if @children.nil? || @children.length == 0
|
577
|
+
raise DOMException.new(DOMException::NOT_FOUND_ERR)
|
578
|
+
end
|
579
|
+
index = _getChildIndex(oldChild)
|
580
|
+
raise DOMException.new(DOMException::NOT_FOUND_ERR) if !index
|
581
|
+
_removeNode(index, oldChild)
|
582
|
+
_insertNodes(index, newChild)
|
583
|
+
end
|
584
|
+
|
585
|
+
=begin
|
586
|
+
--- Node#removeChild(oldChild)
|
587
|
+
|
588
|
+
[DOM]
|
589
|
+
remove the children node oldChild.
|
590
|
+
=end
|
591
|
+
## [DOM]
|
592
|
+
def removeChild(oldChild)
|
593
|
+
if @children.nil? || @children.length == 0
|
594
|
+
raise DOMException.new(DOMException::NOT_FOUND_ERR)
|
595
|
+
end
|
596
|
+
index = _getChildIndex(oldChild)
|
597
|
+
raise DOMException.new(DOMException::NOT_FOUND_ERR) if !index
|
598
|
+
_removeNode(index, oldChild)
|
599
|
+
oldChild
|
600
|
+
end
|
601
|
+
|
602
|
+
=begin
|
603
|
+
--- Node#appendChild(newChild)
|
604
|
+
|
605
|
+
[DOM]
|
606
|
+
adds the node newChild to the end of the list of children of this node.
|
607
|
+
=end
|
608
|
+
## [DOM]
|
609
|
+
def appendChild(newChild)
|
610
|
+
@children = NodeList.new if !@children
|
611
|
+
_insertNodes(-1, newChild)
|
612
|
+
end
|
613
|
+
|
614
|
+
=begin
|
615
|
+
--- Node#hasChildNodes()
|
616
|
+
|
617
|
+
[DOM]
|
618
|
+
returns true if node has children, or return false if node has no children.
|
619
|
+
=end
|
620
|
+
## [DOM]
|
621
|
+
def hasChildNodes
|
622
|
+
!@children.nil? && @children.length > 0
|
623
|
+
end
|
624
|
+
|
625
|
+
## get the Node object by IDs
|
626
|
+
## [experimental implement]
|
627
|
+
def _searchID(value, ids = nil)
|
628
|
+
if ids.nil?
|
629
|
+
doc = nil
|
630
|
+
if nodeType == DOCUMENT_NODE
|
631
|
+
doc = self
|
632
|
+
elsif !ownerDocument.nil?
|
633
|
+
doc = ownerDocument
|
634
|
+
else
|
635
|
+
return nil
|
636
|
+
end
|
637
|
+
ids = doc._getIDAttrs
|
638
|
+
end
|
639
|
+
if nodeType == ELEMENT_NODE && _getIDVals(ids).include?(value)
|
640
|
+
return self
|
641
|
+
elsif !@children.nil?
|
642
|
+
@children.each do |node|
|
643
|
+
if !(match = node._searchID(value, ids)).nil?
|
644
|
+
return match
|
645
|
+
end
|
646
|
+
end
|
647
|
+
end
|
648
|
+
return nil
|
649
|
+
end
|
650
|
+
|
651
|
+
def _getMyLocation(parent)
|
652
|
+
index = parent._getChildIndex(self)
|
653
|
+
if !index.nil?
|
654
|
+
"child(#{index + 1},#all)"
|
655
|
+
else
|
656
|
+
nil
|
657
|
+
end
|
658
|
+
end
|
659
|
+
|
660
|
+
=begin
|
661
|
+
--- Node#makeXPointer(use_id = true)
|
662
|
+
|
663
|
+
return XPointer's expression of this node.
|
664
|
+
=end
|
665
|
+
def makeXPointer(use_id = true)
|
666
|
+
if use_id && !attributes.nil? && !(idvals = _getIDVals).empty?
|
667
|
+
"id(#{idvals[0]})"
|
668
|
+
elsif @parent.nil? || @parent.nodeType == DOCUMENT_NODE
|
669
|
+
"root()"
|
670
|
+
else
|
671
|
+
@parent.makeXPointer(use_id) + "." + self._getMyLocation(@parent)
|
672
|
+
end
|
673
|
+
end
|
674
|
+
|
675
|
+
## [Masaki Fukushima]
|
676
|
+
def _child(reverse = false)
|
677
|
+
return if @children.nil?
|
678
|
+
@children.reversible_each(reverse) do |child|
|
679
|
+
yield child
|
680
|
+
end
|
681
|
+
end
|
682
|
+
|
683
|
+
## [Masaki Fukushima]
|
684
|
+
def _descendant(reverse = false)
|
685
|
+
return if @children.nil?
|
686
|
+
@children.reversible_each(reverse) do |child|
|
687
|
+
yield child
|
688
|
+
child._descendant(reverse) do |node|
|
689
|
+
yield node
|
690
|
+
end
|
691
|
+
end
|
692
|
+
end
|
693
|
+
|
694
|
+
## [Masaki Fukushima]
|
695
|
+
def _ancestor(reverse = false)
|
696
|
+
return if @parent.nil?
|
697
|
+
yield @parent if !reverse
|
698
|
+
@parent._ancestor(reverse) do |node| yield node end
|
699
|
+
yield @parent if reverse
|
700
|
+
end
|
701
|
+
|
702
|
+
## [Masaki Fukushima]
|
703
|
+
def __sibling(reverse, only_appeared_before_self)
|
704
|
+
return if @parent.nil?
|
705
|
+
self_appeared = false
|
706
|
+
@parent.childNodes.reversible_each(reverse) do |node|
|
707
|
+
if node == self
|
708
|
+
self_appeared = true
|
709
|
+
next
|
710
|
+
end
|
711
|
+
if only_appeared_before_self
|
712
|
+
break if self_appeared
|
713
|
+
yield node
|
714
|
+
else # only appeared after self
|
715
|
+
yield node if self_appeared
|
716
|
+
end
|
717
|
+
end
|
718
|
+
end
|
719
|
+
|
720
|
+
## [Masaki Fukushima]
|
721
|
+
def _psibling(reverse = false)
|
722
|
+
__sibling(!reverse, reverse) do |sib|
|
723
|
+
yield sib
|
724
|
+
end
|
725
|
+
end
|
726
|
+
|
727
|
+
## [Masaki Fukushima]
|
728
|
+
def _fsibling(reverse = false)
|
729
|
+
__sibling(reverse, reverse) do |sib|
|
730
|
+
yield sib
|
731
|
+
end
|
732
|
+
end
|
733
|
+
|
734
|
+
## [Masaki Fukushima]
|
735
|
+
def _preceding(reverse = false)
|
736
|
+
return if @parent.nil?
|
737
|
+
prev_sib = previousSibling
|
738
|
+
if prev_sib
|
739
|
+
prev_sib._preceding(reverse) {|node| yield node} if reverse
|
740
|
+
yield prev_sib
|
741
|
+
prev_sib._descendant(!reverse) {|node| yield node}
|
742
|
+
prev_sib._preceding(reverse) {|node| yield node} if !reverse
|
743
|
+
else
|
744
|
+
@parent._preceding(reverse) {|node| yield node} if reverse
|
745
|
+
yield @parent
|
746
|
+
@parent._preceding(reverse) {|node| yield node} if !reverse
|
747
|
+
end
|
748
|
+
end
|
749
|
+
|
750
|
+
## [Masaki Fukushima]
|
751
|
+
def _following(reverse = false)
|
752
|
+
return if @parent.nil?
|
753
|
+
next_sib = nextSibling
|
754
|
+
if next_sib
|
755
|
+
next_sib._following(reverse) {|node| yield node} if reverse
|
756
|
+
yield next_sib
|
757
|
+
next_sib._descendant(reverse) {|node| yield node}
|
758
|
+
next_sib._following(reverse) {|node| yield node} if !reverse
|
759
|
+
else
|
760
|
+
@parent._following(reverse) {|node| yield node} if reverse
|
761
|
+
yield @parent
|
762
|
+
@parent._following(reverse) {|node| yield node} if !reverse
|
763
|
+
end
|
764
|
+
end
|
765
|
+
|
766
|
+
## [Masaki Fukushima]
|
767
|
+
def _matchAttribute?(attr, value)
|
768
|
+
case value
|
769
|
+
when '*'
|
770
|
+
return !attr.nil?
|
771
|
+
when '#IMPLIED'
|
772
|
+
return attr.nil?
|
773
|
+
else
|
774
|
+
return false if attr.nil?
|
775
|
+
end
|
776
|
+
|
777
|
+
case value
|
778
|
+
when /^"([^"]*)"$/, /^'([^']*)'$/
|
779
|
+
ignore_case = false
|
780
|
+
value = $1
|
781
|
+
when Spec::Name
|
782
|
+
ignore_case = true
|
783
|
+
else
|
784
|
+
raise "invalid attribute value: #{value}"
|
785
|
+
end
|
786
|
+
if ignore_case
|
787
|
+
return attr.nodeValue.downcase == value.downcase
|
788
|
+
else
|
789
|
+
return attr.nodeValue == value
|
790
|
+
end
|
791
|
+
end
|
792
|
+
|
793
|
+
## [Masaki Fukushima]
|
794
|
+
def _matchNodeAttributes?(node, attributes)
|
795
|
+
return true if attributes.nil?
|
796
|
+
raise TypeError if !attributes.is_a?(Hash)
|
797
|
+
return true if attributes.length == 0
|
798
|
+
return false if node.nodeType != ELEMENT_NODE
|
799
|
+
|
800
|
+
attributes.each do |name, value|
|
801
|
+
case name
|
802
|
+
when '*'
|
803
|
+
return catch(:match) {
|
804
|
+
node.attributes.each do |attr|
|
805
|
+
throw(:match, true) if _matchAttribute?(attr, value)
|
806
|
+
end
|
807
|
+
false
|
808
|
+
}
|
809
|
+
when Spec::Name
|
810
|
+
attr = node.attributes[name] unless node.attributes.nil?
|
811
|
+
return _matchAttribute?(attr, value)
|
812
|
+
else
|
813
|
+
raise "invalid attribute name: '#{name}'"
|
814
|
+
end
|
815
|
+
end
|
816
|
+
end
|
817
|
+
|
818
|
+
## [Masaki Fukushima]
|
819
|
+
def _matchNodeType?(node, ntype)
|
820
|
+
case ntype
|
821
|
+
when '#element'
|
822
|
+
return (node.nodeType == ELEMENT_NODE)
|
823
|
+
when '#pi'
|
824
|
+
return (node.nodeType == PROCESSING_INSTRUCTION_NODE)
|
825
|
+
when '#comment'
|
826
|
+
return (node.nodeType == COMMENT_NODE)
|
827
|
+
when '#text'
|
828
|
+
return (node.nodeType == TEXT_NODE ||
|
829
|
+
node.nodeType == CDATA_SECTION_NODE)
|
830
|
+
when '#cdata'
|
831
|
+
return (node.nodeType == CDATA_SECTION_NODE)
|
832
|
+
when '#all'
|
833
|
+
case node.nodeType
|
834
|
+
when ELEMENT_NODE, PROCESSING_INSTRUCTION_NODE, COMMENT_NODE,
|
835
|
+
TEXT_NODE, CDATA_SECTION_NODE
|
836
|
+
return true
|
837
|
+
else
|
838
|
+
return false
|
839
|
+
end
|
840
|
+
when /^#/
|
841
|
+
raise "unknown node type: '#{ntype}'"
|
842
|
+
when Spec::Name
|
843
|
+
return (node.nodeType == ELEMENT_NODE && node.nodeName == ntype)
|
844
|
+
else
|
845
|
+
raise "invalid element type: '#{ntype}'"
|
846
|
+
end
|
847
|
+
end
|
848
|
+
|
849
|
+
## [Masaki Fukushima]
|
850
|
+
def _matchNode?(node, ntype, attributes)
|
851
|
+
_matchNodeType?(node, ntype) &&
|
852
|
+
_matchNodeAttributes?(node, attributes)
|
853
|
+
end
|
854
|
+
|
855
|
+
## [Masaki Fukushima]
|
856
|
+
def _nodesByRelativeLocationTerm(location)
|
857
|
+
if location !~ /^([a-z]+)\(([^\)]*)\)$/
|
858
|
+
raise "invalid relative location: '#{location}'"
|
859
|
+
end
|
860
|
+
keyword = $1
|
861
|
+
args = $2.split(/,/)
|
862
|
+
number = args.shift
|
863
|
+
ntype = args.shift
|
864
|
+
ntype = '#element' if ntype.nil?
|
865
|
+
attributes = args
|
866
|
+
|
867
|
+
reverse = false
|
868
|
+
# check instance number
|
869
|
+
case number
|
870
|
+
when nil, ''
|
871
|
+
raise "missing instance number: '#{location}'"
|
872
|
+
when 'all'
|
873
|
+
when Spec::Instance
|
874
|
+
number = number.to_i
|
875
|
+
if number < 0
|
876
|
+
reverse = true
|
877
|
+
number = -number
|
878
|
+
end
|
879
|
+
else
|
880
|
+
raise "unknown instance number: '#{number}'"
|
881
|
+
end
|
882
|
+
|
883
|
+
# check attributes
|
884
|
+
if attributes.length % 2 != 0
|
885
|
+
raise " missing attribute value: '#{location}'"
|
886
|
+
end
|
887
|
+
attributes = Hash[*attributes]
|
888
|
+
|
889
|
+
# iterate over nodes specified with keyword
|
890
|
+
i = 0
|
891
|
+
self.send("_#{keyword}", reverse) do |node|
|
892
|
+
next unless _matchNode?(node, ntype, attributes)
|
893
|
+
if number == "all"
|
894
|
+
yield node
|
895
|
+
else
|
896
|
+
i += 1
|
897
|
+
if i >= number
|
898
|
+
yield node
|
899
|
+
break
|
900
|
+
end
|
901
|
+
end
|
902
|
+
end
|
903
|
+
end
|
904
|
+
|
905
|
+
## [Masaki Fukushima]
|
906
|
+
def _nodesByLocationTerms(location, pre_keyword = nil)
|
907
|
+
if location !~ /^([a-z]*)\(([^)]*)\)(\.(.+))?$/
|
908
|
+
raise "invalid location: \"#{location}\""
|
909
|
+
end
|
910
|
+
keyword = $1
|
911
|
+
args = $2
|
912
|
+
rest = $4
|
913
|
+
## omitted keyword
|
914
|
+
keyword = pre_keyword if keyword == ''
|
915
|
+
if keyword.nil?
|
916
|
+
raise "cannot determine preceding keyword: \"#{location}\""
|
917
|
+
end
|
918
|
+
|
919
|
+
case keyword
|
920
|
+
when 'child', 'descendant', 'ancestor', 'psibling', 'fsibling',
|
921
|
+
'preceding', 'following'
|
922
|
+
# relative location term
|
923
|
+
_nodesByRelativeLocationTerm("#{keyword}(#{args})") do |node|
|
924
|
+
if rest.nil?
|
925
|
+
yield node
|
926
|
+
else
|
927
|
+
node._nodesByLocationTerms(rest, keyword) do |n|
|
928
|
+
yield n
|
929
|
+
end
|
930
|
+
end
|
931
|
+
end
|
932
|
+
when 'attr'
|
933
|
+
# attribute location term
|
934
|
+
if args !~ Spec::Name
|
935
|
+
raise "invalid attribute name: '#{args}'"
|
936
|
+
end
|
937
|
+
attr = attributes[args]
|
938
|
+
value = (attr.nil? ? nil : Text.new(attr.nodeValue))
|
939
|
+
if rest.nil?
|
940
|
+
yield value
|
941
|
+
elsif !value.nil?
|
942
|
+
value._nodesByLocationTerms(rest) do |node|
|
943
|
+
yield node
|
944
|
+
end
|
945
|
+
end
|
946
|
+
when 'span', 'string'
|
947
|
+
raise "unsupported keyword: '#{keyword}'"
|
948
|
+
else
|
949
|
+
raise "unknown keyword: '#{keyword}'"
|
950
|
+
end
|
951
|
+
end
|
952
|
+
|
953
|
+
## [Masaki Fukushima]
|
954
|
+
def _getNodeByAbsoluteLocationTerm(location)
|
955
|
+
case location
|
956
|
+
when 'root()', ''
|
957
|
+
if nodeType == DOCUMENT_NODE
|
958
|
+
root = documentElement
|
959
|
+
elsif !ownerDocument.nil?
|
960
|
+
root = ownerDocument.documentElement
|
961
|
+
end
|
962
|
+
root = self if root.nil?
|
963
|
+
return root
|
964
|
+
when 'origin()'
|
965
|
+
return self
|
966
|
+
when /^id\(([^\)]*)\)$/
|
967
|
+
value = $1
|
968
|
+
raise "invalid id value: #{value}" if value !~ Spec::Name
|
969
|
+
return _searchID(value)
|
970
|
+
when /^html\(([^\)]*)\)$/
|
971
|
+
value = $1
|
972
|
+
return getNodesByXPointer("root().descendant(1,A,NAME,\"#{value}\")")[0]
|
973
|
+
else
|
974
|
+
raise "unknown keyword: #{location}"
|
975
|
+
end
|
976
|
+
end
|
977
|
+
|
978
|
+
=begin
|
979
|
+
--- Node#getNodeByXPointer(pointer)
|
980
|
+
|
981
|
+
return node indicated by the XPointer pointer.
|
982
|
+
=end
|
983
|
+
## [Masaki Fukushima]
|
984
|
+
def getNodesByXPointer(pointer)
|
985
|
+
if pointer !~ /^([a-z]+)\(([^)]*)\)(\.(.+))?$/
|
986
|
+
raise "invalid XPointer: \"#{pointer}\""
|
987
|
+
end
|
988
|
+
keyword = $1
|
989
|
+
args = $2
|
990
|
+
rest = $4
|
991
|
+
|
992
|
+
case keyword
|
993
|
+
when 'root', 'origin', 'id', 'html'
|
994
|
+
src = _getNodeByAbsoluteLocationTerm("#{keyword}(#{args})")
|
995
|
+
else
|
996
|
+
src = _getNodeByAbsoluteLocationTerm("root()")
|
997
|
+
rest = pointer
|
998
|
+
end
|
999
|
+
|
1000
|
+
ret = NodeList.new
|
1001
|
+
if src.nil?
|
1002
|
+
# no match
|
1003
|
+
elsif rest.nil?
|
1004
|
+
yield src if iterator?
|
1005
|
+
ret << src
|
1006
|
+
else
|
1007
|
+
src._nodesByLocationTerms(rest) do |node|
|
1008
|
+
yield node if iterator?
|
1009
|
+
ret << node
|
1010
|
+
end
|
1011
|
+
end
|
1012
|
+
ret
|
1013
|
+
end
|
1014
|
+
|
1015
|
+
=begin
|
1016
|
+
--- Node#ownerDocument()
|
1017
|
+
|
1018
|
+
[DOM]
|
1019
|
+
Document object associated with this node.
|
1020
|
+
=end
|
1021
|
+
## [DOM]
|
1022
|
+
## Floating objects are not owned by any documents.
|
1023
|
+
def ownerDocument
|
1024
|
+
return @ownerDocument if @ownerDocument
|
1025
|
+
parent = self.parentNode
|
1026
|
+
return nil if parent.nil?
|
1027
|
+
if parent.nodeType == DOCUMENT_NODE
|
1028
|
+
return parent
|
1029
|
+
else
|
1030
|
+
return parent.ownerDocument
|
1031
|
+
end
|
1032
|
+
end
|
1033
|
+
|
1034
|
+
def ownerDocument=(document); @ownerDocument = document; end
|
1035
|
+
|
1036
|
+
|
1037
|
+
=begin
|
1038
|
+
--- Node#cloneNode()
|
1039
|
+
|
1040
|
+
[DOM]
|
1041
|
+
return the copy of the Node.
|
1042
|
+
=end
|
1043
|
+
## [DOM]
|
1044
|
+
def cloneNode(deep = true, *args)
|
1045
|
+
ret = self.class.new(*args)
|
1046
|
+
if (deep)
|
1047
|
+
@children.each do |child|
|
1048
|
+
ret.appendChild(child.cloneNode(true))
|
1049
|
+
end
|
1050
|
+
end if @children
|
1051
|
+
ret
|
1052
|
+
end
|
1053
|
+
|
1054
|
+
=begin
|
1055
|
+
--- Node#trim(preserve = false)
|
1056
|
+
|
1057
|
+
trim extra whitespaces.
|
1058
|
+
=end
|
1059
|
+
## trim extra whitespaces
|
1060
|
+
## if attribute 'xml:space' is 'preserve',
|
1061
|
+
## don't trim any white spaces
|
1062
|
+
def trim(preserve = false)
|
1063
|
+
return nil if @children.nil?
|
1064
|
+
children = @children.to_a.dup
|
1065
|
+
children.each do |child|
|
1066
|
+
if !preserve && (child.nodeType == TEXT_NODE ||
|
1067
|
+
child.nodeType == CDATA_SECTION_NODE)
|
1068
|
+
if child.trim == ""
|
1069
|
+
self.removeChild(child)
|
1070
|
+
end
|
1071
|
+
else
|
1072
|
+
child.trim(preserve)
|
1073
|
+
end
|
1074
|
+
end
|
1075
|
+
nil
|
1076
|
+
end
|
1077
|
+
|
1078
|
+
|
1079
|
+
end
|
1080
|
+
|
1081
|
+
=begin
|
1082
|
+
== Class XML::DOM::NamedNodeMap
|
1083
|
+
|
1084
|
+
=end
|
1085
|
+
|
1086
|
+
class NamedNodeMap
|
1087
|
+
|
1088
|
+
=begin
|
1089
|
+
=== Class Methods
|
1090
|
+
|
1091
|
+
--- NamedNodeMap.new(nodes = nil)
|
1092
|
+
|
1093
|
+
creates a new NamedNodeMap.
|
1094
|
+
=end
|
1095
|
+
def initialize(nodes = nil)
|
1096
|
+
@nodes = {}
|
1097
|
+
nodes.each do |node|
|
1098
|
+
@nodes[node.nodeName] = node
|
1099
|
+
end if nodes
|
1100
|
+
end
|
1101
|
+
|
1102
|
+
=begin
|
1103
|
+
=== Methods
|
1104
|
+
|
1105
|
+
--- NamedNodeMap#getNamedItem(name)
|
1106
|
+
|
1107
|
+
[DOM]
|
1108
|
+
retrieves a node specified by name.
|
1109
|
+
=end
|
1110
|
+
## [DOM]
|
1111
|
+
def getNamedItem(name)
|
1112
|
+
@nodes[name]
|
1113
|
+
end
|
1114
|
+
|
1115
|
+
=begin
|
1116
|
+
--- NamedNodeMap#setNamedItem(node)
|
1117
|
+
|
1118
|
+
[DOM]
|
1119
|
+
adds a node using its nodeName attribute.
|
1120
|
+
=end
|
1121
|
+
## [DOM]
|
1122
|
+
def setNamedItem(node)
|
1123
|
+
@nodes[node.nodeName] = node
|
1124
|
+
end
|
1125
|
+
|
1126
|
+
=begin
|
1127
|
+
--- NamedNodeMap#removeNamedItem(name)
|
1128
|
+
|
1129
|
+
[DOM]
|
1130
|
+
removes a node specified by name.
|
1131
|
+
=end
|
1132
|
+
## [DOM]
|
1133
|
+
def removeNamedItem(name)
|
1134
|
+
ret = @nodes[name]
|
1135
|
+
@nodes[name] = nil
|
1136
|
+
ret
|
1137
|
+
end
|
1138
|
+
|
1139
|
+
=begin
|
1140
|
+
--- NamedNodeMap#item(index)
|
1141
|
+
|
1142
|
+
[DOM]
|
1143
|
+
returns the index item in the map.
|
1144
|
+
=end
|
1145
|
+
## [DOM]
|
1146
|
+
def item(index)
|
1147
|
+
v = @nodes.to_a[index]
|
1148
|
+
return v[1] if v
|
1149
|
+
nil
|
1150
|
+
end
|
1151
|
+
|
1152
|
+
=begin
|
1153
|
+
--- NamedNodeMap#[](name)
|
1154
|
+
|
1155
|
+
returns nodes associated to name.
|
1156
|
+
=end
|
1157
|
+
def [](name)
|
1158
|
+
@nodes[name]
|
1159
|
+
end
|
1160
|
+
|
1161
|
+
=begin
|
1162
|
+
--- NamedNodeMap#[]=(name, node)
|
1163
|
+
|
1164
|
+
sets node named name.
|
1165
|
+
=end
|
1166
|
+
def []=(name, node)
|
1167
|
+
raise "parameter error" if node.nodeName != name
|
1168
|
+
@nodes[name] = node
|
1169
|
+
end
|
1170
|
+
|
1171
|
+
=begin
|
1172
|
+
--- NamedNodeMap#each()
|
1173
|
+
|
1174
|
+
iterates over each pair of name and node(name, node) of the namedNodeMap.
|
1175
|
+
=end
|
1176
|
+
def each
|
1177
|
+
@nodes.each do |key, value|
|
1178
|
+
yield(value)
|
1179
|
+
end
|
1180
|
+
end
|
1181
|
+
|
1182
|
+
=begin
|
1183
|
+
--- NamedNodeMap#size()
|
1184
|
+
|
1185
|
+
[DOM]
|
1186
|
+
returns the number of nodes in the map.
|
1187
|
+
=end
|
1188
|
+
## [DOM]
|
1189
|
+
def size
|
1190
|
+
@nodes.length
|
1191
|
+
end
|
1192
|
+
alias length size
|
1193
|
+
|
1194
|
+
## get nodeValues by names
|
1195
|
+
## names ::= name ('|' name)*
|
1196
|
+
def _getValues(names)
|
1197
|
+
ret = []
|
1198
|
+
names.split('|').each do |name|
|
1199
|
+
if !@nodes[name].nil?
|
1200
|
+
ret.push(@nodes[name].nodeValue)
|
1201
|
+
end
|
1202
|
+
end
|
1203
|
+
ret
|
1204
|
+
end
|
1205
|
+
end
|
1206
|
+
|
1207
|
+
=begin
|
1208
|
+
== Class XML::DOM::NodeList
|
1209
|
+
|
1210
|
+
|
1211
|
+
=end
|
1212
|
+
class NodeList
|
1213
|
+
|
1214
|
+
=begin
|
1215
|
+
=== Class Methods
|
1216
|
+
|
1217
|
+
--- NodeList.new(nodes = nil)
|
1218
|
+
|
1219
|
+
creates a new NodeList.
|
1220
|
+
=end
|
1221
|
+
def initialize(nodes = nil)
|
1222
|
+
if nodes.nil?
|
1223
|
+
@nodes = []
|
1224
|
+
elsif nodes.is_a?(Array)
|
1225
|
+
@nodes = nodes
|
1226
|
+
else
|
1227
|
+
raise "parameter error"
|
1228
|
+
end
|
1229
|
+
end
|
1230
|
+
|
1231
|
+
=begin
|
1232
|
+
=== Methods
|
1233
|
+
|
1234
|
+
--- NodeList#item(index)
|
1235
|
+
|
1236
|
+
[DOM]
|
1237
|
+
return the indexth item in the NodeList.
|
1238
|
+
=end
|
1239
|
+
## [DOM]
|
1240
|
+
def item(index)
|
1241
|
+
@nodes[index]
|
1242
|
+
end
|
1243
|
+
|
1244
|
+
=begin
|
1245
|
+
--- NodeList#size()
|
1246
|
+
|
1247
|
+
return size of NodeList.
|
1248
|
+
=end
|
1249
|
+
def size
|
1250
|
+
@nodes.length
|
1251
|
+
end
|
1252
|
+
alias length size
|
1253
|
+
|
1254
|
+
=begin
|
1255
|
+
--- NodeList#[](index)
|
1256
|
+
|
1257
|
+
return indexth node of the NodeList.
|
1258
|
+
=end
|
1259
|
+
def [](index)
|
1260
|
+
@nodes[index]
|
1261
|
+
end
|
1262
|
+
|
1263
|
+
=begin
|
1264
|
+
--- NodeList#[]=(*p)
|
1265
|
+
|
1266
|
+
set node of indexth node of the NodeList.
|
1267
|
+
=end
|
1268
|
+
def []=(*p)
|
1269
|
+
if p.length == 2
|
1270
|
+
@nodes[p[0]] = p[1]
|
1271
|
+
elsif p.length == 3
|
1272
|
+
@nodes[p[0], p[1]] = p[2]
|
1273
|
+
end
|
1274
|
+
end
|
1275
|
+
|
1276
|
+
=begin
|
1277
|
+
--- NodeList#each
|
1278
|
+
|
1279
|
+
iterates over each node of the NodeList.
|
1280
|
+
=end
|
1281
|
+
def each
|
1282
|
+
@nodes.each do |value|
|
1283
|
+
yield(value)
|
1284
|
+
end
|
1285
|
+
end
|
1286
|
+
|
1287
|
+
=begin
|
1288
|
+
--- NodeList#reversible_each(reverse = false)
|
1289
|
+
|
1290
|
+
iterates over each node of the reversed NodeList.
|
1291
|
+
=end
|
1292
|
+
## [Masaki Fukushima]
|
1293
|
+
def reversible_each(reverse = false)
|
1294
|
+
if !reverse
|
1295
|
+
@nodes.each do |value|
|
1296
|
+
yield(value)
|
1297
|
+
end
|
1298
|
+
else
|
1299
|
+
@nodes.reverse_each do |value|
|
1300
|
+
yield(value)
|
1301
|
+
end
|
1302
|
+
end
|
1303
|
+
end
|
1304
|
+
|
1305
|
+
=begin
|
1306
|
+
--- NodeList#push(*nodes)
|
1307
|
+
|
1308
|
+
adds nodes into the NodeList.
|
1309
|
+
=end
|
1310
|
+
def push(*nodes)
|
1311
|
+
nodes.each do |node|
|
1312
|
+
if node.is_a?(Array)
|
1313
|
+
self.push(*node)
|
1314
|
+
elsif node.is_a?(NodeList)
|
1315
|
+
@nodes.concat(node.to_a)
|
1316
|
+
elsif node.is_a?(Node)
|
1317
|
+
@nodes << node
|
1318
|
+
else
|
1319
|
+
raise "parameter error"
|
1320
|
+
end
|
1321
|
+
end
|
1322
|
+
self
|
1323
|
+
end
|
1324
|
+
|
1325
|
+
=begin
|
1326
|
+
--- NodeList#concat(*nodes)
|
1327
|
+
|
1328
|
+
alias of NodeList#push.
|
1329
|
+
=end
|
1330
|
+
alias concat push
|
1331
|
+
|
1332
|
+
=begin
|
1333
|
+
--- NodeList#pop
|
1334
|
+
|
1335
|
+
pops and returns the last node of the NodeList.
|
1336
|
+
=end
|
1337
|
+
def pop
|
1338
|
+
@nodes.pop
|
1339
|
+
end
|
1340
|
+
|
1341
|
+
=begin
|
1342
|
+
--- NodeList#shift
|
1343
|
+
|
1344
|
+
removes and returns the first node of the NodeList.
|
1345
|
+
=end
|
1346
|
+
def shift
|
1347
|
+
@nodes.shift
|
1348
|
+
end
|
1349
|
+
|
1350
|
+
=begin
|
1351
|
+
--- NodeList#to_s
|
1352
|
+
|
1353
|
+
returns the string representation of the NodeList.
|
1354
|
+
=end
|
1355
|
+
def to_s
|
1356
|
+
@nodes.to_s
|
1357
|
+
end
|
1358
|
+
|
1359
|
+
=begin
|
1360
|
+
--- NodeList#reverse
|
1361
|
+
|
1362
|
+
returns the reversed NodeList.
|
1363
|
+
=end
|
1364
|
+
def reverse
|
1365
|
+
@nodes.reverse
|
1366
|
+
end
|
1367
|
+
|
1368
|
+
=begin
|
1369
|
+
--- NodeList#to_a
|
1370
|
+
|
1371
|
+
converts the NodeList into an array.
|
1372
|
+
=end
|
1373
|
+
def to_a
|
1374
|
+
@nodes
|
1375
|
+
end
|
1376
|
+
|
1377
|
+
=begin
|
1378
|
+
--- NodeList#+(nodes)
|
1379
|
+
|
1380
|
+
return the newly created concatenated NodeList.
|
1381
|
+
=end
|
1382
|
+
def +(nodes)
|
1383
|
+
if nodes.nil?
|
1384
|
+
NodeList.new(@nodes)
|
1385
|
+
elsif nodes.is_a?(Array)
|
1386
|
+
NodeList.new(@nodes + nodes)
|
1387
|
+
elsif nodes.is_a?(NodeList)
|
1388
|
+
NodeList.new(@nodes + nodes.to_a)
|
1389
|
+
elsif nodes.is_a?(Node)
|
1390
|
+
NodeList.new(@nodes + [nodes])
|
1391
|
+
else
|
1392
|
+
raise "parameter error"
|
1393
|
+
end
|
1394
|
+
end
|
1395
|
+
|
1396
|
+
=begin
|
1397
|
+
--- NodeList#<<(nodes)
|
1398
|
+
|
1399
|
+
appends nodes to the NodeList.
|
1400
|
+
=end
|
1401
|
+
## modified by Masaki Fukushima
|
1402
|
+
def <<(nodes)
|
1403
|
+
if nodes.nil?
|
1404
|
+
## no change
|
1405
|
+
elsif nodes.is_a?(Array)
|
1406
|
+
@nodes.concat(nodes)
|
1407
|
+
elsif nodes.is_a?(NodeList)
|
1408
|
+
@nodes.concat(nodes.to_a)
|
1409
|
+
elsif nodes.is_a?(Node)
|
1410
|
+
@nodes << nodes
|
1411
|
+
else
|
1412
|
+
raise "parameter error"
|
1413
|
+
end
|
1414
|
+
self
|
1415
|
+
end
|
1416
|
+
|
1417
|
+
## get nodeValues by names
|
1418
|
+
## names ::= name ('|' name)*
|
1419
|
+
def _getValues(names)
|
1420
|
+
ret = []
|
1421
|
+
names.split('|').each do |name|
|
1422
|
+
if !@nodes[name].nil?
|
1423
|
+
ret.push(@nodes[name].nodeValue)
|
1424
|
+
end
|
1425
|
+
end
|
1426
|
+
ret
|
1427
|
+
end
|
1428
|
+
end
|
1429
|
+
|
1430
|
+
=begin
|
1431
|
+
== Class XML::DOM::DocumentFragment
|
1432
|
+
|
1433
|
+
=== superclass
|
1434
|
+
Node
|
1435
|
+
|
1436
|
+
=end
|
1437
|
+
class DocumentFragment<Node
|
1438
|
+
|
1439
|
+
=begin
|
1440
|
+
=== Class Methods
|
1441
|
+
|
1442
|
+
--- DocumentFragment.new(*children)
|
1443
|
+
|
1444
|
+
creates a new DocumentFragment.
|
1445
|
+
=end
|
1446
|
+
|
1447
|
+
def initialize(*children)
|
1448
|
+
super(*children)
|
1449
|
+
end
|
1450
|
+
|
1451
|
+
=begin
|
1452
|
+
=== Methods
|
1453
|
+
|
1454
|
+
--- DocumentFragment#nodeType
|
1455
|
+
|
1456
|
+
[DOM]
|
1457
|
+
returns the nodeType.
|
1458
|
+
=end
|
1459
|
+
## [DOM]
|
1460
|
+
def nodeType
|
1461
|
+
DOCUMENT_FRAGMENT_NODE
|
1462
|
+
end
|
1463
|
+
|
1464
|
+
=begin
|
1465
|
+
--- DocumentFragment#nodeName
|
1466
|
+
|
1467
|
+
[DOM]
|
1468
|
+
returns the nodeName.
|
1469
|
+
=end
|
1470
|
+
## [DOM]
|
1471
|
+
def nodeName
|
1472
|
+
"#document-fragment"
|
1473
|
+
end
|
1474
|
+
|
1475
|
+
=begin
|
1476
|
+
--- DocumentFragment#parentNode=(p)
|
1477
|
+
|
1478
|
+
returns the parent of this node.
|
1479
|
+
=end
|
1480
|
+
## DocumentFragment should not have the parent node.
|
1481
|
+
def parentNode=(p)
|
1482
|
+
@children.each do |child|
|
1483
|
+
child.parentNode = p
|
1484
|
+
end if @children
|
1485
|
+
end
|
1486
|
+
|
1487
|
+
def _checkNode(node)
|
1488
|
+
unless node.nodeType == ELEMENT_NODE ||
|
1489
|
+
node.nodeType == PROCESSING_INSTRUCTION_NODE ||
|
1490
|
+
node.nodeType == COMMENT_NODE ||
|
1491
|
+
node.nodeType == TEXT_NODE ||
|
1492
|
+
node.nodeType == CDATA_SECTION_NODE ||
|
1493
|
+
node.nodeType == ENTITY_REFERENCE_NODE
|
1494
|
+
raise DOMException.new(DOMException::HIERARCHY_REQUEST_ERR)
|
1495
|
+
end
|
1496
|
+
end
|
1497
|
+
|
1498
|
+
end
|
1499
|
+
|
1500
|
+
=begin
|
1501
|
+
== Class XML::DOM::Document
|
1502
|
+
|
1503
|
+
=== superclass
|
1504
|
+
Node
|
1505
|
+
|
1506
|
+
=end
|
1507
|
+
class Document<Node
|
1508
|
+
=begin
|
1509
|
+
=== Class Methods
|
1510
|
+
--- Document.new(*children)
|
1511
|
+
|
1512
|
+
creates a new Document.
|
1513
|
+
=end
|
1514
|
+
|
1515
|
+
## new([child1, child2, ...]) or
|
1516
|
+
## new(child1, child2, ...)
|
1517
|
+
## child?: String or Node
|
1518
|
+
def initialize(*children)
|
1519
|
+
super(*children)
|
1520
|
+
end
|
1521
|
+
|
1522
|
+
=begin
|
1523
|
+
=== Methods
|
1524
|
+
|
1525
|
+
--- Document#nodeType
|
1526
|
+
|
1527
|
+
[DOM]
|
1528
|
+
returns the nodeType.
|
1529
|
+
=end
|
1530
|
+
## [DOM]
|
1531
|
+
def nodeType
|
1532
|
+
DOCUMENT_NODE
|
1533
|
+
end
|
1534
|
+
|
1535
|
+
=begin
|
1536
|
+
--- Document#nodeName
|
1537
|
+
|
1538
|
+
[DOM]
|
1539
|
+
returns the nodeName.
|
1540
|
+
=end
|
1541
|
+
## [DOM]
|
1542
|
+
def nodeName
|
1543
|
+
"#document"
|
1544
|
+
end
|
1545
|
+
|
1546
|
+
=begin
|
1547
|
+
--- Document#documentElement
|
1548
|
+
|
1549
|
+
[DOM]
|
1550
|
+
returns root element of the Docuemnt.
|
1551
|
+
=end
|
1552
|
+
## [DOM]
|
1553
|
+
def documentElement
|
1554
|
+
@children.each do |child|
|
1555
|
+
if child.nodeType == ELEMENT_NODE
|
1556
|
+
return child
|
1557
|
+
end
|
1558
|
+
end if @children
|
1559
|
+
nil
|
1560
|
+
end
|
1561
|
+
|
1562
|
+
=begin
|
1563
|
+
--- Document#doctype
|
1564
|
+
|
1565
|
+
[DOM]
|
1566
|
+
returns DTD associated with this document.
|
1567
|
+
=end
|
1568
|
+
## [DOM]
|
1569
|
+
def doctype
|
1570
|
+
@children.each do |child|
|
1571
|
+
if child.nodeType == DOCUMENT_TYPE_NODE
|
1572
|
+
return child
|
1573
|
+
end
|
1574
|
+
end if @children
|
1575
|
+
nil
|
1576
|
+
end
|
1577
|
+
|
1578
|
+
=begin
|
1579
|
+
--- Document#getElementsByTagName(tagname)
|
1580
|
+
|
1581
|
+
[DOM]
|
1582
|
+
returns a NodeList of all the Elements with a given tag name.
|
1583
|
+
=end
|
1584
|
+
## [DOM] (but this is not "live")
|
1585
|
+
def getElementsByTagName(tagname)
|
1586
|
+
ret = NodeList.new
|
1587
|
+
@children.each do |node|
|
1588
|
+
if node.nodeType == ELEMENT_NODE
|
1589
|
+
if tagname == '*' || node.nodeName == tagname
|
1590
|
+
ret << node
|
1591
|
+
end
|
1592
|
+
ret << node.getElementsByTagName(tagname)
|
1593
|
+
end
|
1594
|
+
end if @children
|
1595
|
+
ret
|
1596
|
+
end
|
1597
|
+
|
1598
|
+
=begin
|
1599
|
+
--- Document#createElement(tagName)
|
1600
|
+
|
1601
|
+
[DOM]
|
1602
|
+
creates a Element.
|
1603
|
+
=end
|
1604
|
+
## [DOM]
|
1605
|
+
def createElement(tagName)
|
1606
|
+
ret = Element.new(tagName)
|
1607
|
+
ret.ownerDocument = self
|
1608
|
+
ret
|
1609
|
+
end
|
1610
|
+
|
1611
|
+
=begin
|
1612
|
+
--- Document#createTextNode(data)
|
1613
|
+
|
1614
|
+
[DOM]
|
1615
|
+
creates a TextNode.
|
1616
|
+
=end
|
1617
|
+
## [DOM]
|
1618
|
+
def createTextNode(data)
|
1619
|
+
ret = Text.new(data)
|
1620
|
+
ret.ownerDocument = self
|
1621
|
+
ret
|
1622
|
+
end
|
1623
|
+
|
1624
|
+
=begin
|
1625
|
+
--- Document#createCDATASection(data)
|
1626
|
+
|
1627
|
+
[DOM]
|
1628
|
+
creates a CDATASection.
|
1629
|
+
=end
|
1630
|
+
## [DOM]
|
1631
|
+
def createCDATASection(data)
|
1632
|
+
ret = CDATASection.new(data)
|
1633
|
+
ret.ownerDocument = self
|
1634
|
+
ret
|
1635
|
+
end
|
1636
|
+
|
1637
|
+
=begin
|
1638
|
+
--- Document#createComment(data)
|
1639
|
+
|
1640
|
+
[DOM]
|
1641
|
+
create a Comment.
|
1642
|
+
=end
|
1643
|
+
## [DOM]
|
1644
|
+
def createComment(data)
|
1645
|
+
ret = Comment.new(data)
|
1646
|
+
ret.ownerDocument = self
|
1647
|
+
ret
|
1648
|
+
end
|
1649
|
+
|
1650
|
+
=begin
|
1651
|
+
--- Document#createProcessingInstruction(target, data)
|
1652
|
+
|
1653
|
+
[DOM]
|
1654
|
+
create a ProcessingInstruction.
|
1655
|
+
=end
|
1656
|
+
## [DOM]
|
1657
|
+
def createProcessingInstruction(target, data)
|
1658
|
+
ret = ProcessingInstruction.new(target, data)
|
1659
|
+
ret.ownerDocument = self
|
1660
|
+
ret
|
1661
|
+
end
|
1662
|
+
|
1663
|
+
=begin
|
1664
|
+
--- Document#createAttribute(name)
|
1665
|
+
|
1666
|
+
[DOM]
|
1667
|
+
create a Attribute.
|
1668
|
+
=end
|
1669
|
+
## [DOM]
|
1670
|
+
def createAttribute(name)
|
1671
|
+
ret = Attr.new(name)
|
1672
|
+
ret.ownerDocument = self
|
1673
|
+
ret
|
1674
|
+
end
|
1675
|
+
|
1676
|
+
=begin
|
1677
|
+
--- Document#createEntityReference(name)
|
1678
|
+
|
1679
|
+
[DOM]
|
1680
|
+
create a EntityReference.
|
1681
|
+
=end
|
1682
|
+
## [DOM]
|
1683
|
+
def createEntityReference(name)
|
1684
|
+
ret = EntityReference.new(name)
|
1685
|
+
ret.ownerDocument = self
|
1686
|
+
ret
|
1687
|
+
end
|
1688
|
+
|
1689
|
+
=begin
|
1690
|
+
--- Document#createDocumentFragment()
|
1691
|
+
|
1692
|
+
[DOM]
|
1693
|
+
create a DocumentFragment.
|
1694
|
+
=end
|
1695
|
+
## [DOM]
|
1696
|
+
def createDocumentFragment
|
1697
|
+
ret = DocumentFragment.new
|
1698
|
+
ret.ownerDocument = self
|
1699
|
+
ret
|
1700
|
+
end
|
1701
|
+
|
1702
|
+
## set the ID list by the attribute name with the element name
|
1703
|
+
## (or wildcard)
|
1704
|
+
## [experimental implement]
|
1705
|
+
def _setIDAttr(attrname, elemname = '*')
|
1706
|
+
@idattrs = {} if @idattrs.nil?
|
1707
|
+
@idattrs[elemname] = attrname
|
1708
|
+
end
|
1709
|
+
|
1710
|
+
## get the ID list
|
1711
|
+
## [experimental implement]
|
1712
|
+
def _getIDAttrs
|
1713
|
+
return {'*'=>'id'} if @idattrs.nil?
|
1714
|
+
@idattrs
|
1715
|
+
end
|
1716
|
+
|
1717
|
+
## [DOM]
|
1718
|
+
def implementation
|
1719
|
+
return @implemantation if @implemantation
|
1720
|
+
## singleton
|
1721
|
+
@implemantation = DOMImplementation.instance
|
1722
|
+
end
|
1723
|
+
|
1724
|
+
def implementation=(impl)
|
1725
|
+
@implemantation = impl
|
1726
|
+
end
|
1727
|
+
|
1728
|
+
def _checkNode(node)
|
1729
|
+
unless node.nodeType == ELEMENT_NODE ||
|
1730
|
+
node.nodeType == PROCESSING_INSTRUCTION_NODE ||
|
1731
|
+
node.nodeType == COMMENT_NODE ||
|
1732
|
+
node.nodeType == DOCUMENT_TYPE_NODE
|
1733
|
+
raise DOMException.new(DOMException::HIERARCHY_REQUEST_ERR)
|
1734
|
+
end
|
1735
|
+
|
1736
|
+
if node.nodeType == ELEMENT_NODE
|
1737
|
+
@children.each do |n|
|
1738
|
+
if n.nodeType == ELEMENT_NODE
|
1739
|
+
raise DOMException.new(DOMException::HIERARCHY_REQUEST_ERR)
|
1740
|
+
end
|
1741
|
+
end
|
1742
|
+
end
|
1743
|
+
|
1744
|
+
if node.nodeType == DOCUMENT_TYPE_NODE
|
1745
|
+
@children.each do |n|
|
1746
|
+
if n.nodeType == DOCUMENT_TYPE_NODE
|
1747
|
+
raise DOMException.new(DOMException::HIERARCHY_REQUEST_ERR)
|
1748
|
+
end
|
1749
|
+
end
|
1750
|
+
end
|
1751
|
+
end
|
1752
|
+
|
1753
|
+
end
|
1754
|
+
|
1755
|
+
=begin
|
1756
|
+
== Class XML::DOM::Attr
|
1757
|
+
|
1758
|
+
=== superclass
|
1759
|
+
Node
|
1760
|
+
|
1761
|
+
=end
|
1762
|
+
class Attr<Node
|
1763
|
+
## new(name, [text1, text2, ...]) or
|
1764
|
+
## new(name, text1, text2, ...)
|
1765
|
+
## name: String
|
1766
|
+
## text?: String or Node
|
1767
|
+
|
1768
|
+
=begin
|
1769
|
+
=== Class Methods
|
1770
|
+
|
1771
|
+
--- Attr.new(name = nil, *text)
|
1772
|
+
|
1773
|
+
create a new Attr.
|
1774
|
+
=end
|
1775
|
+
def initialize(name = nil, *text)
|
1776
|
+
super(text)
|
1777
|
+
raise "parameter error" if !name
|
1778
|
+
@name = name
|
1779
|
+
@name.freeze
|
1780
|
+
end
|
1781
|
+
|
1782
|
+
=begin
|
1783
|
+
=== Methods
|
1784
|
+
|
1785
|
+
--- Attr#nodeType()
|
1786
|
+
|
1787
|
+
[DOM]
|
1788
|
+
returns the nodeType.
|
1789
|
+
=end
|
1790
|
+
## [DOM]
|
1791
|
+
def nodeType
|
1792
|
+
ATTRIBUTE_NODE
|
1793
|
+
end
|
1794
|
+
|
1795
|
+
=begin
|
1796
|
+
--- Attr#nodeName()
|
1797
|
+
|
1798
|
+
[DOM]
|
1799
|
+
returns the nodeName.
|
1800
|
+
=end
|
1801
|
+
## [DOM]
|
1802
|
+
def nodeName
|
1803
|
+
@name
|
1804
|
+
end
|
1805
|
+
|
1806
|
+
=begin
|
1807
|
+
--- Attr#nodeValue()
|
1808
|
+
|
1809
|
+
[DOM]
|
1810
|
+
returns the nodeValue.
|
1811
|
+
=end
|
1812
|
+
## [DOM]
|
1813
|
+
def nodeValue
|
1814
|
+
ret = ""
|
1815
|
+
@children.each do |child|
|
1816
|
+
ret << child.nodeValue
|
1817
|
+
end if @children
|
1818
|
+
ret
|
1819
|
+
end
|
1820
|
+
|
1821
|
+
=begin
|
1822
|
+
--- Attr#nodeValue=(text)
|
1823
|
+
|
1824
|
+
[DOM]
|
1825
|
+
returns the value of this node.
|
1826
|
+
=end
|
1827
|
+
## [DOM]
|
1828
|
+
def nodeValue=(text)
|
1829
|
+
self.childNodes = [text]
|
1830
|
+
end
|
1831
|
+
|
1832
|
+
=begin
|
1833
|
+
--- Attr#to_s()
|
1834
|
+
|
1835
|
+
return the string representation of the Attr.
|
1836
|
+
=end
|
1837
|
+
def to_s
|
1838
|
+
value = ""
|
1839
|
+
nodeValue.each_byte do |code|
|
1840
|
+
case code
|
1841
|
+
when 9, 10, 13
|
1842
|
+
value << sprintf("&#x%X;", code)
|
1843
|
+
when ?&
|
1844
|
+
value << "&"
|
1845
|
+
when ?"
|
1846
|
+
value << """
|
1847
|
+
when ?<
|
1848
|
+
value << "<"
|
1849
|
+
else
|
1850
|
+
value << code
|
1851
|
+
end
|
1852
|
+
end
|
1853
|
+
"#{@name}=\"#{value}\""
|
1854
|
+
end
|
1855
|
+
|
1856
|
+
=begin
|
1857
|
+
--- Attr#dump(depth = 0)
|
1858
|
+
|
1859
|
+
dump the Attr.
|
1860
|
+
=end
|
1861
|
+
def dump(depth = 0)
|
1862
|
+
print ' ' * depth * 2
|
1863
|
+
print "// #{self.to_s}\n"
|
1864
|
+
end
|
1865
|
+
|
1866
|
+
=begin
|
1867
|
+
--- Attr#cloneNode(deep = true)
|
1868
|
+
|
1869
|
+
[DOM]
|
1870
|
+
returns the copy of the Attr.
|
1871
|
+
=end
|
1872
|
+
## [DOM]
|
1873
|
+
def cloneNode(deep = true)
|
1874
|
+
super(deep, @name)
|
1875
|
+
end
|
1876
|
+
|
1877
|
+
=begin
|
1878
|
+
--- Attr#name()
|
1879
|
+
|
1880
|
+
[DOM]
|
1881
|
+
alias of nodeName.
|
1882
|
+
=end
|
1883
|
+
## [DOM]
|
1884
|
+
alias name nodeName
|
1885
|
+
|
1886
|
+
=begin
|
1887
|
+
--- Attr#value()
|
1888
|
+
|
1889
|
+
alias of nodeValue.
|
1890
|
+
|
1891
|
+
--- Attr#value=(value)
|
1892
|
+
|
1893
|
+
[DOM]
|
1894
|
+
alias of nodeValue=.
|
1895
|
+
=end
|
1896
|
+
## [DOM]
|
1897
|
+
alias value nodeValue
|
1898
|
+
alias value= nodeValue=
|
1899
|
+
|
1900
|
+
## [DOM]
|
1901
|
+
def specified; @specified; end
|
1902
|
+
def specified=(is_specified); @specified = is_specified; end
|
1903
|
+
|
1904
|
+
def _checkNode(node)
|
1905
|
+
unless node.nodeType == TEXT_NODE ||
|
1906
|
+
node.nodeType == ENTITY_REFERENCE_NODE
|
1907
|
+
raise DOMException.new(DOMException::HIERARCHY_REQUEST_ERR)
|
1908
|
+
end
|
1909
|
+
end
|
1910
|
+
|
1911
|
+
end
|
1912
|
+
|
1913
|
+
=begin
|
1914
|
+
== Class XML::DOM::Attribute
|
1915
|
+
|
1916
|
+
alias of Attr.
|
1917
|
+
=end
|
1918
|
+
Attribute = Attr
|
1919
|
+
|
1920
|
+
=begin
|
1921
|
+
== Class XML::DOM::Element
|
1922
|
+
|
1923
|
+
=== superclass
|
1924
|
+
Node
|
1925
|
+
|
1926
|
+
=end
|
1927
|
+
class Element<Node
|
1928
|
+
|
1929
|
+
=begin
|
1930
|
+
=== Class Methods
|
1931
|
+
|
1932
|
+
--- Element.new(tag = nil, attrs = nil, *children)
|
1933
|
+
|
1934
|
+
create a new Element.
|
1935
|
+
=end
|
1936
|
+
## new(tag, attrs, [child1, child2, ...]) or
|
1937
|
+
## new(tag, attrs, child1, child2, ...)
|
1938
|
+
## tag: String
|
1939
|
+
## attrs: Hash, Attr or Array of Attr (or nil)
|
1940
|
+
## child?: String or Node
|
1941
|
+
def initialize(tag = nil, attr = nil, *children)
|
1942
|
+
super(*children)
|
1943
|
+
raise "parameter error" if !tag
|
1944
|
+
@name = tag.freeze
|
1945
|
+
if attr.nil?
|
1946
|
+
@attr = NamedNodeMap.new([])
|
1947
|
+
elsif attr.is_a?(Hash)
|
1948
|
+
nodes = []
|
1949
|
+
attr.each do |key, value|
|
1950
|
+
nodes.push(Attr.new(key, value))
|
1951
|
+
end
|
1952
|
+
@attr = NamedNodeMap.new(nodes)
|
1953
|
+
elsif attr.is_a?(Array)
|
1954
|
+
@attr = NamedNodeMap.new(attr)
|
1955
|
+
elsif attr.is_a?(Attr)
|
1956
|
+
@attr = NamedNodeMap.new([attr])
|
1957
|
+
else
|
1958
|
+
raise "parameter error: #{attr}"
|
1959
|
+
end
|
1960
|
+
end
|
1961
|
+
|
1962
|
+
=begin
|
1963
|
+
=== Methods
|
1964
|
+
|
1965
|
+
--- Element#nodeType()
|
1966
|
+
|
1967
|
+
[DOM]
|
1968
|
+
returns the nodeType.
|
1969
|
+
=end
|
1970
|
+
## [DOM]
|
1971
|
+
def nodeType
|
1972
|
+
ELEMENT_NODE
|
1973
|
+
end
|
1974
|
+
|
1975
|
+
=begin
|
1976
|
+
--- Element#nodeName()
|
1977
|
+
|
1978
|
+
[DOM]
|
1979
|
+
returns the nodeName.
|
1980
|
+
=end
|
1981
|
+
## [DOM]
|
1982
|
+
def nodeName
|
1983
|
+
@name
|
1984
|
+
end
|
1985
|
+
|
1986
|
+
=begin
|
1987
|
+
--- Element#attributes()
|
1988
|
+
|
1989
|
+
[DOM]
|
1990
|
+
returns the attributes of this Element.
|
1991
|
+
=end
|
1992
|
+
## [DOM]
|
1993
|
+
def attributes
|
1994
|
+
if iterator?
|
1995
|
+
@attr.each do |key, value|
|
1996
|
+
yield(value)
|
1997
|
+
end if @attr
|
1998
|
+
else
|
1999
|
+
@attr
|
2000
|
+
end
|
2001
|
+
end
|
2002
|
+
|
2003
|
+
=begin
|
2004
|
+
--- Element#to_s()
|
2005
|
+
|
2006
|
+
return the string representation of the Element.
|
2007
|
+
=end
|
2008
|
+
def to_s
|
2009
|
+
attr = ''
|
2010
|
+
@attr.each do |a|
|
2011
|
+
attr << ' ' + a.to_s
|
2012
|
+
end if @attr
|
2013
|
+
content = super
|
2014
|
+
if content != ''
|
2015
|
+
ret = "<#{@name}#{attr}>#{content}</#{@name}>"
|
2016
|
+
else
|
2017
|
+
ret = "<#{@name}#{attr}/>"
|
2018
|
+
end
|
2019
|
+
ret << "\n" if parentNode.nodeType == DOCUMENT_NODE
|
2020
|
+
ret
|
2021
|
+
end
|
2022
|
+
|
2023
|
+
=begin
|
2024
|
+
--- Element#dump(depth = 0)
|
2025
|
+
|
2026
|
+
dumps the Element.
|
2027
|
+
=end
|
2028
|
+
def dump(depth = 0)
|
2029
|
+
attr = ''
|
2030
|
+
@attr.each do |a| ## self.attributes do |a|
|
2031
|
+
attr += a.to_s + ", "
|
2032
|
+
end if @attr
|
2033
|
+
attr.chop!
|
2034
|
+
attr.chop!
|
2035
|
+
print ' ' * depth * 2
|
2036
|
+
print "#{@name}(#{attr})\n"
|
2037
|
+
@children.each do |child|
|
2038
|
+
child.dump(depth + 1)
|
2039
|
+
end if @children
|
2040
|
+
end
|
2041
|
+
|
2042
|
+
=begin
|
2043
|
+
--- Element#tagName()
|
2044
|
+
|
2045
|
+
[DOM]
|
2046
|
+
alias of nodeName.
|
2047
|
+
=end
|
2048
|
+
## [DOM]
|
2049
|
+
alias tagName nodeName
|
2050
|
+
|
2051
|
+
=begin
|
2052
|
+
--- Element#getAttribute(name)
|
2053
|
+
|
2054
|
+
[DOM]
|
2055
|
+
retrieves an attribute value by name.
|
2056
|
+
=end
|
2057
|
+
## [DOM]
|
2058
|
+
def getAttribute(name)
|
2059
|
+
attr = getAttributeNode(name)
|
2060
|
+
if attr.nil?
|
2061
|
+
''
|
2062
|
+
else
|
2063
|
+
attr.nodeValue
|
2064
|
+
end
|
2065
|
+
end
|
2066
|
+
|
2067
|
+
=begin
|
2068
|
+
--- Element#setAttribute(name, value)
|
2069
|
+
|
2070
|
+
[DOM]
|
2071
|
+
adds a new attribute.
|
2072
|
+
=end
|
2073
|
+
## [DOM]
|
2074
|
+
def setAttribute(name, value)
|
2075
|
+
if @ownerDocument
|
2076
|
+
attr = @ownerDocument.createAttribute(name)
|
2077
|
+
attr.appendChild(@ownerDocument.createTextNode(value))
|
2078
|
+
else
|
2079
|
+
attr = Attribute.new(name)
|
2080
|
+
attr.appendChild(Text.new(value))
|
2081
|
+
end
|
2082
|
+
setAttributeNode(attr)
|
2083
|
+
end
|
2084
|
+
|
2085
|
+
=begin
|
2086
|
+
--- Element#removeAttribute(name)
|
2087
|
+
|
2088
|
+
[DOM]
|
2089
|
+
remove an attribute by name.
|
2090
|
+
=end
|
2091
|
+
## [DOM]
|
2092
|
+
def removeAttribute(name)
|
2093
|
+
ret = getAttributeNode(name)
|
2094
|
+
removeAttributeNode(ret) if ret
|
2095
|
+
end
|
2096
|
+
|
2097
|
+
=begin
|
2098
|
+
--- Element#getAttributeNode(name)
|
2099
|
+
|
2100
|
+
[DOM]
|
2101
|
+
retrieves an Attr node by name.
|
2102
|
+
=end
|
2103
|
+
## [DOM]
|
2104
|
+
def getAttributeNode(name)
|
2105
|
+
@attr.getNamedItem(name)
|
2106
|
+
end
|
2107
|
+
|
2108
|
+
=begin
|
2109
|
+
--- Element#setAttributeNode(newAttr)
|
2110
|
+
|
2111
|
+
[DOM]
|
2112
|
+
adds a new attribute.
|
2113
|
+
=end
|
2114
|
+
## [DOM]
|
2115
|
+
def setAttributeNode(newAttr)
|
2116
|
+
ret = getAttributeNode(newAttr.nodeName)
|
2117
|
+
if ret == newAttr
|
2118
|
+
raise DOMException.new(DOMException::INUSE_ATTRIBUTE_ERR)
|
2119
|
+
end
|
2120
|
+
@attr.setNamedItem(newAttr)
|
2121
|
+
ret
|
2122
|
+
end
|
2123
|
+
|
2124
|
+
=begin
|
2125
|
+
--- Element#removeAttributeNode(oldAttr)
|
2126
|
+
|
2127
|
+
[DOM]
|
2128
|
+
removes the specified attribute.
|
2129
|
+
=end
|
2130
|
+
## [DOM]
|
2131
|
+
def removeAttributeNode(oldAttr)
|
2132
|
+
ret = getAttributeNode(oldAttr.nodeName)
|
2133
|
+
if ret.nil? || ret != oldAttr
|
2134
|
+
raise DOMException.new(DOMException::NOT_FOUND_ERR)
|
2135
|
+
end
|
2136
|
+
@attr.removeNamedItem(oldAttr.nodeName)
|
2137
|
+
ret
|
2138
|
+
end
|
2139
|
+
|
2140
|
+
=begin
|
2141
|
+
--- Element#getElementsByTagName(tagname)
|
2142
|
+
|
2143
|
+
[DOM]
|
2144
|
+
returns a NodeList of all descendant elements with given tag name.
|
2145
|
+
=end
|
2146
|
+
## [DOM] (but this is not "live")
|
2147
|
+
def getElementsByTagName(tagname)
|
2148
|
+
ret = NodeList.new
|
2149
|
+
@children.each do |node|
|
2150
|
+
if node.nodeType == ELEMENT_NODE
|
2151
|
+
if tagname == '*' || node.nodeName == tagname
|
2152
|
+
ret << node
|
2153
|
+
end
|
2154
|
+
ret << node.getElementsByTagName(tagname)
|
2155
|
+
end
|
2156
|
+
end if @children
|
2157
|
+
ret
|
2158
|
+
end
|
2159
|
+
|
2160
|
+
def _getMyLocation(parent)
|
2161
|
+
index = 1
|
2162
|
+
parent.childNodes do |child|
|
2163
|
+
if child == self
|
2164
|
+
return "child(#{index},#{@name})"
|
2165
|
+
end
|
2166
|
+
if child.nodeType == ELEMENT_NODE && child.nodeName == @name
|
2167
|
+
index += 1
|
2168
|
+
end
|
2169
|
+
end
|
2170
|
+
nil
|
2171
|
+
end
|
2172
|
+
|
2173
|
+
|
2174
|
+
=begin
|
2175
|
+
--- Element#normalize
|
2176
|
+
|
2177
|
+
[DOM]
|
2178
|
+
puts all Text nodes in the full depth of the sub-tree under this
|
2179
|
+
Eelemnt.
|
2180
|
+
=end
|
2181
|
+
## [DOM]
|
2182
|
+
def normalize
|
2183
|
+
return if @children.nil?
|
2184
|
+
old = nil
|
2185
|
+
children = @children.to_a.dup
|
2186
|
+
children.each do |child|
|
2187
|
+
if !old.nil? && old.nodeType == TEXT_NODE &&
|
2188
|
+
child.nodeType == TEXT_NODE
|
2189
|
+
old.appendData(child.nodeValue)
|
2190
|
+
self.removeChild(child)
|
2191
|
+
else
|
2192
|
+
if child.nodeType == ELEMENT_NODE
|
2193
|
+
child.normalize
|
2194
|
+
end
|
2195
|
+
old = child
|
2196
|
+
end
|
2197
|
+
end
|
2198
|
+
end
|
2199
|
+
|
2200
|
+
=begin
|
2201
|
+
--- Element#cloneNode(deep = true)
|
2202
|
+
|
2203
|
+
[DOM]
|
2204
|
+
returns the copy of the Element.
|
2205
|
+
=end
|
2206
|
+
## [DOM]
|
2207
|
+
def cloneNode(deep = true)
|
2208
|
+
attrs = []
|
2209
|
+
@attr.each do |attr|
|
2210
|
+
attrs.push(attr.cloneNode(true))
|
2211
|
+
end
|
2212
|
+
super(deep, @name, attrs)
|
2213
|
+
end
|
2214
|
+
|
2215
|
+
## get the list of nodeValues by IDs
|
2216
|
+
## [experimental implement]
|
2217
|
+
def _getIDVals(ids = nil)
|
2218
|
+
if ids.nil?
|
2219
|
+
doc = ownerDocument
|
2220
|
+
return [] if doc.nil?
|
2221
|
+
ids = doc._getIDAttrs
|
2222
|
+
end
|
2223
|
+
|
2224
|
+
idelem = []
|
2225
|
+
if !ids[nodeName].nil?
|
2226
|
+
return attributes._getValues(ids[nodeName])
|
2227
|
+
elsif !ids['*'].nil?
|
2228
|
+
return attributes._getValues(ids['*'])
|
2229
|
+
end
|
2230
|
+
return []
|
2231
|
+
end
|
2232
|
+
|
2233
|
+
=begin
|
2234
|
+
--- Element#trim(preserve = false)
|
2235
|
+
|
2236
|
+
trim extra whitespaces.
|
2237
|
+
=end
|
2238
|
+
## trim extra whitespaces
|
2239
|
+
## if attribute 'xml:space' is 'preserve',
|
2240
|
+
## don't trim any white spaces
|
2241
|
+
def trim(preserve = false)
|
2242
|
+
if !attributes['xml:space'].nil?
|
2243
|
+
value = attributes['xml:space'].nodeValue
|
2244
|
+
if value == 'preserve'
|
2245
|
+
preserve = true
|
2246
|
+
elsif value == 'default'
|
2247
|
+
preserve = false
|
2248
|
+
end
|
2249
|
+
end
|
2250
|
+
return nil if @children.nil?
|
2251
|
+
children = @children.to_a.dup
|
2252
|
+
children.each do |child|
|
2253
|
+
if !preserve && (child.nodeType == TEXT_NODE ||
|
2254
|
+
child.nodeType == CDATA_SECTION_NODE)
|
2255
|
+
if child.trim == ""
|
2256
|
+
self.removeChild(child)
|
2257
|
+
end
|
2258
|
+
else
|
2259
|
+
child.trim(preserve)
|
2260
|
+
end
|
2261
|
+
end
|
2262
|
+
nil
|
2263
|
+
end
|
2264
|
+
|
2265
|
+
def _checkNode(node)
|
2266
|
+
unless node.nodeType == ELEMENT_NODE ||
|
2267
|
+
node.nodeType == TEXT_NODE ||
|
2268
|
+
node.nodeType == COMMENT_NODE ||
|
2269
|
+
node.nodeType == PROCESSING_INSTRUCTION_NODE ||
|
2270
|
+
node.nodeType == CDATA_SECTION_NODE ||
|
2271
|
+
node.nodeType == ENTITY_REFERENCE_NODE
|
2272
|
+
raise DOMException.new(DOMException::HIERARCHY_REQUEST_ERR)
|
2273
|
+
end
|
2274
|
+
end
|
2275
|
+
|
2276
|
+
end
|
2277
|
+
|
2278
|
+
=begin
|
2279
|
+
== Class XML::DOM::CharacterData
|
2280
|
+
|
2281
|
+
=== superclass
|
2282
|
+
Node
|
2283
|
+
|
2284
|
+
=end
|
2285
|
+
class CharacterData<Node
|
2286
|
+
|
2287
|
+
=begin
|
2288
|
+
=== Class Methods
|
2289
|
+
|
2290
|
+
--- CharacterData.new(text)
|
2291
|
+
|
2292
|
+
creates a new CharacterData.
|
2293
|
+
=end
|
2294
|
+
## new(text)
|
2295
|
+
## text: String
|
2296
|
+
def initialize(text = nil)
|
2297
|
+
super()
|
2298
|
+
raise "parameter error" if !text
|
2299
|
+
@value = text
|
2300
|
+
end
|
2301
|
+
|
2302
|
+
=begin
|
2303
|
+
=== Methods
|
2304
|
+
|
2305
|
+
--- CharacterData#data()
|
2306
|
+
|
2307
|
+
[DOM]
|
2308
|
+
returns the character data of the node.
|
2309
|
+
=end
|
2310
|
+
## [DOM]
|
2311
|
+
def data
|
2312
|
+
@value.dup
|
2313
|
+
end
|
2314
|
+
|
2315
|
+
=begin
|
2316
|
+
--- CharacterData#data=(p)
|
2317
|
+
|
2318
|
+
[DOM]
|
2319
|
+
set the character data of the node.
|
2320
|
+
=end
|
2321
|
+
## [DOM]
|
2322
|
+
def data=(p)
|
2323
|
+
@value = p
|
2324
|
+
end
|
2325
|
+
|
2326
|
+
=begin
|
2327
|
+
--- CharacterData#length()
|
2328
|
+
|
2329
|
+
[DOM]
|
2330
|
+
returns length of this CharacterData.
|
2331
|
+
=end
|
2332
|
+
## [DOM]
|
2333
|
+
def length
|
2334
|
+
@value.length
|
2335
|
+
end
|
2336
|
+
|
2337
|
+
=begin
|
2338
|
+
--- CharacterData#substringData(start, count)
|
2339
|
+
|
2340
|
+
[DOM]
|
2341
|
+
extracts a range of data from the node.
|
2342
|
+
=end
|
2343
|
+
## [DOM]
|
2344
|
+
def substringData(start, count)
|
2345
|
+
if start < 0 || start > @value.length || count < 0
|
2346
|
+
raise DOMException.new(DOMException::INDEX_SIZE_ERR)
|
2347
|
+
end
|
2348
|
+
## if the sum of start and count > length,
|
2349
|
+
## return all characters to the end of the value.
|
2350
|
+
@value[start, count]
|
2351
|
+
end
|
2352
|
+
|
2353
|
+
=begin
|
2354
|
+
--- CharacterData#appendData(str)
|
2355
|
+
|
2356
|
+
[DOM]
|
2357
|
+
append the string to the end of the character data.
|
2358
|
+
=end
|
2359
|
+
## [DOM]
|
2360
|
+
def appendData(str)
|
2361
|
+
@value << str
|
2362
|
+
end
|
2363
|
+
|
2364
|
+
=begin
|
2365
|
+
--- CharacterData#insertData(offset, str)
|
2366
|
+
|
2367
|
+
[DOM]
|
2368
|
+
insert a string at the specified character offset.
|
2369
|
+
=end
|
2370
|
+
## [DOM]
|
2371
|
+
def insertData(offset, str)
|
2372
|
+
if offset < 0 || offset > @value.length
|
2373
|
+
raise DOMException.new(DOMException::INDEX_SIZE_ERR)
|
2374
|
+
end
|
2375
|
+
@value[offset, 0] = str
|
2376
|
+
end
|
2377
|
+
|
2378
|
+
=begin
|
2379
|
+
--- CharacterData#deleteData(offset, count)
|
2380
|
+
|
2381
|
+
[DOM]
|
2382
|
+
removes a range of characters from the node.
|
2383
|
+
=end
|
2384
|
+
## [DOM]
|
2385
|
+
def deleteData(offset, count)
|
2386
|
+
if offset < 0 || offset > @value.length || count < 0
|
2387
|
+
raise DOMException.new(DOMException::INDEX_SIZE_ERR)
|
2388
|
+
end
|
2389
|
+
@value[offset, count] = ''
|
2390
|
+
end
|
2391
|
+
|
2392
|
+
=begin
|
2393
|
+
--- CharacterData#replaceData(offset, count, str)
|
2394
|
+
|
2395
|
+
[DOM]
|
2396
|
+
replaces the characters starting at the specified character offset
|
2397
|
+
with specified string.
|
2398
|
+
=end
|
2399
|
+
## [DOM]
|
2400
|
+
def replaceData(offset, count, str)
|
2401
|
+
if offset < 0 || offset > @value.length || count < 0
|
2402
|
+
raise DOMException.new(DOMException::INDEX_SIZE_ERR)
|
2403
|
+
end
|
2404
|
+
@value[offset, count] = str
|
2405
|
+
end
|
2406
|
+
|
2407
|
+
=begin
|
2408
|
+
--- CharacterData#cloneData(deep = true)
|
2409
|
+
|
2410
|
+
[DOM]
|
2411
|
+
returns the copy of the CharacterData.
|
2412
|
+
=end
|
2413
|
+
## [DOM]
|
2414
|
+
def cloneNode(deep = true)
|
2415
|
+
super(deep, @value.dup)
|
2416
|
+
end
|
2417
|
+
|
2418
|
+
=begin
|
2419
|
+
--- Text#nodeValue
|
2420
|
+
|
2421
|
+
[DOM]
|
2422
|
+
return nodevalue.
|
2423
|
+
|
2424
|
+
=end
|
2425
|
+
## [DOM]
|
2426
|
+
def nodeValue
|
2427
|
+
@value
|
2428
|
+
end
|
2429
|
+
|
2430
|
+
=begin
|
2431
|
+
--- CharacterData#nodeValue=(p)
|
2432
|
+
|
2433
|
+
[DOM]
|
2434
|
+
set nodevalue as p.
|
2435
|
+
=end
|
2436
|
+
## [DOM]
|
2437
|
+
def nodeValue=(p)
|
2438
|
+
@value = p
|
2439
|
+
end
|
2440
|
+
|
2441
|
+
end
|
2442
|
+
|
2443
|
+
=begin
|
2444
|
+
== Class XML::DOM::Text
|
2445
|
+
|
2446
|
+
=== superclass
|
2447
|
+
Node
|
2448
|
+
|
2449
|
+
=end
|
2450
|
+
class Text<CharacterData
|
2451
|
+
|
2452
|
+
=begin
|
2453
|
+
=== Class Methods
|
2454
|
+
|
2455
|
+
--- Text.new(text)
|
2456
|
+
|
2457
|
+
creates a new Text.
|
2458
|
+
=end
|
2459
|
+
## new(text)
|
2460
|
+
## text: String
|
2461
|
+
def initialize(text = nil)
|
2462
|
+
super(text)
|
2463
|
+
end
|
2464
|
+
|
2465
|
+
=begin
|
2466
|
+
=== Methods
|
2467
|
+
|
2468
|
+
--- Text#nodeType
|
2469
|
+
|
2470
|
+
[DOM]
|
2471
|
+
returns the nodeType.
|
2472
|
+
=end
|
2473
|
+
## [DOM]
|
2474
|
+
def nodeType
|
2475
|
+
TEXT_NODE
|
2476
|
+
end
|
2477
|
+
|
2478
|
+
=begin
|
2479
|
+
--- Text#nodeName
|
2480
|
+
|
2481
|
+
[DOM]
|
2482
|
+
returns the nodeName.
|
2483
|
+
=end
|
2484
|
+
## [DOM]
|
2485
|
+
def nodeName
|
2486
|
+
"#text"
|
2487
|
+
end
|
2488
|
+
|
2489
|
+
=begin
|
2490
|
+
--- Text#to_s
|
2491
|
+
|
2492
|
+
return the string representation of the Text.
|
2493
|
+
=end
|
2494
|
+
def to_s
|
2495
|
+
ret = ""
|
2496
|
+
@value.each_byte do |code|
|
2497
|
+
case (code)
|
2498
|
+
when 13
|
2499
|
+
ret << sprintf("&#x%X;", code)
|
2500
|
+
when ?&
|
2501
|
+
ret << "&"
|
2502
|
+
when ?<
|
2503
|
+
ret << "<"
|
2504
|
+
when ?>
|
2505
|
+
ret << ">"
|
2506
|
+
else
|
2507
|
+
ret << code
|
2508
|
+
end
|
2509
|
+
end
|
2510
|
+
ret
|
2511
|
+
end
|
2512
|
+
|
2513
|
+
=begin
|
2514
|
+
--- Text#dump(depth = 0)
|
2515
|
+
|
2516
|
+
dumps the Text.
|
2517
|
+
=end
|
2518
|
+
def dump(depth = 0)
|
2519
|
+
print ' ' * depth * 2
|
2520
|
+
print "#{@value.inspect}\n"
|
2521
|
+
end
|
2522
|
+
|
2523
|
+
def _getMyLocation(parent)
|
2524
|
+
index = 1
|
2525
|
+
parent.childNodes do |child|
|
2526
|
+
if child == self
|
2527
|
+
return "child(#{index},#text)"
|
2528
|
+
end
|
2529
|
+
if child.nodeType == TEXT_NODE
|
2530
|
+
index += 1
|
2531
|
+
end
|
2532
|
+
end
|
2533
|
+
nil
|
2534
|
+
end
|
2535
|
+
|
2536
|
+
=begin
|
2537
|
+
--- Text#splitText(offset)
|
2538
|
+
|
2539
|
+
[DOM]
|
2540
|
+
breaks this Text node into two Text nodes at the specified offset.
|
2541
|
+
=end
|
2542
|
+
## [DOM]
|
2543
|
+
def splitText(offset)
|
2544
|
+
if offset > @value.length || offset < 0
|
2545
|
+
raise DOMException.new(DOMException::INDEX_SIZE_ERR)
|
2546
|
+
end
|
2547
|
+
newText = @value[offset, @value.length]
|
2548
|
+
newNode = Text.new(newText)
|
2549
|
+
if !self.parentNode.nil?
|
2550
|
+
self.parentNode.insertAfter(newNode, self)
|
2551
|
+
end
|
2552
|
+
@value[offset, @value.length] = ""
|
2553
|
+
newNode
|
2554
|
+
end
|
2555
|
+
|
2556
|
+
=begin
|
2557
|
+
--- Text#trim(preserve = false)
|
2558
|
+
|
2559
|
+
trim extra whitespaces.
|
2560
|
+
=end
|
2561
|
+
def trim(preserve = false)
|
2562
|
+
if !preserve
|
2563
|
+
@value.sub!(/\A\s*([\s\S]*?)\s*\Z/, "\\1")
|
2564
|
+
return @value
|
2565
|
+
end
|
2566
|
+
nil
|
2567
|
+
end
|
2568
|
+
|
2569
|
+
end
|
2570
|
+
|
2571
|
+
=begin
|
2572
|
+
== Class XML::DOM::Comment
|
2573
|
+
|
2574
|
+
=== superclass
|
2575
|
+
CharacterData
|
2576
|
+
|
2577
|
+
=end
|
2578
|
+
class Comment<CharacterData
|
2579
|
+
|
2580
|
+
=begin
|
2581
|
+
=== Class Methods
|
2582
|
+
|
2583
|
+
--- Comment.new(text)
|
2584
|
+
|
2585
|
+
creates a new Comment.
|
2586
|
+
=end
|
2587
|
+
## new(text)
|
2588
|
+
## text: String
|
2589
|
+
def initialize(text = nil)
|
2590
|
+
super(text)
|
2591
|
+
raise "parameter error" if !text
|
2592
|
+
end
|
2593
|
+
|
2594
|
+
=begin
|
2595
|
+
=== Methods
|
2596
|
+
|
2597
|
+
--- Comment#nodeType
|
2598
|
+
|
2599
|
+
[DOM]
|
2600
|
+
returns the nodeType.
|
2601
|
+
=end
|
2602
|
+
## [DOM]
|
2603
|
+
def nodeType
|
2604
|
+
COMMENT_NODE
|
2605
|
+
end
|
2606
|
+
|
2607
|
+
=begin
|
2608
|
+
--- Comment#nodeName
|
2609
|
+
|
2610
|
+
[DOM]
|
2611
|
+
returns the nodeName.
|
2612
|
+
=end
|
2613
|
+
## [DOM]
|
2614
|
+
def nodeName
|
2615
|
+
"#comment"
|
2616
|
+
end
|
2617
|
+
|
2618
|
+
=begin
|
2619
|
+
--- Comment#to_s
|
2620
|
+
|
2621
|
+
returns the string representation of the Comment.
|
2622
|
+
=end
|
2623
|
+
def to_s
|
2624
|
+
ret = "<!--#{@value}-->"
|
2625
|
+
ret << "\n" if parentNode.nodeType == DOCUMENT_NODE
|
2626
|
+
ret
|
2627
|
+
end
|
2628
|
+
|
2629
|
+
=begin
|
2630
|
+
--- Comment#dump(depth =0)
|
2631
|
+
|
2632
|
+
dumps the Comment.
|
2633
|
+
=end
|
2634
|
+
def dump(depth = 0)
|
2635
|
+
print ' ' * depth * 2
|
2636
|
+
print "<!--#{@value.inspect}-->\n"
|
2637
|
+
end
|
2638
|
+
|
2639
|
+
def _getMyLocation(parent)
|
2640
|
+
index = 1
|
2641
|
+
parent.childNodes do |child|
|
2642
|
+
if child == self
|
2643
|
+
return "child(#{index},#comment)"
|
2644
|
+
end
|
2645
|
+
if child.nodeType == COMMENT_NODE
|
2646
|
+
index += 1
|
2647
|
+
end
|
2648
|
+
end
|
2649
|
+
nil
|
2650
|
+
end
|
2651
|
+
end
|
2652
|
+
|
2653
|
+
|
2654
|
+
## Extended Interfaces
|
2655
|
+
|
2656
|
+
=begin
|
2657
|
+
== Class XML::DOM::CDATASection
|
2658
|
+
|
2659
|
+
=== superclass
|
2660
|
+
Text
|
2661
|
+
|
2662
|
+
=end
|
2663
|
+
class CDATASection<Text
|
2664
|
+
=begin
|
2665
|
+
=== Class Methods
|
2666
|
+
|
2667
|
+
--- CDATASection.new(text = nil)
|
2668
|
+
|
2669
|
+
creates a new CDATASection.
|
2670
|
+
=end
|
2671
|
+
def initialize(text = nil)
|
2672
|
+
super(text)
|
2673
|
+
raise "parameter error" if !text
|
2674
|
+
end
|
2675
|
+
|
2676
|
+
=begin
|
2677
|
+
=== Methods
|
2678
|
+
|
2679
|
+
--- CDATASection#nodeType
|
2680
|
+
|
2681
|
+
[DOM]
|
2682
|
+
returns the nodeType.
|
2683
|
+
=end
|
2684
|
+
## [DOM]
|
2685
|
+
def nodeType
|
2686
|
+
CDATA_SECTION_NODE
|
2687
|
+
end
|
2688
|
+
|
2689
|
+
=begin
|
2690
|
+
--- CDATASection#nodeName
|
2691
|
+
|
2692
|
+
[DOM]
|
2693
|
+
returns the nodeName.
|
2694
|
+
=end
|
2695
|
+
## [DOM]
|
2696
|
+
def nodeName
|
2697
|
+
"#cdata-section"
|
2698
|
+
end
|
2699
|
+
|
2700
|
+
=begin
|
2701
|
+
--- CDATASection#to_s
|
2702
|
+
|
2703
|
+
returns the string representation of the CDATASection.
|
2704
|
+
=end
|
2705
|
+
def to_s
|
2706
|
+
"<![CDATA[#{@value}]]>"
|
2707
|
+
end
|
2708
|
+
|
2709
|
+
=begin
|
2710
|
+
--- CDATASection#dump(depth = 0)
|
2711
|
+
|
2712
|
+
dumps the CDATASection.
|
2713
|
+
=end
|
2714
|
+
def dump(depth = 0)
|
2715
|
+
print ' ' * depth * 2
|
2716
|
+
print "<![CDATA[#{@value.inspect}]]>\n"
|
2717
|
+
end
|
2718
|
+
|
2719
|
+
def _getMyLocation(parent)
|
2720
|
+
index = 1
|
2721
|
+
parent.childNodes do |child|
|
2722
|
+
if child == self
|
2723
|
+
return "child(#{index},#cdata)"
|
2724
|
+
end
|
2725
|
+
if child.nodeType == CDATA_SECTION_NODE
|
2726
|
+
index += 1
|
2727
|
+
end
|
2728
|
+
end
|
2729
|
+
nil
|
2730
|
+
end
|
2731
|
+
end
|
2732
|
+
|
2733
|
+
=begin
|
2734
|
+
== Class XML::DOM::DocumentType
|
2735
|
+
|
2736
|
+
=== superclass
|
2737
|
+
Node
|
2738
|
+
=end
|
2739
|
+
class DocumentType<Node
|
2740
|
+
|
2741
|
+
=begin
|
2742
|
+
=== Class Methods
|
2743
|
+
|
2744
|
+
--- DocumentType.new(name, value = nil, *children)
|
2745
|
+
|
2746
|
+
creates a new DocuemntType.
|
2747
|
+
=end
|
2748
|
+
def initialize(name, value = nil, *children)
|
2749
|
+
super(*children)
|
2750
|
+
raise "parameter error" if !name
|
2751
|
+
@name = name.freeze
|
2752
|
+
@value = value.freeze
|
2753
|
+
end
|
2754
|
+
|
2755
|
+
=begin
|
2756
|
+
=== Methods
|
2757
|
+
|
2758
|
+
--- DocumentType#nodeType
|
2759
|
+
|
2760
|
+
[DOM]
|
2761
|
+
returns the nodeType.
|
2762
|
+
=end
|
2763
|
+
## [DOM]
|
2764
|
+
def nodeType
|
2765
|
+
DOCUMENT_TYPE_NODE
|
2766
|
+
end
|
2767
|
+
|
2768
|
+
=begin
|
2769
|
+
--- DocumentType#nodeName
|
2770
|
+
|
2771
|
+
[DOM]
|
2772
|
+
returns the nodeName.
|
2773
|
+
=end
|
2774
|
+
## [DOM]
|
2775
|
+
def nodeName
|
2776
|
+
@name
|
2777
|
+
end
|
2778
|
+
|
2779
|
+
=begin
|
2780
|
+
--- DocumentType#to_s
|
2781
|
+
|
2782
|
+
returns the string representation of the DocumentType.
|
2783
|
+
=end
|
2784
|
+
def to_s
|
2785
|
+
ret = "<!DOCTYPE " + @name
|
2786
|
+
if !@value.nil?
|
2787
|
+
ret <<= " " + @value
|
2788
|
+
end
|
2789
|
+
if !@children.nil? && @children.length > 0
|
2790
|
+
ret <<= " [\n"
|
2791
|
+
@children.each do |child|
|
2792
|
+
if child.nodeType == PROCESSING_INSTRUCTION_NODE ||
|
2793
|
+
child.nodeType == COMMENT_NODE
|
2794
|
+
ret <<= child.to_s + "\n"
|
2795
|
+
else
|
2796
|
+
ret <<= child.nodeValue + "\n"
|
2797
|
+
end
|
2798
|
+
end
|
2799
|
+
ret <<= "]"
|
2800
|
+
end
|
2801
|
+
ret <<= ">"
|
2802
|
+
end
|
2803
|
+
|
2804
|
+
=begin
|
2805
|
+
--- DocumentType#dump(depth = 0)
|
2806
|
+
|
2807
|
+
dumps the DocumentType.
|
2808
|
+
=end
|
2809
|
+
def dump(depth = 0)
|
2810
|
+
print ' ' * depth * 2
|
2811
|
+
print "<!DOCTYPE #{@name} #{@value} [\n"
|
2812
|
+
@children.each do |child|
|
2813
|
+
print ' ' * (depth + 1) * 2
|
2814
|
+
if child.nodeType == PROCESSING_INSTRUCTION_NODE ||
|
2815
|
+
child.nodeType == COMMENT_NODE
|
2816
|
+
child.dump
|
2817
|
+
else
|
2818
|
+
print child.nodeValue, "\n"
|
2819
|
+
end
|
2820
|
+
end if @children
|
2821
|
+
print ' ' * depth * 2
|
2822
|
+
print "]>\n"
|
2823
|
+
end
|
2824
|
+
|
2825
|
+
=begin
|
2826
|
+
--- DocumentType#cloneNode(deep = true)
|
2827
|
+
|
2828
|
+
[DOM]
|
2829
|
+
returns the copy of the DocumentType.
|
2830
|
+
=end
|
2831
|
+
## [DOM]
|
2832
|
+
def cloneNode(deep = true)
|
2833
|
+
super(deep, @name, @value)
|
2834
|
+
end
|
2835
|
+
|
2836
|
+
## [DOM]
|
2837
|
+
## def entities; @entities; end
|
2838
|
+
## def notations; @notations; end
|
2839
|
+
end
|
2840
|
+
|
2841
|
+
=begin
|
2842
|
+
== Class XML::DOM::Notation
|
2843
|
+
|
2844
|
+
=== superclass
|
2845
|
+
Node
|
2846
|
+
=end
|
2847
|
+
class Notation<Node
|
2848
|
+
=begin
|
2849
|
+
=== Class Methods
|
2850
|
+
|
2851
|
+
--- Notation.new(name, pubid, sysid)
|
2852
|
+
|
2853
|
+
creates a new Notation.
|
2854
|
+
=end
|
2855
|
+
def initialize(name, pubid, sysid)
|
2856
|
+
super()
|
2857
|
+
@name = name.freeze
|
2858
|
+
@pubid = pubid.freeze
|
2859
|
+
@sysid = sysid.freeze
|
2860
|
+
end
|
2861
|
+
|
2862
|
+
=begin
|
2863
|
+
=== Methods
|
2864
|
+
|
2865
|
+
--- Notation#nodeType
|
2866
|
+
|
2867
|
+
[DOM]
|
2868
|
+
returns the nodeType.
|
2869
|
+
=end
|
2870
|
+
## [DOM]
|
2871
|
+
def nodeType
|
2872
|
+
NOTATION_NODE
|
2873
|
+
end
|
2874
|
+
|
2875
|
+
=begin
|
2876
|
+
--- Notation#nodeName
|
2877
|
+
|
2878
|
+
[DOM]
|
2879
|
+
returns the nodeName.
|
2880
|
+
=end
|
2881
|
+
## [DOM]
|
2882
|
+
def nodeName
|
2883
|
+
@name
|
2884
|
+
end
|
2885
|
+
|
2886
|
+
=begin
|
2887
|
+
--- Notation#publicId
|
2888
|
+
|
2889
|
+
returns the publicId of the Notation.
|
2890
|
+
=end
|
2891
|
+
def publicId
|
2892
|
+
@pubid
|
2893
|
+
end
|
2894
|
+
|
2895
|
+
=begin
|
2896
|
+
--- Notation#systemId
|
2897
|
+
|
2898
|
+
returns the systemId of the Notation.
|
2899
|
+
=end
|
2900
|
+
def systemId
|
2901
|
+
@sysid
|
2902
|
+
end
|
2903
|
+
|
2904
|
+
=begin
|
2905
|
+
--- Notation#cloneNode(deep = true)
|
2906
|
+
|
2907
|
+
[DOM]
|
2908
|
+
returns the copy of the Notation.
|
2909
|
+
=end
|
2910
|
+
## [DOM]
|
2911
|
+
def cloneNode(deep = true)
|
2912
|
+
super(deep, @name, @pubid, @sysid)
|
2913
|
+
end
|
2914
|
+
end
|
2915
|
+
|
2916
|
+
=begin
|
2917
|
+
== Class XML::DOM::Entity
|
2918
|
+
|
2919
|
+
=== superclass
|
2920
|
+
Node
|
2921
|
+
=end
|
2922
|
+
class Entity<Node
|
2923
|
+
|
2924
|
+
=begin
|
2925
|
+
=== Class Methods
|
2926
|
+
|
2927
|
+
--- Entity.new(name, pubid, sysid, notation)
|
2928
|
+
|
2929
|
+
creates a new Entity.
|
2930
|
+
=end
|
2931
|
+
def initialize(name, pubid, sysid, notation)
|
2932
|
+
super()
|
2933
|
+
@name = name.freeze
|
2934
|
+
@pubid = pubid.freeze
|
2935
|
+
@sysid = sysid.freeze
|
2936
|
+
@notation = notation.freeze
|
2937
|
+
end
|
2938
|
+
|
2939
|
+
=begin
|
2940
|
+
=== Methods
|
2941
|
+
|
2942
|
+
--- Entity#nodeType
|
2943
|
+
|
2944
|
+
[DOM]
|
2945
|
+
returns the nodeType.
|
2946
|
+
=end
|
2947
|
+
## [DOM]
|
2948
|
+
def nodeType
|
2949
|
+
ENTITY_NODE
|
2950
|
+
end
|
2951
|
+
|
2952
|
+
=begin
|
2953
|
+
--- Entity#nodeName
|
2954
|
+
|
2955
|
+
[DOM]
|
2956
|
+
returns the nodeName.
|
2957
|
+
=end
|
2958
|
+
## [DOM]
|
2959
|
+
def nodeName
|
2960
|
+
@name
|
2961
|
+
end
|
2962
|
+
|
2963
|
+
=begin
|
2964
|
+
--- Entity#publicId
|
2965
|
+
|
2966
|
+
returns the publicId of the Entity.
|
2967
|
+
=end
|
2968
|
+
def publicId
|
2969
|
+
@pubid
|
2970
|
+
end
|
2971
|
+
|
2972
|
+
=begin
|
2973
|
+
--- Entity#systemId
|
2974
|
+
|
2975
|
+
returns the systemId of the Entity.
|
2976
|
+
=end
|
2977
|
+
def systemId
|
2978
|
+
@sysid
|
2979
|
+
end
|
2980
|
+
|
2981
|
+
=begin
|
2982
|
+
--- Entity#notationName
|
2983
|
+
|
2984
|
+
returns the notationname of the Entity.
|
2985
|
+
=end
|
2986
|
+
def notationName
|
2987
|
+
@notation
|
2988
|
+
end
|
2989
|
+
|
2990
|
+
=begin
|
2991
|
+
--- Entity#cloneNode(deep = true)
|
2992
|
+
|
2993
|
+
[DOM]
|
2994
|
+
returns the copy of the Entity.
|
2995
|
+
=end
|
2996
|
+
## [DOM]
|
2997
|
+
def cloneNode(deep = true)
|
2998
|
+
super(deep, @name, @pubid, @sysid, @notation)
|
2999
|
+
end
|
3000
|
+
|
3001
|
+
def _checkNode(node)
|
3002
|
+
unless node.nodeType == ELEMENT_NODE ||
|
3003
|
+
node.nodeType == PROCESSING_INSTRUCTION_NODE ||
|
3004
|
+
node.nodeType == COMMENT_NODE ||
|
3005
|
+
node.nodeType == TEXT_NODE ||
|
3006
|
+
node.nodeType == CDATA_SECTION_NODE ||
|
3007
|
+
node.nodeType == ENTITY_REFERENCE_NODE
|
3008
|
+
raise DOMException.new(DOMException::HIERARCHY_REQUEST_ERR)
|
3009
|
+
end
|
3010
|
+
end
|
3011
|
+
|
3012
|
+
end
|
3013
|
+
|
3014
|
+
=begin
|
3015
|
+
== Class XML::DOM::EntityReference
|
3016
|
+
|
3017
|
+
=== superclass
|
3018
|
+
Node
|
3019
|
+
=end
|
3020
|
+
class EntityReference<Node
|
3021
|
+
|
3022
|
+
=begin
|
3023
|
+
=== Class Methods
|
3024
|
+
|
3025
|
+
--- EntityReference.new(name, *children)
|
3026
|
+
|
3027
|
+
creates a new EntityReference.
|
3028
|
+
=end
|
3029
|
+
def initialize(name, *children)
|
3030
|
+
super(*children)
|
3031
|
+
raise "parameter error" if !name
|
3032
|
+
@name = name.freeze
|
3033
|
+
end
|
3034
|
+
|
3035
|
+
=begin
|
3036
|
+
=== Methods
|
3037
|
+
|
3038
|
+
--- EntityReference#nodeType
|
3039
|
+
|
3040
|
+
[DOM]
|
3041
|
+
returns the nodeType.
|
3042
|
+
=end
|
3043
|
+
## [DOM]
|
3044
|
+
def nodeType
|
3045
|
+
ENTITY_REFERENCE_NODE
|
3046
|
+
end
|
3047
|
+
|
3048
|
+
=begin
|
3049
|
+
--- EntityReference#nodeName
|
3050
|
+
|
3051
|
+
[DOM]
|
3052
|
+
returns the nodeName.
|
3053
|
+
=end
|
3054
|
+
## [DOM]
|
3055
|
+
def nodeName
|
3056
|
+
@name
|
3057
|
+
end
|
3058
|
+
|
3059
|
+
=begin
|
3060
|
+
--- EntityReference#to_s
|
3061
|
+
|
3062
|
+
returns the string representation of the EntityReference.
|
3063
|
+
=end
|
3064
|
+
## reference form or expanded form?
|
3065
|
+
def to_s
|
3066
|
+
"&#{@name};"
|
3067
|
+
end
|
3068
|
+
|
3069
|
+
=begin
|
3070
|
+
--- EntityReference#dump(depth = 0)
|
3071
|
+
|
3072
|
+
dumps the EntityReference.
|
3073
|
+
=end
|
3074
|
+
def dump(depth = 0)
|
3075
|
+
print ' ' * depth * 2
|
3076
|
+
print "&#{@name}{\n"
|
3077
|
+
@children.each do |child|
|
3078
|
+
child.dump(depth + 1)
|
3079
|
+
end if @children
|
3080
|
+
print ' ' * depth * 2
|
3081
|
+
print "}\n"
|
3082
|
+
end
|
3083
|
+
|
3084
|
+
=begin
|
3085
|
+
--- EntityReference#cloneNode(deep = true)
|
3086
|
+
|
3087
|
+
[DOM]
|
3088
|
+
returns the copy of the EntityReference.
|
3089
|
+
=end
|
3090
|
+
## [DOM]
|
3091
|
+
def cloneNode(deep = true)
|
3092
|
+
super(deep, @name)
|
3093
|
+
end
|
3094
|
+
|
3095
|
+
def _checkNode(node)
|
3096
|
+
unless node.nodeType == ELEMENT_NODE ||
|
3097
|
+
node.nodeType == PROCESSING_INSTRUCTION_NODE ||
|
3098
|
+
node.nodeType == COMMENT_NODE ||
|
3099
|
+
node.nodeType == TEXT_NODE ||
|
3100
|
+
node.nodeType == CDATA_SECTION_NODE ||
|
3101
|
+
node.nodeType == ENTITY_REFERENCE_NODE
|
3102
|
+
raise DOMException.new(DOMException::HIERARCHY_REQUEST_ERR)
|
3103
|
+
end
|
3104
|
+
end
|
3105
|
+
|
3106
|
+
end
|
3107
|
+
|
3108
|
+
=begin
|
3109
|
+
== Class XML::DOM::ProcessingInstruction
|
3110
|
+
|
3111
|
+
=== superclass
|
3112
|
+
Node
|
3113
|
+
|
3114
|
+
=end
|
3115
|
+
class ProcessingInstruction<Node
|
3116
|
+
|
3117
|
+
=begin
|
3118
|
+
=== Class Methods
|
3119
|
+
|
3120
|
+
--- ProcessingInstruction.new(target = nil, data = nil)
|
3121
|
+
|
3122
|
+
creates a new ProcessingInstruction.
|
3123
|
+
=end
|
3124
|
+
## new(target, data)
|
3125
|
+
## target: String
|
3126
|
+
## data: String
|
3127
|
+
def initialize(target = nil, data = nil)
|
3128
|
+
super()
|
3129
|
+
raise "parameter error" if !data
|
3130
|
+
@target = target.freeze
|
3131
|
+
@data = data.freeze
|
3132
|
+
@value = target.dup
|
3133
|
+
@value << " #{data}" if data != ""
|
3134
|
+
@value.freeze
|
3135
|
+
end
|
3136
|
+
|
3137
|
+
=begin
|
3138
|
+
=== Methods
|
3139
|
+
|
3140
|
+
--- ProcessingInstruction#nodeType
|
3141
|
+
|
3142
|
+
[DOM]
|
3143
|
+
returns the nodeType.
|
3144
|
+
=end
|
3145
|
+
## [DOM]
|
3146
|
+
def nodeType
|
3147
|
+
PROCESSING_INSTRUCTION_NODE
|
3148
|
+
end
|
3149
|
+
|
3150
|
+
=begin
|
3151
|
+
--- ProcessingInstruction#nodeName
|
3152
|
+
|
3153
|
+
[DOM]
|
3154
|
+
returns the nodeName.
|
3155
|
+
=end
|
3156
|
+
## [DOM]
|
3157
|
+
def nodeName
|
3158
|
+
"#proccessing-instruction"
|
3159
|
+
end
|
3160
|
+
|
3161
|
+
=begin
|
3162
|
+
--- ProcessingInstruction#target
|
3163
|
+
|
3164
|
+
[DOM]
|
3165
|
+
returns the target of the ProcessingInstruction.
|
3166
|
+
=end
|
3167
|
+
## [DOM]
|
3168
|
+
def target
|
3169
|
+
@target
|
3170
|
+
end
|
3171
|
+
|
3172
|
+
=begin
|
3173
|
+
--- ProcessingInstruction#target=(p)
|
3174
|
+
|
3175
|
+
[DOM]
|
3176
|
+
set p to the target of the ProcessingInstruction.
|
3177
|
+
=end
|
3178
|
+
## [DOM]
|
3179
|
+
def target=(p)
|
3180
|
+
@target = p.freeze
|
3181
|
+
@value = @target.dup
|
3182
|
+
@value << " #{@data}" if @data != ""
|
3183
|
+
@value.freeze
|
3184
|
+
end
|
3185
|
+
|
3186
|
+
=begin
|
3187
|
+
--- ProcessingInstruction#data
|
3188
|
+
|
3189
|
+
[DOM]
|
3190
|
+
return the content of the ProcessingInstruction.
|
3191
|
+
=end
|
3192
|
+
## [DOM]
|
3193
|
+
def data
|
3194
|
+
@data
|
3195
|
+
end
|
3196
|
+
|
3197
|
+
=begin
|
3198
|
+
--- ProcessingInstruction#data=(p)
|
3199
|
+
|
3200
|
+
[DOM]
|
3201
|
+
sets p to the content of the ProcessingInstruction.
|
3202
|
+
=end
|
3203
|
+
## [DOM]
|
3204
|
+
def data=(p)
|
3205
|
+
@data = p.freeze
|
3206
|
+
@value = @target.dup
|
3207
|
+
@value << " #{@data}" if @data != ""
|
3208
|
+
@value.freeze
|
3209
|
+
end
|
3210
|
+
|
3211
|
+
=begin
|
3212
|
+
--- ProcessingInstruction#nodeValue
|
3213
|
+
|
3214
|
+
[DOM]
|
3215
|
+
return nodevalue.
|
3216
|
+
|
3217
|
+
=end
|
3218
|
+
## [DOM]
|
3219
|
+
def nodeValue
|
3220
|
+
@value
|
3221
|
+
end
|
3222
|
+
|
3223
|
+
## inhibit changing value without target= or data=
|
3224
|
+
undef nodeValue=
|
3225
|
+
|
3226
|
+
=begin
|
3227
|
+
--- ProcessingInstruction#to_s
|
3228
|
+
|
3229
|
+
returns the string representation of the ProcessingInstruction.
|
3230
|
+
=end
|
3231
|
+
def to_s
|
3232
|
+
ret = "<?#{@value}?>"
|
3233
|
+
ret << "\n" if parentNode.nodeType == DOCUMENT_NODE
|
3234
|
+
ret
|
3235
|
+
end
|
3236
|
+
|
3237
|
+
=begin
|
3238
|
+
--- ProcessingInstruction#dump(depth = 0)
|
3239
|
+
|
3240
|
+
dumps the ProcessingInstruction.
|
3241
|
+
=end
|
3242
|
+
def dump(depth = 0)
|
3243
|
+
print ' ' * depth * 2
|
3244
|
+
print "<?#{@value.inspect}?>\n"
|
3245
|
+
end
|
3246
|
+
|
3247
|
+
def _getMyLocation(parent)
|
3248
|
+
index = 1
|
3249
|
+
parent.childNodes do |child|
|
3250
|
+
if child == self
|
3251
|
+
return "child(#{index},#pi)"
|
3252
|
+
end
|
3253
|
+
if child.nodeType == PROCESSING_INSTRUCTION_NODE
|
3254
|
+
index += 1
|
3255
|
+
end
|
3256
|
+
end
|
3257
|
+
nil
|
3258
|
+
end
|
3259
|
+
|
3260
|
+
=begin
|
3261
|
+
--- ProcessingInstruction#cloneNode(deep = true)
|
3262
|
+
|
3263
|
+
[DOM]
|
3264
|
+
returns the copy of the ProcessingInstruction.
|
3265
|
+
=end
|
3266
|
+
## [DOM]
|
3267
|
+
def cloneNode(deep = true)
|
3268
|
+
super(deep, @target.dup, @data.dup)
|
3269
|
+
end
|
3270
|
+
end
|
3271
|
+
|
3272
|
+
end
|
3273
|
+
|
3274
|
+
SimpleTree = DOM
|
3275
|
+
|
3276
|
+
end
|