meteor 0.9.12 → 0.9.13

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.
@@ -0,0 +1,684 @@
1
+ # -* coding: UTF-8 -*-
2
+ # frozen_string_literal: true
3
+
4
+ module Meteor
5
+ module Ml
6
+ module Html4
7
+ #
8
+ # HTML4 parser (HTMLパーサ)
9
+ #
10
+ class ParserImpl < Meteor::Core::Kernel
11
+ # KAIGYO_CODE = "\r?\n|\r"
12
+ # KAIGYO_CODE = "\r\n|\n|\r"
13
+ KAIGYO_CODE = ["\r\n", "\n", "\r"]
14
+ BR = '<br>'
15
+
16
+ # @@match_tag = "br|hr|img|input|meta|base"
17
+ @@match_tag = ['br', 'hr', 'img', 'input', 'meta', 'base'] #[Array] void elemets (空要素)
18
+ # @@match_tag_2 = "textarea|option|pre"
19
+ @@match_tag_2 =['textarea', 'option', 'pre'] #[Array] elements where line breaks do not need to be converted to <br> (改行を<br>に変換する必要のない要素)
20
+
21
+ @@match_tag_sng = ['texarea', 'select', 'option', 'form', 'fieldset'] #[Array] non-nestable elements (入れ子にできない要素)
22
+
23
+ @@attr_logic = ['disabled', 'readonly', 'checked', 'selected', 'multiple'] #[Array] boolean elements (論理値で指定する属性)
24
+
25
+ # DISABLE_ELEMENT = "input|textarea|select|optgroup"
26
+ DISABLE_ELEMENT = ['input', 'textarea', 'select', 'optgroup'] #[Array] elements with the disabled attribute (disabled属性のある要素)
27
+ # READONLY_TYPE = "text|password"
28
+ READONLY_TYPE = ['text', 'password'] #[Array] the type of an input element with a readonly attribute (readonly属性のあるinput要素のタイプ)
29
+
30
+ SELECTED_M = '\\sselected\\s|\\sselected$|\\sSELECTED\\s|\\sSELECTED$'
31
+ # SELECTED_M = [' selected ',' selected',' SELECTED ',' SELECTED']
32
+ SELECTED_R = 'selected\\s|selected$|SELECTED\\s|SELECTED$'
33
+ CHECKED_M = '\\schecked\\s|\\schecked$|\\sCHECKED\\s|\\sCHECKED$'
34
+ # CHECKED_M = [' checked ',' checked',' CHECKED ',' CHECKED']
35
+ CHECKED_R = 'checked\\s|checked$|CHECKED\\s|CHECKED$'
36
+ DISABLED_M = '\\sdisabled\\s|\\sdisabled$|\\sDISABLED\\s|\\sDISABLED$'
37
+ # DISABLED_M = [' disabled ',' disiabled',' DISABLED ',' DISABLED']
38
+ DISABLED_R = 'disabled\\s|disabled$|DISABLED\\s|DISABLED$'
39
+ READONLY_M = '\\sreadonly\\s|\\sreadonly$|\\sREADONLY\\s|\\sREADONLY$'
40
+ # READONLY_M = [' readonly ',' readonly',' READONLY ',' READONLY']
41
+ READONLY_R = 'readonly\\s|readonly$|READONLY\\s|READONLY$'
42
+ MULTIPLE_M = '\\smultiple\\s|\\smultiple$|\\sMULTIPLE\\s|\\sMULTIPLE$'
43
+ # MULTIPLE_M = [' multiple ',' multiple',' MULTIPLE ',' MULTIPLE']
44
+ MULTIPLE_R = 'multiple\\s|multiple$|MULTIPLE\\s|MULTIPLE$'
45
+
46
+ # @@pattern_true = Regexp.new("true")
47
+ # @@pattern_false = Regexp.new("false")
48
+
49
+ PATTERN_UNESCAPE = '&(amp|quot|apos|gt|lt|nbsp);'
50
+ GET_ATTRS_MAP2 = '\\s(disabled|readonly|checked|selected|multiple)'
51
+
52
+ @@pattern_selected_m = Regexp.new(SELECTED_M)
53
+ @@pattern_selected_r = Regexp.new(SELECTED_R)
54
+ @@pattern_checked_m = Regexp.new(CHECKED_M)
55
+ @@pattern_checked_r = Regexp.new(CHECKED_R)
56
+ @@pattern_disabled_m = Regexp.new(DISABLED_M)
57
+ @@pattern_disabled_r = Regexp.new(DISABLED_R)
58
+ @@pattern_readonly_m = Regexp.new(READONLY_M)
59
+ @@pattern_readonly_r = Regexp.new(READONLY_R)
60
+ @@pattern_multiple_m = Regexp.new(MULTIPLE_M)
61
+ @@pattern_multiple_r = Regexp.new(MULTIPLE_R)
62
+
63
+ @@pattern_unescape = Regexp.new(PATTERN_UNESCAPE)
64
+ @@pattern_get_attrs_map2 = Regexp.new(GET_ATTRS_MAP2)
65
+
66
+ # @@pattern_match_tag = Regexp.new(@@match_tag)
67
+ # @@pattern_match_tag2 = Regexp.new(@@match_tag_2)
68
+
69
+ TABLE_FOR_ESCAPE_ = {
70
+ '&' => '&amp;',
71
+ '"' => '&quot;',
72
+ '\'' => '&apos;',
73
+ '<' => '&lt;',
74
+ '>' => '&gt;',
75
+ ' ' => '&nbsp;',
76
+ }
77
+
78
+ TABLE_FOR_ESCAPE_CONTENT_ = {
79
+ '&' => '&amp;',
80
+ '"' => '&quot;',
81
+ '\'' => '&apos;',
82
+ '<' => '&lt;',
83
+ '>' => '&gt;',
84
+ ' ' => '&nbsp;',
85
+ "\r\n" => '<br>',
86
+ "\r" => '<br>',
87
+ "\n" => '<br>',
88
+ }
89
+
90
+ PATTERN_ESCAPE = "[&\"'<> ]"
91
+ PATTERN_ESCAPE_CONTENT = "[&\"'<> \\n]"
92
+
93
+ @@pattern_escape = Regexp.new(PATTERN_ESCAPE)
94
+ @@pattern_escape_content = Regexp.new(PATTERN_ESCAPE_CONTENT)
95
+ @@pattern_br_2 = Regexp.new(BR)
96
+
97
+ #
98
+ # initializer (イニシャライザ)
99
+ # @overload initialize
100
+ # @overload initialize(ps)
101
+ # @param [Meteor::Parser] ps parser (パーサ)
102
+ #
103
+ def initialize(*args)
104
+ super()
105
+ @doc_type = Parser::HTML4
106
+ case args.length
107
+ when ZERO
108
+ # initialize_0
109
+ when ONE
110
+ initialize_1(args[0])
111
+ else
112
+ raise ArgumentError
113
+ end
114
+ end
115
+
116
+ #
117
+ # initializer (イニシャライザ)
118
+ #
119
+ # def initialize_0
120
+ # end
121
+ #
122
+ # private :initialize_0
123
+
124
+ #
125
+ # initializer (イニシャライザ)
126
+ # @param [Meteor::Parser] ps paser (パーサ)
127
+ #
128
+ def initialize_1(ps)
129
+ @root.document = String.new(ps.document)
130
+ self.document_hook = String.new(ps.document_hook)
131
+ @root.content_type = String.new(ps.root_element.content_type)
132
+ @root.charset = ps.root_element.charset
133
+ @root.kaigyo_code = ps.root_element.kaigyo_code
134
+ end
135
+
136
+ private :initialize_1
137
+
138
+ #
139
+ # parse document (ドキュメントを解析する)
140
+ #
141
+ def parse
142
+ analyze_ml
143
+ end
144
+
145
+ #
146
+ # analyze document (ドキュメントをパースする)
147
+ #
148
+ def analyze_ml
149
+ analyze_content_type
150
+ analyze_kaigyo_code
151
+
152
+ @res = nil
153
+ end
154
+
155
+ private :analyze_ml
156
+
157
+ #
158
+ # get content type (コンテントタイプを取得する)
159
+ # @return [String] conent type (コンテントタイプ)
160
+ #
161
+ def content_type
162
+ @root.content_type
163
+ end
164
+
165
+ #
166
+ # analyze document , set content type (ドキュメントをパースし、コンテントタイプをセットする)
167
+ #
168
+ def analyze_content_type
169
+ @error_check = false
170
+
171
+ element_3('meta', 'http-equiv', 'Content-Type')
172
+
173
+ if !@elm_
174
+ element_3('meta', 'http-equiv', 'Content-Type')
175
+ end
176
+
177
+ @error_check = true
178
+
179
+ if @elm_
180
+ content = @elm_.attr('content')
181
+ content_arr = content&.split(';')
182
+ @root.content_type = content_arr&.at(0) || ''
183
+ @root.charset = content_arr&.at(1)&.split('=')&.at(1) || ''
184
+ else
185
+ @root.content_type = ''
186
+ end
187
+ end
188
+
189
+ protected :analyze_content_type
190
+
191
+ #
192
+ # analuze document , set newline (ドキュメントをパースし、改行コードをセットする)
193
+ #
194
+ def analyze_kaigyo_code
195
+ for a in KAIGYO_CODE
196
+ if @root.document.include?(a)
197
+ @root.kaigyo_code = a
198
+ # puts "kaigyo:" << @root.kaigyo_code
199
+ end
200
+ end
201
+ end
202
+
203
+ protected :analyze_kaigyo_code
204
+
205
+ #
206
+ # get element using tag name (要素のタグ名で検索し、要素を取得する)
207
+ # @param [String] name tag name (タグ名)
208
+ # @return [Meteor::Element] element (要素)
209
+ #
210
+ def element_1(name)
211
+ @_name = Regexp.quote(name)
212
+
213
+ # case of void element (空要素の場合(<->内容あり要素の場合))
214
+ if is_match(@@match_tag, name)
215
+ # void element search pattern (空要素検索用パターン)
216
+ @pattern_cc = String.new('') << "<" << @_name << '(|\\s[^<>]*)>'
217
+ # @pattern_cc = "<#{@_name}(|\\s[^<>]*)>"
218
+ @pattern = Meteor::Core::Util::PatternCache.get(@pattern_cc)
219
+ @res = @pattern.match(@root.document)
220
+ if @res
221
+ element_without_1(name)
222
+ else
223
+ if @error_check
224
+ puts Meteor::Exception::NoSuchElementException.new(name).message
225
+ end
226
+ @elm_ = nil
227
+ end
228
+ else
229
+ # search pattern of element with content (内容あり要素検索用パターン()
230
+ # @pattern_cc = String.new('') << "<" << @_name << '(|\\s[^<>]*)>(((?!(' << @_name
231
+ # @pattern_cc << '[^<>]*>)).)*)<\\/' << @_name << '>'
232
+ @pattern_cc = "<#{@_name}(|\\s[^<>]*)>(((?!(#{tag}[^<>]*>)).)*)<\\/#{@_name}>"
233
+
234
+ @pattern = Meteor::Core::Util::PatternCache.get(@pattern_cc)
235
+ # search of element with content (内容あり要素検索)
236
+ @res = @pattern.match(@root.document)
237
+ # case of element with content (内容あり要素の場合)
238
+ if @res
239
+ element_with_1(name)
240
+ else
241
+ if @error_check
242
+ puts Meteor::Exception::NoSuchElementException.new(name).message
243
+ end
244
+ @elm_ = nil
245
+ end
246
+ end
247
+
248
+ @elm_
249
+ end
250
+
251
+ private :element_1
252
+
253
+ def element_without_1(name)
254
+ @elm_ = Meteor::Element.new(name)
255
+ # attribute (属性)
256
+ @elm_.attributes = @res[1]
257
+ # void element search pattern (空要素検索用パターン)
258
+ @elm_.pattern = @pattern_cc
259
+
260
+ @elm_.document = @res[0]
261
+
262
+ @elm_.parser = self
263
+ end
264
+
265
+ private :element_without_1
266
+
267
+ #
268
+ # get element using tag name and attribute(name="value") (要素のタグ名、属性(属性名="属性値")で検索し、要素を取得する)
269
+ # @param [String] name tag name (タグ名)
270
+ # @param [String] attr_name attribute name (属性名)
271
+ # @param [String] attr_value attribute value (属性値)
272
+ # @param [true,false] quote quote flag (クオート・フラグ)
273
+ # @return [Meteor::Element] element (要素)
274
+ #
275
+ def element_3(name, attr_name, attr_value, quote = true)
276
+
277
+ element_quote_3(name, attr_name, attr_value) if quote
278
+
279
+ # case of void element (空要素の場合(<->内容あり要素の場合))
280
+ if is_match(@@match_tag, name)
281
+ # void element search pattern (空要素検索パターン)
282
+ # @pattern_cc = String.new('') << "<" << @_name << '(\\s[^<>]*' << @_attr_name << '="'
283
+ # @pattern_cc << @_attr_value << '"[^<>]*)>'
284
+ @pattern_cc = "<#{@_name}(\\s[^<>]*#{@_attr_name}=\"#{@_attr_value}\"[^<>]*)>"
285
+
286
+ @pattern = Meteor::Core::Util::PatternCache.get(@pattern_cc)
287
+ # void element search (空要素検索)
288
+ @res = @pattern.match(@root.document)
289
+ if @res
290
+ element_without_3(name)
291
+ else
292
+ if @error_check
293
+ puts Meteor::Exception::NoSuchElementException.new(name, attr_name, attr_value).message
294
+ end
295
+ @elm_ = nil
296
+ end
297
+ else
298
+ # search pattern of element with content (内容あり要素検索パターン)
299
+ # @pattern_cc = String.new('') << "<" << @_name << '(\\s[^<>]*' << @_attr_name << '="'
300
+ # @pattern_cc << @_attr_value << '"[^<>]*)>(((?!(' << @_name
301
+ # @pattern_cc << '[^<>]*>)).)*)<\\/' << @_name << '>'
302
+ @pattern_cc = "<#{@_name}(\\s[^<>]*#{@_attr_name}=\"#{@_attr_value}\"[^<>]*)>(((?!(#{@_name}[^<>]*>)).)*)<\\/#{@_name}>"
303
+
304
+ @pattern = Meteor::Core::Util::PatternCache.get(@pattern_cc)
305
+ # search of element with content (内容あり要素検索)
306
+ @res = @pattern.match(@root.document)
307
+
308
+ if !@res && !is_match(@@match_tag_sng, name)
309
+ @res = element_with_3_2
310
+ end
311
+
312
+ if @res
313
+ element_with_3_1(name)
314
+ else
315
+ if @error_check
316
+ puts Meteor::Exception::NoSuchElementException.new(name, attr_name, attr_value).message
317
+ end
318
+ @elm_ = nil
319
+ end
320
+ end
321
+
322
+ @elm_
323
+ end
324
+
325
+ private :element_3
326
+
327
+ def element_without_3(name)
328
+ element_without_3_1(name, '"[^<>]*)>')
329
+ end
330
+
331
+ private :element_without_3
332
+
333
+ #
334
+ # get element using attribute(name="value") (属性(属性名="属性値")で検索し、要素を取得する)
335
+ # @param [String] attr_name attribute name (属性名)
336
+ # @param [String] attr_value attribute value (属性値)
337
+ # @return [Meteor::Element] element (要素)
338
+ #
339
+ def element_2(attr_name, attr_value)
340
+
341
+ element_quote_2(attr_name, attr_value)
342
+
343
+ # @pattern_cc = String.new('') << '<([^<>"]*)\\s[^<>]*' << @_attr_name << '="' << @_attr_value
344
+ # @pattern_cc << '"[^<>]*>'
345
+ @pattern_cc = "<([^<>\"]*)\\s[^<>]*#{@_attr_name}=\"#{@_attr_value}\"[^<>]*>"
346
+
347
+ @pattern = Meteor::Core::Util::PatternCache.get(@pattern_cc)
348
+ @res = @pattern.match(@root.document)
349
+
350
+ if @res
351
+ element_3(@res[1], attr_name, attr_value)
352
+ else
353
+ if @error_check
354
+ puts Meteor::Exception::NoSuchElementException.new(attr_name, attr_value).message
355
+ end
356
+ @elm_ = nil
357
+ end
358
+
359
+ @elm_
360
+ end
361
+
362
+ private :element_2
363
+
364
+ #
365
+ # get element using tag name and attribute1,2(name="value") (要素のタグ名と属性1・属性2(属性名="属性値")で検索し、要素を取得する)
366
+ # @param [String] name tag name (タグ名)
367
+ # @param [String] attr_name1 attribute name1 (属性名1)
368
+ # @param [String] attr_value1 attribute value1 (属性値1)
369
+ # @param [String] attr_name2 attribute name2 (属性名2)
370
+ # @param [String] attr_value2 attribute value2 (属性値2)
371
+ # @return [Meteor::Element] element (要素)
372
+ #
373
+ def element_5(name, attr_name1, attr_value1, attr_name2, attr_value2)
374
+
375
+ element_quote_5(name, attr_name1, attr_value1, attr_name2, attr_value2)
376
+
377
+ # 空要素の場合(<->内容あり要素の場合)
378
+ if is_match(@@match_tag, name)
379
+ # void element search pattern (空要素検索パターン)
380
+ # @pattern_cc = String.new('') << "<" << @_name << '(\\s[^<>]*(?:' << @_attr_name1 << '="'
381
+ # @pattern_cc << @_attr_value1 << '"[^<>]*' << @_attr_name2 << '="'
382
+ # @pattern_cc << @_attr_value2 << '"|' << @_attr_name2 << '="'
383
+ # @pattern_cc << @_attr_value2 << '"[^<>]*' << @_attr_name1 << '="'
384
+ # @pattern_cc << @_attr_value1 << '")[^<>]*)>'
385
+ @pattern_cc = "<#{@_name}(\\s[^<>]*(?:#{@_attr_name1}=\"#{@_attr_value1}\"[^<>]*#{@_attr_name2}=\"#{@_attr_value2}\"|#{@_attr_name2}=\"#{@_attr_value2}\"[^<>]*#{@_attr_name1}=\"#{@_attr_value1}\")[^<>]*)>"
386
+
387
+ @pattern = Meteor::Core::Util::PatternCache.get(@pattern_cc)
388
+ # void element search (空要素検索)
389
+ @res = @pattern.match(@root.document)
390
+
391
+ if @res
392
+ element_without_5(name)
393
+ else
394
+ if @error_check
395
+ puts Meteor::Exception::NoSuchElementException.new(name, attr_name1, attr_value1, attr_name2, attr_value2).message
396
+ end
397
+ @elm_ = nil
398
+ end
399
+ else
400
+ # search pattern of element with content (内容あり要素検索パターン)
401
+ # @pattern_cc = String.new('') << "<" << @_name << '(\\s[^<>]*(?:' << @_attr_name1 << '="'
402
+ # @pattern_cc << @_attr_value1 << '"[^<>]*' << @_attr_name2 << '="'
403
+ # @pattern_cc << @_attr_value2 << '"|' << @_attr_name2 << '="'
404
+ # @pattern_cc << @_attr_value2 << '"[^<>]*' << @_attr_name1 << '="'
405
+ # @pattern_cc << @_attr_value1 << '")[^<>]*)>(((?!(' << @_name
406
+ # @pattern_cc << '[^<>]*>)).)*)<\\/' << @_name << '>'
407
+ @pattern_cc = "<#{@_name}(\\s[^<>]*(?:#{@_attr_name1}=\"#{@_attr_value1}\"[^<>]*#{@_attr_name2}=\"#{@_attr_value2}\"|#{@_attr_name2}=\"#{@_attr_value2}\"[^<>]*#{@_attr_name1}=\"#{@_attr_value1}\")[^<>]*)>(((?!(#{@_name}[^<>]*>)).)*)<\\/#{@_name}>"
408
+
409
+ @pattern = Meteor::Core::Util::PatternCache.get(@pattern_cc)
410
+ # search of element with content (内容あり要素検索)
411
+ @res = @pattern.match(@root.document)
412
+
413
+ if !@res && !is_match(@@match_tag_sng, tag)
414
+ @res = element_with_5_2
415
+ end
416
+
417
+ if @res
418
+ element_with_5_1(name)
419
+ else
420
+ if @error_check
421
+ puts Meteor::Exception::NoSuchElementException.new(name, attr_name1, attr_value1, attr_name2, attr_value2).message
422
+ end
423
+ @elm_ = nil
424
+ end
425
+ end
426
+
427
+ @elm_
428
+ end
429
+
430
+ private :element_5
431
+
432
+ def element_without_5(name)
433
+ element_without_5_1(name, '")[^<>]*)>')
434
+ end
435
+
436
+ private :element_without_5
437
+
438
+ #
439
+ # get element using attribute1,2(name="value") (属性1・属性2(属性名="属性値")で検索し、要素を取得する)
440
+ #
441
+ # @param [String] attr_name1 attribute name1 (属性名1)
442
+ # @param [String] attr_value1 attribute value1 (属性値1)
443
+ # @param [String] attr_name2 attribute name2 (属性名2)
444
+ # @param [String] attr_value2 attribute value2 (属性値2)
445
+ # @return [Meteor::Element] element (要素)
446
+ #
447
+ def element_4(attr_name1, attr_value1, attr_name2, attr_value2)
448
+ element_quote_4(attr_name1, attr_value1, attr_name2, attr_value2)
449
+
450
+ # @pattern_cc = String.new('') << '<([^<>"]*)\\s([^<>]*(' << @_attr_name1 << '="' << @_attr_value1
451
+ # @pattern_cc << '"[^<>]*' << @_attr_name2 << '="' << @_attr_value2
452
+ # @pattern_cc << '"|' << @_attr_name2 << '="' << @_attr_value2
453
+ # @pattern_cc << '"[^<>]*' << @_attr_name1 << '="' << @_attr_value1
454
+ # @pattern_cc << '")[^<>]*)>'
455
+ @pattern_cc = "<([^<>\"]*)\\s([^<>]*(#{@_attr_name1}=\"#{@_attr_value1}\"[^<>]*#{@_attr_name2}=\"#{@_attr_value2}\"|#{@_attr_name2}=\"#{@_attr_value2}\"[^<>]*#{@_attr_name1}=\"#{@_attr_value1}\")[^<>]*)>"
456
+
457
+ @pattern = Meteor::Core::Util::PatternCache.get(@pattern_cc)
458
+
459
+ @res = @pattern.match(@root.document)
460
+
461
+ if @res
462
+ element_5(@res[1], attr_name1, attr_value1, attr_name2, attr_value2)
463
+ else
464
+ if @error_check
465
+ puts Meteor::Exception::NoSuchElementException.new(attr_name1, attr_value1, attr_name2, attr_value2).message
466
+ end
467
+ @elm_ = nil
468
+ end
469
+
470
+ @elm_
471
+ end
472
+
473
+ private :element_4
474
+
475
+ def edit_attrs_(elm, attr_name, attr_value)
476
+ if is_match('selected', attr_name) && is_match('option', elm.name)
477
+ edit_attrs_5(elm, attr_name, attr_value, @@pattern_selected_m, @@pattern_selected_r)
478
+ elsif is_match('multiple', attr_name) && is_match('select', elm.name)
479
+ edit_attrs_5(elm, attr_name, attr_value, @@pattern_multiple_m, @@pattern_multiple_r)
480
+ elsif is_match('disabled', attr_name) && is_match(DISABLE_ELEMENT, elm.name)
481
+ edit_attrs_5(elm, attr_name, attr_value, @@pattern_disabled_m, @@pattern_disabled_r)
482
+ elsif is_match('checked', attr_name) && is_match('input', elm.name) && is_match('radio', get_type(elm))
483
+ edit_attrs_5(elm, attr_name, attr_value, @@pattern_checked_m, @@pattern_checked_r)
484
+ elsif is_match('readonly', attr_name) && (is_match('textarea', elm.name) || (is_match('input', elm.name) && is_match(READONLY_TYPE, get_type(elm))))
485
+ edit_attrs_5(elm, attr_name, attr_value, @@pattern_readonly_m, @@pattern_readonly_r)
486
+ else
487
+ super(elm, attr_name, attr_value)
488
+ end
489
+ end
490
+
491
+ private :edit_attrs_
492
+
493
+ def edit_attrs_5(elm, attr_name, attr_value, match_p, replace)
494
+ if true.equal?(attr_value) || is_match("true", attr_value)
495
+ @res = match_p.match(elm.attributes)
496
+
497
+ if !@res
498
+ if !''.eql?(elm.attributes) && !''.eql?(elm.attributes.strip)
499
+ elm.attributes = String.new('') << ' ' << elm.attributes.strip
500
+ else
501
+ elm.attributes = String.new('')
502
+ end
503
+ elm.attributes << ' ' << attr_name
504
+ # else
505
+ end
506
+ elsif false.equal?(attr_value) || is_match("false", attr_value)
507
+ elm.attributes.sub!(replace, '')
508
+ end
509
+ end
510
+
511
+ private :edit_attrs_5
512
+
513
+ def edit_document_1(elm)
514
+ edit_document_2(elm, '>')
515
+ end
516
+
517
+ private :edit_document_1
518
+
519
+ def get_attr_value_(elm, attr_name)
520
+ if is_match('selected', attr_name) && is_match('option', elm.name)
521
+ get_attr_value_r(elm, @@pattern_selected_m)
522
+ elsif is_match('multiple', attr_name) && is_match('select', elm.name)
523
+ get_attr_value_r(elm, @@pattern_multiple_m)
524
+ elsif is_match('disabled', attr_name) && is_match(DISABLE_ELEMENT, elm.name)
525
+ get_attr_value_r(elm, @@pattern_disabled_m)
526
+ elsif is_match('checked', attr_name) && is_match('input', elm.name) && is_match('radio', get_type(elm))
527
+ get_attr_value_r(elm, @@pattern_checked_m)
528
+ elsif is_match('readonly', attr_name) && (is_match('textarea', elm.name) || (is_match('input', elm.name) && is_match(READONLY_TYPE, get_type(elm))))
529
+ get_attr_value_r(elm, @@pattern_readonly_m)
530
+ else
531
+ super(elm, attr_name)
532
+ end
533
+ end
534
+
535
+ private :get_attr_value_
536
+
537
+ def get_type(elm)
538
+ if !elm.type_value
539
+ elm.type_value = get_attr_value_(elm, 'type')
540
+ if !elm.type_value
541
+ elm.type_value = get_attr_value_(elm, "TYPE")
542
+ end
543
+ end
544
+ elm.type_value
545
+ end
546
+
547
+ private :get_type
548
+
549
+ def get_attr_value_r(elm, match_p)
550
+
551
+ @res = match_p.match(elm.attributes)
552
+
553
+ if @res
554
+ "true"
555
+ else
556
+ "false"
557
+ end
558
+ end
559
+
560
+ private :get_attr_value_r
561
+
562
+ #
563
+ # get attribute map (属性マップを取得する)
564
+ # @param [Meteor::Element] elm element (要素)
565
+ # @return [Hash] attribute map (属性マップ)
566
+ #
567
+ def get_attrs(elm)
568
+ attrs = Hash.new
569
+
570
+ elm.attributes.scan(@@pattern_get_attrs_map) do |a, b|
571
+ attrs.store(a, unescape(b))
572
+ end
573
+
574
+ elm.attributes.scan(@@pattern_get_attrs_map2) do |a|
575
+ attrs.store(a[0], "true")
576
+ end
577
+
578
+ attrs
579
+ end
580
+
581
+ private :get_attrs
582
+
583
+ #
584
+ # get attribute map of element (要素の属性マップを取得する)
585
+ # @param [Meteor::Element] elm element (要素)
586
+ # @return [Meteor::AttributeMap] attribute map (属性マップ)
587
+ #
588
+ def get_attr_map(elm)
589
+ attrs = Meteor::AttributeMap.new
590
+
591
+ elm.attributes.scan(@@pattern_get_attrs_map) do |a, b|
592
+ attrs.store(a, unescape(b))
593
+ end
594
+
595
+ elm.attributes.scan(@@pattern_get_attrs_map2) do |a|
596
+ attrs.store(a[0], "true")
597
+ end
598
+
599
+ attrs.recordable = true
600
+
601
+ attrs
602
+ end
603
+
604
+ private :get_attr_map
605
+
606
+ def remove_attrs_(elm, attr_name)
607
+ if !is_match(@@attr_logic, attr_name)
608
+ # attribute search pattern (属性検索用パターン)
609
+ @pattern = Meteor::Core::Util::PatternCache.get(String.new('') << attr_name << '="[^"]*"\\s?')
610
+ # @pattern = Meteor::Core::Util::PatternCache.get("#{attr_name}=\"[^\"]*\"\\s?")
611
+ elm.attributes.sub!(@pattern, '')
612
+ else
613
+ # attribute search pattern (属性検索用パターン)
614
+ @pattern = Meteor::Core::Util::PatternCache.get(attr_name)
615
+ elm.attributes.sub!(@pattern, '')
616
+ end
617
+ end
618
+
619
+ private :remove_attrs_
620
+
621
+ def escape(content)
622
+ # 特殊文字の置換
623
+ content = content.gsub(@@pattern_escape, TABLE_FOR_ESCAPE_)
624
+
625
+ content
626
+ end
627
+
628
+ def escape_content(content, elm)
629
+ # 特殊文字の置換
630
+ content = content.gsub(@@pattern_escape_content, TABLE_FOR_ESCAPE_CONTENT_)
631
+
632
+ content
633
+ end
634
+
635
+ private :escape
636
+ private :escape_content
637
+
638
+ def unescape(content)
639
+ # replace special character (特殊文字の置換)
640
+ # 「<」<-「&lt;」
641
+ # 「>」<-「&gt;」
642
+ # 「"」<-「&quotl」
643
+ # 「 」<-「&nbsp;」
644
+ # 「&」<-「&amp;」
645
+ content.gsub(@@pattern_unescape) do
646
+ case $1
647
+ when 'amp'
648
+ '&'
649
+ when 'quot'
650
+ '"'
651
+ when 'apos'
652
+ "'"
653
+ when 'gt'
654
+ '>'
655
+ when 'lt'
656
+ '<'
657
+ when 'nbsp'
658
+ ' '
659
+ end
660
+ end
661
+
662
+ content
663
+ end
664
+
665
+ private :unescape
666
+
667
+ def unescape_content(content, elm)
668
+ content_ = unescape(content)
669
+
670
+ if elm.cx || !is_match(@@match_tag_2, elm.name)
671
+ if content.include?(BR)
672
+ # 「<br>」->「¥r?¥n」
673
+ content_.gsub!(@@pattern_br_2, @root.kaigyo_code)
674
+ end
675
+ end
676
+
677
+ content_
678
+ end
679
+
680
+ private :unescape_content
681
+ end
682
+ end
683
+ end
684
+ end