asip-meteor 0.9.0

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/lib/meteor.rb ADDED
@@ -0,0 +1,4221 @@
1
+ # -* coding: UTF-8 -*-
2
+ # Meteor - A lightweight (X)HTML & XML parser
3
+ #
4
+ # Copyright (C) 2008 Yasumasa Ashida.
5
+ #
6
+ # This program is free software; you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation; either version 2 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # This program is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License
17
+ # along with this program; if not, write to the Free Software
18
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19
+ #
20
+ # @author Yasumasa Ashida
21
+ # @version 0.9.0
22
+ #
23
+ if RUBY_VERSION < '1.9.0' then
24
+ require 'kconv'
25
+ end
26
+
27
+
28
+ module Meteor
29
+
30
+ VERSION = "0.9.0"
31
+
32
+ #
33
+ # 要素クラス
34
+ #
35
+ class Element
36
+
37
+ #
38
+ # イニシャライザ
39
+ # @param [Array] args 引数配列
40
+ #
41
+ def initialize(*args)
42
+ case args.length
43
+ when 1
44
+ if args[0].kind_of?(String) then
45
+ initialize_s(args[0])
46
+ elsif args[0].kind_of?(Meteor::Element)
47
+ initialize_e(args[0])
48
+ else
49
+ raise ArgumentError
50
+ end
51
+ else
52
+ raise ArgumentError
53
+ end
54
+ end
55
+
56
+ #
57
+ # イニシャライザ
58
+ # @param [String] name タグ名
59
+ #
60
+ def initialize_s(name)
61
+ @name = name
62
+ #@attributes = nil
63
+ #@mixed_content = nil
64
+ #@pattern = nil
65
+ #@document = nil
66
+ #@parser=nil
67
+ #@empty = false
68
+ #@cx = false
69
+ #@mono = false
70
+ #@parent = false
71
+ @arguments = AttributeMap.new
72
+ end
73
+
74
+ #
75
+ # イニシャライザ
76
+ # @param [Meteor::Element] elm 要素
77
+ #
78
+ def initialize_e(elm)
79
+ @name = elm.name
80
+ @attributes = String.new(elm.attributes)
81
+ @mixed_content = String.new(elm.mixed_content)
82
+ @pattern = String.new(elm.pattern)
83
+ @document = String.new(elm.document)
84
+ @empty = elm.empty
85
+ @cx = elm.cx
86
+ @mono = elm.mono
87
+ @parent = elm.parent
88
+ @parser = elm.parser
89
+ @arguments = AttributeMap.new(elm.arguments)
90
+ end
91
+
92
+ attr_accessor :name
93
+ attr_accessor :attributes
94
+ attr_accessor :mixed_content
95
+ attr_accessor :pattern
96
+ attr_accessor :document
97
+ attr_accessor :empty
98
+ attr_accessor :cx
99
+ attr_accessor :mono
100
+ attr_accessor :parent
101
+ attr_accessor :parser
102
+ attr_accessor :type_value
103
+ attr_accessor :arguments
104
+
105
+ #
106
+ # 属性を編集する or 属性の値を取得する
107
+ #
108
+ # @param [Array] args 引数配列
109
+ # @return [String] 属性値
110
+ #
111
+ def attribute(*args)
112
+ @parser.attribute(self,*args)
113
+ end
114
+
115
+ #
116
+ # 属性マップを取得する
117
+ #
118
+ # @return [Meteor::AttributeMap] 属性マップ
119
+ #
120
+ def attributeMap
121
+ @parser.attributeMap(self)
122
+ end
123
+
124
+ #
125
+ # 内容をセットする or 内容を取得する
126
+ #
127
+ # @param [Array] args 引数配列
128
+ # @return [String] 内容
129
+ #
130
+ def content(*args)
131
+ @parser.content(self,*args)
132
+ end
133
+
134
+ #
135
+ # 属性を編集するor内容をセットする
136
+ #
137
+ # @param [String] name 属性の名前
138
+ # @param [String] value 属性の値or内容
139
+ #
140
+ def []=(name,value)
141
+ if !name.kind_of?(String) || name != ':content' then
142
+ attribute(name,value)
143
+ else
144
+ content(value)
145
+ end
146
+ end
147
+
148
+ #
149
+ # 属性の値or内容を取得する
150
+ #
151
+ # @param [String] name 属性の名前
152
+ # @return [String] 属性の値or内容
153
+ #
154
+ def [](name)
155
+ if !name.kind_of?(String) || name != ':content' then
156
+ getAttributeValue(name)
157
+ else
158
+ content()
159
+ end
160
+ end
161
+
162
+ #
163
+ # 属性を削除する
164
+ #
165
+ # @param args 引数配列
166
+ #
167
+ def removeAttribute(*args)
168
+ @parser.removeAttribute(self,*args)
169
+ end
170
+
171
+ #
172
+ # 要素を削除する
173
+ #
174
+ def remove
175
+ @parser.removeElement(self)
176
+ end
177
+
178
+ end
179
+
180
+ #
181
+ # ルート要素クラス
182
+ #
183
+ class RootElement
184
+
185
+ #
186
+ # イニシャライザ
187
+ #
188
+ def initialize()
189
+ #コンテントタイプ
190
+ @contentType = ''
191
+ #改行コード
192
+ @kaigyoCode = ''
193
+ #文字コード
194
+ @characterEncoding=''
195
+
196
+ #フックドキュメント
197
+ @hookDocument =''
198
+ #フック判定フラグ
199
+ #@hook = false
200
+ #単一要素フック判定フラグ
201
+ #@monoHook = false
202
+ #要素
203
+ #@element = nil
204
+ #変更可能要素
205
+ #@mutableElement = nil
206
+ end
207
+
208
+ attr_accessor :contentType
209
+ attr_accessor :kaigyoCode
210
+ attr_accessor :characterEncoding
211
+ attr_accessor :hookDocument
212
+ attr_accessor :hook;
213
+ attr_accessor :monoHook
214
+ attr_accessor :element
215
+ attr_accessor :mutableElement
216
+ attr_accessor :document
217
+ end
218
+
219
+ #
220
+ # 属性マップクラス
221
+ #
222
+ class AttributeMap
223
+
224
+ def initialize(*args)
225
+ case args.length
226
+ when 0
227
+ initialize_0
228
+ when 1
229
+ initialize_1(args[0])
230
+ else
231
+ raise ArgumentError
232
+ end
233
+ end
234
+
235
+ #
236
+ # イニシャライザ
237
+ #
238
+ def initialize_0
239
+ @map = Hash.new
240
+ if RUBY_VERSION < '1.9.0'
241
+ @names = Array.new
242
+ end
243
+ @recordable = false
244
+ end
245
+
246
+ #
247
+ # イニシャライザ
248
+ #
249
+ def initialize_1(attrMap)
250
+ #@map = Marshal.load(Marshal.dump(attrMap.map))
251
+ @map = attrMap.map.dup
252
+ if RUBY_VERSION < '1.9.0'
253
+ @names = Array.new(attrMap.names)
254
+ end
255
+ @recordable = attrMap.recordable
256
+ end
257
+
258
+ #
259
+ # 属性名と属性値を対としてセットする
260
+ #
261
+ # @param [String] name 属性名
262
+ # @param [String] value 属性値
263
+ #
264
+ def store(name,value)
265
+
266
+ if !@map[name] then
267
+ attr = Attribute.new
268
+ attr.name = name
269
+ attr.value = value
270
+ if @recordable then
271
+ attr.changed = true
272
+ attr.removed = false
273
+ end
274
+ @map[name] = attr
275
+ if RUBY_VERSION < "1.9.0"
276
+ @names << name
277
+ end
278
+ else
279
+ attr = @map[name]
280
+ if @recordable && attr.value != value then
281
+ attr.changed = true
282
+ attr.removed = false
283
+ end
284
+ attr.value = value
285
+ #@map[name] = attr
286
+ end
287
+ end
288
+
289
+ #
290
+ # 属性名配列を取得する
291
+ #
292
+ # @return [Array] 属性名配列
293
+ #
294
+ def names
295
+ if RUBY_VERSION < "1.9.0"
296
+ @names
297
+ else
298
+ @map.keys
299
+ end
300
+ end
301
+
302
+ #
303
+ # 属性名で属性値を取得する
304
+ #
305
+ # @param [String] name 属性名
306
+ # @return [String] 属性値
307
+ #
308
+ def fetch(name)
309
+ if @map[name] && !@map[name].removed then
310
+ @map[name].value
311
+ end
312
+ end
313
+
314
+ #
315
+ # 属性名に対応した属性を削除する
316
+ #
317
+ # @param name 属性名
318
+ #
319
+ def delete(name)
320
+ if @map[name] && @recordable then
321
+ @map[name].removed = true
322
+ @map[name].changed = false
323
+ end
324
+ end
325
+
326
+ #
327
+ # 属性名で属性の変更状況を取得する
328
+ #
329
+ # @return [TrueClass][FalseClass] 属性の変更状況
330
+ #
331
+ def changed(name)
332
+ if @map[name] then
333
+ @map[name].changed
334
+ end
335
+ end
336
+
337
+ #
338
+ # 属性名で属性の削除状況を取得する
339
+ #
340
+ # @return [TrueClass][FalseClass] 属性の削除状況
341
+ #
342
+ def removed(name)
343
+ if @map[name] then
344
+ @map[name].removed
345
+ end
346
+ end
347
+
348
+ attr_accessor :map
349
+ attr_accessor :recordable
350
+
351
+ #
352
+ # 属性名と属性値を対としてセットする
353
+ #
354
+ # @param [String] name 属性名
355
+ # @param [String] value 属性値
356
+ #
357
+ def [](name,value)
358
+ store(name,value)
359
+ end
360
+
361
+ #
362
+ # 属性名で属性値を取得する
363
+ #
364
+ # @param [String] name 属性名
365
+ # @return [String] 属性値
366
+ #
367
+ def [](name)
368
+ fetch(name)
369
+ end
370
+ end
371
+
372
+ #
373
+ # 属性クラス
374
+ #
375
+ class Attribute
376
+
377
+ #
378
+ # イニシャライザ
379
+ #
380
+ def initialize
381
+ #@name = nil
382
+ #@value = nil
383
+ #@changed = false
384
+ #@removed = false
385
+ end
386
+
387
+ attr_accessor :name
388
+ attr_accessor :value
389
+ attr_accessor :changed
390
+ attr_accessor :removed
391
+
392
+ end
393
+
394
+ #
395
+ # パーサ共通クラス
396
+ #
397
+ class Parser
398
+ HTML = 0
399
+ XHTML = 1
400
+ XML = 2
401
+ end
402
+
403
+ #
404
+ # パーサファクトリクラス
405
+ #
406
+ class ParserFactory
407
+
408
+ #
409
+ # パーサファクトリを生成する
410
+ #
411
+ # @param [Array] args 引数配列
412
+ # @return [Meteor::ParserFactory] パーサファクトリ
413
+ #
414
+ def self.build(*args)
415
+ case args.length
416
+ when 3
417
+ build_3(args[0],args[1],args[2])
418
+ when 2
419
+ build_2(args[0],args[1])
420
+ else
421
+ raise ArgumentError
422
+ end
423
+ end
424
+
425
+ #
426
+ # パーサファクトリを生成する
427
+ #
428
+ # @param [Fixnum] type パーサのタイプ
429
+ # @param [String] path ファイルパス
430
+ # @param [String] encoding エンコーディング
431
+ # @return [Meteor::ParserFactory] パーサファクトリ
432
+ #
433
+ def self.build_3(type,path,encoding)
434
+ psf = ParserFactory.new
435
+
436
+ case type
437
+ when Parser::HTML then
438
+ html = Meteor::Core::Html::ParserImpl.new()
439
+ html.read(path, encoding)
440
+ psf.setParser(html)
441
+ when Parser::XHTML then
442
+ xhtml = Meteor::Core::Xhtml::ParserImpl.new()
443
+ xhtml.read(path, encoding)
444
+ psf.setParser(xhtml)
445
+ when Parser::XML then
446
+ xml = Meteor::Core::Xml::ParserImpl.new()
447
+ xml.read(path, encoding)
448
+ psf.setParser(xml)
449
+ end
450
+
451
+ psf
452
+ end
453
+ #protected :build_3
454
+
455
+ #
456
+ # パーサファクトリを生成する
457
+ #
458
+ # @param [Fixnum] type パーサのタイプ
459
+ # @param [String] document ドキュメント
460
+ # @return [Meteor::ParserFactory] パーサファクトリ
461
+ #
462
+ def self.build_2(type,document)
463
+ psf = ParserFactory.new
464
+
465
+ case type
466
+ when Parser::HTML then
467
+ html = Meteor::Core::Html::ParserImpl.new()
468
+ html.parse(document)
469
+ psf.setParser(html)
470
+ when Parser::XHTML then
471
+ xhtml = Meteor::Core::Xhtml::ParserImpl.new()
472
+ xhtml.parse(document)
473
+ psf.setParser(xhtml)
474
+ when Parser::XML then
475
+ xml = Meteor::Core::Xml::ParserImpl.new()
476
+ xml.parse(document)
477
+ psf.setParser(xml)
478
+ end
479
+
480
+ psf
481
+ end
482
+ #protected :build_2
483
+
484
+ #
485
+ # パーサをセットする
486
+ #
487
+ # @param [Meteor::Parser] パーサ
488
+ #
489
+ def setParser(pif)
490
+ @pif = pif
491
+ end
492
+
493
+ #
494
+ # パーサを取得する
495
+ #
496
+ # @return [Meteor::Parser] パーサ
497
+ #
498
+ def getParser
499
+
500
+ if @pif.instance_of?(Meteor::Core::Html::ParserImpl) then
501
+ Meteor::Core::Html::ParserImpl.new(@pif)
502
+ elsif @pif.instance_of?(Meteor::Core::Xhtml::ParserImpl) then
503
+ Meteor::Core::Xhtml::ParserImpl.new(@pif)
504
+ elsif @pif.instance_of?(Meteor::Core::Xml::ParserImpl) then
505
+ Meteor::Core::Xml::ParserImpl.new(@pif)
506
+ end
507
+ end
508
+
509
+ end
510
+
511
+ module Hook
512
+
513
+ #
514
+ # フッククラス
515
+ #
516
+ class Hooker
517
+
518
+ #
519
+ # イニシャライザ
520
+ #
521
+ def initialize
522
+ end
523
+
524
+ def doAction(elm,pif)
525
+ #内容あり要素の場合
526
+ if elm.empty then
527
+ pif2 = pif.child(elm)
528
+ execute(pif2)
529
+ pif2.flush
530
+ end
531
+ end
532
+
533
+ def execute(pif)
534
+ end
535
+ end
536
+
537
+ #
538
+ # ループフッククラス
539
+ #
540
+ class Looper
541
+
542
+ #
543
+ # イニシャライザ
544
+ #
545
+ def initialize
546
+ end
547
+
548
+ def doAction(elm,pif,list)
549
+ #内容あり要素の場合
550
+ if elm.empty then
551
+ pif2 = pif.child(elm)
552
+
553
+ list.each { |item|
554
+ if pif2.rootElement.hook then
555
+ pif2.rootElement.document = elm.mixed_content
556
+ #elsif pif2.rootElement.monoHook then
557
+ end
558
+ execute(pif2,item)
559
+ }
560
+ pif2.flush
561
+ end
562
+ end
563
+
564
+ def execute(pif,item)
565
+ end
566
+ end
567
+ end
568
+
569
+ module Core
570
+
571
+ #
572
+ # パーサコアクラス
573
+ #
574
+ class Kernel < Meteor::Parser
575
+
576
+ EMPTY = ''
577
+ SPACE = " "
578
+ DOUBLE_QUATATION = "\""
579
+ TAG_OPEN = "<"
580
+ TAG_OPEN3 = "</"
581
+ TAG_OPEN4 = "<\\\\/"
582
+ TAG_CLOSE = ">"
583
+ TAG_CLOSE2 = "\\/>"
584
+ TAG_CLOSE3 = "/>"
585
+ ATTR_EQ = "=\""
586
+ #element
587
+ #TAG_SEARCH_1_1 = "([^<>]*)>(((?!(<\\/"
588
+ TAG_SEARCH_1_1 = "(\\s?[^<>]*)>(((?!("
589
+ #TAG_SEARCH_1_2 = ")).)*)<\\/";
590
+ TAG_SEARCH_1_2 = "[^<>]*>)).)*)<\\/"
591
+ TAG_SEARCH_1_3 = "(\\s?[^<>]*)\\/>"
592
+ #TAG_SEARCH_1_4 = "([^<>\\/]*)>"
593
+ TAG_SEARCH_1_4 = "(\\s[^<>\\/]*>|((?!([^<>]*\\/>))[^<>]*>))"
594
+ TAG_SEARCH_1_4_2 = "(\\s[^<>]*)>"
595
+
596
+ TAG_SEARCH_NC_1_1 = "\\s?[^<>]*>((?!("
597
+ TAG_SEARCH_NC_1_2 = "[^<>]*>)).)*<\\/"
598
+ TAG_SEARCH_NC_1_3 = "\\s?[^<>]*\\/>"
599
+ TAG_SEARCH_NC_1_4 = "(?:\\s[^<>\\/]*>|((?!([^<>]*\\/>))[^<>]*>))"
600
+ TAG_SEARCH_NC_1_4_2 = "\\s[^<>]*>"
601
+
602
+ #TAG_SEARCH_2_1 = "\\s([^<>]*"
603
+ TAG_SEARCH_2_1 = "(\\s[^<>]*"
604
+ TAG_SEARCH_2_1_2 = "(\\s[^<>]*(?:"
605
+ #TAG_SEARCH_2_2 = "\"[^<>]*)>(((?!(<\\/"
606
+ TAG_SEARCH_2_2 = "\"[^<>]*)>(((?!("
607
+ TAG_SEARCH_2_2_2 = "\")[^<>]*)>(((?!("
608
+ TAG_SEARCH_2_3 = "\"[^<>]*)"
609
+ TAG_SEARCH_2_3_2 = "\"[^<>]*)\\/>"
610
+ TAG_SEARCH_2_3_2_2 = "\")[^<>]*)\\/>"
611
+ #TAG_SEARCH_2_4 = "\"[^<>\\/]*>"
612
+ TAG_SEARCH_2_4 = "(?:[^<>\\/]*>|((?!([^<>]*\\/>))[^<>]*>))"
613
+ #TAG_SEARCH_2_4_2 = "\"[^<>\\/]*)>"
614
+ TAG_SEARCH_2_4_2 = "(?:[^<>\\/]*>|(?:(?!([^<>]*\\/>))[^<>]*>)))"
615
+ TAG_SEARCH_2_4_2_2 = "\")([^<>\\/]*>|((?!([^<>]*\\/>))[^<>]*>)))"
616
+ TAG_SEARCH_2_4_2_3 = "\""
617
+ TAG_SEARCH_2_4_3 = "\"[^<>]*)>"
618
+ TAG_SEARCH_2_4_3_2 = "\")[^<>]*)>"
619
+ TAG_SEARCH_2_4_4 = "\"[^<>]*>"
620
+
621
+ TAG_SEARCH_2_6 = "\"[^<>]*"
622
+ TAG_SEARCH_2_7 = "\"|"
623
+
624
+ TAG_SEARCH_NC_2_1 = "\\s[^<>]*"
625
+ TAG_SEARCH_NC_2_1_2 = "\\s[^<>]*(?:"
626
+ TAG_SEARCH_NC_2_2 = "\"[^<>]*>((?!("
627
+ TAG_SEARCH_NC_2_2_2 = "\")[^<>]*>((?!("
628
+ TAG_SEARCH_NC_2_3 = "\"[^<>]*)"
629
+ TAG_SEARCH_NC_2_3_2 = "\"[^<>]*\\/>"
630
+ TAG_SEARCH_NC_2_3_2_2 = "\")[^<>]*\\/>"
631
+ TAG_SEARCH_NC_2_4 = "(?:[^<>\\/]*>|((?!([^<>]*\\/>))[^<>]*>))"
632
+ TAG_SEARCH_NC_2_4_2 = "(?:[^<>\\/]*>|((?!([^<>]*\\/>))[^<>]*>))"
633
+ TAG_SEARCH_NC_2_4_2_2 = "\")(?:[^<>\\/]*>|((?!([^<>]*\\/>))[^<>]*>))"
634
+ TAG_SEARCH_NC_2_4_2_3 = "\""
635
+ TAG_SEARCH_NC_2_4_3 = "\"[^<>]*>"
636
+ TAG_SEARCH_NC_2_4_3_2 = "\")[^<>]*>"
637
+ TAG_SEARCH_NC_2_4_4 = "\"[^<>]*>"
638
+ TAG_SEARCH_NC_2_6 = "\"[^<>]*"
639
+ TAG_SEARCH_NC_2_7 = "\"|"
640
+
641
+ TAG_SEARCH_3_1 = "<([^<>\"]*)\\s[^<>]*"
642
+ TAG_SEARCH_3_1_2 = "<([^<>\"]*)\\s([^<>]*"
643
+ TAG_SEARCH_3_1_2_2 = "<([^<>\"]*)\\s([^<>]*("
644
+
645
+ TAG_SEARCH_3_2 = "\"[^<>]*\\/>"
646
+ TAG_SEARCH_3_2_2 = "\"[^<>]*)\\/>"
647
+ TAG_SEARCH_3_2_2_2 = "\")[^<>]*)\\/>"
648
+
649
+ TAG_SEARCH_4_1 = "(\\s[^<>\\/]*)>("
650
+ TAG_SEARCH_4_2 = ".*?<"
651
+ #TAG_SEARCH_4_3 = "\\s[^<>\\/]*>"
652
+ TAG_SEARCH_4_3 = "(\\s[^<>\\/]*>|((?!([^<>]*\\/>))[^<>]*>))"
653
+ TAG_SEARCH_4_4 = "<\\/"
654
+ TAG_SEARCH_4_5 = ".*?<\/"
655
+ TAG_SEARCH_4_6 = ".*?)<\/"
656
+ #TAG_SEARCH_4_7 = "\"[^<>\\/]*)>("
657
+ TAG_SEARCH_4_7 = "\"(?:[^<>\\/]*>|(?!([^<>]*\\/>))[^<>]*>))("
658
+ TAG_SEARCH_4_7_2 = "\")(?:[^<>\\/]*>|(?!([^<>]*\\/>))[^<>]*>))("
659
+
660
+ TAG_SEARCH_NC_3_1 = "<[^<>\"]*\\s[^<>]*"
661
+ TAG_SEARCH_NC_3_1_2 = "<([^<>\"]*)\\s(?:[^<>]*"
662
+ TAG_SEARCH_NC_3_1_2_2 = "<([^<>\"]*)\\s(?:[^<>]*("
663
+ TAG_SEARCH_NC_3_2 = "\"[^<>]*\\/>"
664
+ TAG_SEARCH_NC_3_2_2 = "\"[^<>]*)\\/>"
665
+ TAG_SEARCH_NC_3_2_2_2 = "\")[^<>]*)\\/>"
666
+ #TAG_SEARCH_NC_4_1 = "(?:\\s[^<>\\/]*)>("
667
+ #TAG_SEARCH_NC_4_2 = ".*?<"
668
+ #TAG_SEARCH_NC_4_3 = "(?:\\s[^<>\\/]*>|((?!([^<>]*\\/>))[^<>]*>))"
669
+ #TAG_SEARCH_NC_4_4 = "<\\/"
670
+ #TAG_SEARCH_NC_4_5 = ".*?<\/"
671
+ #TAG_SEARCH_NC_4_6 = ".*?<\/"
672
+ #TAG_SEARCH_NC_4_7 = "\"(?:[^<>\\/]*>|(?!([^<>]*\\/>))[^<>]*>))("
673
+ #TAG_SEARCH_NC_4_7_2 = "\")(?:[^<>\\/]*>|(?!([^<>]*\\/>))[^<>]*>))("
674
+
675
+ #setAttribute
676
+ SET_ATTR_1 = "=\"[^\"]*\""
677
+ #getAttributeValue
678
+ GET_ATTR_1 = "=\"([^\"]*)\""
679
+ #attributeMap
680
+ #todo
681
+ GET_ATTRS_MAP = "([^\\s]*)=\"([^\"]*)\""
682
+ #removeAttribute
683
+ ERASE_ATTR_1 = "=\"[^\"]*\"\\s"
684
+
685
+ #cxtag
686
+ SEARCH_CX_1 = "<!--\\s@"
687
+ SEARCH_CX_2 = "\\s([^<>]*id=\""
688
+ SEARCH_CX_3 = "\"[^<>]*)-->(((?!(<!--\\s\\/@"
689
+ SEARCH_CX_4 = ")).)*)<!--\\s\\/@"
690
+ SEARCH_CX_5 = "\\s-->"
691
+ SEARCH_CX_6 = "<!--\\s@([^<>]*)\\s[^<>]*id=\""
692
+
693
+ #setElementToCXTag
694
+ SET_CX_1 = "<!-- @"
695
+ SET_CX_2 = "-->"
696
+ SET_CX_3 = "<!-- /@"
697
+ SET_CX_4 = " -->"
698
+
699
+ #setMonoInfo
700
+ SET_MONO_1 = "\\A[^<>]*\\Z"
701
+
702
+ #clean
703
+ CLEAN_1 = "<!--\\s@[^<>]*\\s[^<>]*(\\s)*-->"
704
+ CLEAN_2 = "<!--\\s\\/@[^<>]*(\\s)*-->"
705
+ #escape
706
+ AND_1 = '&'
707
+ AND_2 = '&amp;'
708
+ LT_1 = '<'
709
+ LT_2 = '&lt;'
710
+ GT_1 = '>'
711
+ GT_2 = '&gt;'
712
+ QO_2 = '&quot;'
713
+ AP_1 = '\''
714
+ AP_2 = '&apos;'
715
+ #EN_1 = "\\\\"
716
+ EN_1 = "\\"
717
+ #EN_2 = "\\\\\\\\"
718
+ #DOL_1 = "\\\$"
719
+ #DOL_2 = "\\\\\\$"
720
+ #PLUS_1 = "\\\+"
721
+ #PLUS_2 = "\\\\\\+"
722
+
723
+ SUB_REGEX1 = "(\\\\*)\\\\([0-9]+)"
724
+ SUB_REGEX2 = "\\1\\1\\\\\\\\\\2"
725
+ SUB_REGEX3 = "\\1\\1\\1\\1\\\\\\\\\\\\\\\\\\2"
726
+
727
+ @@pattern_get_attrs_map = Regexp.new(GET_ATTRS_MAP)
728
+
729
+ #BRAC_OPEN_1 = "\\\("
730
+ #BRAC_OPEN_2 = "\\\\\\("
731
+ #BRAC_CLOSE_1 = "\\\)"
732
+ #BRAC_CLOSE_2 = "\\\\\\)"
733
+ #SBRAC_OPEN_1 = "\\\["
734
+ #SBRAC_OPEN_2 = "\\\\\\["
735
+ #SBRAC_CLOSE_1 = "\\\]"
736
+ #SBRAC_CLOSE_2 = "\\\\\\]"
737
+ #CBRAC_OPEN_1 = "\\\{"
738
+ #CBRAC_OPEN_2 = "\\\\\\{"
739
+ #CBRAC_CLOSE_1 = "\\\}"
740
+ #CBRAC_CLOSE_2 = "\\\\\\}"
741
+ #COMMA_1 = "\\\."
742
+ #COMMA_2 = "\\\\\\."
743
+ #VLINE_1 = "\\\|"
744
+ #VLINE_2 = "\\\\\\|"
745
+ #QMARK_1 = "\\\?"
746
+ #QMARK_2 = "\\\\\\?"
747
+ #ASTERISK_1 = "\\\*"
748
+ #ASTERISK_2 = "\\\\\\*"
749
+
750
+ #@@pattern_en = Regexp.new(EN_1)
751
+ #@@pattern_dol = Regexp.new(DOL_1)
752
+ #@@pattern_plus = Regexp.new(PLUS_1)
753
+ #@@pattern_brac_open = Regexp.new(BRAC_OPEN_1)
754
+ #@@pattern_brac_close = Regexp.new(BRAC_CLOSE_1)
755
+ #@@pattern_sbrac_open = Regexp.new(SBRAC_OPEN_1)
756
+ #@@pattern_sbrac_close = Regexp.new(SBRAC_CLOSE_1)
757
+ #@@pattern_cbrac_open = Regexp.new(CBRAC_OPEN_1)
758
+ #@@pattern_cbrac_close = Regexp.new(CBRAC_CLOSE_1)
759
+ #@@pattern_comma = Regexp.new(COMMA_1)
760
+ #@@pattern_vline = Regexp.new(VLINE_1)
761
+ #@@pattern_qmark = Regexp.new(QMARK_1)
762
+ #@@pattern_asterisk = Regexp.new(ASTERISK_1)
763
+
764
+ @@pattern_sub_regex1 = Regexp.new(SUB_REGEX1)
765
+
766
+ @@pattern_clean1 = Regexp.new(CLEAN_1)
767
+ @@pattern_clean2 = Regexp.new(CLEAN_2)
768
+
769
+
770
+ #
771
+ # イニシャライザ
772
+ # @param [Array] args 引数配列
773
+ #
774
+ def initialize(*args)
775
+ #親要素
776
+ #@parent = nil;
777
+
778
+ #正規表現パターン
779
+ #@pattern = nil
780
+ #ルート要素
781
+ @root = RootElement.new
782
+ if RUBY_VERSION >= '1.9.0' then
783
+ @e_cache = Hash.new()
784
+ else
785
+ @e_cache = Meteor::Core::Util::OrderHash.new
786
+ end
787
+ #@res = nil
788
+ #@_attributes = nil
789
+ #@_mixed_content = nil
790
+ #@pattern_cc = nil
791
+ #@pattern_cc_1 = nil
792
+ #@pattern_cc_1b = nil
793
+ #@pattern_cc_1_1 = nil
794
+ #@pattern_cc_1_2 = nil
795
+ #@pattern_cc_2 = nil
796
+ #@pattern_cc_2_1 = nil
797
+ #@pattern_cc_2_2 = nil
798
+ #@cnt = 0
799
+ #@position = 0
800
+ #@position2 = 0
801
+ #@_elmName = nil
802
+ #@_attrName = nil
803
+ #@_attrValue = nil
804
+ #@_attrName1 = nil
805
+ #@_attrValue1 = nil
806
+ #@_attrName2 = nil
807
+ #@_attrValue2 = nil
808
+
809
+ #@sbuf = nil;
810
+ #@rx_document = nil;
811
+ #@rx_document2 = nil;
812
+ end
813
+
814
+ #
815
+ # ドキュメントをセットする
816
+ #
817
+ # @param [String] doc ドキュメント
818
+ #
819
+ def document=(doc)
820
+ @root.document = doc
821
+ end
822
+
823
+ #
824
+ # ドキュメントを取得する
825
+ #
826
+ # @return [String] ドキュメント
827
+ #
828
+ def document
829
+ @root.document
830
+ end
831
+
832
+ attr_accessor :parent
833
+
834
+ #
835
+ # フックフラグをセットする
836
+ #
837
+ # @param [TrueClass][FalseClass] hook フックフラグ
838
+ #
839
+ def hook=(hook)
840
+ @root.hook = hook
841
+ end
842
+
843
+ #
844
+ # フックフラグを取得する
845
+ #
846
+ # @return [TrueClass][FalseClass] フックフラグ
847
+ #
848
+ def hook
849
+ @root.hook
850
+ end
851
+
852
+ #
853
+ # 単一要素フックフラグをセットする
854
+ #
855
+ # @pamam [TrueClass][FalseClass] hook 単一要素フックフラグ
856
+ #
857
+ def monoHook=(hook)
858
+ @root.monoHook = hook
859
+ end
860
+
861
+ #
862
+ # 単一要素フックフラグを取得する
863
+ #
864
+ # @return [TrueClass][FalseClass] 単一要素フックフラグ
865
+ #
866
+ def monoHook
867
+ @root.monoHook
868
+ end
869
+
870
+ #
871
+ # フックドキュメントをセットする
872
+ #
873
+ # @param [String] hookDocument フックドキュメント
874
+ #
875
+ def hookDocument=(hookDocument)
876
+ @root.hookDocument = hookDocument
877
+ end
878
+
879
+ #
880
+ # フックドキュメントを取得する
881
+ #
882
+ # @return [String] フックドキュメント
883
+ #
884
+ def hookDocument
885
+ @root.hookDocument
886
+ end
887
+
888
+ #
889
+ # 文字エンコーディングをセットする
890
+ #
891
+ # @param [String] enc 文字エンコーディング
892
+ #
893
+ def characterEncoding=(enc)
894
+ @root.characterEncoding = enc
895
+ end
896
+
897
+ #
898
+ # 文字エンコーディングを取得する
899
+ #
900
+ # @param [String] 文字エンコーディング
901
+ #
902
+ def characterEncoding
903
+ @root.characterEncoding
904
+ end
905
+
906
+ #
907
+ # ルート要素を取得する
908
+ #
909
+ # @return [Meteor::RootElement] ルート要素
910
+ #
911
+ def rootElement
912
+ @root
913
+ end
914
+
915
+ #
916
+ # ファイルを読み込み、パーサにセットする
917
+ #
918
+ # @param [String] filePath 入力ファイルの絶対パス
919
+ # @param [String] encoding 入力ファイルの文字コード
920
+ #
921
+ def read(filePath, encoding)
922
+
923
+ #try {
924
+ @characterEncoding = encoding
925
+ #ファイルのオープン
926
+ if RUBY_VERSION >= '1.9.0' then
927
+ io = File.open(filePath,'r:' << encoding)
928
+ #読込及び格納
929
+ @root.document = io.read
930
+ else
931
+ #読込及び格納
932
+ io = open(filePath,'r')
933
+ @root.document = io.read
934
+ @root.document = @root.document.kconv(get_encoding(), Kconv.guess(@root.document))
935
+ end
936
+
937
+ #ファイルのクローズ
938
+ io.close
939
+
940
+ #@root.document = str
941
+
942
+ #} catch (FileNotFoundException e) {
943
+ #FileNotFoundException時の処理
944
+ #e.printStackTrace();
945
+ #@document = EMPTY;
946
+ #} catch (Exception e) {
947
+ # //上記以外の例外時の処理
948
+ # e.printStackTrace();
949
+ # this.setDocument(EMPTY);
950
+ #}
951
+
952
+ end
953
+
954
+ def get_encoding()
955
+ case @characterEncoding
956
+ when "UTF-8"
957
+ Kconv::UTF8
958
+ when "ISO-2022-JP"
959
+ Kconv::JIS
960
+ when "Shift_JIS"
961
+ Kconv::SJIS
962
+ when "EUC-JP"
963
+ Kconv::EUC
964
+ when "ASCII"
965
+ Kconv::ASCII
966
+ #when "UTF-16"
967
+ # return KConv::UTF16
968
+ else
969
+ KConv::UTF8
970
+ end
971
+ end
972
+ private :get_encoding
973
+
974
+ #
975
+ # 要素を取得する
976
+ #
977
+ # @param [Array] args 引数配列
978
+ # @return [Meteor::Element] 要素
979
+ #
980
+ def element(*args)
981
+ case args.length
982
+ when 1
983
+ element_1(args[0])
984
+ when 2
985
+ element_2(args[0],args[1])
986
+ when 3
987
+ element_3(args[0],args[1],args[2])
988
+ when 4
989
+ element_4(args[0],args[1],args[2],args[3])
990
+ when 5
991
+ element_5(args[0],args[1],args[2],args[3],args[4])
992
+ else
993
+ raise ArgumentError
994
+ end
995
+ end
996
+
997
+ #
998
+ # 要素名で検索し、要素を取得する
999
+ #
1000
+ # @param [String] elmName 要素名
1001
+ # @return [Meteor::Element] 要素
1002
+ #
1003
+ def element_1(elmName)
1004
+
1005
+ @_elmName = escapeRegex(elmName)
1006
+
1007
+ #空要素検索用パターン
1008
+ @pattern_cc_1 = '' << TAG_OPEN << @_elmName << TAG_SEARCH_1_3
1009
+
1010
+ @pattern = Meteor::Core::Util::PatternCache.get(@pattern_cc_1)
1011
+ #空要素検索
1012
+ @res1 = @pattern.match(@root.document)
1013
+
1014
+ #内容あり要素検索用パターン
1015
+ @pattern_cc_2 = '' << TAG_OPEN << @_elmName << TAG_SEARCH_1_1 << elmName
1016
+ @pattern_cc_2 << TAG_SEARCH_1_2 << @_elmName << TAG_CLOSE
1017
+
1018
+ @pattern = Meteor::Core::Util::PatternCache.get(@pattern_cc_2)
1019
+ #内容あり要素検索
1020
+ @res2 = @pattern.match(@root.document)
1021
+
1022
+ if @res1 && @res2 then
1023
+ if @res1.end(0) < @res2.end(0) then
1024
+ @res = @res1
1025
+ @pattern_cc = @pattern_cc_1
1026
+ @elm_ = elementWithoutContent_1(elmName)
1027
+ elsif @res1.end(0) > @res2.end(0)
1028
+ @res = @res2
1029
+ @pattern_cc = @pattern_cc_2
1030
+ @elm_ = elementWithContent_1(elmName)
1031
+ end
1032
+ elsif @res1 && !@res2 then
1033
+ @res = @res1
1034
+ @pattern_cc = @pattern_cc_1
1035
+ @elm_ = elementWithoutContent_1(elmName)
1036
+ elsif !@res1 && @res2 then
1037
+ @res = @res2
1038
+ @pattern_cc = @pattern_cc_2
1039
+ @elm_ = elementWithContent_1(elmName)
1040
+ elsif !@res1 && !@res2 then
1041
+ @elm_ = nil
1042
+ #raise NoSuchElementException.new(elmName);
1043
+ end
1044
+
1045
+ @elm_
1046
+ end
1047
+ private :element_1
1048
+
1049
+ def elementWithContent_1(elmName)
1050
+
1051
+ @elm_ = Element.new(elmName)
1052
+ #属性
1053
+ @elm_.attributes = @res[1]
1054
+ #内容
1055
+ @elm_.mixed_content = @res[2]
1056
+ #全体
1057
+ @elm_.document = @res[0]
1058
+
1059
+ @pattern_cc = '' << TAG_OPEN << @_elmName << TAG_SEARCH_NC_1_1 << elmName
1060
+ @pattern_cc << TAG_SEARCH_NC_1_2 << @_elmName << TAG_CLOSE
1061
+
1062
+ #内容あり要素検索用パターン
1063
+ @elm_.pattern = @pattern_cc
1064
+
1065
+ @elm_.empty = true
1066
+
1067
+ @elm_.parser = self
1068
+
1069
+ @elm_
1070
+ end
1071
+ private :elementWithContent_1
1072
+
1073
+ def elementWithoutContent_1(elmName)
1074
+ #要素
1075
+ @elm_ = Element.new(elmName)
1076
+ #属性
1077
+ @elm_.attributes = @res[1]
1078
+ #全体
1079
+ @elm_.document = @res[0]
1080
+ #空要素検索用パターン
1081
+ @pattern_cc = '' << TAG_OPEN << @_elmName << TAG_SEARCH_NC_1_3
1082
+ @elm_.pattern = @pattern_cc
1083
+
1084
+ @elm_.empty = false
1085
+
1086
+ @elm_.parser = self
1087
+
1088
+ @elm_
1089
+ end
1090
+ private :elementWithoutContent_1
1091
+
1092
+ #
1093
+ # 要素名と属性で検索し、要素を取得する
1094
+ #
1095
+ # @param [String] elmName 要素名
1096
+ # @param [String] attrName 属性名
1097
+ # @param [String] attrValue 属性値
1098
+ # @return [Meteor::Element] 要素
1099
+ #
1100
+ def element_3(elmName,attrName,attrValue)
1101
+
1102
+ @_elmName = escapeRegex(elmName)
1103
+ @_attrName = escapeRegex(attrName)
1104
+ @_attrValue = escapeRegex(attrValue)
1105
+
1106
+ #空要素検索用パターン
1107
+ @pattern_cc_1 = '' << TAG_OPEN << @_elmName << TAG_SEARCH_2_1 << @_attrName << ATTR_EQ
1108
+ @pattern_cc_1 << @_attrValue << TAG_SEARCH_2_3_2
1109
+ @pattern = Meteor::Core::Util::PatternCache.get(@pattern_cc_1)
1110
+ #空要素検索
1111
+ @res1 = @pattern.match(@root.document)
1112
+
1113
+ #内容あり要素検索パターン
1114
+ @pattern_cc_2 = '' << TAG_OPEN << @_elmName << TAG_SEARCH_2_1 << @_attrName << ATTR_EQ
1115
+ @pattern_cc_2 << @_attrValue << TAG_SEARCH_2_2 << @_elmName
1116
+ @pattern_cc_2 << TAG_SEARCH_1_2 << @_elmName << TAG_CLOSE
1117
+ @pattern = Meteor::Core::Util::PatternCache.get(@pattern_cc_2)
1118
+ #内容あり要素検索
1119
+ @res2 = @pattern.match(@root.document)
1120
+
1121
+ if !@res2 then
1122
+ @res2 = elementWithContent_3_2(elmName)
1123
+ @pattern_cc_2 = @pattern_cc
1124
+ end
1125
+
1126
+ if @res1 && @res2 then
1127
+ if @res1.begin(0) < @res2.begin(0) then
1128
+ @res = @res1
1129
+ @pattern_cc = @pattern_cc_1
1130
+ elementWithoutContent_3(elmName)
1131
+ elsif @res1.begin(0) > @res2.begin(0)
1132
+ @res = @res2
1133
+ @pattern_cc = @pattern_cc_2
1134
+ elementWithContent_3_1(elmName)
1135
+ end
1136
+ elsif @res1 && !@res2 then
1137
+ @res = @res1
1138
+ @pattern_cc = @pattern_cc_1
1139
+ elementWithoutContent_3(elmName)
1140
+ elsif !@res1 && @res2 then
1141
+ @res = @res2
1142
+ @pattern_cc = @pattern_cc_2
1143
+ elementWithContent_3_1(elmName)
1144
+ elsif !@res1 && !@res2 then
1145
+ @elm_ = nil
1146
+ #raise NoSuchElementException.new(elmName,attrName,attrValue);
1147
+ end
1148
+
1149
+ if @elm_ then
1150
+ @elm_.arguments.store(attrName, attrValue)
1151
+ @elm_.arguments.recordable = true
1152
+ end
1153
+
1154
+ @elm_
1155
+ end
1156
+ private :element_3
1157
+
1158
+ def elementWithContent_3_1(elmName)
1159
+
1160
+ if @res.captures.length == 4 then
1161
+ #要素
1162
+ @elm_ = Element.new(elmName)
1163
+ #属性
1164
+ @elm_.attributes = @res[1]
1165
+ #内容
1166
+ @elm_.mixed_content = @res[2]
1167
+ #全体
1168
+ @elm_.document = @res[0]
1169
+ #内容あり要素検索用パターン
1170
+ @pattern_cc = ''<< TAG_OPEN << @_elmName << TAG_SEARCH_NC_2_1 << @_attrName << ATTR_EQ
1171
+ @pattern_cc << @_attrValue << TAG_SEARCH_NC_2_2 << @_elmName
1172
+ @pattern_cc << TAG_SEARCH_NC_1_2 << @_elmName << TAG_CLOSE
1173
+ @elm_.pattern = @pattern_cc
1174
+
1175
+ @elm_.empty = true
1176
+
1177
+ @elm_.parser = self
1178
+
1179
+ elsif @res.captures.length == 6 then
1180
+ #内容
1181
+ @elm_ = Element.new(elmName)
1182
+ #属性
1183
+ @elm_.attributes = @res[1].chop
1184
+ #内容
1185
+ @elm_.mixed_content = @res[3]
1186
+ #全体
1187
+ @elm_.document = @res[0]
1188
+ #内容あり要素検索用パターン
1189
+ @elm_.pattern = @pattern_cc
1190
+
1191
+ @elm_.empty = true
1192
+
1193
+ @elm_.parser = self
1194
+ end
1195
+ end
1196
+ private :elementWithContent_3_1
1197
+
1198
+ def elementWithContent_3_2(elmName)
1199
+ @cnt = 0
1200
+
1201
+ @pattern_cc_1 = '' << TAG_OPEN << @_elmName << TAG_SEARCH_2_1 << @_attrName << ATTR_EQ
1202
+ @pattern_cc_1 << @_attrValue << TAG_SEARCH_2_4_2
1203
+
1204
+ @pattern_cc_1b = '' << TAG_OPEN << @_elmName << TAG_SEARCH_1_4
1205
+
1206
+ @pattern_cc_1_1 = '' << TAG_OPEN << @_elmName << TAG_SEARCH_2_1 << @_attrName << ATTR_EQ
1207
+ @pattern_cc_1_1 << @_attrValue << TAG_SEARCH_4_7
1208
+
1209
+ @pattern_cc_1_2 = '' << TAG_SEARCH_4_2 << @_elmName << TAG_SEARCH_4_3
1210
+
1211
+ @pattern_cc_2 = '' << TAG_SEARCH_4_4 << @_elmName << TAG_CLOSE
1212
+
1213
+ @pattern_cc_2_1 = '' << TAG_SEARCH_4_5 << @_elmName << TAG_CLOSE
1214
+
1215
+ @pattern_cc_2_2 = '' << TAG_SEARCH_4_6 << @_elmName << TAG_CLOSE
1216
+
1217
+ #内容あり要素検索
1218
+ @pattern = Meteor::Core::Util::PatternCache.get(@pattern_cc_1)
1219
+
1220
+ @sbuf = '';
1221
+
1222
+ if RUBY_VERSION >= '1.9.0' then
1223
+
1224
+ @position = 0
1225
+
1226
+ while (@res = @pattern.match(@root.document,@position)) || @cnt > 0
1227
+
1228
+ if @res then
1229
+
1230
+ if @cnt > 0 then
1231
+
1232
+ @position2 = @res.end(0)
1233
+
1234
+ @pattern = Meteor::Core::Util::PatternCache.get(@pattern_cc_2)
1235
+ @res = @pattern.match(@root.document,@position)
1236
+
1237
+ if @res then
1238
+
1239
+ @position = @res.end(0)
1240
+
1241
+ if @position > @position2 then
1242
+
1243
+ if @cnt == 0 then
1244
+ @sbuf << @pattern_cc_1_1
1245
+ else
1246
+ @sbuf << @pattern_cc_1_2
1247
+ end
1248
+
1249
+ @cnt += 1
1250
+
1251
+ @position = @position2
1252
+ else
1253
+
1254
+ @cnt -= 1
1255
+
1256
+ if @cnt != 0 then
1257
+ @sbuf << @pattern_cc_2_1
1258
+ else
1259
+ @sbuf << @pattern_cc_2_2
1260
+ end
1261
+
1262
+ if @cnt == 0 then
1263
+ break
1264
+ end
1265
+ end
1266
+ else
1267
+
1268
+ if @cnt == 0 then
1269
+ @sbuf << @pattern_cc_1_1
1270
+ else
1271
+ @sbuf << @pattern_cc_1_2
1272
+ end
1273
+
1274
+ @cnt += 1
1275
+
1276
+ @position = @position2
1277
+ end
1278
+ else
1279
+
1280
+ @position = @res.end(0)
1281
+
1282
+ if @cnt == 0 then
1283
+ @sbuf << @pattern_cc_1_1
1284
+ else
1285
+ @sbuf << @pattern_cc_1_2
1286
+ end
1287
+
1288
+ @cnt += 1
1289
+ end
1290
+ else
1291
+
1292
+ @pattern = Meteor::Core::Util::PatternCache.get(@pattern_cc_2)
1293
+ @res = @pattern.match(@root.document,@position)
1294
+
1295
+ if @res then
1296
+ @cnt -= 1
1297
+
1298
+ if @cnt != 0 then
1299
+ @sbuf << @pattern_cc_2_1
1300
+ else
1301
+ @sbuf << @pattern_cc_2_2
1302
+ end
1303
+
1304
+ @position = @res.end(0)
1305
+ end
1306
+
1307
+ if !@res then
1308
+ break
1309
+ end
1310
+
1311
+ if @cnt == 0 then
1312
+ break
1313
+ end
1314
+ end
1315
+
1316
+ @pattern = Meteor::Core::Util::PatternCache.get(@pattern_cc_1b)
1317
+ end
1318
+ else
1319
+
1320
+ @rx_document = @root.document
1321
+
1322
+ while (@res = @pattern.match(@rx_document)) || @cnt > 0
1323
+
1324
+ if @res then
1325
+
1326
+ if @cnt > 0 then
1327
+
1328
+ @rx_document2 = @res.post_match
1329
+ @pattern = Meteor::Core::Util::PatternCache.get(@pattern_cc_2)
1330
+
1331
+ @res = @pattern.match(@rx_document)
1332
+
1333
+ if @res then
1334
+
1335
+ @rx_document = @res.post_match
1336
+
1337
+ if @rx_document2.length > @rx_document.length then
1338
+
1339
+ if @cnt == 0 then
1340
+ @sbuf << @pattern_cc_1_1
1341
+ else
1342
+ @sbuf << @pattern_cc_1_2
1343
+ end
1344
+
1345
+ @cnt += 1
1346
+
1347
+ @rx_document = @rx_document2
1348
+ else
1349
+
1350
+ @cnt -= 1
1351
+
1352
+ if @cnt != 0 then
1353
+ @sbuf << @pattern_cc_2_1
1354
+ else
1355
+ @sbuf << @pattern_cc_2_2
1356
+ end
1357
+
1358
+ if @cnt == 0 then
1359
+ break
1360
+ end
1361
+ end
1362
+ else
1363
+
1364
+ if @cnt == 0 then
1365
+ @sbuf << @pattern_cc_1_1
1366
+ else
1367
+ @sbuf << @pattern_cc_1_2
1368
+ end
1369
+
1370
+ @cnt += 1
1371
+
1372
+ @rx_document = @rx_document2
1373
+ end
1374
+ else
1375
+
1376
+ @rx_document = @res.post_match
1377
+
1378
+ if @cnt == 0 then
1379
+ @sbuf << @pattern_cc_1_1
1380
+ else
1381
+ @sbuf << @pattern_cc_1_2
1382
+ end
1383
+
1384
+ @cnt += 1
1385
+ end
1386
+ else
1387
+
1388
+ @pattern = Meteor::Core::Util::PatternCache.get(@pattern_cc_2)
1389
+ @res = @pattern.match(@rx_document)
1390
+
1391
+ if @res then
1392
+ @cnt -= 1
1393
+
1394
+ if @cnt != 0 then
1395
+ @sbuf << @pattern_cc_2_1
1396
+ else
1397
+ @sbuf << @pattern_cc_2_2
1398
+ end
1399
+
1400
+ @rx_document = @res.post_match
1401
+ end
1402
+
1403
+ if !@res then
1404
+ break
1405
+ end
1406
+
1407
+ if @cnt == 0 then
1408
+ break
1409
+ end
1410
+ end
1411
+
1412
+ @pattern = Meteor::Core::Util::PatternCache.get(@pattern_cc_1b)
1413
+ end
1414
+ end
1415
+
1416
+ @pattern_cc = @sbuf
1417
+
1418
+ if @sbuf.length == 0 || @cnt != 0 then
1419
+ # raise NoSuchElementException.new(elmName,attrName,attrValue);
1420
+ return nil;
1421
+ end
1422
+
1423
+ @pattern = Meteor::Core::Util::PatternCache.get(@pattern_cc)
1424
+ @res = @pattern.match(@root.document)
1425
+
1426
+ @res
1427
+ end
1428
+ private :elementWithContent_3_2
1429
+
1430
+ def elementWithoutContent_3(elmName)
1431
+ elementWithoutContent_3_1(elmName,TAG_SEARCH_NC_2_3_2)
1432
+ end
1433
+ private :elementWithoutContent_3
1434
+
1435
+ def elementWithoutContent_3_1(elmName,closer)
1436
+
1437
+ #要素
1438
+ @elm_ = Element.new(elmName)
1439
+ #属性
1440
+ @elm_.attributes = @res[1];
1441
+ #全体
1442
+ @elm_.document = @res[0]
1443
+ #空要素検索用パターン
1444
+ @pattern_cc = '' << TAG_OPEN << @_elmName << TAG_SEARCH_NC_2_1 << @_attrName << ATTR_EQ
1445
+ @pattern_cc << @_attrValue << closer
1446
+ @elm_.pattern = @pattern_cc
1447
+
1448
+ @elm_.parser = self
1449
+ end
1450
+ private :elementWithoutContent_3_1
1451
+
1452
+ #
1453
+ # 属性(属性名="属性値")で検索し、要素を取得する
1454
+ #
1455
+ # @param [String] attrName 属性名
1456
+ # @param [String] attrValue 属性値
1457
+ # @return [Meteor::Element] 要素
1458
+ #
1459
+ def element_2(attrName,attrValue)
1460
+
1461
+ @_attrName = escapeRegex(attrName)
1462
+ @_attrValue = escapeRegex(attrValue)
1463
+
1464
+ #@pattern_cc = '' << TAG_SEARCH_3_1 << @_attrName << ATTR_EQ << @_attrValue << TAG_SEARCH_2_4
1465
+ @pattern_cc = '' << TAG_SEARCH_3_1 << @_attrName << ATTR_EQ << @_attrValue << TAG_SEARCH_2_4_2_3
1466
+ @pattern = Meteor::Core::Util::PatternCache.get(@pattern_cc)
1467
+
1468
+ @res = @pattern.match(@root.document)
1469
+
1470
+ if @res then
1471
+ @elm_ = element_3(@res[1], attrName, attrValue)
1472
+ else
1473
+ @elm_ = nil
1474
+ end
1475
+
1476
+ @elm_
1477
+ end
1478
+ private :element_2
1479
+
1480
+ #
1481
+ # 要素名と属性1・属性2で検索し、要素を取得する
1482
+ #
1483
+ # @param [String] elmName 要素の名前
1484
+ # @param [String] attrName1 属性名1
1485
+ # @param [String] attrValue1 属性値2
1486
+ # @param [String] attrName2 属性名2
1487
+ # @param [String] attrValue2 属性値2
1488
+ # @return [Meteor::Element] 要素
1489
+ #
1490
+ def element_5(elmName,attrName1,attrValue1,attrName2,attrValue2)
1491
+
1492
+ @_elmName = escapeRegex(elmName)
1493
+ @_attrName1 = escapeRegex(attrName1)
1494
+ @_attrName2 = escapeRegex(attrName2)
1495
+ @_attrValue1 = escapeRegex(attrValue1)
1496
+ @_attrValue2 = escapeRegex(attrValue2)
1497
+
1498
+ #空要素検索用パターン
1499
+ @pattern_cc_1 = '' << TAG_OPEN << @_elmName << TAG_SEARCH_2_1_2 << @_attrName1 << ATTR_EQ
1500
+ @pattern_cc_1 << @_attrValue1 << TAG_SEARCH_2_6 << @_attrName2 << ATTR_EQ
1501
+ @pattern_cc_1 << @_attrValue2 << TAG_SEARCH_2_7 << @_attrName2 << ATTR_EQ
1502
+ @pattern_cc_1 << @_attrValue2 << TAG_SEARCH_2_6 << @_attrName1 << ATTR_EQ
1503
+ @pattern_cc_1 << @_attrValue1 << TAG_SEARCH_2_3_2_2
1504
+ @pattern = Meteor::Core::Util::PatternCache.get(@pattern_cc_1)
1505
+ #空要素検索
1506
+ @res1 = @pattern.match(@root.document)
1507
+
1508
+ #内容あり要素検索パターン
1509
+ @pattern_cc_2 = '' << TAG_OPEN << @_elmName << TAG_SEARCH_2_1_2 << @_attrName1 << ATTR_EQ
1510
+ @pattern_cc_2 << @_attrValue1 << TAG_SEARCH_2_6 << @_attrName2 << ATTR_EQ
1511
+ @pattern_cc_2 << @_attrValue2 << TAG_SEARCH_2_7 << @_attrName2 << ATTR_EQ
1512
+ @pattern_cc_2 << @_attrValue2 << TAG_SEARCH_2_6 << @_attrName1 << ATTR_EQ
1513
+ @pattern_cc_2 << @_attrValue1 << TAG_SEARCH_2_2_2 << @_elmName
1514
+ @pattern_cc_2 << TAG_SEARCH_1_2 << @_elmName << TAG_CLOSE
1515
+ @pattern = Meteor::Core::Util::PatternCache.get(@pattern_cc_2)
1516
+ #内容あり要素検索
1517
+ @res2 = @pattern.match(@root.document)
1518
+
1519
+ if !@res2 then
1520
+ @res2 = elementWithContent_5_2(elmName)
1521
+ @pattern_cc_2 = @pattern_cc
1522
+ end
1523
+
1524
+ if @res1 && @res2 then
1525
+ if @res1.begin(0) < @res2.begin(0) then
1526
+ @res = @res1
1527
+ @pattern_cc = @pattern_cc_1
1528
+ elementWithoutContent_5(elmName)
1529
+ elsif @res1.begin(0) > @res2.begin(0)
1530
+ @res = @res2
1531
+ @pattern_cc = @pattern_cc_2
1532
+ elementWithContent_5_1(elmName)
1533
+ end
1534
+ elsif @res1 && !@res2 then
1535
+ @res = @res1
1536
+ @pattern_cc = @pattern_cc_1
1537
+ elementWithoutContent_5(elmName)
1538
+ elsif !@res1 && @res2 then
1539
+ @res = @res2
1540
+ @pattern_cc = @pattern_cc_2
1541
+ elementWithContent_5_1(elmName)
1542
+ elsif !@res1 && !@res2 then
1543
+ @elm_ = nil
1544
+ #raise NoSuchElementException.new(elmName,attrName1,attrValue1,attrName2,attrValue2);
1545
+ end
1546
+
1547
+ if @elm_ then
1548
+ @elm_.arguments.store(attrName1, attrValue1)
1549
+ @elm_.arguments.store(attrName2, attrValue2)
1550
+ @elm_.arguments.recordable = true
1551
+ end
1552
+
1553
+ @elm_
1554
+ end
1555
+ private :element_5
1556
+
1557
+ def elementWithContent_5_1(elmName)
1558
+
1559
+ if @res.captures.length == 4 then
1560
+ #要素
1561
+ @elm_ = Element.new(elmName)
1562
+ #属性
1563
+ @elm_.attributes = @res[1]
1564
+ #内容
1565
+ @elm_.mixed_content = @res[2]
1566
+ #全体
1567
+ @elm_.document = @res[0]
1568
+ #内容あり要素検索用パターン
1569
+ @pattern_cc = '' << TAG_OPEN << @_elmName << TAG_SEARCH_NC_2_1_2 << @_attrName1 << ATTR_EQ
1570
+ @pattern_cc << @_attrValue1 << TAG_SEARCH_NC_2_6 << @_attrName2 << ATTR_EQ
1571
+ @pattern_cc << @_attrValue2 << TAG_SEARCH_NC_2_7 << @_attrName2 << ATTR_EQ
1572
+ @pattern_cc << @_attrValue2 << TAG_SEARCH_NC_2_6 << @_attrName1 << ATTR_EQ
1573
+ @pattern_cc << @_attrValue1 << TAG_SEARCH_NC_2_2_2 << @_elmName
1574
+ @pattern_cc << TAG_SEARCH_NC_1_2 << @_elmName << TAG_CLOSE
1575
+ @elm_.pattern = @pattern_cc
1576
+ #
1577
+ @elm_.empty = true
1578
+
1579
+ @elm_.parser = self
1580
+
1581
+ elsif @res.captures.length == 6 then
1582
+
1583
+ @elm_ = Element.new(elmName)
1584
+ #属性
1585
+ @elm_.attributes = @res[1].chop
1586
+ #要素
1587
+ @elm_.mixed_content = @res[3]
1588
+ #全体
1589
+ @elm_.document = @res[0]
1590
+ #要素ありタグ検索用パターン
1591
+ @elm_.pattern = @pattern_cc
1592
+
1593
+ @elm_.empty = true
1594
+
1595
+ @elm_.parser = self
1596
+ end
1597
+ end
1598
+ private :elementWithContent_5_1
1599
+
1600
+ def elementWithContent_5_2(elmName)
1601
+ @cnt = 0
1602
+
1603
+ @pattern_cc_1 = '' << TAG_OPEN << @_elmName << TAG_SEARCH_2_1_2 << @_attrName1 << ATTR_EQ
1604
+ @pattern_cc_1 << @_attrValue1 << TAG_SEARCH_2_6 << @_attrName2 << ATTR_EQ
1605
+ @pattern_cc_1 << @_attrValue2 << TAG_SEARCH_2_7 << @_attrName2 << ATTR_EQ
1606
+ @pattern_cc_1 << @_attrValue2 << TAG_SEARCH_2_6 << @_attrName1 << ATTR_EQ
1607
+ @pattern_cc_1 << @_attrValue1 << TAG_SEARCH_2_4_2_2
1608
+
1609
+ @pattern_cc_1b = '' << TAG_OPEN << elmName << TAG_SEARCH_1_4
1610
+
1611
+ @pattern_cc_1_1 = '' << TAG_OPEN << @_elmName << TAG_SEARCH_2_1_2 << @_attrName1 << ATTR_EQ
1612
+ @pattern_cc_1_1 << @_attrValue1 << TAG_SEARCH_2_6 << @_attrName2 << ATTR_EQ
1613
+ @pattern_cc_1_1 << @_attrValue2 << TAG_SEARCH_2_7 << @_attrName2 << ATTR_EQ
1614
+ @pattern_cc_1_1 << @_attrValue2 << TAG_SEARCH_2_6 << @_attrName1 << ATTR_EQ
1615
+ @pattern_cc_1_1 << @_attrValue1 << TAG_SEARCH_4_7_2
1616
+
1617
+ @pattern_cc_1_2 = '' << TAG_SEARCH_4_2 << @_elmName << TAG_SEARCH_4_3
1618
+
1619
+ @pattern_cc_2 = '' << TAG_SEARCH_4_4 << @_elmName << TAG_CLOSE
1620
+
1621
+ @pattern_cc_2_1 = '' << TAG_SEARCH_4_5 << @_elmName << TAG_CLOSE
1622
+
1623
+ @pattern_cc_2_2 = '' << TAG_SEARCH_4_6 << @_elmName << TAG_CLOSE
1624
+
1625
+ #内容あり要素検索
1626
+ @pattern = Meteor::Core::Util::PatternCache.get(@pattern_cc_1)
1627
+
1628
+ @sbuf = ''
1629
+
1630
+ if RUBY_VERSION >= '1.9.0' then
1631
+
1632
+ @position = 0
1633
+
1634
+ while (@res = @pattern.match(@root.document,@position)) || @cnt > 0
1635
+
1636
+ if @res then
1637
+
1638
+ if @cnt > 0 then
1639
+
1640
+ @position2 = @res.end(0)
1641
+
1642
+ @pattern = Meteor::Core::Util::PatternCache.get(@pattern_cc_2)
1643
+ @res = @pattern.match(@root.document,@position)
1644
+
1645
+ if @res then
1646
+
1647
+ @position = @res.end(0)
1648
+
1649
+ if @position > @position2 then
1650
+
1651
+ if @cnt == 0 then
1652
+ @sbuf << @pattern_cc_1_1
1653
+ else
1654
+ @sbuf << @pattern_cc_1_2
1655
+ end
1656
+
1657
+ @cnt << 1
1658
+
1659
+ @position = @position2
1660
+ else
1661
+
1662
+ @cnt -= 1
1663
+
1664
+ if @cnt != 0 then
1665
+ @sbuf << @pattern_cc_2_1
1666
+ else
1667
+ @sbuf << @pattern_cc_2_2
1668
+ end
1669
+
1670
+ if @cnt == 0 then
1671
+ break
1672
+ end
1673
+ end
1674
+ else
1675
+
1676
+ if @cnt == 0 then
1677
+ @sbuf << @pattern_cc_1_1
1678
+ else
1679
+ @sbuf << @pattern_cc_1_2
1680
+ end
1681
+
1682
+ @cnt += 1
1683
+
1684
+ @position = @position2
1685
+ end
1686
+ else
1687
+ @position = @res.end(0)
1688
+
1689
+ if @cnt == 0 then
1690
+ @sbuf << @pattern_cc_1_1
1691
+ else
1692
+ @sbuf << @pattern_cc_1_2
1693
+ end
1694
+
1695
+ @cnt += 1
1696
+ end
1697
+ else
1698
+
1699
+ @pattern = Meteor::Core::Util::PatternCache.get(@pattern_cc_2)
1700
+ @res = @pattern.match(@root.document,@position)
1701
+
1702
+ if @res then
1703
+
1704
+ @cnt -= 1
1705
+
1706
+ if @cnt != 0 then
1707
+ @sbuf << @pattern_cc_2_1
1708
+ else
1709
+ @sbuf << @pattern_cc_2_2
1710
+ end
1711
+
1712
+ @position = @res.end(0)
1713
+ end
1714
+
1715
+ if @cnt == 0 then
1716
+ break
1717
+ end
1718
+
1719
+ if !@res then
1720
+ break
1721
+ end
1722
+ end
1723
+
1724
+ @pattern = Meteor::Core::Util::PatternCache.get(@pattern_cc_1b)
1725
+ end
1726
+ else
1727
+
1728
+ @rx_document = @root.document
1729
+
1730
+ while (@res = @pattern.match(@rx_document)) || @cnt > 0
1731
+
1732
+ if @res then
1733
+
1734
+ if @cnt > 0 then
1735
+
1736
+ @rx_document2 = @res.post_match
1737
+
1738
+ @pattern = Meteor::Core::Util::PatternCache.get(@pattern_cc_2)
1739
+ @res = @pattern.match(@rx_document)
1740
+
1741
+ if @res then
1742
+
1743
+ @rx_document = @res.post_match
1744
+
1745
+ if @rx_document2.length > @rx_document.length then
1746
+
1747
+ if @cnt == 0 then
1748
+ @sbuf << @pattern_cc_1_1
1749
+ else
1750
+ @sbuf << @pattern_cc_1_2
1751
+ end
1752
+
1753
+ @cnt += 1
1754
+
1755
+ @rx_document = @rx_document2
1756
+ else
1757
+
1758
+ @cnt -= 1
1759
+
1760
+ if @cnt != 0 then
1761
+ @sbuf << @pattern_cc_2_1
1762
+ else
1763
+ @sbuf << @pattern_cc_2_2
1764
+ end
1765
+
1766
+ if @cnt == 0 then
1767
+ break
1768
+ end
1769
+ end
1770
+ else
1771
+
1772
+ if @cnt == 0 then
1773
+ @sbuf << @pattern_cc_1_1
1774
+ else
1775
+ @sbuf << @pattern_cc_1_2
1776
+ end
1777
+
1778
+ @cnt += 1
1779
+
1780
+ @rx_document = @rx_document2
1781
+ end
1782
+ else
1783
+ @rx_document = @res.post_match
1784
+
1785
+ if @cnt == 0 then
1786
+ @sbuf << @pattern_cc_1_1
1787
+ else
1788
+ @sbuf << @pattern_cc_1_2
1789
+ end
1790
+
1791
+ @cnt += 1
1792
+ end
1793
+ else
1794
+
1795
+ @pattern = Meteor::Core::Util::PatternCache.get(@pattern_cc_2)
1796
+ @res = @pattern.match(@rx_document)
1797
+
1798
+ if @res then
1799
+
1800
+ @cnt -= 1
1801
+
1802
+ if @cnt != 0 then
1803
+ @sbuf << @pattern_cc_2_1
1804
+ else
1805
+ @sbuf << @pattern_cc_2_2
1806
+ end
1807
+
1808
+ @rx_document = @res.post_match
1809
+ end
1810
+
1811
+ if @cnt == 0 then
1812
+ break
1813
+ end
1814
+
1815
+ if !@res then
1816
+ break
1817
+ end
1818
+ end
1819
+
1820
+ @pattern = Meteor::Core::Util::PatternCache.get(@pattern_cc_1b)
1821
+ end
1822
+ end
1823
+
1824
+ @pattern_cc = @sbuf
1825
+
1826
+ if @sbuf.length == 0 || @cnt != 0 then
1827
+ # raise NoSuchElementException.new(elmName,attrName1,attrValue1,attrName2,attrValue2);
1828
+ return nil
1829
+ end
1830
+
1831
+ @pattern = Meteor::Core::Util::PatternCache.get(@pattern_cc)
1832
+ @res = @pattern.match(@root.document)
1833
+
1834
+ @res
1835
+ end
1836
+ private :elementWithContent_5_2
1837
+
1838
+ def elementWithoutContent_5(elmName)
1839
+ elementWithoutContent_5_1(elmName,TAG_SEARCH_NC_2_3_2_2);
1840
+ end
1841
+ private :elementWithoutContent_5
1842
+
1843
+ def elementWithoutContent_5_1(elmName,closer)
1844
+
1845
+ #要素
1846
+ @elm_ = Element.new(elmName)
1847
+ #属性
1848
+ @elm_.attributes = @res[1]
1849
+ #全体
1850
+ @elm_.document = @res[0]
1851
+ #空要素検索用パターン
1852
+ @pattern_cc = '' << TAG_OPEN << @_elmName << TAG_SEARCH_NC_2_1_2 << @_attrName1 << ATTR_EQ
1853
+ @pattern_cc << @_attrValue1 << TAG_SEARCH_NC_2_6 << @_attrName2 << ATTR_EQ
1854
+ @pattern_cc << @_attrValue2 << TAG_SEARCH_NC_2_7 << @_attrName2 << ATTR_EQ
1855
+ @pattern_cc << @_attrValue2 << TAG_SEARCH_NC_2_6 << @_attrName1 << ATTR_EQ
1856
+ @pattern_cc << @_attrValue1 << closer
1857
+ @elm_.pattern = @pattern_cc
1858
+
1859
+ @elm_.parser = self
1860
+ end
1861
+ private :elementWithoutContent_5_1
1862
+
1863
+ #
1864
+ # 属性1・属性2(属性名="属性値")で検索し、要素を取得する
1865
+ #
1866
+ # @param [String] attrName1 属性名1
1867
+ # @param [String] attrValue1 属性値1
1868
+ # @param [String] attrName2 属性名2
1869
+ # @param [String]attrValue2 属性値2
1870
+ # @return [Meteor::Element] 要素
1871
+ #
1872
+ def element_4(attrName1,attrValue1,attrName2,attrValue2)
1873
+
1874
+ @_attrName1 = escapeRegex(attrName1)
1875
+ @_attrName2 = escapeRegex(attrName2)
1876
+ @_attrValue1 = escapeRegex(attrValue1)
1877
+ @_attrValue2 = escapeRegex(attrValue2)
1878
+
1879
+ @pattern_cc = '' << TAG_SEARCH_3_1_2_2 << @_attrName1 << ATTR_EQ
1880
+ @pattern_cc << @_attrValue1 << TAG_SEARCH_2_6 << @_attrName2 << ATTR_EQ
1881
+ @pattern_cc << @_attrValue2 << TAG_SEARCH_2_7 << @_attrName2 << ATTR_EQ
1882
+ @pattern_cc << @_attrValue2 << TAG_SEARCH_2_6 << @_attrName1 << ATTR_EQ
1883
+ @pattern_cc << @_attrValue1 << TAG_SEARCH_2_4_2_3
1884
+
1885
+ @pattern = PatternCache.get(@pattern_cc)
1886
+
1887
+ @res = @pattern.match(@root.document)
1888
+
1889
+ if @res then
1890
+ @elm_ = element_5(@res[1], attrName1, attrValue1,attrName2, attrValue2);
1891
+ else
1892
+ @elm_ = nil
1893
+ end
1894
+
1895
+ @elm_
1896
+ end
1897
+ private :element_4
1898
+
1899
+ #
1900
+ # 要素の属性をセットする or 属性の値を取得する
1901
+ #
1902
+ # @param [Array] args 引数配列
1903
+ # @return [String] 属性値
1904
+ #
1905
+ def attribute(*args)
1906
+ case args.length
1907
+ when 1
1908
+ getAttributeValue_1(args[0])
1909
+ when 2
1910
+ if args[0].kind_of?(Meteor::Element) && args[1].kind_of?(String) then
1911
+ getAttributeValue_2(args[0],args[1])
1912
+ elsif args[0].kind_of?(String) && args[1].kind_of?(String) then
1913
+ setAttribute_2(args[0],args[1])
1914
+ elsif args[0].kind_of?(Meteor::Element) && args[1].kind_of?(Meteor::AttributeMap) then
1915
+ setAttribute_2_m(args[0],args[1])
1916
+ else
1917
+ raise ArgumentError
1918
+ end
1919
+ when 3
1920
+ setAttribute_3(args[0],args[1],args[2])
1921
+ else
1922
+ raise ArgumentError
1923
+ end
1924
+ end
1925
+
1926
+ #
1927
+ # 要素の属性を編集する
1928
+ #
1929
+ # @param [Meteor::Element] elm 要素
1930
+ # @param [String] attrName 属性名
1931
+ # @param [String] attrValue 属性値
1932
+ #
1933
+ def setAttribute_3(elm,attrName,attrValue)
1934
+ if !elm.cx then
1935
+ #属性群の更新
1936
+ editAttributes_(elm,attrName,attrValue)
1937
+
1938
+ if elm.arguments.map.include?(attrName) then
1939
+ elm.arguments.store(attrName, attrValue)
1940
+ end
1941
+
1942
+ @e_cache.store(elm.object_id, elm)
1943
+ end
1944
+ end
1945
+ private :setAttribute_3
1946
+
1947
+ def editAttributes_(elm,attrName,attrValue)
1948
+
1949
+ attrValue = escape(attrValue)
1950
+
1951
+ @pattern = Meteor::Core::Util::PatternCache.get('' << attrName << SET_ATTR_1)
1952
+
1953
+ #属性検索
1954
+ @res = @pattern.match(elm.attributes)
1955
+
1956
+ #検索対象属性の存在判定
1957
+ if @res then
1958
+
1959
+ @_attrValue = attrValue
1960
+ #replace2Regex(@_attrValue)
1961
+ if elm.parser.rootElement.hook || elm.parser.rootElement.monoHook then
1962
+ replace4Regex(@_attrValue)
1963
+ else
1964
+ replace2Regex(@_attrValue)
1965
+ end
1966
+ #属性の置換
1967
+ elm.attributes.sub!(@pattern,'' << attrName << ATTR_EQ << @_attrValue << DOUBLE_QUATATION)
1968
+ else
1969
+ #属性文字列の最後に新規の属性を追加する
1970
+ if EMPTY != elm.attributes && EMPTY != elm.attributes.strip then
1971
+ elm.attributes = '' << SPACE << elm.attributes.strip
1972
+ else
1973
+ elm.attributes = ''
1974
+ end
1975
+
1976
+ elm.attributes << SPACE << attrName << ATTR_EQ << attrValue << DOUBLE_QUATATION
1977
+ end
1978
+
1979
+ end
1980
+ private :editAttributes_
1981
+
1982
+ def editDocument_1(elm)
1983
+ editDocument_2(elm,TAG_CLOSE3)
1984
+ end
1985
+ private :editDocument_1
1986
+
1987
+ def editDocument_2(elm,closer)
1988
+ if !elm.parent then
1989
+
1990
+ if !elm.cx then
1991
+ @_attributes = elm.attributes
1992
+ replace2Regex(@_attributes)
1993
+
1994
+ if elm.empty then
1995
+ #内容あり要素の場合
1996
+ @_content = elm.mixed_content
1997
+ #replace2Regex(@_content)
1998
+ if elm.parser.rootElement.hook || elm.parser.rootElement.monoHook then
1999
+ replace4Regex(@_content)
2000
+ else
2001
+ replace2Regex(@_content)
2002
+ end
2003
+
2004
+ #タグ検索用パターン
2005
+ @pattern = Meteor::Core::Util::PatternCache.get(elm.pattern)
2006
+ @root.document.sub!(@pattern,'' << TAG_OPEN << elm.name << @_attributes << TAG_CLOSE << @_content << TAG_OPEN3 << elm.name << TAG_CLOSE)
2007
+ #@root.document.sub!(@pattern,"<#{elm.name}#{@_attributes}>#{@_content}</#{elm.name}>")
2008
+ else
2009
+ #空要素の場合
2010
+ #タグ置換用パターン
2011
+ @pattern = Meteor::Core::Util::PatternCache.get(elm.pattern)
2012
+ @root.document.sub!(@pattern,'' << TAG_OPEN << elm.name << @_attributes << closer)
2013
+ end
2014
+ else
2015
+ @_content = elm.mixed_content
2016
+ if elm.parser.rootElement.hook || elm.parser.rootElement.monoHook then
2017
+ replace4Regex(@_content)
2018
+ else
2019
+ replace2Regex(@_content)
2020
+ end
2021
+
2022
+ @pattern = Meteor::Core::Util::PatternCache.get(elm.pattern)
2023
+
2024
+ #タグ置換
2025
+ @pattern_cc = '' << SET_CX_1 << elm.name << SPACE << elm.attributes << SET_CX_2
2026
+ @pattern_cc << @_content << SET_CX_3 << elm.name << SET_CX_4
2027
+ #@pattern_cc = "<!-- @#{elm.name} #{elm.attributes}-->#{@_content}<!-- /@#{elm.name} -->"
2028
+ @root.document.sub!(@pattern,@pattern_cc)
2029
+ end
2030
+ end
2031
+ end
2032
+ private :editDocument_2
2033
+
2034
+ def editPattern_(elm)
2035
+ if !elm.parent then
2036
+
2037
+ elm.arguments.map.each{ |name,attr|
2038
+
2039
+ if attr.changed then
2040
+ @_attrValue = attr.value
2041
+ replace2Regex(@_attrValue)
2042
+
2043
+ @pattern_cc = '' << name << SET_ATTR_1
2044
+ #@pattern_cc = "#{attrName}=\"[^\"]*\""
2045
+ @pattern = Meteor::Core::Util::PatternCache.get(@pattern_cc)
2046
+ elm.pattern.gsub!(@pattern,'' << name << ATTR_EQ << @_attrValue << DOUBLE_QUATATION)
2047
+ #elm.pattern.sub!(@pattern,"#{attrName}=\"#{@_attrValue}\"")
2048
+ elsif attr.removed then
2049
+ @pattern_cc = '' << name << SET_ATTR_1
2050
+ #@pattern_cc = "#{attrName}=\"[^\"]*\""
2051
+ @pattern = Meteor::Core::Util::PatternCache.get(@pattern_cc)
2052
+ elm.pattern.gsub!(@pattern,EMPTY)
2053
+ end
2054
+ }
2055
+ end
2056
+ end
2057
+ private :editPattern_
2058
+
2059
+ #
2060
+ # 要素の属性を編集する
2061
+ #
2062
+ # @param [String] attrName 属性名
2063
+ # @param [String] attrValue 属性値
2064
+ #
2065
+ def setAttribute_2(attrName,attrValue)
2066
+ if @root.hook || @root.monoHook then
2067
+ setAttribute_3(@root.mutableElement, attrName, attrValue)
2068
+ end
2069
+ end
2070
+ private :setAttribute_2
2071
+
2072
+ #
2073
+ # 要素の属性値を取得する
2074
+ #
2075
+ # @param [Meteor::Element] elm 要素
2076
+ # @param [String] attrName 属性名
2077
+ # @return [String] 属性値
2078
+ #
2079
+ def getAttributeValue_2(elm,attrName)
2080
+ getAttributeValue_(elm,attrName)
2081
+ end
2082
+ private :getAttributeValue_2
2083
+
2084
+ def getAttributeValue_(elm,attrName)
2085
+
2086
+ #属性検索用パターン
2087
+ @pattern = Meteor::Core::Util::PatternCache.get('' << attrName << GET_ATTR_1)
2088
+
2089
+ @res = @pattern.match(elm.attributes)
2090
+
2091
+ if @res then
2092
+ unescape(@res[1])
2093
+ else
2094
+ nil
2095
+ end
2096
+ end
2097
+ private :getAttributeValue_
2098
+
2099
+ #
2100
+ # 要素の属性値を取得する
2101
+ #
2102
+ # @param [String] attrName 属性名
2103
+ # @return [String] 属性値
2104
+ #
2105
+ def getAttributeValue_1(attrName)
2106
+ if @root.hook || @root.monoHook then
2107
+ getAttributeValue_2(@root.mutableElement, attrName)
2108
+ else
2109
+ nil
2110
+ end
2111
+ end
2112
+ private :getAttributeValue_1
2113
+
2114
+ #
2115
+ # 属性マップを取得する
2116
+ #
2117
+ # @param [Array] args 引数配列
2118
+ # @return [Meteor::AttributeMap] 属性マップ
2119
+ #
2120
+ def attributeMap(*args)
2121
+ case args.length
2122
+ when 0
2123
+ getAttributeMap_0
2124
+ when 1
2125
+ getAttributeMap_1(args[0])
2126
+ else
2127
+ raise ArgumentError
2128
+ end
2129
+ end
2130
+
2131
+ #
2132
+ # 属性マップを取得する
2133
+ #
2134
+ # @param [Meteor::Element] elm 要素
2135
+ # @return [Meteor::AttributeMap] 属性マップ
2136
+ #
2137
+ def getAttributeMap_1(elm)
2138
+ attrs = Meteor::AttributeMap.new
2139
+
2140
+ elm.attributes.scan(@@pattern_get_attrs_map){ |a,b|
2141
+ attrs.store(a,unescape(b))
2142
+ }
2143
+ attrs.recordable = true
2144
+
2145
+ attrs
2146
+ end
2147
+ private :getAttributeMap_1
2148
+
2149
+ #
2150
+ # 要素の属性マップを取得する
2151
+ #
2152
+ # @return [Meteor::AttributeMap] 属性マップ
2153
+ #
2154
+ def getAttributeMap_0()
2155
+ if @root.hook || @root.monoHook then
2156
+ getAttributeMap_1(@root.mutableElement)
2157
+ else
2158
+ nil
2159
+ end
2160
+ end
2161
+ private :getAttributeMap_0
2162
+
2163
+ #
2164
+ # 要素の属性を編集する
2165
+ #
2166
+ # @param [Meteor::Element] elm 要素
2167
+ # @param [Meteor::AttributeMap] attrMap 属性マップ
2168
+ #
2169
+ def setAttribute_2_m(elm,attrMap)
2170
+ if !elm.cx then
2171
+ attrMap.map.each{|name,attr|
2172
+ if attrMap.changed(name) then
2173
+ editAttributes_(elm,name,attr.value)
2174
+ elsif attrMap.removed(name) then
2175
+ removeAttributes_(elm,name)
2176
+ end
2177
+ }
2178
+
2179
+ @e_cache.store(elm.object_id,elm)
2180
+ end
2181
+ end
2182
+ private :setAttribute_2_m
2183
+
2184
+ #
2185
+ # 要素の内容をセットする or 内容を取得する
2186
+ #
2187
+ # @param [Array] args 引数配列
2188
+ # @return [String] 内容
2189
+ #
2190
+ def content(*args)
2191
+ case args.length
2192
+ when 1
2193
+ if args[0].kind_of?(Meteor::Element) then
2194
+ getContent_1(args[0])
2195
+ elsif args[0].kind_of?(String) then
2196
+ setContent_1(args[0])
2197
+ end
2198
+ when 2
2199
+ if args[0].kind_of?(Meteor::Element) && args[1].kind_of?(String) then
2200
+ setContent_2_s(args[0],args[1])
2201
+ elsif args[0].kind_of?(String) && (args[1].kind_of?(TrueClass) || args[1].kind_of?(FalseClsss)) then
2202
+ setContent_2_b(args[0],args[1])
2203
+ else
2204
+ raise ArgumentError
2205
+ end
2206
+ when 3
2207
+ setContent_3(args[0],args[1],args[2])
2208
+ else
2209
+ raise ArgumentError
2210
+ end
2211
+ end
2212
+
2213
+ #
2214
+ # 要素の内容をセットする
2215
+ #
2216
+ # @param [Meteor::Element] elm 要素
2217
+ # @param [String] mixed_content 要素の内容
2218
+ # @param [TrueClass][FalseClass] entityRef エンティティ参照フラグ
2219
+ #
2220
+ def setContent_3(elm,content,entityRef=true)
2221
+
2222
+ if entityRef then
2223
+ content = escapeContent(content,elm.name)
2224
+ end
2225
+
2226
+ elm.mixed_content = content
2227
+
2228
+ @e_cache.store(elm.object_id,elm)
2229
+
2230
+ end
2231
+ private :setContent_3
2232
+
2233
+ #
2234
+ # 要素の内容を編集する
2235
+ #
2236
+ # @param [Meteor::Element] 要素
2237
+ # @param [String] mixed_content 要素の内容
2238
+ #
2239
+ def setContent_2_s(elm,content)
2240
+ setContent_3(elm, content)
2241
+ end
2242
+ private :setContent_2_s
2243
+
2244
+ #
2245
+ # 要素の内容を編集する
2246
+ #
2247
+ # @param [String] mixed_content 内容
2248
+ #
2249
+ def setContent_1(content)
2250
+ if @root.monoHook then
2251
+ setContent_2_s(@root.mutableElement, content)
2252
+ end
2253
+ end
2254
+ private :setContent_1
2255
+
2256
+ #
2257
+ # 要素の内容を編集する
2258
+ #
2259
+ # @param [String] mixed_content 内容
2260
+ # @param [TrueClass][FalseClass] entityRef エンティティ参照フラグ
2261
+ #
2262
+ def setContent_2_b(content,entityRef)
2263
+ if @root.monoHook then
2264
+ setContent_3(@root.mutableElement, content, entityRef)
2265
+ end
2266
+ end
2267
+ private :setContent_2_b
2268
+
2269
+ def getContent_1(elm)
2270
+ if !elm.cx then
2271
+ if elm.empty then
2272
+ unescapeContent(elm.mixed_content,elm.name)
2273
+ end
2274
+ else
2275
+ nil
2276
+ end
2277
+ end
2278
+ private :getContent_1
2279
+
2280
+ #
2281
+ # 要素の属性を消す
2282
+ #
2283
+ # @param [Array] args 引数配列
2284
+ #
2285
+ def removeAttribute(*args)
2286
+ case args.length
2287
+ when 1
2288
+ removeAttribute_1(args[0])
2289
+ when 2
2290
+ removeAttribute_2(args[0],args[1])
2291
+ else
2292
+ raise ArgumentError
2293
+ end
2294
+ end
2295
+
2296
+ #
2297
+ # 要素の属性を消す
2298
+ #
2299
+ # @param [Meteor::Element] elm 要素
2300
+ # @param [String] attrName 属性名
2301
+ #
2302
+ def removeAttribute_2(elm,attrName)
2303
+ if !elm.cx then
2304
+
2305
+ removeAttributes_(elm,attrName)
2306
+
2307
+ if elm.arguments.map.include?(attrName) then
2308
+ elm.arguments.delete(attrName)
2309
+ end
2310
+
2311
+ @e_cache.store(elm.object_id,elm)
2312
+ end
2313
+ end
2314
+ private :removeAttribute_2
2315
+
2316
+ def removeAttributes_(elm,attrName)
2317
+ #属性検索用パターン
2318
+ @pattern = Meteor::Core::Util::PatternCache.get('' << attrName << ERASE_ATTR_1)
2319
+ #属性の置換
2320
+ elm.attributes.sub!(@pattern,EMPTY)
2321
+ end
2322
+ private :removeAttributes_
2323
+
2324
+ #
2325
+ # 要素の属性を消す
2326
+ #
2327
+ # @param [String] attrName 属性名
2328
+ #
2329
+ def removeAttribute_1(attrName)
2330
+ if @root.hook || @root.monoHook then
2331
+ removeAttribute_2(@root.mutableElement, attrName)
2332
+ end
2333
+ end
2334
+ private :removeAttribute_1
2335
+
2336
+ #
2337
+ # 要素を消す
2338
+ #
2339
+ # @param [Meteor::Element] elm 要素
2340
+ #
2341
+ def removeElement(elm)
2342
+ replace(elm,EMPTY)
2343
+ @e_cache.delete(elm.object_id)
2344
+ end
2345
+
2346
+ #
2347
+ # CX(コメント拡張)タグを取得する
2348
+ #
2349
+ # @param [Array] args 引数配列
2350
+ # @return [Meteor::Element] 要素
2351
+ #
2352
+ def cxtag(*args)
2353
+ case args.length
2354
+ when 1
2355
+ cxtag_1(args[0])
2356
+ when 2
2357
+ cxtag_2(args[0],args[1])
2358
+ else
2359
+ raise ArgumentError
2360
+ end
2361
+ end
2362
+
2363
+ #
2364
+ # 要素名とID属性で検索し、CX(コメント拡張)タグを取得する
2365
+ #
2366
+ # @param [String] elmName 要素名
2367
+ # @param [String] id ID属性値
2368
+ # @return [Meteor::Element] 要素
2369
+ #
2370
+ def cxtag_2(elmName,id)
2371
+
2372
+ #CXタグ検索用パターン
2373
+ @pattern_cc = '' << SEARCH_CX_1 << elmName << SEARCH_CX_2
2374
+ @pattern_cc << id << SEARCH_CX_3 << elmName << SEARCH_CX_4 << elmName << SEARCH_CX_5
2375
+
2376
+ @pattern = Meteor::Core::Util::PatternCache.get(@pattern_cc)
2377
+ #CXタグ検索
2378
+ @res = @pattern.match(@root.document)
2379
+
2380
+ if @res then
2381
+ #要素
2382
+ @elm_ = Element.new(elmName)
2383
+
2384
+ @elm_.cx = true
2385
+ #属性
2386
+ @elm_.attributes = @res[1]
2387
+ #内容
2388
+ @elm_.mixed_content = @res[2]
2389
+ #全体
2390
+ @elm_.document = @res[0]
2391
+ #要素検索パターン
2392
+ @elm_.pattern = @pattern_cc
2393
+
2394
+ @elm_.empty = true
2395
+
2396
+ @elm_.parser = self
2397
+ else
2398
+ @elm_ = nil
2399
+ end
2400
+
2401
+ @elm_
2402
+ end
2403
+ private :cxtag_2
2404
+
2405
+ #
2406
+ # ID属性で検索し、CX(コメント拡張)タグを取得する
2407
+ #
2408
+ # @param [String] id ID属性値
2409
+ # @return [Meteor::Element] 要素
2410
+ #
2411
+ def cxtag_1(id)
2412
+
2413
+ @pattern_cc = '' << SEARCH_CX_6 << id << DOUBLE_QUATATION
2414
+
2415
+ @pattern = Meteor::Core::Util::PatternCache.get(@pattern_cc)
2416
+
2417
+ @res = @pattern.match(@root.document)
2418
+
2419
+ if @res then
2420
+ @elm_ = cxtag(@res[1],id)
2421
+ else
2422
+ @elm_ = nil
2423
+ end
2424
+
2425
+ @elm_
2426
+ end
2427
+ private :cxtag_1
2428
+
2429
+ #
2430
+ # 要素を置換する
2431
+ #
2432
+ # @param [Meteor::Element] elm 要素
2433
+ # @param [String] replaceDocument 置換文字列
2434
+ #
2435
+ def replace(elm,replaceDocument)
2436
+ #文字エスケープ
2437
+ if replaceDocument.size > 0 && elm.parent && elm.mono then
2438
+ replace2Regex(replaceDocument)
2439
+ end
2440
+ #タグ置換パターン
2441
+ @pattern = Meteor::Core::Util::PatternCache.get(elm.pattern)
2442
+ #タグ置換
2443
+ @root.document.sub!(@pattern,replaceDocument)
2444
+ end
2445
+
2446
+ def reflect()
2447
+
2448
+ @e_cache.values.each { |item|
2449
+ editDocument_1(item)
2450
+ editPattern_(item)
2451
+ }
2452
+ @e_cache.clear
2453
+ end
2454
+ protected :reflect
2455
+
2456
+ #
2457
+ # 出力する
2458
+ #
2459
+ def print
2460
+ reflect()
2461
+
2462
+ if @root.hook then
2463
+ @_attributes = @root.mutableElement.attributes
2464
+ replace2Regex(@_attributes)
2465
+ if @root.element.cx then
2466
+ #@root.hookDocument << SET_CX_1 << @root.mutableElement.name << SPACE
2467
+ #@root.hookDocument << @_attributes << SET_CX_2
2468
+ #@root.hookDocument << @root.document << SET_CX_3
2469
+ #@root.hookDocument << @root.mutableElement.name << SET_CX_4
2470
+ @root.hookDocument << "<!-- @#{@root.mutableElement.name} #{@_attributes}-->#{@root.document}<!-- /@#{@root.mutableElement.name} -->"
2471
+ else
2472
+ #@root.hookDocument << TAG_OPEN << @root.mutableElement.name
2473
+ #@root.hookDocument << @_attributes << TAG_CLOSE << @root.document
2474
+ #@root.hookDocument << TAG_OPEN3 << @root.mutableElement.name << TAG_CLOSE
2475
+ @root.hookDocument << "<#{@root.mutableElement.name}#{@_attributes}>#{@root.document}</#{@root.mutableElement.name}>"
2476
+ end
2477
+ @root.mutableElement = Element.new(@root.element)
2478
+ @root.document = String.new(@root.element.mixed_content)
2479
+ else
2480
+ if @root.monoHook then
2481
+ if @root.element.cx then
2482
+ #@root.hookDocument << SET_CX_1 << @root.mutableElement.name << SPACE
2483
+ #@root.hookDocument << @root.mutableElement.attributes << SET_CX_2
2484
+ #@root.hookDocument << @root.mutableElement.mixed_content << SET_CX_3
2485
+ #@root.hookDocument << @root.mutableElement.name << SET_CX_4
2486
+ @root.hookDocument << "<!-- @#{@root.mutableElement.name} #{@root.mutableElement.attributes}-->#{@root.mutableElement.mixed_content}<!-- /@#{@root.mutableElement.name} -->"
2487
+ else
2488
+ #@root.hookDocument << TAG_OPEN << @root.mutableElement.name
2489
+ #@root.hookDocument << @root.mutableElement.attributes << TAG_CLOSE << @root.mutableElement.mixed_content
2490
+ #@root.hookDocument << TAG_OPEN3 << @root.mutableElement.name << TAG_CLOSE
2491
+ @root.hookDocument << "<#{@root.mutableElement.name}#{@root.mutableElement.attributes}>#{@root.mutableElement.mixed_content}</#{@root.mutableElement.name}>"
2492
+ end
2493
+ @root.mutableElement = Element.new(@root.element)
2494
+ else
2495
+ #フック判定がFALSEの場合
2496
+ clean
2497
+ end
2498
+ end
2499
+ end
2500
+
2501
+ def clean
2502
+ #CX開始タグ置換
2503
+ @pattern = @@pattern_clean1
2504
+ @root.document.gsub!(@pattern,EMPTY)
2505
+ #CX終了タグ置換
2506
+ @pattern = @@pattern_clean2
2507
+ @root.document.gsub!(@pattern,EMPTY)
2508
+ #@root.document = @root.document << "<!-- Powered by Meteor (C)Yasumasa Ashida -->"
2509
+ end
2510
+ private :clean
2511
+
2512
+ #
2513
+ # 子パーサを取得する
2514
+ #
2515
+ # @param [Meteor::Element] elm 要素
2516
+ # @return [Meteor::Parser] 子パーサ
2517
+ #
2518
+ def child(elm)
2519
+ if elm.empty then
2520
+ #内容あり要素の場合
2521
+ setMonoInfo(elm)
2522
+
2523
+ pif2 = create(self)
2524
+
2525
+ elm.parent=true
2526
+ pif2.parent = self
2527
+ pif2.rootElement.element = elm
2528
+ pif2.rootElement.mutableElement = Element.new(elm)
2529
+ pif2.rootElement.kaigyoCode = @root.kaigyoCode
2530
+
2531
+ if elm.mono then
2532
+ pif2.rootElement.monoHook = true
2533
+
2534
+ pif2
2535
+ else
2536
+ pif2.rootElement.document = String.new(elm.mixed_content)
2537
+ pif2.rootElement.hook = true
2538
+
2539
+ pif2
2540
+ end
2541
+ end
2542
+ end
2543
+
2544
+ def setMonoInfo(elm)
2545
+ end
2546
+ private :setMonoInfo
2547
+
2548
+ #
2549
+ # 反映する
2550
+ #
2551
+ def flush
2552
+ if @root.hook || @root.monoHook then
2553
+ if @root.element then
2554
+ @parent.reflect
2555
+ @parent.replace(@root.element, @root.hookDocument)
2556
+ end
2557
+ end
2558
+ end
2559
+
2560
+ #
2561
+ #
2562
+ #
2563
+ def execute(*args)
2564
+ case args.length
2565
+ when 1
2566
+ execute_2(args[0],args[1])
2567
+ when 2
2568
+ execute_3(args[0],args[1],args[2])
2569
+ else
2570
+ raise ArgumentError
2571
+ end
2572
+ end
2573
+
2574
+ def execute_2(elm,hook)
2575
+ hook.doAction(elm, self)
2576
+ end
2577
+ private :execute_2
2578
+
2579
+ def execute_3(elm,loop,list)
2580
+ loop.doAction(elm, this, list)
2581
+ end
2582
+ private :execute_3
2583
+
2584
+ #
2585
+ # 正規表現対象文字を置換する
2586
+ #
2587
+ # @param [String] element 入力文字列
2588
+ # @return [String] 出力文字列
2589
+ #
2590
+ def escapeRegex(element)
2591
+ ##「\」->[\\]
2592
+ #element.gsub!(@@pattern_en,EN_2)
2593
+ ##「$」->「\$」
2594
+ #element.gsub!(@@pattern_dol,DOL_2)
2595
+ ##「+」->「\+」
2596
+ #element.gsub!(@@pattern_plus,PLUS_2)
2597
+ #todo
2598
+ ##「(」->「\(」
2599
+ #element.gsub!(@@pattern_brac_open,BRAC_OPEN_2)
2600
+ ##「)」->「\)」
2601
+ #element.gsub!(@@pattern_brac_close,BRAC_CLOSE_2)
2602
+ ##「[」->「\[」
2603
+ #element.gsub!(@@pattern_sbrac_open,SBRAC_OPEN_2)
2604
+ ##「]」->「\]」
2605
+ #element.gsub!(@@pattern_sbrac_close,SBRAC_CLOSE_2)
2606
+ ##「{」->「\{」
2607
+ #element.gsub!(@@pattern_cbrac_open,CBRAC_OPEN_2)
2608
+ ##「}」->「\}」
2609
+ #element.gsub!(@@pattern_cbrac_close,CBRAC_CLOSE_2)
2610
+ ##「.」->「\.」
2611
+ #element.gsub!(@@pattern_comma,COMMA_2)
2612
+ ##「|」->「\|」
2613
+ #element.gsub!(@@pattern_vline,VLINE_2)
2614
+ ##「?」->「\?」
2615
+ #element.gsub!(@@pattern_qmark,QMARK_2)
2616
+ ##「*」->「\*」
2617
+ #element.gsub!(@@pattern_asterisk,ASTERISK_2)
2618
+ Regexp.quote(element)
2619
+
2620
+ end
2621
+ private :escapeRegex
2622
+
2623
+ def replace2Regex(element)
2624
+ if element.include?(EN_1) then
2625
+ element.gsub!(@@pattern_sub_regex1,SUB_REGEX2)
2626
+ end
2627
+ end
2628
+ private :replace2Regex
2629
+
2630
+ def replace4Regex(element)
2631
+ if element.include?(EN_1) then
2632
+ element.gsub!(@@pattern_sub_regex1,SUB_REGEX3)
2633
+ end
2634
+ end
2635
+ private :replace4Regex
2636
+
2637
+ #
2638
+ # @param [String] element 入力文字列
2639
+ # @return [String] 出力文字列
2640
+ #
2641
+ def escape(element)
2642
+ element;
2643
+ end
2644
+ private :escape
2645
+
2646
+ #
2647
+ # @param [String] element 入力文字列
2648
+ # @param [String] elmName 要素名
2649
+ # @return [String] 出力文字列
2650
+ #
2651
+ def escapeContent(element,elmName)
2652
+ element
2653
+ end
2654
+ private :escapeContent
2655
+
2656
+ #
2657
+ # @param [String] element 入力文字列
2658
+ # @return [String] 出力文字列
2659
+ #
2660
+ def unescape(element)
2661
+ element;
2662
+ end
2663
+ private :unescape
2664
+
2665
+ #
2666
+ # @param [String] element 入力文字列
2667
+ # @param [String] elmName 要素名
2668
+ # @return [String] 出力文字列
2669
+ #
2670
+ def unescapeContent(element,elmName)
2671
+ element;
2672
+ end
2673
+ private :unescapeContent
2674
+
2675
+ def isMatch(regex,str)
2676
+ if regex.kind_of?(Regexp) then
2677
+ if regex.match(str.downcase) then
2678
+ true
2679
+ else
2680
+ false
2681
+ end
2682
+ elsif regex.kind_of?(Array) then
2683
+ str = str.downcase
2684
+ regex.each { |item|
2685
+ if item.eql?(str) then
2686
+ return true
2687
+ end
2688
+ }
2689
+ return false
2690
+ elsif regex.kind_of?(String) then
2691
+ if regex.eql?(str.downcase) then
2692
+ true
2693
+ else
2694
+ false
2695
+ end
2696
+ else
2697
+ raise ArgumentError
2698
+ end
2699
+ end
2700
+ private :isMatch
2701
+
2702
+
2703
+ def create(pif)
2704
+ if pif.instance_of?(Meteor::Core::Html::ParserImpl) then
2705
+ pif = Meteor::Core::Html::ParserImpl.new
2706
+ elsif pif.instance_of?(Meteor::Core::Xhtml::ParserImpl) then
2707
+ pif = Meteor::Core::Xhtml::ParserImpl.new
2708
+ elsif pif.instance_of?(Meteor::Core::Xml::ParserImpl) then
2709
+ pif = Meteor::Core::Xml::ParserImpl.new
2710
+ else
2711
+ pif = nil
2712
+ end
2713
+
2714
+ end
2715
+ private :create
2716
+
2717
+ #
2718
+ # 要素の属性or内容をセットする
2719
+ # @param [String] name 属性名
2720
+ # @param [String] value 属性値or内容
2721
+ #
2722
+ def []=(name,value)
2723
+ if !name.kind_of?(String)|| name != ':content' then
2724
+ attribute(name,value)
2725
+ else
2726
+ content(value)
2727
+ end
2728
+ end
2729
+
2730
+ #
2731
+ # 要素の属性値or内容を取得する
2732
+ # @param [String] name 属性名
2733
+ # @return [String] 属性値or内容
2734
+ #
2735
+ def [](name)
2736
+ if !name.kind_of?(String)|| name != ':content' then
2737
+ attribute(name)
2738
+ else
2739
+ content()
2740
+ end
2741
+ end
2742
+ end
2743
+
2744
+ module Util
2745
+
2746
+ #
2747
+ # パターンキャッシュクラス
2748
+ #
2749
+ class PatternCache
2750
+ @@regexCache = Hash.new
2751
+
2752
+ #
2753
+ # イニシャライザ
2754
+ #
2755
+ def initialize
2756
+ end
2757
+
2758
+ def self.get(*args)
2759
+ case args.length
2760
+ when 1
2761
+ get_1(args[0])
2762
+ when 2
2763
+ get_2(args[0],args[1])
2764
+ else
2765
+ raise ArgumentError
2766
+ end
2767
+ end
2768
+
2769
+ #
2770
+ # パターンを取得する
2771
+ # @param [String] regex 正規表現
2772
+ # @return [Regexp] パターン
2773
+ #
2774
+ def self.get_1(regex)
2775
+ #pattern = @@regexCache[regex]
2776
+ #
2777
+ #if pattern == nil then
2778
+ if regex.kind_of?(String) then
2779
+ if !@@regexCache[regex.to_sym] then
2780
+ #pattern = Regexp.new(regex)
2781
+ #@@regexCache[regex] = pattern
2782
+ @@regexCache[regex.to_sym] = Regexp.new(regex,Regexp::MULTILINE)
2783
+ end
2784
+
2785
+ #return pattern
2786
+ @@regexCache[regex.to_sym]
2787
+ elsif regex.kind_of?(Symbol) then
2788
+ if !@@regexCache[regex] then
2789
+ @@regexCache[regex] = Regexp.new(regex.to_s,Regexp::MULTILINE)
2790
+ end
2791
+
2792
+ @@regexCache[regex]
2793
+ end
2794
+ end
2795
+
2796
+ #
2797
+ # パターンを取得する
2798
+ # @param [String] regex 正規表現
2799
+ # @return [Regexp] パターン
2800
+ #
2801
+ def self.get_2(regex,option)
2802
+ #pattern = @@regexCache[regex]
2803
+ #
2804
+ #if pattern == nil then
2805
+ if regex.kind_of?(String) then
2806
+ if !@@regexCache[regex.to_sym] then
2807
+ #pattern = Regexp.new(regex)
2808
+ #@@regexCache[regex] = pattern
2809
+ @@regexCache[regex.to_sym] = Regexp.new(regex,option)
2810
+ end
2811
+
2812
+ #return pattern
2813
+ @@regexCache[regex.to_sym]
2814
+ elsif regex.kind_of?(Symbol) then
2815
+ if !@@regexCache[regex] then
2816
+ @@regexCache[regex] = Regexp.new(regex.to_s,option)
2817
+ end
2818
+
2819
+ @@regexCache[regex]
2820
+ end
2821
+ end
2822
+ end
2823
+
2824
+ class OrderHash <Hash
2825
+
2826
+ def initialize
2827
+ @keys = Array.new
2828
+ @values = Array.new
2829
+ end
2830
+
2831
+ attr_accessor :keys
2832
+ attr_accessor :values
2833
+
2834
+ def store(key, value)
2835
+ super(key, value)
2836
+ unless @keys.include?(key)
2837
+ @keys << key
2838
+ @values << value
2839
+ end
2840
+ end
2841
+
2842
+ def clear
2843
+ @keys.clear
2844
+ @values.clear
2845
+ super
2846
+ end
2847
+
2848
+ def delete(key)
2849
+ if @keys.include?(key)
2850
+ @keys.delete(key)
2851
+ @values.delete(fetch(key))
2852
+ super(key)
2853
+ elsif
2854
+ yield(key)
2855
+ end
2856
+ end
2857
+
2858
+ #superとして、Hash#[]=を呼び出す
2859
+ def []=(key, value)
2860
+ store(key, value)
2861
+ end
2862
+
2863
+ def each
2864
+ @keys.each{|k|
2865
+ arr_tmp = Array.new
2866
+ arr_tmp << k
2867
+ arr_tmp << self[k]
2868
+ yield(arr_tmp)
2869
+ }
2870
+ return self
2871
+ end
2872
+
2873
+ def each_pair
2874
+ @keys.each{|k|
2875
+ yield(k, self[k])
2876
+ }
2877
+ return self
2878
+ end
2879
+
2880
+ def map
2881
+ arr_tmp = Array.new
2882
+ @keys.each{|k|
2883
+ arg_arr = Array.new
2884
+ arg_arr << k
2885
+ arg_arr << self[k]
2886
+ arr_tmp << yield(arg_arr)
2887
+ }
2888
+ return arr_tmp
2889
+ end
2890
+
2891
+ def sort_hash(&block)
2892
+ if block_given?
2893
+ arr_tmp = self.sort(&block)
2894
+ elsif
2895
+ arr_tmp = self.sort
2896
+ end
2897
+ hash_tmp = OrderHash.new
2898
+ arr_tmp.each{|item|
2899
+ hash_tmp[item[0]] = item[1]
2900
+ }
2901
+ return hash_tmp
2902
+ end
2903
+ end
2904
+ end
2905
+
2906
+ module Html
2907
+ #
2908
+ # HTMLパーサ
2909
+ #
2910
+ class ParserImpl < Meteor::Core::Kernel
2911
+
2912
+ KAIGYO_CODE = "(\r?\n|\r)"
2913
+ NBSP_2 = '&nbsp;'
2914
+ BR_1 = "\r?\n|\r"
2915
+ BR_2 = "<br>"
2916
+
2917
+ META = 'META'
2918
+ META_S = 'meta'
2919
+
2920
+ #MATCH_TAG = "br|hr|img|input|meta|base"
2921
+ MATCH_TAG = ['br','hr','img','input','meta','base']
2922
+ #MATCH_TAG_2 = "textarea|option|pre"
2923
+ MATCH_TAG_2 =['textarea','option','pre']
2924
+
2925
+ HTTP_EQUIV = 'http-equiv'
2926
+ CONTENT_TYPE = 'Content-Type'
2927
+ CONTENT = 'content'
2928
+
2929
+ ATTR_LOGIC = ['disabled','readonly','checked','selected','multiple']
2930
+ OPTION = 'option'
2931
+ SELECTED = 'selected'
2932
+ INPUT = 'input'
2933
+ CHECKED = 'checked'
2934
+ RADIO = 'radio'
2935
+ #DISABLE_ELEMENT = "input|textarea|select|optgroup"
2936
+ DISABLE_ELEMENT = ['input','textarea','select','optgroup']
2937
+ DISABLED = 'disabled'
2938
+ #READONLY_TYPE = "text|password"
2939
+ READONLY_TYPE = ['text','password']
2940
+ TEXTAREA = 'textarea'
2941
+ READONLY='readonly'
2942
+ SELECT = 'select'
2943
+ MULTIPLE = 'multiple'
2944
+
2945
+ #@@pattern_option = Regexp.new(OPTION)
2946
+ #@@pattern_selected = Regexp.new(SELECTED)
2947
+ #@@pattern_input = Regexp.new(INPUT)
2948
+ #@@pattern_checked = Regexp.new(CHECKED)
2949
+ #@@pattern_radio = Regexp.new(RADIO)
2950
+ #@@pattern_disable_element = Regexp.new(DISABLE_ELEMENT)
2951
+ #@@pattern_disabled = Regexp.new(DISABLED)
2952
+ #@@pattern_readonly_type = Regexp.new(READONLY_TYPE)
2953
+ #@@pattern_textarea = Regexp.new(TEXTAREA)
2954
+ #@@pattern_readonly = Regexp.new(READONLY)
2955
+ #@@pattern_select = Regexp.new(SELECT)
2956
+ #@@pattern_multiple = Regexp.new(MULTIPLE)
2957
+
2958
+ SELECTED_M = "\\sselected\\s|\\sselected$|\\sSELECTED\\s|\\sSELECTED$"
2959
+ SELECTED_R = "selected\\s|selected$|SELECTED\\s|SELECTED$"
2960
+ CHECKED_M = "\\schecked\\s|\\schecked$|\\sCHECKED\\s|\\sCHECKED$"
2961
+ CHECKED_R = "checked\\s|checked$|CHECKED\\s|CHECKED$"
2962
+ DISABLED_M = "\\sdisabled\\s|\\sdisabled$|\\sDISABLED\\s|\\sDISABLED$"
2963
+ DISABLED_R = "disabled\\s|disabled$|DISABLED\\s|DISABLED$"
2964
+ READONLY_M = "\\sreadonly\\s|\\sreadonly$|\\sREADONLY\\s|\\sREADONLY$"
2965
+ READONLY_R = "readonly\\s|readonly$|READONLY\\s|READONLY$"
2966
+ MULTIPLE_M = "\\smultiple\\s|\\smultiple$|\\sMULTIPLE\\s|\\sMULTIPLE$"
2967
+ MULTIPLE_R = "multiple\\s|multiple$|MULTIPLE\\s|MULTIPLE$"
2968
+
2969
+ @@pattern_selected_m = Regexp.new(SELECTED_M)
2970
+ @@pattern_selected_r = Regexp.new(SELECTED_R)
2971
+ @@pattern_checked_m = Regexp.new(CHECKED_M)
2972
+ @@pattern_checked_r = Regexp.new(CHECKED_R)
2973
+ @@pattern_disabled_m = Regexp.new(DISABLED_M)
2974
+ @@pattern_disabled_r = Regexp.new(DISABLED_R)
2975
+ @@pattern_readonly_m = Regexp.new(READONLY_M)
2976
+ @@pattern_readonly_r = Regexp.new(READONLY_R)
2977
+ @@pattern_multiple_m = Regexp.new(MULTIPLE_M)
2978
+ @@pattern_multiple_r = Regexp.new(MULTIPLE_R)
2979
+
2980
+ TRUE = 'true'
2981
+ FALSE = 'false'
2982
+
2983
+ #@@pattern_true = Regexp.new(TRUE)
2984
+ #@@pattern_false = Regexp.new(FALSE)
2985
+
2986
+ TYPE_L = 'type'
2987
+ TYPE_U = 'TYPE'
2988
+
2989
+ @@pattern_and_1 = Regexp.new(AND_1)
2990
+ @@pattern_lt_1 = Regexp.new(LT_1)
2991
+ @@pattern_gt_1 = Regexp.new(GT_1)
2992
+ @@pattern_dq_1 = Regexp.new(DOUBLE_QUATATION)
2993
+ @@pattern_space_1 = Regexp.new(SPACE)
2994
+ @@pattern_br_1 = Regexp.new(BR_1)
2995
+ @@pattern_lt_2 = Regexp.new(LT_2)
2996
+ @@pattern_gt_2 = Regexp.new(GT_2)
2997
+ @@pattern_dq_2 = Regexp.new(QO_2)
2998
+ @@pattern_space_2 = Regexp.new(NBSP_2)
2999
+ @@pattern_and_2 = Regexp.new(AND_2)
3000
+ @@pattern_br_2 = Regexp.new(BR_2)
3001
+
3002
+ #@@pattern_match_tag = Regexp.new(MATCH_TAG)
3003
+ @@pattern_set_mono1 = Regexp.new(SET_MONO_1)
3004
+ #@@pattern_match_tag2 = Regexp.new(MATCH_TAG_2)
3005
+
3006
+ GET_ATTRS_MAP2="\\s(disabled|readonly|checked|selected|multiple)"
3007
+ @@pattern_get_attrs_map2 = Regexp.new(GET_ATTRS_MAP2)
3008
+
3009
+ #
3010
+ # イニシャライザ
3011
+ #
3012
+ # @param [Array] args 引数配列
3013
+ #
3014
+ def initialize(*args)
3015
+ super(args)
3016
+ case args.length
3017
+ when 0
3018
+ initialize_0
3019
+ when 1
3020
+ initialize_1(args[0])
3021
+ else
3022
+ raise ArgumentError
3023
+ end
3024
+ end
3025
+
3026
+ #
3027
+ # イニシャライザ
3028
+ #
3029
+ def initialize_0
3030
+ end
3031
+ private :initialize_0
3032
+
3033
+ #
3034
+ # イニシャライザ
3035
+ # @param [Meteor::Parser] ps パーサ
3036
+ #
3037
+ def initialize_1(ps)
3038
+ @root.document = String.new(ps.document)
3039
+ @root.hookDocument = String.new(ps.hookDocument)
3040
+ @root.hook = ps.hook
3041
+ @root.monoHook = ps.monoHook
3042
+ @root.contentType = String.new(ps.contentType);
3043
+ end
3044
+ private :initialize_1
3045
+
3046
+ #
3047
+ # ドキュメントをパーサにセットする
3048
+ #
3049
+ # @param [String] document ドキュメント
3050
+ #
3051
+ def parse(document)
3052
+ @root.document = document
3053
+ analyzeML()
3054
+ end
3055
+
3056
+ #
3057
+ # ファイルを読み込み、パーサにセットする
3058
+ #
3059
+ # @param [String] filePath ファイルパス
3060
+ # @param [String] encoding エンコーディング
3061
+ #
3062
+ def read(filePath,encoding)
3063
+ super(filePath,encoding)
3064
+ analyzeML()
3065
+ end
3066
+
3067
+ #
3068
+ # ドキュメントをパースする
3069
+ #
3070
+ def analyzeML()
3071
+ #content-typeの取得
3072
+ analyzeContentType()
3073
+ #改行コードの取得
3074
+ analyzeKaigyoCode()
3075
+
3076
+ @res = nil
3077
+ end
3078
+ private :analyzeML
3079
+
3080
+ # コンテントタイプを取得する
3081
+ #
3082
+ # @return [Streing]コンテントタイプ
3083
+ #
3084
+ def contentType()
3085
+ @root.contentType
3086
+ end
3087
+
3088
+ #
3089
+ # ドキュメントをパースし、コンテントタイプをセットする
3090
+ #
3091
+ def analyzeContentType()
3092
+ @elm_ = element(META_S,HTTP_EQUIV,CONTENT_TYPE)
3093
+
3094
+ if !@elm_ then
3095
+ @elm_ = element(META,HTTP_EQUIV,CONTENT_TYPE)
3096
+ end
3097
+
3098
+ if @elm_ then
3099
+ @root.contentType = @elm_.attribute(CONTENT)
3100
+ else
3101
+ @root.contentType = EMPTY
3102
+ end
3103
+ end
3104
+ private :analyzeContentType
3105
+
3106
+ #
3107
+ # ドキュメントをパースし、改行コードをセットする
3108
+ #
3109
+ def analyzeKaigyoCode()
3110
+ #改行コード取得
3111
+ @pattern = Regexp.new(KAIGYO_CODE)
3112
+ @res = @pattern.match(@root.document)
3113
+
3114
+ if @res then
3115
+ @root.kaigyoCode = @res[1]
3116
+ end
3117
+ end
3118
+ private :analyzeKaigyoCode
3119
+
3120
+ #
3121
+ # 要素名で検索し、要素を取得する
3122
+ #
3123
+ # @param [String] elmName 要素名
3124
+ # @return [Meteor::Element] 要素
3125
+ #
3126
+ def element_1(elmName)
3127
+ @_elmName = escapeRegex(elmName)
3128
+
3129
+ #空要素の場合(<->内容あり要素の場合)
3130
+ if isMatch(MATCH_TAG,elmName) then
3131
+ #空要素検索用パターン
3132
+ @pattern_cc = '' << TAG_OPEN << @_elmName << TAG_SEARCH_1_4_2
3133
+ @pattern = Meteor::Core::Util::PatternCache.get(@pattern_cc)
3134
+ @res = @pattern.match(@root.document)
3135
+ if @res then
3136
+ elementWithoutContent_1(elmName)
3137
+ else
3138
+ @elm_ = nil
3139
+ end
3140
+ else
3141
+ #内容あり要素検索用パターン
3142
+ @pattern_cc = '' << TAG_OPEN << @_elmName << TAG_SEARCH_1_1 << elmName
3143
+ @pattern_cc << TAG_SEARCH_1_2 << @_elmName << TAG_CLOSE
3144
+
3145
+ @pattern = Meteor::Core::Util::PatternCache.get(@pattern_cc)
3146
+ #内容あり要素検索
3147
+ @res = @pattern.match(@root.document)
3148
+ #内容あり要素の場合
3149
+ if @res then
3150
+ elementWithContent_1(elmName)
3151
+ else
3152
+ @elm_ = nil
3153
+ end
3154
+ end
3155
+
3156
+ @elm_
3157
+ end
3158
+ private :element_1
3159
+
3160
+ def elementWithoutContent_1(elmName)
3161
+ @elm_ = Element.new(elmName)
3162
+ #属性
3163
+ @elm_.attributes = @res[1]
3164
+ #空要素検索用パターン
3165
+ @elm_.pattern = @pattern_cc
3166
+
3167
+ @elm_.document = @res[0]
3168
+
3169
+ @elm.parser = self
3170
+ end
3171
+ private :elementWithoutContent_1
3172
+
3173
+ #
3174
+ # 要素名、属性(属性名="属性値")で検索し、要素を取得する
3175
+ #
3176
+ # @param [String] elmName 要素名
3177
+ # @param [String] attrName 属性名
3178
+ # @param [String] attrValue 属性値
3179
+ # @return [Meteor::Element] 要素
3180
+ #
3181
+ def element_3(elmName,attrName,attrValue)
3182
+
3183
+ @_elmName = escapeRegex(elmName)
3184
+ @_attrName = escapeRegex(attrName)
3185
+ @_attrValue = escapeRegex(attrValue)
3186
+ #空要素の場合(<->内容あり要素の場合)
3187
+ if isMatch(MATCH_TAG,elmName) then
3188
+ #空要素検索パターン
3189
+ @pattern_cc = '' << TAG_OPEN << @_elmName << TAG_SEARCH_2_1 << @_attrName << ATTR_EQ
3190
+ @pattern_cc << @_attrValue << TAG_SEARCH_2_4_3
3191
+ @pattern = Meteor::Core::Util::PatternCache.get(@pattern_cc)
3192
+ #空要素検索
3193
+ @res = @pattern.match(@root.document)
3194
+ if @res then
3195
+ elementWithoutContent_3(elmName)
3196
+ else
3197
+ @elm_ = nil
3198
+ end
3199
+ else
3200
+ #内容あり要素検索パターン
3201
+ @pattern_cc = '' << TAG_OPEN << @_elmName << TAG_SEARCH_2_1 << @_attrName << ATTR_EQ
3202
+ @pattern_cc << @_attrValue << TAG_SEARCH_2_2 << @_elmName
3203
+ @pattern_cc << TAG_SEARCH_1_2 << @_elmName << TAG_CLOSE
3204
+ @pattern = Meteor::Core::Util::PatternCache.get(@pattern_cc)
3205
+ #内容あり要素検索
3206
+ @res = @pattern.match(@root.document)
3207
+
3208
+ if !@res then
3209
+ @res = elementWithContent_3_2(elmName)
3210
+ end
3211
+
3212
+ if @res then
3213
+ elementWithContent_3_1(elmName)
3214
+ else
3215
+ @elm_ = nil
3216
+ end
3217
+ end
3218
+
3219
+ if @elm_ then
3220
+ @elm_.arguments.store(attrName, attrValue)
3221
+ @elm_.arguments.recordable = true
3222
+ end
3223
+
3224
+ @elm_
3225
+ end
3226
+ private :element_3
3227
+
3228
+ def elementWithoutContent_3(elmName)
3229
+ elementWithoutContent_3_1(elmName,TAG_SEARCH_NC_2_4_3)
3230
+ end
3231
+ private :elementWithoutContent_3
3232
+
3233
+ #
3234
+ # 属性(属性名="属性値")で検索し、要素を取得する
3235
+ #
3236
+ # @param [String] attrName 属性名
3237
+ # @param [String] attrValue 属性値
3238
+ # @return [Meteor::Element] 要素
3239
+ #
3240
+ def element_2(attrName,attrValue)
3241
+ @_attrName = escapeRegex(attrName)
3242
+ @_attrValue = escapeRegex(attrValue)
3243
+
3244
+ @pattern_cc = '' << TAG_SEARCH_3_1 << @_attrName << ATTR_EQ << @_attrValue
3245
+ @pattern_cc << TAG_SEARCH_2_4_4
3246
+ @pattern = Meteor::Core::Util::PatternCache.get(@pattern_cc)
3247
+ @res = @pattern.match(@root.document)
3248
+
3249
+ if @res then
3250
+ @elm_ = element_3(@res[1],attrName,attrValue)
3251
+ else
3252
+ @elm_ = nil
3253
+ end
3254
+
3255
+ @elm_
3256
+ end
3257
+ private :element_2
3258
+
3259
+ #
3260
+ # 要素名と属性1・属性2(属性名="属性値")で検索し、要素を取得する
3261
+ #
3262
+ # @param [String] elmName 要素名
3263
+ # @param attrName1 属性名1
3264
+ # @param attrValue1 属性値1
3265
+ # @param attrName2 属性名2
3266
+ # @param attrValue2 属性値2
3267
+ # @return [Meteor::Element] 要素
3268
+ #
3269
+ def element_5(elmName,attrName1,attrValue1,attrName2,attrValue2)
3270
+
3271
+ @_elmName = escapeRegex(elmName)
3272
+ @_attrName1 = escapeRegex(attrName1)
3273
+ @_attrValue1 = escapeRegex(attrValue1)
3274
+ @_attrName2 = escapeRegex(attrName2)
3275
+ @_attrValue2 = escapeRegex(attrValue2)
3276
+
3277
+ #空要素の場合(<->内容あり要素の場合)
3278
+ if isMatch(MATCH_TAG,elmName) then
3279
+ #空要素検索パターン
3280
+ @pattern_cc = '' << TAG_OPEN << @_elmName << TAG_SEARCH_2_1_2 << @_attrName1 << ATTR_EQ
3281
+ @pattern_cc << @_attrValue1 << TAG_SEARCH_2_6 << @_attrName2 << ATTR_EQ
3282
+ @pattern_cc << @_attrValue2 << TAG_SEARCH_2_7 << @_attrName2 << ATTR_EQ
3283
+ @pattern_cc << @_attrValue2 << TAG_SEARCH_2_6 << @_attrName1 << ATTR_EQ
3284
+ @pattern_cc << @_attrValue1 << TAG_SEARCH_2_4_3_2
3285
+ @pattern = Meteor::Core::Util::PatternCache.get(@pattern_cc)
3286
+ #空要素検索
3287
+ @res = @pattern.match(@root.document)
3288
+
3289
+ if @res then
3290
+ elementWithoutContent_5(elmName)
3291
+ else
3292
+ @elm_ = nil
3293
+ end
3294
+ else
3295
+ #内容あり要素検索パターン
3296
+ @pattern_cc = '' << TAG_OPEN << @_elmName << TAG_SEARCH_2_1_2 << @_attrName1 << ATTR_EQ
3297
+ @pattern_cc << @_attrValue1 << TAG_SEARCH_2_6 << @_attrName2 << ATTR_EQ
3298
+ @pattern_cc << @_attrValue2 << TAG_SEARCH_2_7 << @_attrName2 << ATTR_EQ
3299
+ @pattern_cc << @_attrValue2 << TAG_SEARCH_2_6 << @_attrName1 << ATTR_EQ
3300
+ @pattern_cc << @_attrValue1 << TAG_SEARCH_2_2_2 << @_elmName
3301
+ @pattern_cc << TAG_SEARCH_1_2 << @_elmName << TAG_CLOSE
3302
+ @pattern = Meteor::Core::Util::PatternCache.get(@pattern_cc)
3303
+ #内容あり要素検索
3304
+ @res = @pattern.match(@root.document)
3305
+
3306
+ if !@res then
3307
+ @res = elementWithContent_5_2(elmName)
3308
+ end
3309
+
3310
+ if @res then
3311
+ elementWithContent_5_1(elmName)
3312
+ else
3313
+ @elm_ = nil
3314
+ end
3315
+ end
3316
+
3317
+ if @elm_ then
3318
+ @elm_.arguments.store(attrName1, attrValue1)
3319
+ @elm_.arguments.store(attrName2, attrValue2)
3320
+ @elm_.arguments.recordable = true
3321
+ end
3322
+
3323
+ @elm_
3324
+ end
3325
+ private :element_5
3326
+
3327
+ def elementWithoutContent_5(elmName)
3328
+ elementWithoutContent_5_1(elmName,TAG_SEARCH_NC_2_4_3_2)
3329
+ end
3330
+ private :elementWithoutContent_5
3331
+
3332
+ #
3333
+ # 属性1・属性2(属性名="属性値")で検索し、要素を取得する
3334
+ #
3335
+ # @param [String] attrName1 属性名1
3336
+ # @param [String] attrValue1 属性値1
3337
+ # @param [String] attrName2 属性名2
3338
+ # @param [String] attrValue2 属性値2
3339
+ # @return [Meteor::Element] 要素
3340
+ #
3341
+ def element_4(attrName1,attrValue1,attrName2,attrValue2)
3342
+ @_attrName1 = escapeRegex(attrName1)
3343
+ @_attrValue1 = escapeRegex(attrValue1)
3344
+ @_attrName2 = escapeRegex(attrName2)
3345
+ @_attrValue2 = escapeRegex(attrValue2)
3346
+
3347
+ @pattern_cc = '' << TAG_SEARCH_3_1_2_2 << @_attrName1 << ATTR_EQ << @_attrValue1
3348
+ @pattern_cc << TAG_SEARCH_2_6 << @_attrName2 << ATTR_EQ << @_attrValue2
3349
+ @pattern_cc << TAG_SEARCH_2_7 << @_attrName2 << ATTR_EQ << @_attrValue2
3350
+ @pattern_cc << TAG_SEARCH_2_6 << @_attrName1 << ATTR_EQ << @_attrValue1
3351
+ @pattern_cc << TAG_SEARCH_2_4_3_2
3352
+
3353
+ @pattern = Patterncache.get(@pattern_cc)
3354
+
3355
+ @res = @pattern.match(@root.document)
3356
+
3357
+ if @res then
3358
+ @elm_ = element_5(@res[1],attrName1,attrValue1,attrName2,attrValue2)
3359
+ else
3360
+ @elm_ = nil
3361
+ end
3362
+
3363
+ @elm_
3364
+ end
3365
+ private :element_4
3366
+
3367
+ def editAttributes_(elm,attrName,attrValue)
3368
+ if isMatch(SELECTED, attrName) && isMatch(OPTION,elm.name) then
3369
+ editAttributes_5(elm,attrName,attrValue,@@pattern_selected_m,@@pattern_selected_r)
3370
+ elsif isMatch(MULTIPLE, attrName) && isMatch(SELECT,elm.name)
3371
+ editAttributes_5(elm,attrName,attrValue,@@pattern_multiple_m,@@pattern_multiple_r)
3372
+ elsif isMatch(DISABLED, attrName) && isMatch(DISABLE_ELEMENT, elm.name) then
3373
+ editAttributes_5(elm,attrName,attrValue,@@pattern_disabled_m,@@pattern_disabled_r)
3374
+ elsif isMatch(CHECKED, attrName) && isMatch(INPUT,elm.name) && isMatch(RADIO, getType(elm)) then
3375
+ editAttributes_5(elm,attrName,attrValue,@@pattern_checked_m,@@pattern_checked_r)
3376
+ elsif isMatch(READONLY, attrName) && (isMatch(TEXTAREA,elm.name) || (isMatch(INPUT,elm.name) && isMatch(READONLY_TYPE, getType(elm)))) then
3377
+ editAttributes_5(elm,attrName,attrValue,@@pattern_readonly_m,@@pattern_readonly_r)
3378
+ else
3379
+ super(elm,attrName,attrValue)
3380
+ end
3381
+ end
3382
+ private :editAttributes_
3383
+
3384
+ def editAttributes_5(elm,attrName,attrValue,match_p,replace)
3385
+ #attrValue = escape(attrValue)
3386
+
3387
+ if isMatch(TRUE, attrValue) then
3388
+ @res = match_p.match(elm.attributes)
3389
+
3390
+ if !@res then
3391
+ if !EMPTY.eql?(elm.attributes) && !EMPTY.eql?(elm.attributes.strip) then
3392
+ elm.attributes = '' << SPACE << elm.attributes.strip
3393
+ else
3394
+ elm.attributes = ''
3395
+ end
3396
+ elm.attributes << SPACE << attrName
3397
+ #else
3398
+ end
3399
+ elsif isMatch(FALSE, attrValue) then
3400
+ elm.attributes.sub!(replace,EMPTY)
3401
+ end
3402
+
3403
+ end
3404
+ private :editAttributes_5
3405
+
3406
+ def editDocument_1(elm)
3407
+ editDocument_2(elm,TAG_CLOSE)
3408
+ end
3409
+ private :editDocument_1
3410
+
3411
+ def getAttributeValue_(elm,attrName)
3412
+ if isMatch(SELECTED, attrName) && isMatch(OPTION,elm.name) then
3413
+ getAttributeValue_2_r(elm,@@pattern_selected_m)
3414
+ elsif isMatch(MULTIPLE, attrName) && isMatch(SELECT,elm.name)
3415
+ getAttributeValue_2_r(elm,@@pattern_multiple_m)
3416
+ elsif isMatch(DISABLED, attrName) && isMatch(DISABLE_ELEMENT, elm.name) then
3417
+ getAttributeValue_2_r(elm,@@pattern_disabled_m)
3418
+ elsif isMatch(CHECKED, attrName) && isMatch(INPUT,elm.name) && isMatch(RADIO, getType(elm)) then
3419
+ getAttributeValue_2_r(elm,@@pattern_checked_m)
3420
+ elsif isMatch(READONLY, attrName) && (isMatch(TEXTAREA,elm.name) || (isMatch(INPUT,elm.name) && isMatch(READONLY_TYPE, getType(elm)))) then
3421
+ getAttributeValue_2_r(elm,@@pattern_readonly_m)
3422
+ else
3423
+ super(elm,attrName)
3424
+ end
3425
+ end
3426
+ private :getAttributeValue_
3427
+
3428
+ def getType(elm)
3429
+ if !elm.type_value
3430
+ elm.type_value = getAttributeValue_2(elm, TYPE_L)
3431
+ if !elm.type_value then
3432
+ elm.type_value = getAttributeValue_2(elm, TYPE_U)
3433
+ end
3434
+ end
3435
+ elm.type_value
3436
+ end
3437
+ private :getType
3438
+
3439
+ def getAttributeValue_2_r(elm,match_p)
3440
+
3441
+ @res = match_p.match(elm.attributes)
3442
+
3443
+ if @res then
3444
+ TRUE
3445
+ else
3446
+ FALSE
3447
+ end
3448
+ end
3449
+ private :getAttributeValue_2_r
3450
+
3451
+ #
3452
+ # 要素の属性マップを取得する
3453
+ #
3454
+ # @param [Meteor::Element] elm 要素
3455
+ # @return [Meteor::AttributeMap] 属性マップ
3456
+ #
3457
+ def getAttributeMap_1(elm)
3458
+ attrs = Meteor::AttributeMap.new
3459
+
3460
+ elm.attributes.scan(@@pattern_get_attrs_map){ |a,b|
3461
+ attrs.store(a,unescape(b))
3462
+ }
3463
+
3464
+ elm.attributes.scan(@@pattern_get_attrs_map2){ |a|
3465
+ attrs.store(a, TRUE)
3466
+ }
3467
+
3468
+ attrs.recordable = true
3469
+
3470
+ attrs
3471
+ end
3472
+ private :getAttributeMap_1
3473
+
3474
+ def removeAttributes_(elm,attrName)
3475
+ #検索対象属性の論理型是非判定
3476
+ if !isMatch(ATTR_LOGIC,attrName) then
3477
+ #属性検索用パターン
3478
+ @pattern = Meteor::Core::Util::PatternCache.get('' << attrName << ERASE_ATTR_1)
3479
+ elm.attributes.sub!(@pattern, EMPTY)
3480
+ else
3481
+ #属性検索用パターン
3482
+ @pattern = Meteor::Core::Util::PatternCache.get(attrName)
3483
+ elm.attributes.sub!(@pattern, EMPTY)
3484
+ #end
3485
+ end
3486
+ end
3487
+ private :removeAttributes_
3488
+
3489
+ def setMonoInfo(elm)
3490
+
3491
+ @res = @@pattern_set_mono1.match(elm.mixed_content)
3492
+
3493
+ if @res then
3494
+ elm.mono = true
3495
+ if elm.cx then
3496
+ @pattern_cc = '' << SET_CX_1 << elm.name << SPACE << elm.attributes << SET_CX_2 << elm.mixed_content << SET_CX_3 << elm.name << SET_CX_4
3497
+ else
3498
+ if elm.empty then
3499
+ @pattern_cc = '' << TAG_OPEN << elm.name << elm.attributes << TAG_CLOSE << elm.mixed_content << TAG_OPEN3 << elm.name << TAG_CLOSE
3500
+ else
3501
+ @pattern_cc = '' << TAG_OPEN << elm.name << elm.attributes << TAG_CLOSE
3502
+ end
3503
+ end
3504
+ elm.document = @pattern_cc
3505
+ end
3506
+ end
3507
+ private :setMonoInfo
3508
+
3509
+ def escape(element)
3510
+ #特殊文字の置換
3511
+ #「&」->「&amp;」
3512
+ if element.include?(AND_1) then
3513
+ element.gsub!(@@pattern_and_1,AND_2)
3514
+ end
3515
+ #「<」->「&lt;」
3516
+ if element.include?(LT_1) then
3517
+ element.gsub!(@@pattern_lt_1,LT_2)
3518
+ end
3519
+ #「>」->「&gt;」
3520
+ if element.include?(GT_1) then
3521
+ element.gsub!(@@pattern_gt_1,GT_2)
3522
+ end
3523
+ #「"」->「&quotl」
3524
+ if element.include?(DOUBLE_QUATATION) then
3525
+ element.gsub!(@@pattern_dq_1,QO_2)
3526
+ end
3527
+ #「 」->「&nbsp;」
3528
+ if element.include?(SPACE) then
3529
+ element.gsub!(@@pattern_space_1,NBSP_2)
3530
+ end
3531
+
3532
+ element
3533
+ end
3534
+ private :escape
3535
+
3536
+ def escapeContent(element,elmName)
3537
+ element = escape(element)
3538
+
3539
+ if !isMatch(MATCH_TAG_2,elmName) then
3540
+ #「¥r?¥n」->「<br>」
3541
+ element.gsub!(@@pattern_br_1, BR_2)
3542
+ end
3543
+
3544
+ element
3545
+ end
3546
+ private :escapeContent
3547
+
3548
+ def unescape(element)
3549
+ #特殊文字の置換
3550
+ #「<」<-「&lt;」
3551
+ if element.include?(LT_2) then
3552
+ element.gsub!(@@pattern_lt_2,LT_1)
3553
+ end
3554
+ #「>」<-「&gt;」
3555
+ if element.include?(GT_2) then
3556
+ element.gsub!(@@pattern_gt_2,GT_1)
3557
+ end
3558
+ #「"」<-「&quotl」
3559
+ if element.include?(QO_2) then
3560
+ element.gsub!(@@pattern_dq_2,DOUBLE_QUATATION)
3561
+ end
3562
+ #「 」<-「&nbsp;」
3563
+ if element.include?(NBSP_2) then
3564
+ element.gsub!(@@pattern_space_2,SPACE)
3565
+ end
3566
+ #「&」<-「&amp;」
3567
+ if element.include?(AND_2) then
3568
+ element.gsub!(@@pattern_and_2,AND_1)
3569
+ end
3570
+ element
3571
+ end
3572
+ private :unescape
3573
+
3574
+ def unescapeContent(element,elmName)
3575
+ element = unescape(element)
3576
+
3577
+ if !isMatch(@@pattern_match_tag2,elmName) then
3578
+ #「<br>」->「¥r?¥n」
3579
+ if element.include?(BR_2) then
3580
+ element.gsub!(@@pattern_br_2, @root.kaigyoCode)
3581
+ end
3582
+ end
3583
+
3584
+ element
3585
+ end
3586
+ private :unescapeContent
3587
+
3588
+ end
3589
+ end
3590
+
3591
+ module Xhtml
3592
+
3593
+ #
3594
+ # XHTMLパーサ
3595
+ #
3596
+ class ParserImpl < Meteor::Core::Kernel
3597
+
3598
+ KAIGYO_CODE = "(\r?\n|\r)"
3599
+ NBSP_2 = '&nbsp;'
3600
+ BR_1 = "\r?\n|\r"
3601
+ BR_2 = '<br/>'
3602
+ BR_3 = "<br\\/>"
3603
+
3604
+ META = 'META'
3605
+ META_S = 'meta'
3606
+
3607
+ #MATCH_TAG_2 = "textarea|option|pre"
3608
+ MATCH_TAG_2 = ['textarea','option','pre']
3609
+
3610
+ ATTR_LOGIC = ['disabled','readonly','checked','selected','multiple']
3611
+ OPTION = 'option'
3612
+ SELECTED = 'selected'
3613
+ INPUT = 'input'
3614
+ CHECKED = 'checked'
3615
+ RADIO = 'radio'
3616
+ #DISABLE_ELEMENT = "input|textarea|select|optgroup"
3617
+ DISABLE_ELEMENT = ['input','textarea','select','optgroup']
3618
+ DISABLED = 'disabled'
3619
+ #READONLY_TYPE = "text|password"
3620
+ READONLY_TYPE = ['text','password']
3621
+ TEXTAREA = 'textarea'
3622
+ READONLY='readonly'
3623
+ SELECT = 'select'
3624
+ MULTIPLE = 'multiple'
3625
+
3626
+ #@@pattern_option = Regexp.new(OPTION)
3627
+ #@@pattern_selected = Regexp.new(SELECTED)
3628
+ #@@pattern_input = Regexp.new(INPUT)
3629
+ #@@pattern_checked = Regexp.new(CHECKED)
3630
+ #@@pattern_radio = Regexp.new(RADIO)
3631
+ #@@pattern_disable_element = Regexp.new(DISABLE_ELEMENT)
3632
+ #@@pattern_disabled = Regexp.new(DISABLED)
3633
+ #@@pattern_readonly_type = Regexp.new(READONLY_TYPE)
3634
+ #@@pattern_textarea = Regexp.new(TEXTAREA)
3635
+ #@@pattern_readonly = Regexp.new(READONLY)
3636
+ #@@pattern_select = Regexp.new(SELECT)
3637
+ #@@pattern_multiple = Regexp.new(MULTIPLE)
3638
+
3639
+ SELECTED_M = "\\sselected=\"[^\"]*\"\\s|\\sselected=\"[^\"]*\"$|\\sSELECTED=\"[^\"]*\"\\s|\\sSELECTED=\"[^\"]*\"$"
3640
+ SELECTED_M1 = "\\sselected=\"([^\"]*)\"\\s|\\sselected=\"([^\"]*)\"$|\\sSELECTED=\"([^\"]*)\"\\s|\\sSELECTED=\"([^\"]*)\"$"
3641
+ SELECTED_R = "selected=\"[^\"]*\"|SELECTED=\"[^\"]*\""
3642
+ SELECTED_U = "selected=\"selected\""
3643
+ CHECKED_M = "\\schecked=\"[^\"]*\"\\s|\\schecked=\"[^\"]*\"$|\\sCHECKED=\"[^\"]*\"\\s|\\sCHECKED=\"[^\"]*\"$"
3644
+ CHECKED_M1 = "\\schecked=\"([^\"]*)\"\\s|\\schecked=\"([^\"]*)\"$|\\sCHECKED=\"([^\"]*)\"\\s|\\sCHECKED=\"([^\"]*)\"$"
3645
+ CHECKED_R = "checked=\"[^\"]*\"|CHECKED=\"[^\"]*\""
3646
+ CHECKED_U = "checked=\"checked\""
3647
+ DISABLED_M = "\\sdisabled=\"[^\"]*\"\\s|\\sdisabled=\"[^\"]*\"$|\\sDISABLED=\"[^\"]*\"\\s|\\sDISABLED=\"[^\"]*\"$"
3648
+ DISABLED_M1 = "\\sdisabled=\"([^\"]*)\"\\s|\\sdisabled=\"([^\"]*)\"$|\\sDISABLED=\"([^\"]*)\"\\s|\\sDISABLED=\"([^\"]*)\"$"
3649
+ DISABLED_R = "disabled=\"[^\"]*\"|DISABLED=\"[^\"]*\""
3650
+ DISABLED_U = "disabled=\"disabled\""
3651
+ READONLY_M = "\\sreadonly=\"[^\"]*\"\\s|\\sreadonly=\"[^\"]*\"$|\\sREADONLY=\"[^\"]*\"\\s|\\sREADONLY=\"[^\"]*\"$"
3652
+ READONLY_M1 = "\\sreadonly=\"([^\"]*)\"\\s|\\sreadonly=\"([^\"]*)\"$|\\sREADONLY=\"([^\"]*)\"\\s|\\sREADONLY=\"([^\"]*)\"$"
3653
+ READONLY_R = "readonly=\"[^\"]*\"|READONLY=\"[^\"]*\""
3654
+ READONLY_U = "readonly=\"readonly\""
3655
+ MULTIPLE_M = "\\smultiple=\"[^\"]*\"\\s|\\smultiple=\"[^\"]*\"$|\\sMULTIPLE=\"[^\"]*\"\\s|\\sMULTIPLE=\"[^\"]*\"$"
3656
+ MULTIPLE_M1 = "\\smultiple=\"([^\"]*)\"\\s|\\smultiple=\"([^\"]*)\"$|\\sMULTIPLE=\"([^\"]*)\"\\s|\\sMULTIPLE=\"([^\"]*)\"$"
3657
+ MULTIPLE_R = "multiple=\"[^\"]*\"|MULTIPLE=\"[^\"]*\""
3658
+ MULTIPLE_U = "multiple=\"multiple\""
3659
+
3660
+ HTTP_EQUIV = 'http-equiv'
3661
+ CONTENT_TYPE = 'Content-Type'
3662
+ CONTENT = 'content'
3663
+
3664
+ @@pattern_selected_m = Regexp.new(SELECTED_M)
3665
+ @@pattern_selected_m1 = Regexp.new(SELECTED_M1)
3666
+ @@pattern_selected_r = Regexp.new(SELECTED_R)
3667
+ @@pattern_checked_m = Regexp.new(CHECKED_M)
3668
+ @@pattern_checked_m1 = Regexp.new(CHECKED_M1)
3669
+ @@pattern_checked_r = Regexp.new(CHECKED_R)
3670
+ @@pattern_disabled_m = Regexp.new(DISABLED_M)
3671
+ @@pattern_disabled_m1 = Regexp.new(DISABLED_M1)
3672
+ @@pattern_disabled_r = Regexp.new(DISABLED_R)
3673
+ @@pattern_readonly_m = Regexp.new(READONLY_M)
3674
+ @@pattern_readonly_m1 = Regexp.new(READONLY_M1)
3675
+ @@pattern_readonly_r = Regexp.new(READONLY_R)
3676
+ @@pattern_multiple_m = Regexp.new(MULTIPLE_M)
3677
+ @@pattern_multiple_m1 = Regexp.new(MULTIPLE_M1)
3678
+ @@pattern_multiple_r = Regexp.new(MULTIPLE_R)
3679
+
3680
+ TRUE = 'true'
3681
+ FALSE = 'false'
3682
+
3683
+ TYPE_L = 'type'
3684
+ TYPE_U = 'TYPE'
3685
+
3686
+ @@pattern_and_1 = Regexp.new(AND_1)
3687
+ @@pattern_lt_1 = Regexp.new(LT_1)
3688
+ @@pattern_gt_1 = Regexp.new(GT_1)
3689
+ @@pattern_dq_1 = Regexp.new(DOUBLE_QUATATION)
3690
+ @@pattern_space_1 = Regexp.new(SPACE)
3691
+ @@pattern_br_1 = Regexp.new(BR_1)
3692
+ @@pattern_lt_2 = Regexp.new(LT_2)
3693
+ @@pattern_gt_2 = Regexp.new(GT_2)
3694
+ @@pattern_dq_2 = Regexp.new(QO_2)
3695
+ @@pattern_space_2 = Regexp.new(NBSP_2)
3696
+ @@pattern_and_2 = Regexp.new(AND_2)
3697
+ @@pattern_br_2 = Regexp.new(BR_3)
3698
+
3699
+ #@@pattern_match_tag = Regexp.new(MATCH_TAG)
3700
+ @@pattern_set_mono1 = Regexp.new(SET_MONO_1)
3701
+ #@@pattern_match_tag2 = Regexp.new(MATCH_TAG_2)
3702
+
3703
+ #
3704
+ # イニシャライザ
3705
+ # @param [Array] args 引数配列
3706
+ #
3707
+ def initialize(*args)
3708
+ super(args)
3709
+ case args.length
3710
+ when 0
3711
+ initialize_0
3712
+ when 1
3713
+ initialize_1(args[0])
3714
+ else
3715
+ raise ArgumentError
3716
+ end
3717
+ end
3718
+
3719
+ #
3720
+ # イニシャライザ
3721
+ #
3722
+ def initialize_0
3723
+ end
3724
+ private :initialize_0
3725
+
3726
+ #
3727
+ # イニシャライザ
3728
+ #
3729
+ # @param [Meteor::Parser] ps パーサ
3730
+ #
3731
+ def initialize_1(ps)
3732
+ @root.document = String.new(ps.document)
3733
+ @root.hookDocument = String.new(ps.hookDocument)
3734
+ @root.hook = ps.hook
3735
+ @root.monoHook = ps.monoHook
3736
+ @root.contentType = String.new(ps.contentType);
3737
+ end
3738
+ private :initialize_1
3739
+
3740
+ #
3741
+ # ドキュメントをパーサにセットする
3742
+ #
3743
+ # @param [String] document ドキュメント
3744
+ #
3745
+ def parse(document)
3746
+ @root.document = document
3747
+ analyzeML()
3748
+ end
3749
+
3750
+ #
3751
+ # ファイルを読み込み、パーサにセットする
3752
+ #
3753
+ # @param filePath ファイルパス
3754
+ # @param encoding エンコーディング
3755
+ #
3756
+ def read(filePath,encoding)
3757
+ super(filePath,encoding)
3758
+ analyzeML()
3759
+ end
3760
+
3761
+ #
3762
+ # ドキュメントをパースする
3763
+ #
3764
+ def analyzeML()
3765
+ #mixed_content-typeの取得
3766
+ analyzeContentType()
3767
+ #改行コードの取得
3768
+ analyzeKaigyoCode()
3769
+ @res = nil
3770
+ end
3771
+ private :analyzeML
3772
+
3773
+ #
3774
+ # コンテントタイプを取得する
3775
+ #
3776
+ # @return [String] コンテントタイプ
3777
+ #
3778
+ def contentType()
3779
+ @root.contentType
3780
+ end
3781
+
3782
+ #
3783
+ # ドキュメントをパースし、コンテントタイプをセットする
3784
+ #
3785
+ def analyzeContentType()
3786
+ @elm_ = element(META_S,HTTP_EQUIV,CONTENT_TYPE)
3787
+
3788
+ if !@elm_ then
3789
+ @elm_ = element(META,HTTP_EQUIV,CONTENT_TYPE)
3790
+ end
3791
+
3792
+ if @elm_ then
3793
+ @root.contentType = @elm_.attribute(CONTENT)
3794
+ else
3795
+ @root.contentType = EMPTY
3796
+ end
3797
+ end
3798
+ private :analyzeContentType
3799
+
3800
+ #
3801
+ # ドキュメントをパースし、改行コードをセットする
3802
+ #
3803
+ def analyzeKaigyoCode()
3804
+ #改行コード取得
3805
+ @pattern = Regexp.new(KAIGYO_CODE)
3806
+ @res = @pattern.match(@root.document)
3807
+
3808
+ if @res then
3809
+ @root.kaigyoCode = @res[1]
3810
+ end
3811
+ end
3812
+ private :analyzeKaigyoCode
3813
+
3814
+ def editAttributes_(elm,attrName,attrValue)
3815
+
3816
+ if isMatch(SELECTED, attrName) && isMatch(OPTION,elm.name) then
3817
+ editAttributes_5(elm,attrValue,@@pattern_selected_m,@@pattern_selected_r,SELECTED_U)
3818
+ elsif isMatch(MULTIPLE, attrName) && isMatch(SELECT,elm.name)
3819
+ editAttributes_5(elm,attrValue,@@pattern_multiple_m,@@pattern_multiple_r,MULTIPLE_U)
3820
+ elsif isMatch(DISABLED, attrName) && isMatch(DISABLE_ELEMENT, elm.name) then
3821
+ editAttributes_5(elm,attrValue,@@pattern_disabled_m,@@pattern_disabled_r,DISABLED_U)
3822
+ elsif isMatch(CHECKED, attrName) && isMatch(INPUT,elm.name) && isMatch(RADIO,getType(elm)) then
3823
+ editAttributes_5(elm,attrValue,@@pattern_checked_m,@@pattern_checked_r,CHECKED_U)
3824
+ elsif isMatch(READONLY, attrName) && (isMatch(TEXTAREA,elm.name) || (isMatch(INPUT,elm.name) && isMatch(READONLY_TYPE, getType(elm)))) then
3825
+ editAttributes_5(elm,attrValue,@@pattern_readonly_m,@@pattern_readonly_r,READONLY_U)
3826
+ else
3827
+ super(elm,attrName,attrValue)
3828
+ end
3829
+
3830
+ end
3831
+ private :editAttributes_
3832
+
3833
+ def editAttributes_5(elm,attrValue,match_p,replaceRegex,replaceUpdate)
3834
+
3835
+ #attrValue = escape(attrValue)
3836
+
3837
+ if isMatch(TRUE,attrValue) then
3838
+
3839
+ @res = match_p.match(elm.attributes)
3840
+
3841
+ if !@res then
3842
+ #属性文字列の最後に新規の属性を追加する
3843
+ if elm.attributes != EMPTY then
3844
+ elm.attributes = '' << SPACE << elm.attributes.strip
3845
+ #else
3846
+ end
3847
+ elm.attributes << SPACE << replaceUpdate
3848
+ else
3849
+ #属性の置換
3850
+ elm.attributes.gsub!(replaceRegex,replaceUpdate)
3851
+ end
3852
+ elsif isMatch(FALSE,attrValue) then
3853
+ #attrName属性が存在するなら削除
3854
+ #属性の置換
3855
+ elm.attributes.gsub!(replaceRegex, EMPTY)
3856
+ end
3857
+
3858
+ end
3859
+ private :editAttributes_5
3860
+
3861
+ def getAttributeValue_(elm,attrName)
3862
+ if isMatch(SELECTED, attrName) && isMatch(OPTION,elm.name) then
3863
+ getAttributeValue_2_r(elm,attrName,@@pattern_selected_m1)
3864
+ elsif isMatch(MULTIPLE, attrName) && isMatch(SELECT,elm.name)
3865
+ getAttributeValue_2_r(elm,attrName,@@pattern_multiple_m1)
3866
+ elsif isMatch(DISABLED, attrName) && isMatch(DISABLE_ELEMENT, elm.name) then
3867
+ getAttributeValue_2_r(elm,attrName,@@pattern_disabled_m1)
3868
+ elsif isMatch(CHECKED, attrName) && isMatch(INPUT,elm.name) && isMatch(RADIO, getType(elm)) then
3869
+ getAttributeValue_2_r(elm,attrName,@@pattern_checked_m1)
3870
+ elsif isMatch(READONLY, attrName) && (isMatch(TEXTAREA,elm.name) || (isMatch(INPUT,elm.name) && isMatch(READONLY_TYPE, getType(elm)))) then
3871
+ getAttributeValue_2_r(elm,attrName,@@pattern_readonly_m1)
3872
+ else
3873
+ super(elm,attrName)
3874
+ end
3875
+ end
3876
+ private :getAttributeValue_
3877
+
3878
+ def getType(elm)
3879
+ if !elm.type_value
3880
+ elm.type_value = getAttributeValue_2(elm, TYPE_L)
3881
+ if !elm.type_value then
3882
+ elm.type_value = getAttributeValue_2(elm, TYPE_U)
3883
+ end
3884
+ end
3885
+ elm.type_value
3886
+ end
3887
+ private :getType
3888
+
3889
+ def getAttributeValue_2_r(elm,attrName,match_p)
3890
+
3891
+ @res = match_p.match(elm.attributes)
3892
+
3893
+ if @res then
3894
+ if @res[1] then
3895
+ if attrName == @res[1] then
3896
+ TRUE
3897
+ else
3898
+ @res[1]
3899
+ end
3900
+ elsif @res[2] then
3901
+ if attrName == @res[2] then
3902
+ TRUE
3903
+ else
3904
+ @res[2]
3905
+ end
3906
+ elsif @res[3] then
3907
+ if attrName == @res[3] then
3908
+ TRUE
3909
+ else
3910
+ @res[3]
3911
+ end
3912
+ elsif @res[4] then
3913
+ if attrName == @res[4] then
3914
+ TRUE
3915
+ else
3916
+ @res[4]
3917
+ end
3918
+ end
3919
+ else
3920
+ FALSE
3921
+ end
3922
+ end
3923
+ private :getAttributeValue_2_r
3924
+
3925
+ #
3926
+ # 属性マップを取得する
3927
+ #
3928
+ # @param [Meteor::Element] elm 要素
3929
+ # @return [Meteor::AttributeMap] 属性マップ
3930
+ #
3931
+ def getAttributeMap_1(elm)
3932
+ attrs = Meteor::AttributeMap.new
3933
+
3934
+ elm.attributes.scan(@@pattern_get_attrs_map){ |a,b|
3935
+ if isMatch(ATTR_LOGIC,a) && a==b then
3936
+ attrs.store(a,TRUE)
3937
+ else
3938
+ attrs.store(a,unescape(b))
3939
+ end
3940
+ }
3941
+ attrs.recordable = true
3942
+
3943
+ attrs
3944
+ end
3945
+ private :getAttributeMap_1
3946
+
3947
+ def setMonoInfo(elm)
3948
+
3949
+ @res = @@pattern_set_mono1.match(elm.mixed_content)
3950
+
3951
+ if @res then
3952
+ elm.mono = true
3953
+ if elm.cx then
3954
+ @pattern_cc = '' << SET_CX_1 << elm.name << SPACE << elm.attributes << SET_CX_2 << elm.mixed_content << SET_CX_3 << elm.name << SET_CX_4
3955
+ else
3956
+ if elm.empty then
3957
+ @pattern_cc = '' << TAG_OPEN << elm.name << elm.attributes << TAG_CLOSE << elm.mixed_content << TAG_OPEN3 << elm.name << TAG_CLOSE
3958
+ else
3959
+ @pattern_cc = '' << TAG_OPEN << elm.name << elm.attributes << TAG_CLOSE3
3960
+ end
3961
+ end
3962
+ elm.document = @pattern_cc
3963
+ end
3964
+ end
3965
+ private :setMonoInfo
3966
+
3967
+ def escape(element)
3968
+ #特殊文字の置換
3969
+ #「&」->「&amp;」
3970
+ if element.include?(AND_1) then
3971
+ element.gsub!(@@pattern_and_1,AND_2)
3972
+ end
3973
+ #「<」->「&lt;」
3974
+ if element.include?(LT_1) then
3975
+ element.gsub!(@@pattern_lt_1,LT_2)
3976
+ end
3977
+ #「>」->「&gt;」
3978
+ if element.include?(GT_1) then
3979
+ element.gsub!(@@pattern_gt_1,GT_2)
3980
+ end
3981
+ #「"」->「&quotl」
3982
+ if element.include?(DOUBLE_QUATATION) then
3983
+ element.gsub!(@@pattern_dq_1,QO_2)
3984
+ end
3985
+ #「 」->「&nbsp;」
3986
+ if element.include?(SPACE) then
3987
+ element.gsub!(@@pattern_space_1,NBSP_2)
3988
+ end
3989
+
3990
+ element
3991
+ end
3992
+ private :escape
3993
+
3994
+ def escapeContent(element,elmName)
3995
+ element = escape(element)
3996
+
3997
+ if !isMatch(MATCH_TAG_2,elmName) then
3998
+ #「¥r?¥n」->「<br>」
3999
+ element.gsub!(@@pattern_br_1, BR_2)
4000
+ end
4001
+
4002
+ element
4003
+ end
4004
+ private :escapeContent
4005
+
4006
+ def unescape(element)
4007
+ #特殊文字の置換
4008
+ #「<」<-「&lt;」
4009
+ if element.include?(LT_2) then
4010
+ element.gsub!(@@pattern_lt_2,LT_1)
4011
+ end
4012
+ #「>」<-「&gt;」
4013
+ if element.include?(GT_2) then
4014
+ element.gsub!(@@pattern_gt_2,GT_1)
4015
+ end
4016
+ #「"」<-「&quotl」
4017
+ if element.include?(QO_2) then
4018
+ element.gsub!(@@pattern_dq_2,DOUBLE_QUATATION)
4019
+ end
4020
+ #「 」<-「&nbsp;」
4021
+ if element.include?(NBSP_2) then
4022
+ element.gsub!(@@pattern_space_2,SPACE)
4023
+ end
4024
+ #「&」<-「&amp;」
4025
+ if element.include?(AND_2) then
4026
+ element.gsub!(@@pattern_and_2,AND_1)
4027
+ end
4028
+
4029
+ element
4030
+ end
4031
+ private :unescape
4032
+
4033
+ def unescapeContent(element,elmName)
4034
+ element = unescape(element)
4035
+
4036
+ if !isMatch(MATCH_TAG_2,elmName) then
4037
+ #「<br>」->「¥r?¥n」
4038
+ if element.include?(BR_2) then
4039
+ element.gsub!(@@pattern_br_2, @root.kaigyoCode)
4040
+ end
4041
+ end
4042
+
4043
+ element
4044
+ end
4045
+ private :unescapeContent
4046
+
4047
+ end
4048
+ end
4049
+
4050
+ module Xml
4051
+
4052
+ #
4053
+ # XMLパーサ
4054
+ #
4055
+ class ParserImpl < Meteor::Core::Kernel
4056
+
4057
+ @@pattern_and_1 = Regexp.new(AND_1)
4058
+ @@pattern_lt_1 = Regexp.new(LT_1)
4059
+ @@pattern_gt_1 = Regexp.new(GT_1)
4060
+ @@pattern_dq_1 = Regexp.new(DOUBLE_QUATATION)
4061
+ @@pattern_ap_1 = Regexp.new(AP_1)
4062
+ @@pattern_lt_2 = Regexp.new(LT_2)
4063
+ @@pattern_gt_2 = Regexp.new(GT_2)
4064
+ @@pattern_dq_2 = Regexp.new(QO_2)
4065
+ @@pattern_ap_2 = Regexp.new(AP_2)
4066
+ @@pattern_and_2 = Regexp.new(AND_2)
4067
+
4068
+ @@pattern_set_mono1 = Regexp.new(SET_MONO_1)
4069
+
4070
+ #
4071
+ # イニシャライザ
4072
+ #
4073
+ # @param [Array] args 引数配列
4074
+ #
4075
+ def initialize(*args)
4076
+ super(args)
4077
+
4078
+ case args.length
4079
+ when 0
4080
+ initialize_0
4081
+ when 1
4082
+ initialize_1(args[0])
4083
+ else
4084
+ raise ArgumentError
4085
+ end
4086
+ end
4087
+
4088
+ #
4089
+ # イニシャライザ
4090
+ #
4091
+ def initialize_0
4092
+ end
4093
+
4094
+ #
4095
+ # イニシャライザ
4096
+ #
4097
+ # @param [Meteor::Parser] ps パーサ
4098
+ #
4099
+ def initialize_1(ps)
4100
+ @root.document = String.new(ps.document)
4101
+ @root.hookDocument = String.new(ps.hookDocument)
4102
+ @root.hook = ps.hook
4103
+ @root.monoHook = ps.monoHook
4104
+ @root.contentType = String.new(ps.contentType);
4105
+ end
4106
+
4107
+ #
4108
+ # ドキュメントをパーサにセットする
4109
+ #
4110
+ # @param [String] document ドキュメント
4111
+ #
4112
+ def parse(document)
4113
+ @root.document = document
4114
+ end
4115
+
4116
+ #
4117
+ # ファイルを読み込み、パーサにセットする
4118
+ #
4119
+ # @param filePath ファイルパス
4120
+ # @param encoding エンコーディング
4121
+ #
4122
+ def read(filePath,encoding)
4123
+ super(filePath, encoding)
4124
+ end
4125
+
4126
+ # コンテントタイプを取得する
4127
+ #
4128
+ # @return [Streing]コンテントタイプ
4129
+ #
4130
+ def contentType()
4131
+ @root.contentType
4132
+ end
4133
+
4134
+ def setMonoInfo(elm)
4135
+
4136
+ @res = @@pattern_set_mono1.match(elm.mixed_content)
4137
+
4138
+ if @res then
4139
+ elm.mono = true
4140
+ if elm.cx then
4141
+ @pattern_cc = '' << SET_CX_1 << elm.name << SPACE << elm.attributes << SET_CX_2 << elm.mixed_content << SET_CX_3 << elm.name << SET_CX_4
4142
+ else
4143
+ if elm.empty then
4144
+ @pattern_cc = '' << TAG_OPEN << elm.name << elm.attributes << TAG_CLOSE << elm.mixed_content << TAG_OPEN3 << elm.name << TAG_CLOSE
4145
+ else
4146
+ @pattern_cc = '' << TAG_OPEN << elm.name << elm.attributes << TAG_CLOSE3
4147
+ end
4148
+ end
4149
+ elm.document = @pattern_cc
4150
+ end
4151
+ end
4152
+ private :setMonoInfo
4153
+
4154
+ def escape(element)
4155
+ #特殊文字の置換
4156
+ #「&」->「&amp;」
4157
+ if element.include?(AND_1) then
4158
+ element.gsub!(@@pattern_and_1,AND_2)
4159
+ end
4160
+ #「<」->「&lt;」
4161
+ if element.include?(LT_1) then
4162
+ element.gsub!(@@pattern_lt_1,LT_2)
4163
+ end
4164
+ #「>」->「&gt;」
4165
+ if element.include?(GT_1) then
4166
+ element.gsub!(@@pattern_gt_1,GT_2)
4167
+ end
4168
+ #「"」->「&quot;」
4169
+ if element.include?(DOUBLE_QUATATION) then
4170
+ element.gsub!(@@pattern_dq_1,QO_2)
4171
+ end
4172
+ #「'」->「&apos;」
4173
+ if element.include?(AP_1) then
4174
+ element.gsub!(@@pattern_ap_1,AP_2)
4175
+ end
4176
+
4177
+ element
4178
+ end
4179
+ private :escape
4180
+
4181
+ def escapeContent(element,elmName)
4182
+ escape(element)
4183
+ end
4184
+ private :escapeContent
4185
+
4186
+ def unescape(element)
4187
+ #特殊文字の置換
4188
+ #「<」<-「&lt;」
4189
+ if element.include?(LT_2) then
4190
+ element.gsub!(@@pattern_lt_2,LT_1)
4191
+ end
4192
+ #「>」<-「&gt;」
4193
+ if element.include?(GT_2) then
4194
+ element.gsub!(@@pattern_gt_2,GT_1)
4195
+ end
4196
+ #「"」<-「&quot;」
4197
+ if element.include?(QO_2) then
4198
+ element.gsub!(@@pattern_dq_2,DOUBLE_QUATATION)
4199
+ end
4200
+ #「'」<-「&apos;」
4201
+ if element.include?(AP_2) then
4202
+ element.gsub!(@@pattern_ap_2,AP_1)
4203
+ end
4204
+ #「&」<-「&amp;」
4205
+ if element.include?(AND_2) then
4206
+ element.gsub!(@@pattern_and_2,AND_1)
4207
+ end
4208
+
4209
+ element
4210
+ end
4211
+ private :unescape
4212
+
4213
+ def unescapeContent(element,elmName)
4214
+ unescape(element)
4215
+ end
4216
+ private :unescapeContent
4217
+
4218
+ end
4219
+ end
4220
+ end
4221
+ end