xmlparser 0.6.81

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/MANIFEST +112 -0
  2. data/README +697 -0
  3. data/README.ja +789 -0
  4. data/Rakefile +34 -0
  5. data/ext/encoding.h +91 -0
  6. data/ext/xmlparser/mkrf_conf.rb +28 -0
  7. data/ext/xmlparser/xmlparser.c +2226 -0
  8. data/lib/sax.rb +1 -0
  9. data/lib/saxdriver.rb +1 -0
  10. data/lib/wget.rb +47 -0
  11. data/lib/xml/dom/builder-ja.rb +58 -0
  12. data/lib/xml/dom/builder.rb +310 -0
  13. data/lib/xml/dom/core.rb +3276 -0
  14. data/lib/xml/dom/digest.rb +94 -0
  15. data/lib/xml/dom/visitor.rb +182 -0
  16. data/lib/xml/dom2/attr.rb +213 -0
  17. data/lib/xml/dom2/cdatasection.rb +76 -0
  18. data/lib/xml/dom2/characterdata.rb +177 -0
  19. data/lib/xml/dom2/comment.rb +81 -0
  20. data/lib/xml/dom2/core.rb +19 -0
  21. data/lib/xml/dom2/document.rb +317 -0
  22. data/lib/xml/dom2/documentfragment.rb +82 -0
  23. data/lib/xml/dom2/documenttype.rb +102 -0
  24. data/lib/xml/dom2/dombuilder.rb +277 -0
  25. data/lib/xml/dom2/dombuilderfilter.rb +12 -0
  26. data/lib/xml/dom2/domentityresolver.rb +13 -0
  27. data/lib/xml/dom2/domentityresolverimpl.rb +37 -0
  28. data/lib/xml/dom2/domexception.rb +95 -0
  29. data/lib/xml/dom2/domimplementation.rb +61 -0
  30. data/lib/xml/dom2/dominputsource.rb +29 -0
  31. data/lib/xml/dom2/element.rb +533 -0
  32. data/lib/xml/dom2/entity.rb +110 -0
  33. data/lib/xml/dom2/entityreference.rb +107 -0
  34. data/lib/xml/dom2/namednodemap.rb +138 -0
  35. data/lib/xml/dom2/node.rb +587 -0
  36. data/lib/xml/dom2/nodelist.rb +231 -0
  37. data/lib/xml/dom2/notation.rb +86 -0
  38. data/lib/xml/dom2/processinginstruction.rb +155 -0
  39. data/lib/xml/dom2/text.rb +128 -0
  40. data/lib/xml/dom2/xpath.rb +398 -0
  41. data/lib/xml/encoding-ja.rb +42 -0
  42. data/lib/xml/parser.rb +13 -0
  43. data/lib/xml/parserns.rb +236 -0
  44. data/lib/xml/sax.rb +353 -0
  45. data/lib/xml/saxdriver.rb +370 -0
  46. data/lib/xml/xpath.rb +3284 -0
  47. data/lib/xml/xpath.ry +2352 -0
  48. data/lib/xmldigest.rb +1 -0
  49. data/lib/xmltree.rb +1 -0
  50. data/lib/xmltreebuilder.rb +1 -0
  51. data/lib/xmltreevisitor.rb +1 -0
  52. metadata +111 -0
data/lib/xml/xpath.ry ADDED
@@ -0,0 +1,2352 @@
1
+ #
2
+ # xpath.ry
3
+ #
4
+ # Copyright (C) Ueno Katsuhiro 2000
5
+ #
6
+ # $Id: xpath.ry,v 1.2 2003/03/12 06:38:21 yoshidam Exp $
7
+ #
8
+
9
+ class Compiler
10
+
11
+ prechigh
12
+ left '|'
13
+ right NEG
14
+ left MUL 'div' 'mod'
15
+ left '+' '-'
16
+ left '<' '>' '<=' '>='
17
+ left '=' '!='
18
+ left 'and'
19
+ left 'or'
20
+ preclow
21
+
22
+ options no_result_var
23
+
24
+
25
+ rule
26
+
27
+ xPath: # none #
28
+ { [] }
29
+ | expr
30
+ {
31
+ expr = val[0].expr('.to_ruby')
32
+ expr.collect! { |i| i or @context }
33
+ expr
34
+ }
35
+ | PATTERN pattern # for XSLT
36
+ {
37
+ expr = val[0].expr('.to_ruby')
38
+ expr.collect! { |i| i or @context }
39
+ expr
40
+ }
41
+
42
+ pattern: locationPath
43
+ | pattern '|' locationPath
44
+ { val[0] ** val[2] }
45
+
46
+ expr: expr 'or' expr
47
+ { val[0].logical_or val[2] }
48
+ | expr 'and' expr
49
+ { val[0].logical_and val[2] }
50
+ | expr '=' expr
51
+ { val[0].eq val[2] }
52
+ | expr '!=' expr
53
+ { val[0].neq val[2] }
54
+ | expr '<' expr
55
+ { val[0].lt val[2] }
56
+ | expr '>' expr
57
+ { val[0].gt val[2] }
58
+ | expr '<=' expr
59
+ { val[0].le val[2] }
60
+ | expr '>=' expr
61
+ { val[0].ge val[2] }
62
+ | expr '+' expr
63
+ { val[0] + val[2] }
64
+ | expr '-' expr
65
+ { val[0] - val[2] }
66
+ | '-' expr =NEG
67
+ { -val[1] }
68
+ | expr MUL expr
69
+ { val[0] * val[2] }
70
+ | expr 'div' expr
71
+ { val[0] / val[2] }
72
+ | expr 'mod' expr
73
+ { val[0] % val[2] }
74
+ | expr '|' expr
75
+ {
76
+ # Why `**' is used for unionizing node-sets is that its
77
+ # precedence is higher than any other binary operators
78
+ # in Ruby.
79
+ val[0] ** val[2]
80
+ }
81
+ | locationPath
82
+ | filterExpr
83
+ | filterExpr '/' relPath
84
+ { val[0] << val[2] }
85
+ | filterExpr '//' relPath
86
+ { val[0].add_step('descendant-or-self') << val[2] }
87
+
88
+ filterExpr: Variable
89
+ {
90
+ Expression.new [ nil,'.get_variable(',val[0].dump,')' ]
91
+ }
92
+ | '(' expr ')'
93
+ { val[1].unarize }
94
+ | Literal
95
+ { Expression.new StringConstant.new(val[0]) }
96
+ | Number
97
+ { Expression.new NumberConstant.new(val[0]) }
98
+ | functionCall
99
+ { Expression.new val[0] }
100
+ | filterExpr predicate
101
+ { val[0].add_predicate val[1] }
102
+
103
+ functionCall: FuncName '(' arguments ')'
104
+ {
105
+ val[2][0,0] = [ nil, ".funcall(#{val[0].dump}" ]
106
+ val[2].push(')')
107
+ }
108
+
109
+ arguments: # none #
110
+ { [] }
111
+ | expr
112
+ { val[0].expr.unshift ', ' }
113
+ | arguments ',' expr
114
+ { val[0].push(', ').concat(val[2].expr) }
115
+
116
+ predicate: '['
117
+ {
118
+ c = @context
119
+ @context = c.succ
120
+ c
121
+ }
122
+ expr
123
+ {
124
+ c = @context
125
+ @context = _values[-2]
126
+ c
127
+ }
128
+ ']'
129
+ {
130
+ expr = val[2]
131
+ valuetype = expr.value_type
132
+ value = expr.value
133
+ if valuetype == :number then
134
+ if value then
135
+ f = value.to_f
136
+ if f > 0 and f.truncate == f then
137
+ [ ".at(#{f.to_i})" ]
138
+ else
139
+ [ '.at(0)' ] # clear
140
+ end
141
+ else
142
+ expr.expr('.to_f').
143
+ unshift('.at(').push(')')
144
+ end
145
+ elsif value then
146
+ if value.true? then
147
+ []
148
+ else
149
+ [ '.at(0)' ] # clear
150
+ end
151
+ else
152
+ c = val[3]
153
+ if valuetype == :ruby_boolean then
154
+ conv = '.true?'
155
+ else
156
+ conv = '.to_predicate'
157
+ end
158
+ a = expr.expr(conv)
159
+ a.collect! { |i| i or c }
160
+ a.unshift(".predicate { |#{c}| ").push(' }')
161
+ end
162
+ }
163
+
164
+ locationPath: '/'
165
+ { LocationPath.new.absolute! }
166
+ | '/' relPath
167
+ { val[1].absolute! }
168
+ | '//' relPath
169
+ {
170
+ path = LocationPath.new
171
+ path.absolute!
172
+ path.add_step('descendant-or-self') << val[1]
173
+ }
174
+ | relPath
175
+
176
+ relPath: step
177
+ { LocationPath.new.add_step(*val[0]) }
178
+ | relPath '/' step
179
+ { val[0].add_step(*val[2]) }
180
+ | relPath '//' step
181
+ {
182
+ val[0].add_step('descendant-or-self').add_step(*val[2])
183
+ }
184
+ # XPath does not permit functions here, but XPointer does.
185
+ | relPath '/' FuncName '('
186
+ {
187
+ c = @context
188
+ @context = c.succ
189
+ c
190
+ }
191
+ arguments
192
+ {
193
+ c = @context
194
+ @context = _values[-2]
195
+ c
196
+ }
197
+ ')'
198
+ {
199
+ on_error unless is_xpointer?
200
+ args = val[5]
201
+ c = val[6]
202
+ args.collect! { |i| i or c }
203
+ args[0] = ".funcall(#{val[2].dump}) { |#{c}| ["
204
+ args.push '] }'
205
+ val[0].add_predicate args
206
+ }
207
+
208
+ step: '.'
209
+ { [ 'self', false, false, false, nil ] }
210
+ | '..'
211
+ { [ 'parent', false, false, false, nil ] }
212
+ | axisSpec nodeTest predicates
213
+ {
214
+ nodetest = val[1]
215
+ unless nodetest[0] then
216
+ axis = val[0]
217
+ if axis != 'attribute' and axis != 'namespace' then
218
+ nodetest[0] = 'element'
219
+ end
220
+ end
221
+ nodetest[0] = false if nodetest[0] == 'node'
222
+ nodetest.unshift(val[0]).push(val[2])
223
+ }
224
+
225
+ predicates: # none #
226
+ | predicates predicate
227
+ { (val[0] || []).concat val[1] }
228
+
229
+ nodeTest: '*'
230
+ { [ false, false, false ] }
231
+ | Name
232
+ {
233
+ if /:/ =~ val[0] then
234
+ [ false, $', $` ] #' <= for racc
235
+ else
236
+ [ false, val[0], nil ]
237
+ end
238
+ }
239
+ | Name ':' '*'
240
+ {
241
+ on_error if /:/ =~ val[0]
242
+ [ false, false, val[0] ]
243
+ }
244
+ | NodeType '(' nodeTestArg ')'
245
+ {
246
+ nodetype = val[0]
247
+ arg = val[2]
248
+ if arg and nodetype != 'processing-instruction' then
249
+ raise CompileError,
250
+ "nodetest #{nodetype}() requires no argument"
251
+ end
252
+ [ nodetype, arg || false, false ]
253
+ }
254
+
255
+ nodeTestArg: # none #
256
+ | Literal
257
+
258
+ axisSpec: # none #
259
+ { 'child' }
260
+ | '@'
261
+ { 'attribute' }
262
+ | AxisName '::'
263
+
264
+ end
265
+
266
+
267
+ ---- inner ----
268
+
269
+ module CompilePhaseObject
270
+
271
+ def invoke_conv(expr, conv_method)
272
+ return unless conv_method
273
+ if conv_method == '.to_number' or
274
+ conv_method == '.to_string' or
275
+ conv_method == '.to_boolean' then
276
+ expr.push conv_method, '(', nil, ')'
277
+ else
278
+ expr.push conv_method
279
+ end
280
+ end
281
+ private :invoke_conv
282
+
283
+ end
284
+
285
+
286
+ module ConstantObject
287
+
288
+ include CompilePhaseObject
289
+
290
+ def to_string
291
+ StringConstant.new to_str
292
+ end
293
+
294
+ def to_number
295
+ NumberConstant.new self
296
+ end
297
+
298
+ def to_boolean
299
+ if true? then
300
+ ConstantTrue
301
+ else
302
+ ConstantFalse
303
+ end
304
+ end
305
+
306
+ end
307
+
308
+
309
+ module BooleanConstant
310
+
311
+ include ConstantObject
312
+
313
+ def value_type
314
+ :boolean
315
+ end
316
+
317
+ def expr(conv_method = nil)
318
+ if conv_method == '.to_ruby' or conv_method == '.true?' then
319
+ [ true?.to_s ]
320
+ else
321
+ ret = [ nil, '.make_boolean(', true?.to_s, ')' ]
322
+ invoke_conv ret, conv_method unless conv_method == '.to_boolean'
323
+ ret
324
+ end
325
+ end
326
+
327
+ end
328
+
329
+ class ConstantTrueClass < XPathTrueClass
330
+ include BooleanConstant
331
+ @instance = new
332
+ end
333
+
334
+ class ConstantFalseClass < XPathFalseClass
335
+ include BooleanConstant
336
+ @instance = new
337
+ end
338
+
339
+ ConstantTrue = ConstantTrueClass.instance
340
+ ConstantFalse = ConstantFalseClass.instance
341
+
342
+
343
+
344
+ class NumberConstant < XPathNumber
345
+
346
+ include ConstantObject
347
+
348
+ def value_type
349
+ :number
350
+ end
351
+
352
+ def initialize(src)
353
+ f = src.to_f
354
+ if src.is_a? ConstantObject and s = dump_float(f) then
355
+ src = s
356
+ end
357
+ @src = [ src ]
358
+ @precedence = 1
359
+ super f
360
+ end
361
+
362
+ attr_reader :precedence
363
+ protected :precedence
364
+
365
+ def to_number
366
+ self
367
+ end
368
+
369
+
370
+ def expr(conv_method = nil)
371
+ @src.collect! { |i|
372
+ if i.is_a? ConstantObject then
373
+ i.expr '.to_f'
374
+ else
375
+ i
376
+ end
377
+ }
378
+ expr = @src
379
+ expr.flatten!
380
+ @src = :draff # for debug
381
+ unless conv_method == '.to_ruby' or conv_method == '.to_f' then
382
+ expr[0, 0] = [ nil, '.make_number(' ]
383
+ expr.push(')')
384
+ invoke_conv expr, conv_method unless conv_method == '.to_number'
385
+ end
386
+ expr
387
+ end
388
+
389
+
390
+ private
391
+
392
+ def dump_float(f)
393
+ if f.finite? and f == eval(s = f.to_s) then
394
+ s
395
+ elsif f.infinite? then
396
+ if f > 0 then
397
+ '(1.0 / 0.0)'
398
+ else
399
+ '(-1.0 / 0.0)'
400
+ end
401
+ elsif f.nan? then
402
+ '(0.0 / 0.0)'
403
+ else
404
+ nil
405
+ end
406
+ end
407
+
408
+
409
+ def concat(op, other, prec)
410
+ @src.unshift('(').push(')') if @precedence < prec
411
+ if other.precedence < prec then
412
+ @src.push(op).push('(').concat(other.expr('.to_f')).push(')')
413
+ else
414
+ @src.push(op).concat(other.expr('.to_f'))
415
+ end
416
+ @precedence = prec
417
+ end
418
+
419
+
420
+ public
421
+
422
+ def self.def_arithmetic_operator(op, precedence)
423
+ module_eval <<_, __FILE__, __LINE__ + 1
424
+ def #{op}(other)
425
+ super other
426
+ if s = dump_float(@value) then
427
+ @src.clear
428
+ @src.push s
429
+ else
430
+ concat ' #{op} ', other, #{precedence}
431
+ end
432
+ self
433
+ end
434
+ _
435
+ end
436
+
437
+ def_arithmetic_operator '+', 0
438
+ def_arithmetic_operator '-', 0
439
+ def_arithmetic_operator '*', 1
440
+ def_arithmetic_operator '/', 1
441
+
442
+ class << self
443
+ undef def_arithmetic_operator
444
+ end
445
+
446
+ def %(other)
447
+ orig = @value
448
+ super other
449
+ if s = dump_float(@value) then
450
+ @src.clear
451
+ @src.push s
452
+ else
453
+ f = other.to_f
454
+ other = -other if orig % f == -@value
455
+ concat ' % ', other, 1
456
+ end
457
+ self
458
+ end
459
+
460
+ def -@
461
+ super
462
+ if s = dump_float(@value) then
463
+ @src.clear
464
+ @src.push s
465
+ else
466
+ if @src.size == 1 then
467
+ @src.unshift '-'
468
+ else
469
+ @src.unshift('-(').push(')')
470
+ end
471
+ @precedence = 1
472
+ end
473
+ self
474
+ end
475
+
476
+ end
477
+
478
+
479
+
480
+ class StringConstant < XPathString
481
+
482
+ include ConstantObject
483
+
484
+ def value_type
485
+ :string
486
+ end
487
+
488
+ def to_string
489
+ self
490
+ end
491
+
492
+ def expr(conv_method = nil)
493
+ if conv_method == '.to_ruby' or conv_method == '.to_str' then
494
+ [ @value.dump ]
495
+ else
496
+ ret = [ nil, '.make_string(', @value.dump, ')' ]
497
+ invoke_conv ret, conv_method unless conv_method == '.to_string'
498
+ ret
499
+ end
500
+ end
501
+
502
+ end
503
+
504
+
505
+
506
+ class Expression
507
+
508
+ include CompilePhaseObject
509
+
510
+ def initialize(expr)
511
+ if expr.is_a? ConstantObject then
512
+ @value = expr
513
+ else
514
+ raise "BUG" unless expr.is_a? Array
515
+ @value = nil
516
+ @valuetype = nil
517
+ @expr = expr
518
+ end
519
+ @unary = true
520
+ end
521
+
522
+ attr_reader :value
523
+
524
+
525
+ def value_type
526
+ if @value then
527
+ @value.value_type
528
+ else
529
+ @valuetype
530
+ end
531
+ end
532
+
533
+
534
+ def unarize
535
+ unless @unary then
536
+ @expr.unshift('(').push(')')
537
+ @unary = true
538
+ end
539
+ self
540
+ end
541
+
542
+
543
+ def self.def_comparison_operator(name, op)
544
+ module_eval <<_, __FILE__, __LINE__ + 1
545
+ def #{name}(other)
546
+ if @value and other.value then
547
+ if @value #{op} other.value then
548
+ @value = ConstantTrue
549
+ else
550
+ @value = ConstantFalse
551
+ end
552
+ @unary = true
553
+ else
554
+ @expr = expr.push(' #{op} ').concat(other.expr)
555
+ @valuetype = :ruby_boolean
556
+ @unary = false
557
+ end
558
+ self
559
+ end
560
+ _
561
+ end
562
+
563
+ def self.def_arithmetic_operator(*ops)
564
+ ops.each { |op|
565
+ module_eval <<_, __FILE__, __LINE__ + 1
566
+ def #{op}(other)
567
+ if @value and other.value then
568
+ @value = @value.to_number #{op} other.value.to_number
569
+ else
570
+ @expr = expr('.to_number').push(' #{op} ')
571
+ # not 'to_number', for a little speed up :-)
572
+ @expr.concat other.expr('.to_f')
573
+ @valuetype = :number
574
+ @unary = false
575
+ end
576
+ self
577
+ end
578
+ _
579
+ }
580
+ end
581
+
582
+ def_comparison_operator 'eq', '=='
583
+ def_comparison_operator 'neq', '!='
584
+ def_comparison_operator 'lt', '<'
585
+ def_comparison_operator 'gt', '>'
586
+ def_comparison_operator 'le', '<='
587
+ def_comparison_operator 'ge', '>='
588
+ def_arithmetic_operator '+', '-', '*', '/', '%'
589
+
590
+ class << self
591
+ undef def_comparison_operator
592
+ undef def_arithmetic_operator
593
+ end
594
+
595
+ def -@
596
+ if @value then
597
+ @value = -@value.to_number
598
+ else
599
+ unarize
600
+ @expr = expr('.to_number').unshift('-')
601
+ end
602
+ self
603
+ end
604
+
605
+ def logical_or(other)
606
+ if @value and @value.true? then
607
+ @value = ConstantTrue
608
+ @unary = true
609
+ @expr = @valuetype = nil
610
+ else
611
+ @expr = expr('.true?').push(' || ').concat(other.expr('.true?'))
612
+ @valuetype = :ruby_boolean
613
+ @unary = false
614
+ end
615
+ self
616
+ end
617
+
618
+ def logical_and(other)
619
+ if @value and not @value.true? then
620
+ @value = ConstantFalse
621
+ @unary = true
622
+ @expr = @valuetype = nil
623
+ else
624
+ @expr = expr('.true?').push(' && ').concat(other.expr('.true?'))
625
+ @valuetype = :ruby_boolean
626
+ @unary = false
627
+ end
628
+ self
629
+ end
630
+
631
+ def **(other)
632
+ @expr = expr.push(' ** ').concat(other.expr)
633
+ @valuetype = nil
634
+ @unary = false
635
+ self
636
+ end
637
+
638
+
639
+ def add_predicate(pred)
640
+ unarize
641
+ @expr = expr.concat(pred)
642
+ @valuetype = nil
643
+ self
644
+ end
645
+
646
+ def <<(other)
647
+ path = other.expr
648
+ path.shift # nil
649
+ path.shift # .to_nodeset
650
+ add_predicate path
651
+ end
652
+
653
+ def add_step(axis)
654
+ add_predicate [ ".step(:#{axis.tr('-','_')})" ]
655
+ end
656
+
657
+
658
+ def expr(conv_method = nil)
659
+ if @value then
660
+ ret = @value.expr(conv_method)
661
+ @value = nil
662
+ elsif @valuetype == :ruby_boolean then
663
+ ret = @expr
664
+ unless conv_method == '.to_ruby' or conv_method == '.true?' then
665
+ ret[0, 0] = [ nil, '.make_boolean(' ]
666
+ ret.push ')'
667
+ invoke_conv ret, conv_method unless conv_method == '.to_boolean'
668
+ end
669
+ elsif @valuetype == :number and conv_method == '.to_number' then
670
+ ret = @expr
671
+ elsif @valuetype == :string and conv_method == '.to_string' then
672
+ ret = @expr
673
+ elsif @valuetype == :boolean and conv_method == '.to_boolean' then
674
+ ret = @expr
675
+ else
676
+ if conv_method then
677
+ unarize
678
+ invoke_conv @expr, conv_method
679
+ end
680
+ ret = @expr
681
+ end
682
+ @expr = :draff # for debug
683
+ ret
684
+ end
685
+
686
+ end
687
+
688
+
689
+
690
+ class LocationPath
691
+
692
+ include CompilePhaseObject
693
+
694
+ def initialize
695
+ @root = false
696
+ @steps = [] # [ axis, [ tests ], predicates ]
697
+ end
698
+
699
+ attr_reader :root, :steps
700
+ protected :root, :steps
701
+
702
+ def absolute!
703
+ @root = true
704
+ self
705
+ end
706
+
707
+
708
+ def add_step(axis, nodetype = false, localpart = false,
709
+ namespace = false, predicate = nil)
710
+ if nodetype == false and localpart == false and namespace == false then
711
+ append_step axis, [], predicate
712
+ else
713
+ append_step axis, [ [ nodetype, localpart, namespace ] ], predicate
714
+ end
715
+ self
716
+ end
717
+
718
+
719
+ def <<(other)
720
+ raise "BUG" if other.root
721
+ other = other.steps
722
+ other.each { |step|
723
+ if step[0] then
724
+ append_step(*step)
725
+ else
726
+ add_predicate(step[2])
727
+ end
728
+ }
729
+ self
730
+ end
731
+
732
+
733
+ def add_predicate(pred)
734
+ @steps.push [ nil, nil, pred ]
735
+ self
736
+ end
737
+
738
+
739
+ def **(other)
740
+ unless other.is_a? LocationPath then
741
+ ret = nil
742
+ else
743
+ othersteps = other.steps
744
+ size = @steps.size
745
+ unless size == othersteps.size then
746
+ othersize = othersteps.size
747
+ if size >= othersize then
748
+ ret = (@steps[0, othersize] == othersize and self)
749
+ else
750
+ ret = (othersteps[0, size] == @steps and other)
751
+ end
752
+ else
753
+ last = @steps.pop
754
+ otherlast = othersteps.pop
755
+ if @steps == othersteps and mix_step(last, otherlast) then
756
+ ret = self
757
+ else
758
+ ret = nil
759
+ end
760
+ @steps.push last
761
+ othersteps.push otherlast
762
+ end
763
+ end
764
+ ret or Expression.new(expr) ** other
765
+ end
766
+
767
+
768
+ private
769
+
770
+ UnifiableAxes = {
771
+ 'descendant' => {
772
+ 'descendant-or-self' => 'descendant',
773
+ },
774
+ 'descendant-or-self' => {
775
+ 'child' => 'descendant',
776
+ 'descendant' => 'descendant',
777
+ 'descendant-or-self' => 'descendant-or-self',
778
+ },
779
+ 'ancestor' => {
780
+ 'ancestor-or-self' => 'ancestor',
781
+ },
782
+ 'ancestor-or-self' => {
783
+ 'parent' => 'ancestor',
784
+ 'ancestor' => 'ancestor',
785
+ 'ancestor-or-self' => 'ancestor-or-self',
786
+ },
787
+ 'following-sibling' => {
788
+ 'following-sibling' => 'following-sibling',
789
+ },
790
+ 'preceding-sibling' => {
791
+ 'preceding-sibling' => 'preceding-sibling',
792
+ },
793
+ 'following' => {
794
+ 'following' => 'following',
795
+ 'following-sibling' => 'following',
796
+ },
797
+ 'preceding' => {
798
+ 'preceding' => 'preceding',
799
+ 'preceding-sibling' => 'preceding',
800
+ },
801
+ 'child' => {
802
+ 'following-sibling' => 'child',
803
+ 'preceding-sibling' => 'child',
804
+ },
805
+ }
806
+ UnifiableAxes.default = {}
807
+
808
+
809
+ def append_step(axis, test, predicate)
810
+ lastaxis, lasttest, lastpred = laststep = @steps.last
811
+ if axis == 'self' and test.empty? then
812
+ @steps.push [ nil, nil, predicate ] if predicate
813
+ elsif lastaxis and lasttest.empty? and
814
+ not lastpred and not predicate and
815
+ w = UnifiableAxes[lastaxis][axis] then
816
+ laststep[0] = w
817
+ laststep[1] = test
818
+ else
819
+ @steps.push [ axis, test, predicate ]
820
+ end
821
+ end
822
+
823
+
824
+ def mix_step(step, other)
825
+ if step[0] and step[0] == other[0] and step[2] == other[2] then
826
+ step[1].concat other[1]
827
+ step
828
+ else
829
+ nil
830
+ end
831
+ end
832
+
833
+
834
+ public
835
+
836
+ def expr(conv_method = nil)
837
+ if @root then
838
+ expr = [ nil, '.root_nodeset' ]
839
+ else
840
+ expr = [ nil, '.to_nodeset' ]
841
+ end
842
+ @steps.each { |axis,test,predicate|
843
+ if axis.nil? then # predicate only
844
+ expr.concat predicate
845
+ elsif test.empty? and not predicate then
846
+ expr.push ".select_all(:#{axis.tr('-','_')})"
847
+ else
848
+ expr.push ".step(:#{axis.tr('-','_')})"
849
+ if test.empty? then
850
+ expr.push ' { |n| n.select_all'
851
+ else
852
+ expr.push ' { |n| n.select { |i| '
853
+ test.each { |nodetype,localpart,namespace|
854
+ if nodetype then
855
+ expr.push "i.node_type == :#{nodetype.tr('-','_')}", ' && '
856
+ end
857
+ if localpart then
858
+ expr.push "i.name_localpart == #{localpart.dump}", ' && '
859
+ end
860
+ if namespace.nil? then
861
+ expr.push 'i.namespace_uri.nil?', ' && '
862
+ elsif namespace then
863
+ namespace = namespace.dump
864
+ expr.push('i.namespace_uri == ', nil,
865
+ ".get_namespace(#{namespace})", ' && ')
866
+ end
867
+ expr[-1] = ' or '
868
+ }
869
+ expr[-1] = ' }'
870
+ end
871
+ expr.concat predicate if predicate
872
+ expr.push ' }'
873
+ end
874
+ }
875
+ @steps = :draff # for debug
876
+ invoke_conv expr, conv_method
877
+ expr
878
+ end
879
+
880
+
881
+ def value_type
882
+ nil
883
+ end
884
+
885
+ def value
886
+ nil
887
+ end
888
+
889
+ def unarize
890
+ self
891
+ end
892
+
893
+ def self.redirect_to_expr(*ops)
894
+ ops.each { |op|
895
+ name = op
896
+ name = op[1..-1] if op[0] == ?.
897
+ module_eval <<_, __FILE__, __LINE__ + 1
898
+ def #{name}(arg) ; Expression.new(expr) #{op} arg ; end
899
+ _
900
+ }
901
+ end
902
+
903
+ redirect_to_expr('.eq', '.neq', '.lt', '.gt', '.le', '.ge',
904
+ '+', '-', '*', '/', '%', '.logical_or', '.logical_and')
905
+
906
+ class << self
907
+ undef redirect_to_expr
908
+ end
909
+
910
+ def -@
911
+ -Expression.new(expr)
912
+ end
913
+
914
+ end
915
+
916
+
917
+
918
+
919
+ Delim = '\\s\\(\\)\\[\\]\\.@,\\/\\|\\*\\+"\'=!<>:'
920
+ Name = "[^-#{Delim}][^#{Delim}]*"
921
+
922
+ Operator = {
923
+ '@' => true, '::' => true, '(' => true, '[' => true,
924
+ :MUL => true, 'and' => true, 'or' => true, 'mod' => true, 'div' => true,
925
+ '/' => true, '//' => true, '|' => true, '+' => true,
926
+ '-' => true, '=' => true, '!=' => true, '<' => true,
927
+ '<=' => true, '>' => true, '>=' => true,
928
+ ':' => false
929
+ # ':' '*' => '*' must not be a MultiplyOperator
930
+ # ':' 'and' => 'and' must be a OperatorName
931
+ }
932
+
933
+ NodeType = {
934
+ 'comment' => true,
935
+ 'text' => true,
936
+ 'processing-instruction' => true,
937
+ 'node' => true,
938
+ }
939
+
940
+
941
+ private
942
+
943
+ def axis?(s)
944
+ /\A[-a-zA-Z]+\z/ =~ s
945
+ end
946
+
947
+ def nodetype?(s)
948
+ NodeType.key? s
949
+ end
950
+
951
+ def tokenize(src)
952
+ token = []
953
+ src.scan(/(\.\.?|\/\/?|::?|!=|[<>]=?|[-()\[\].@,|+=*])|
954
+ ("[^"]*"|'[^']*')|(\d+\.?\d*)|
955
+ (\$?#{Name}(?::#{Name})?)|
956
+ \s+|./ox) { |delim,literal,number,name| #/
957
+ if delim then
958
+ if delim == '*' then
959
+ delim = :MUL if (prev = token[-1]) and not Operator.key? prev[0]
960
+ elsif delim == '::' then
961
+ prev = token[-1]
962
+ if prev and prev[0] == :Name and axis? prev[1] then
963
+ prev[0] = :AxisName
964
+ end
965
+ elsif delim == '(' then
966
+ if (prev = token[-1]) and prev[0] == :Name then
967
+ if nodetype? prev[1] then
968
+ prev[0] = :NodeType
969
+ else
970
+ prev[0] = :FuncName
971
+ end
972
+ end
973
+ end
974
+ token.push [ delim, delim ]
975
+ elsif name then
976
+ prev = token[-1]
977
+ if name[0] == ?$ then
978
+ name[0,1] = ''
979
+ token.push [ :Variable, name ]
980
+ elsif Operator.key? name and
981
+ (prev = token[-1]) and not Operator[prev[0]] then
982
+ token.push [ name, name ]
983
+ else
984
+ token.push [ :Name, name ]
985
+ end
986
+ elsif number then
987
+ number << '.0' unless number.include? ?.
988
+ token.push [ :Number, number ]
989
+ elsif literal then
990
+ literal.chop!
991
+ literal[0,1] = ''
992
+ token.push [ :Literal, literal ]
993
+ else
994
+ s = $&.strip
995
+ token.push [ s, s ] unless s.empty?
996
+ end
997
+ }
998
+ token
999
+ end
1000
+
1001
+
1002
+ public
1003
+
1004
+ def compile(src, pattern = false)
1005
+ @token = tokenize(src)
1006
+ @token.push [ false, :end ]
1007
+ @token.each { |i| p i } if @yydebug
1008
+ @token.reverse!
1009
+ @token.push [ :PATTERN, nil ] if pattern
1010
+ @context = 'context0'
1011
+ ret = do_parse
1012
+ ret = ret.unshift("proc { |context0| ").push(" }").join
1013
+ print ">>>>\n", ret, "\n<<<<\n" if @yydebug
1014
+ XPathProc.new eval(ret), src
1015
+ end
1016
+
1017
+
1018
+ def initialize(debug = false)
1019
+ super()
1020
+ @yydebug = debug
1021
+ end
1022
+
1023
+
1024
+ private
1025
+
1026
+ def next_token
1027
+ @token.pop
1028
+ end
1029
+
1030
+
1031
+ def is_xpointer?
1032
+ false
1033
+ end
1034
+
1035
+
1036
+ def on_error(*args) # tok, val, values
1037
+ raise CompileError, 'parse error'
1038
+ end
1039
+
1040
+
1041
+ ---- header ----
1042
+ #
1043
+ # xpath.rb : generated by racc
1044
+ #
1045
+
1046
+ module XPath
1047
+
1048
+ class Error < StandardError ; end
1049
+ class CompileError < Error ; end
1050
+ class TypeError < Error ; end
1051
+ class NameError < Error ; end
1052
+ class ArgumentError < Error ; end
1053
+ class InvalidOperation < Error ; end
1054
+
1055
+
1056
+ class XPathProc
1057
+
1058
+ def initialize(proc, source)
1059
+ @proc = proc
1060
+ @source = source
1061
+ end
1062
+
1063
+ attr_reader :source
1064
+
1065
+ def call(context)
1066
+ @proc.call context
1067
+ end
1068
+
1069
+ end
1070
+
1071
+
1072
+ def self.compile(src, pattern = false)
1073
+ @compiler = Compiler.new unless defined? @compiler
1074
+ @compiler.compile src, pattern
1075
+ end
1076
+
1077
+
1078
+
1079
+ module XPathObject
1080
+
1081
+ def _type
1082
+ type.name.sub(/\A.*::(?:XPath)?(?=[^:]+\z)/, '')
1083
+ end
1084
+ private :_type
1085
+
1086
+ def type_error(into)
1087
+ raise XPath::TypeError, "failed to convert #{_type} into #{into}"
1088
+ end
1089
+ private :type_error
1090
+
1091
+
1092
+ def to_str # => to Ruby String
1093
+ type_error 'String'
1094
+ end
1095
+
1096
+ def to_f # => to Ruby Float
1097
+ type_error 'Float'
1098
+ end
1099
+
1100
+ def true? # => to Ruby Boolean
1101
+ type_error 'Boolean'
1102
+ end
1103
+
1104
+ def to_ruby # => to Ruby Object
1105
+ self
1106
+ end
1107
+
1108
+ def to_predicate # => to Ruby Float, true or false. shouldn't override.
1109
+ true?
1110
+ end
1111
+
1112
+
1113
+ def to_string(context) # => to XPath String. shouldn't override.
1114
+ context.make_string to_str
1115
+ end
1116
+
1117
+ def to_number(context) # => to XPath Number. shouldn't override.
1118
+ context.make_number to_f
1119
+ end
1120
+
1121
+ def to_boolean(context) # => to XPath Boolean. shouldn't override.
1122
+ context.make_boolean true?
1123
+ end
1124
+
1125
+
1126
+ public
1127
+
1128
+ # called from compiled XPath expression
1129
+
1130
+ def ==(other)
1131
+ if other.is_a? XPathNodeSet or
1132
+ other.is_a? XPathBoolean or other.is_a? XPathNumber then
1133
+ other == self
1134
+ else
1135
+ to_str == other.to_str
1136
+ end
1137
+ end
1138
+
1139
+ def <(other)
1140
+ if other.is_a? XPathNodeSet then
1141
+ other > self
1142
+ else
1143
+ to_f < other.to_f
1144
+ end
1145
+ end
1146
+
1147
+ def >(other)
1148
+ if other.is_a? XPathNodeSet then
1149
+ other < self
1150
+ else
1151
+ to_f > other.to_f
1152
+ end
1153
+ end
1154
+
1155
+ def <=(other)
1156
+ if other.is_a? XPathNodeSet then
1157
+ other >= self
1158
+ else
1159
+ to_f <= other.to_f
1160
+ end
1161
+ end
1162
+
1163
+ def >=(other)
1164
+ if other.is_a? XPathNodeSet then
1165
+ other <= self
1166
+ else
1167
+ to_f >= other.to_f
1168
+ end
1169
+ end
1170
+
1171
+ def **(other)
1172
+ type_error 'NodeSet'
1173
+ end
1174
+
1175
+ def predicate(&block)
1176
+ type_error 'NodeSet'
1177
+ end
1178
+
1179
+ def at(pos)
1180
+ type_error 'NodeSet'
1181
+ end
1182
+
1183
+ def funcall(name) # for XPointer
1184
+ raise XPath::NameError, "undefined function `#{name}' for #{_type}"
1185
+ end
1186
+
1187
+ end
1188
+
1189
+
1190
+
1191
+
1192
+ class XPathBoolean
1193
+
1194
+ include XPathObject
1195
+
1196
+ class << self
1197
+ attr_reader :instance
1198
+ private :new
1199
+ end
1200
+
1201
+ def to_str
1202
+ true?.to_s
1203
+ end
1204
+
1205
+ # def to_f
1206
+ # def true?
1207
+
1208
+ def to_ruby
1209
+ true?
1210
+ end
1211
+
1212
+ def to_boolean(context)
1213
+ self
1214
+ end
1215
+
1216
+ def ==(other)
1217
+ true? == other.true?
1218
+ end
1219
+
1220
+ end
1221
+
1222
+
1223
+ class XPathTrueClass < XPathBoolean
1224
+
1225
+ @instance = new
1226
+
1227
+ def to_f
1228
+ 1.0
1229
+ end
1230
+
1231
+ def true?
1232
+ true
1233
+ end
1234
+
1235
+ end
1236
+
1237
+
1238
+ class XPathFalseClass < XPathBoolean
1239
+
1240
+ @instance = new
1241
+
1242
+ def to_f
1243
+ 0.0
1244
+ end
1245
+
1246
+ def true?
1247
+ false
1248
+ end
1249
+
1250
+ end
1251
+
1252
+
1253
+ XPathTrue = XPathTrueClass.instance
1254
+ XPathFalse = XPathFalseClass.instance
1255
+
1256
+
1257
+
1258
+
1259
+ class XPathNumber
1260
+
1261
+ include XPathObject
1262
+
1263
+ def initialize(num)
1264
+ raise ::TypeError, "must be a Float" unless num.is_a? Float
1265
+ @value = num
1266
+ end
1267
+
1268
+ def to_str
1269
+ if @value.nan? then
1270
+ 'NaN'
1271
+ elsif @value.infinite? then
1272
+ if @value < 0 then
1273
+ '-Infinity'
1274
+ else
1275
+ 'Infinity'
1276
+ end
1277
+ else
1278
+ sprintf("%.100f", @value).gsub(/\.?0+\z/, '') # enough?
1279
+ end
1280
+ end
1281
+
1282
+ def to_f
1283
+ @value
1284
+ end
1285
+
1286
+ def true?
1287
+ @value != 0.0 and not @value.nan?
1288
+ end
1289
+
1290
+ def to_ruby
1291
+ to_f
1292
+ end
1293
+
1294
+ def to_predicate
1295
+ to_f
1296
+ end
1297
+
1298
+ def to_number(context)
1299
+ self
1300
+ end
1301
+
1302
+
1303
+ def ==(other)
1304
+ if other.is_a? XPathNodeSet or other.is_a? XPathBoolean then
1305
+ other == self
1306
+ else
1307
+ @value == other.to_f
1308
+ end
1309
+ end
1310
+
1311
+ def +(other)
1312
+ @value += other.to_f
1313
+ self
1314
+ end
1315
+
1316
+ def -(other)
1317
+ @value -= other.to_f
1318
+ self
1319
+ end
1320
+
1321
+ def *(other)
1322
+ @value *= other.to_f
1323
+ self
1324
+ end
1325
+
1326
+ def /(other)
1327
+ @value /= other.to_f
1328
+ self
1329
+ end
1330
+
1331
+ def %(other)
1332
+ n = other.to_f
1333
+ f = @value % n
1334
+ f = -f if @value < 0
1335
+ f = -f if n < 0
1336
+ @value = f
1337
+ self
1338
+ end
1339
+
1340
+ def -@
1341
+ @value = -@value
1342
+ self
1343
+ end
1344
+
1345
+ def floor
1346
+ @value = @value.floor.to_f
1347
+ self
1348
+ end
1349
+
1350
+ def ceil
1351
+ @value = @value.ceil.to_f
1352
+ self
1353
+ end
1354
+
1355
+ def round
1356
+ f = @value
1357
+ unless f.nan? or f.infinite? then
1358
+ if f >= 0.0 then
1359
+ @value = f.round.to_f
1360
+ elsif f - f.truncate >= -0.5 then
1361
+ @value = f.ceil.to_f
1362
+ else
1363
+ @value = f.floor.to_f
1364
+ end
1365
+ end
1366
+ self
1367
+ end
1368
+
1369
+ end
1370
+
1371
+
1372
+
1373
+
1374
+ class XPathString
1375
+
1376
+ include XPathObject
1377
+
1378
+ def initialize(str)
1379
+ raise ::TypeError, "must be a String" unless str.is_a? String
1380
+ @value = str
1381
+ end
1382
+
1383
+ def to_str
1384
+ @value
1385
+ end
1386
+
1387
+ def to_f
1388
+ if /\A\s*(-?\d+\.?\d*)(?:\s|\z)/ =~ @value then
1389
+ $1.to_f
1390
+ else
1391
+ 0.0 / 0.0 # NaN
1392
+ end
1393
+ end
1394
+
1395
+ def true?
1396
+ not @value.empty?
1397
+ end
1398
+
1399
+ def to_ruby
1400
+ to_str
1401
+ end
1402
+
1403
+ def to_string(context)
1404
+ self
1405
+ end
1406
+
1407
+
1408
+ def concat(s)
1409
+ @value = @value + s
1410
+ self
1411
+ end
1412
+
1413
+ def start_with?(s)
1414
+ /\A#{Regexp.quote(s)}/ =~ @value
1415
+ end
1416
+
1417
+ def contain?(s)
1418
+ /#{Regexp.quote(s)}/ =~ @value
1419
+ end
1420
+
1421
+ def substring_before(s)
1422
+ if /#{Regexp.quote(s)}/ =~ @value then
1423
+ @value = $`
1424
+ else
1425
+ @value = ''
1426
+ end
1427
+ self
1428
+ end
1429
+
1430
+ def substring_after(s)
1431
+ if /#{Regexp.quote(s)}/ =~ @value then
1432
+ @value = $'
1433
+ else
1434
+ @value = ''
1435
+ end
1436
+ self
1437
+ end
1438
+
1439
+ def substring(start, len)
1440
+ start = start.round.to_f
1441
+ if start.infinite? or start.nan? then
1442
+ @value = ''
1443
+ elsif len then
1444
+ len = len.round.to_f
1445
+ maxlen = start + len
1446
+ len = maxlen - 1.0 if len >= maxlen
1447
+ if start <= 1.0 then
1448
+ start = 0
1449
+ else
1450
+ start = start.to_i - 1
1451
+ end
1452
+ if len.nan? or len < 1.0 then
1453
+ @value = ''
1454
+ elsif len.infinite? then
1455
+ # @value = @value[start..-1]
1456
+ /\A[\W\w]{0,#{start}}/ =~ @value
1457
+ @value = $'
1458
+ else
1459
+ # @value = @value[start, len.to_i]
1460
+ /\A[\W\w]{0,#{start}}([\W\w]{0,#{len.to_i}})/ =~ @value
1461
+ @value = $1
1462
+ end
1463
+ elsif start > 1.0 then
1464
+ # @value = @value[(start-1)..-1]
1465
+ /\A[\W\w]{0,#{start.to_i-1}}/ =~ @value
1466
+ @value = $'
1467
+ end
1468
+ raise "BUG" unless @value
1469
+ self
1470
+ end
1471
+
1472
+ def size
1473
+ @value.gsub(/[^\Wa-zA-Z_\d]/, ' ').size
1474
+ end
1475
+
1476
+ def normalize_space
1477
+ @value = @value.strip
1478
+ @value.gsub!(/\s+/, ' ')
1479
+ self
1480
+ end
1481
+
1482
+ def translate(from, to)
1483
+ to = to.split(//)
1484
+ h = {}
1485
+ from.split(//).each_with_index { |i,n|
1486
+ h[i] = to[n] unless h.key? i
1487
+ }
1488
+ @value = @value.gsub(/[#{Regexp.quote(h.keys.join)}]/) { |s| h[s] }
1489
+ self
1490
+ end
1491
+
1492
+ def replace(str)
1493
+ @value = str
1494
+ self
1495
+ end
1496
+
1497
+ end
1498
+
1499
+
1500
+
1501
+
1502
+ ---- footer ----
1503
+
1504
+ #
1505
+ # Client NodeVisitor a NodeAdapter a Node
1506
+ # | | | |
1507
+ # |=| | | |
1508
+ # | |--{visit(node)}-->|=| | |
1509
+ # | | | |---{accept(self)}----------------->|=|
1510
+ # | | |=| | | |
1511
+ # | | | | | |
1512
+ # | | |=|<------------------{on_**(self)}---|=|
1513
+ # | | | | | |
1514
+ # | | | |--{wrap(node)}-->|=| |
1515
+ # | | | | | | |
1516
+ # | | | | |=| |
1517
+ # | |<--[NodeAdapter]--|=| | |
1518
+ # | | | | |
1519
+ # | |-----{request}----------------------->|=| |
1520
+ # | | | | |--{request}--->|=|
1521
+ # | | | | | | |
1522
+ # | | | | |<-----[Data]---|=|
1523
+ # | |<--------------------------[Data]-----|=| |
1524
+ # | | | | |
1525
+ # |=| | | |
1526
+ # | | | |
1527
+ #
1528
+
1529
+
1530
+ class TransparentNodeVisitor
1531
+
1532
+ def visit(node)
1533
+ node
1534
+ end
1535
+
1536
+ end
1537
+
1538
+
1539
+ class NullNodeAdapter
1540
+
1541
+ def node
1542
+ self
1543
+ end
1544
+
1545
+ def root
1546
+ nil
1547
+ end
1548
+
1549
+ def parent
1550
+ nil
1551
+ end
1552
+
1553
+ def children
1554
+ []
1555
+ end
1556
+
1557
+ def each_following_siblings
1558
+ end
1559
+
1560
+ def each_preceding_siblings
1561
+ end
1562
+
1563
+ def attributes
1564
+ []
1565
+ end
1566
+
1567
+ def namespaces
1568
+ []
1569
+ end
1570
+
1571
+ def index
1572
+ 0
1573
+ end
1574
+
1575
+ def node_type
1576
+ nil
1577
+ end
1578
+
1579
+ def name_localpart
1580
+ nil
1581
+ end
1582
+
1583
+ def qualified_name
1584
+ name_localpart
1585
+ end
1586
+
1587
+ def namespace_uri
1588
+ nil
1589
+ end
1590
+
1591
+ def string_value
1592
+ ''
1593
+ end
1594
+
1595
+ def lang
1596
+ nil
1597
+ end
1598
+
1599
+ def select_id(*ids)
1600
+ raise XPath::Error, "selection by ID is not supported"
1601
+ end
1602
+
1603
+ end
1604
+
1605
+
1606
+
1607
+
1608
+ class AxisIterator
1609
+
1610
+ def reverse_order?
1611
+ false
1612
+ end
1613
+
1614
+ end
1615
+
1616
+
1617
+ class ReverseAxisIterator < AxisIterator
1618
+
1619
+ def reverse_order?
1620
+ true
1621
+ end
1622
+
1623
+ end
1624
+
1625
+
1626
+ class SelfIterator < AxisIterator
1627
+
1628
+ def each(node, visitor)
1629
+ yield visitor.visit(node)
1630
+ end
1631
+
1632
+ end
1633
+
1634
+
1635
+ class ChildIterator < AxisIterator
1636
+
1637
+ def each(node, visitor, &block)
1638
+ visitor.visit(node).children.each { |i| yield visitor.visit(i) }
1639
+ end
1640
+
1641
+ end
1642
+
1643
+
1644
+ class ParentIterator < AxisIterator
1645
+
1646
+ def each(node, visitor)
1647
+ parent = visitor.visit(node).parent
1648
+ yield visitor.visit(parent) if parent
1649
+ end
1650
+
1651
+ end
1652
+
1653
+
1654
+ class AncestorIterator < ReverseAxisIterator
1655
+
1656
+ def each(node, visitor)
1657
+ node = visitor.visit(node).parent
1658
+ while node
1659
+ i = visitor.visit(node)
1660
+ parent = i.parent
1661
+ yield i
1662
+ node = parent
1663
+ end
1664
+ end
1665
+
1666
+ end
1667
+
1668
+
1669
+ class AncestorOrSelfIterator < AncestorIterator
1670
+
1671
+ def each(node, visitor)
1672
+ yield visitor.visit(node)
1673
+ super
1674
+ end
1675
+
1676
+ end
1677
+
1678
+
1679
+ class DescendantIterator < AxisIterator
1680
+
1681
+ def each(node, visitor)
1682
+ stack = visitor.visit(node).children.reverse
1683
+ while node = stack.pop
1684
+ i = visitor.visit(node)
1685
+ stack.concat i.children.reverse
1686
+ yield i
1687
+ end
1688
+ end
1689
+
1690
+ end
1691
+
1692
+
1693
+ class DescendantOrSelfIterator < DescendantIterator
1694
+
1695
+ def each(node, visitor)
1696
+ yield visitor.visit(node)
1697
+ super
1698
+ end
1699
+
1700
+ end
1701
+
1702
+
1703
+ class FollowingSiblingIterator < AxisIterator
1704
+
1705
+ def each(node, visitor)
1706
+ visitor.visit(node).each_following_siblings { |i|
1707
+ yield visitor.visit(i)
1708
+ }
1709
+ end
1710
+
1711
+ end
1712
+
1713
+
1714
+ class PrecedingSiblingIterator < ReverseAxisIterator
1715
+
1716
+ def each(node, visitor)
1717
+ visitor.visit(node).each_preceding_siblings { |i|
1718
+ yield visitor.visit(i)
1719
+ }
1720
+ end
1721
+
1722
+ end
1723
+
1724
+
1725
+ class FollowingIterator < DescendantOrSelfIterator
1726
+
1727
+ def each(node, visitor)
1728
+ while parent = (a = visitor.visit(node)).parent
1729
+ a.each_following_siblings { |i| super i, visitor }
1730
+ node = parent
1731
+ end
1732
+ end
1733
+
1734
+ end
1735
+
1736
+
1737
+ class PrecedingIterator < ReverseAxisIterator
1738
+
1739
+ def each(node, visitor)
1740
+ while parent = (adaptor = visitor.visit(node)).parent
1741
+ adaptor.each_preceding_siblings { |i|
1742
+ stack = visitor.visit(i).children.dup
1743
+ while node = stack.pop
1744
+ a = visitor.visit(node)
1745
+ stack.concat a.children
1746
+ yield a
1747
+ end
1748
+ yield visitor.visit(i)
1749
+ }
1750
+ node = parent
1751
+ end
1752
+ end
1753
+
1754
+ end
1755
+
1756
+
1757
+ class AttributeIterator < AxisIterator
1758
+
1759
+ def each(node, visitor)
1760
+ visitor.visit(node).attributes.each { |i| yield visitor.visit(i) }
1761
+ end
1762
+
1763
+ end
1764
+
1765
+
1766
+ class NamespaceIterator < AxisIterator
1767
+
1768
+ def each(node, visitor)
1769
+ visitor.visit(node).namespaces.each { |i| yield visitor.visit(i) }
1770
+ end
1771
+
1772
+ end
1773
+
1774
+
1775
+
1776
+
1777
+ class XPathNodeSet
1778
+
1779
+ class LocationStep < XPathNodeSet
1780
+
1781
+ def initialize(context)
1782
+ @context = context
1783
+ @visitor = context.visitor
1784
+ @nodes = []
1785
+ end
1786
+
1787
+ def set_iterator(iterator)
1788
+ @iterator = iterator
1789
+ end
1790
+
1791
+ def reuse(node)
1792
+ @node = node
1793
+ @nodes.clear
1794
+ end
1795
+
1796
+ def select
1797
+ @iterator.each(@node, @visitor) { |i|
1798
+ node = i.node
1799
+ @nodes.push node if yield(i)
1800
+ }
1801
+ self
1802
+ end
1803
+
1804
+ def select_all
1805
+ @iterator.each(@node, @visitor) { |i| @nodes.push i.node }
1806
+ self
1807
+ end
1808
+
1809
+ end
1810
+
1811
+
1812
+ include XPathObject
1813
+
1814
+ def initialize(context, *nodes)
1815
+ @context = context.dup
1816
+ @visitor = context.visitor
1817
+ nodes.sort! { |a,b| compare_position a, b }
1818
+ @nodes = nodes
1819
+ end
1820
+
1821
+ attr_reader :nodes
1822
+ protected :nodes
1823
+
1824
+
1825
+ def to_str
1826
+ if @nodes.empty? then
1827
+ ''
1828
+ else
1829
+ @visitor.visit(@nodes[0]).string_value
1830
+ end
1831
+ end
1832
+
1833
+ def to_f
1834
+ to_string(@context).to_f
1835
+ end
1836
+
1837
+ def true?
1838
+ not @nodes.empty?
1839
+ end
1840
+
1841
+ def to_ruby
1842
+ @nodes
1843
+ end
1844
+
1845
+
1846
+ def self.def_comparison_operator(*ops)
1847
+ ops.each { |op|
1848
+ module_eval <<_, __FILE__, __LINE__ + 1
1849
+ def #{op}(other)
1850
+ if other.is_a? XPathBoolean then
1851
+ other #{op} self.to_boolean
1852
+ else
1853
+ visitor = @visitor
1854
+ str = @context.make_string('')
1855
+ ret = false
1856
+ @nodes.each { |node|
1857
+ str.replace visitor.visit(node).string_value
1858
+ break if ret = (other #{op} str)
1859
+ }
1860
+ ret
1861
+ end
1862
+ end
1863
+ _
1864
+ }
1865
+ end
1866
+
1867
+ def_comparison_operator '==', '<', '>', '<=', '>='
1868
+
1869
+ class << self
1870
+ undef def_comparison_operator
1871
+ end
1872
+
1873
+ def **(other)
1874
+ super unless other.is_a? XPathNodeSet
1875
+ merge other.nodes
1876
+ self
1877
+ end
1878
+
1879
+
1880
+ def count
1881
+ @nodes.size
1882
+ end
1883
+
1884
+ def first
1885
+ @nodes[0]
1886
+ end
1887
+
1888
+ def each(&block)
1889
+ @nodes.each(&block)
1890
+ end
1891
+
1892
+
1893
+ def funcall(name) # for XPointer
1894
+ raise "BUG" unless block_given?
1895
+ func = ('f_' + name.tr('-', '_')).intern
1896
+ super unless respond_to? func, true
1897
+ size = @nodes.size
1898
+ pos = 1
1899
+ c = @context.dup
1900
+ begin
1901
+ @nodes.collect! { |node|
1902
+ c.reuse node, pos, size
1903
+ pos += 1
1904
+ args = yield(c)
1905
+ send(func, node, *args)
1906
+ }
1907
+ rescue Object::ArgumentError
1908
+ if $@[1] == "#{__FILE__}:#{__LINE__-3}:in `send'" then
1909
+ raise XPath::ArgumentError, "#{$!} for `#{name}'"
1910
+ end
1911
+ raise
1912
+ end
1913
+ self
1914
+ end
1915
+
1916
+
1917
+ private
1918
+
1919
+ def compare_position(node1, node2)
1920
+ visitor = @visitor
1921
+ ancestors1 = []
1922
+ ancestors2 = []
1923
+ p1 = visitor.visit(node1).parent
1924
+ while p1
1925
+ ancestors1.push node1
1926
+ p1 = visitor.visit(node1 = p1).parent
1927
+ end
1928
+ p2 = visitor.visit(node2).parent
1929
+ while p2
1930
+ ancestors2.push node2
1931
+ p2 = visitor.visit(node2 = p2).parent
1932
+ end
1933
+ unless node1 == node2 then
1934
+ raise XPath::Error, "can't compare the positions of given two nodes"
1935
+ end
1936
+ n = -1
1937
+ ancestors1.reverse_each { |node1|
1938
+ node2 = ancestors2[n]
1939
+ unless node1 == node2 then
1940
+ break unless node2
1941
+ return visitor.visit(node1).index - visitor.visit(node2).index
1942
+ end
1943
+ n -= 1
1944
+ }
1945
+ ancestors1.size - ancestors2.size
1946
+ end
1947
+
1948
+
1949
+ def merge(other)
1950
+ if @nodes.empty? or other.empty? then
1951
+ @nodes.concat other
1952
+ elsif (n = compare_position(@nodes.last, other.first)) <= 0 then
1953
+ @nodes.pop if n == 0
1954
+ @nodes.concat other
1955
+ elsif (n = compare_position(other.last, @nodes.first)) <= 0 then
1956
+ other.pop if n == 0
1957
+ @nodes = other.concat(@nodes)
1958
+ else
1959
+ newnodes = []
1960
+ nodes = @nodes
1961
+ until nodes.empty? or other.empty?
1962
+ n = compare_position(nodes.last, other.last)
1963
+ if n > 0 then
1964
+ newnodes.push nodes.pop
1965
+ elsif n < 0 then
1966
+ newnodes.push other.pop
1967
+ else
1968
+ newnodes.push nodes.pop
1969
+ other.pop
1970
+ end
1971
+ end
1972
+ newnodes.reverse!
1973
+ @nodes.concat(other).concat(newnodes)
1974
+ end
1975
+ end
1976
+
1977
+
1978
+ IteratorForAxis = {
1979
+ :self => SelfIterator.new,
1980
+ :child => ChildIterator.new,
1981
+ :parent => ParentIterator.new,
1982
+ :ancestor => AncestorIterator.new,
1983
+ :ancestor_or_self => AncestorOrSelfIterator.new,
1984
+ :descendant => DescendantIterator.new,
1985
+ :descendant_or_self => DescendantOrSelfIterator.new,
1986
+ :following => FollowingIterator.new,
1987
+ :preceding => PrecedingIterator.new,
1988
+ :following_sibling => FollowingSiblingIterator.new,
1989
+ :preceding_sibling => PrecedingSiblingIterator.new,
1990
+ :attribute => AttributeIterator.new,
1991
+ :namespace => NamespaceIterator.new,
1992
+ }
1993
+
1994
+ def get_iterator(axis)
1995
+ ret = IteratorForAxis[axis]
1996
+ unless ret then
1997
+ raise XPath::NameError, "invalid axis `#{axis.id2name.tr('_','-')}'"
1998
+ end
1999
+ ret
2000
+ end
2001
+
2002
+ def make_location_step
2003
+ if defined? @__lstep__ then
2004
+ @__lstep__
2005
+ else
2006
+ @__lstep__ = LocationStep.new(@context)
2007
+ end
2008
+ end
2009
+
2010
+
2011
+ public
2012
+
2013
+ def step(axis)
2014
+ iterator = get_iterator(axis)
2015
+ lstep = make_location_step
2016
+ lstep.set_iterator iterator
2017
+ oldnodes = @nodes
2018
+ @nodes = []
2019
+ oldnodes.each { |node|
2020
+ lstep.reuse node
2021
+ nodes = yield(lstep).nodes
2022
+ nodes.reverse! if iterator.reverse_order?
2023
+ merge nodes
2024
+ }
2025
+ self
2026
+ end
2027
+
2028
+
2029
+ def select_all(axis)
2030
+ iterator = get_iterator(axis)
2031
+ visitor = @visitor
2032
+ oldnodes = @nodes
2033
+ @nodes = []
2034
+ oldnodes.each { |start|
2035
+ nodes = []
2036
+ iterator.each(start, visitor) { |i| nodes.push i.node }
2037
+ nodes.reverse! if iterator.reverse_order?
2038
+ merge nodes
2039
+ }
2040
+ self
2041
+ end
2042
+
2043
+
2044
+ def predicate
2045
+ context = @context
2046
+ size = @nodes.size
2047
+ pos = 1
2048
+ result = nil
2049
+ newnodes = @nodes.reject { |node|
2050
+ context.reuse node, pos, size
2051
+ pos += 1
2052
+ result = yield(context)
2053
+ break if result.is_a? Numeric
2054
+ not result
2055
+ }
2056
+ if result.is_a? Numeric then
2057
+ at result
2058
+ else
2059
+ @nodes = newnodes
2060
+ end
2061
+ self
2062
+ end
2063
+
2064
+
2065
+ def at(pos)
2066
+ n = pos.to_i
2067
+ if n != pos or n <= 0 then
2068
+ node = nil
2069
+ else
2070
+ node = @nodes[n - 1]
2071
+ end
2072
+ @nodes.clear
2073
+ @nodes.push node if node
2074
+ self
2075
+ end
2076
+
2077
+ end
2078
+
2079
+
2080
+
2081
+ class Context
2082
+
2083
+ def initialize(node, namespace = nil, variable = nil, visitor = nil)
2084
+ visitor = TransparentNodeVisitor.new unless visitor
2085
+ @visitor = visitor
2086
+ @node = node
2087
+ @context_position = 1
2088
+ @context_size = 1
2089
+ @variables = variable
2090
+ @namespaces = namespace || {}
2091
+ end
2092
+
2093
+ attr_reader :visitor, :node, :context_position, :context_size
2094
+
2095
+ def reuse(node, pos = 1, size = 1)
2096
+ @variables = nil
2097
+ @node, @context_position, @context_size = node, pos, size
2098
+ end
2099
+
2100
+
2101
+ def get_variable(name)
2102
+ value = @variables && @variables[name] # value should be a XPathObjcect.
2103
+ raise XPath::NameError, "undefined variable `#{name}'" unless value
2104
+ value
2105
+ end
2106
+
2107
+
2108
+ PredefinedNamespace = {
2109
+ 'xml' => 'http://www.w3.org/XML/1998/namespace',
2110
+ }
2111
+
2112
+ def get_namespace(prefix)
2113
+ ret = @namespaces[prefix] || PredefinedNamespace[prefix]
2114
+ raise XPath::Error, "undeclared namespace `#{prefix}'" unless ret
2115
+ ret
2116
+ end
2117
+
2118
+
2119
+ def make_string(str)
2120
+ XPathString.new str
2121
+ end
2122
+
2123
+ def make_number(num)
2124
+ XPathNumber.new num
2125
+ end
2126
+
2127
+ def make_boolean(f)
2128
+ if f then
2129
+ XPathTrue
2130
+ else
2131
+ XPathFalse
2132
+ end
2133
+ end
2134
+
2135
+ def make_nodeset(*nodes)
2136
+ XPathNodeSet.new(self, *nodes)
2137
+ end
2138
+
2139
+
2140
+ def to_nodeset
2141
+ make_nodeset @node
2142
+ end
2143
+
2144
+ def root_nodeset
2145
+ make_nodeset @visitor.visit(@node).root
2146
+ end
2147
+
2148
+
2149
+ def funcall(name, *args)
2150
+ begin
2151
+ send('f_' + name.tr('-', '_'), *args)
2152
+ rescue Object::NameError
2153
+ if $@[0] == "#{__FILE__}:#{__LINE__-2}:in `send'" then
2154
+ raise XPath::NameError, "undefined function `#{name}'"
2155
+ end
2156
+ raise
2157
+ rescue Object::ArgumentError
2158
+ if $@[1] == "#{__FILE__}:#{__LINE__-7}:in `send'" then
2159
+ raise XPath::ArgumentError, "#{$!} for `#{name}'"
2160
+ end
2161
+ raise
2162
+ end
2163
+ end
2164
+
2165
+
2166
+ private
2167
+
2168
+ def must(type, *args)
2169
+ args.each { |i|
2170
+ unless i.is_a? type then
2171
+ s = type.name.sub(/\A.*::(?:XPath)?(?=[^:]+\z)/, '')
2172
+ raise XPath::TypeError, "argument must be #{s}"
2173
+ end
2174
+ }
2175
+ end
2176
+
2177
+ def must_be_nodeset(*args)
2178
+ must XPathNodeSet, *args
2179
+ end
2180
+
2181
+
2182
+ def f_last
2183
+ make_number @context_size.to_f
2184
+ end
2185
+
2186
+ def f_position
2187
+ make_number @context_position.to_f
2188
+ end
2189
+
2190
+ def f_count(nodeset)
2191
+ must_be_nodeset nodeset
2192
+ make_number nodeset.count.to_f
2193
+ end
2194
+
2195
+ def f_id(obj)
2196
+ unless obj.is_a? XPathNodeSet then
2197
+ ids = obj.to_str.strip.split(/\s+/)
2198
+ else
2199
+ ids = []
2200
+ obj.each { |node| ids.push @visitor.visit(node).string_value }
2201
+ end
2202
+ root = @visitor.visit(@node).root
2203
+ make_nodeset(*@visitor.visit(root).select_id(*ids))
2204
+ end
2205
+
2206
+ def f_local_name(nodeset = nil)
2207
+ unless nodeset then
2208
+ n = @node
2209
+ else
2210
+ must_be_nodeset nodeset
2211
+ n = nodeset.first
2212
+ end
2213
+ n = @visitor.visit(n) if n
2214
+ n = n.name_localpart if n
2215
+ n = '' unless n
2216
+ make_string n
2217
+ end
2218
+
2219
+ def f_namespace_uri(nodeset = nil)
2220
+ unless nodeset then
2221
+ n = @node
2222
+ else
2223
+ must_be_nodeset nodeset
2224
+ n = nodeset.first
2225
+ end
2226
+ n = @visitor.visit(n) if n
2227
+ n = n.namespace_uri if n
2228
+ n = '' unless n
2229
+ make_string n
2230
+ end
2231
+
2232
+ def f_name(nodeset = nil)
2233
+ unless nodeset then
2234
+ n = @node
2235
+ else
2236
+ must_be_nodeset nodeset
2237
+ n = nodeset.first
2238
+ end
2239
+ n = @visitor.visit(n) if n
2240
+ n = n.qualified_name if n
2241
+ n = '' unless n
2242
+ make_string n
2243
+ end
2244
+
2245
+
2246
+ def f_string(obj = nil)
2247
+ obj = to_nodeset unless obj
2248
+ obj.to_string self
2249
+ end
2250
+
2251
+ def f_concat(str, str2, *strs)
2252
+ s = str2.to_str.dup
2253
+ strs.each { |i| s << i.to_str }
2254
+ str.to_string(self).concat(s)
2255
+ end
2256
+
2257
+ def f_starts_with(str, sub)
2258
+ make_boolean str.to_string(self).start_with?(sub.to_str)
2259
+ end
2260
+
2261
+ def f_contains(str, sub)
2262
+ make_boolean str.to_string(self).contain?(sub.to_str)
2263
+ end
2264
+
2265
+ def f_substring_before(str, sub)
2266
+ str.to_string(self).substring_before sub.to_str
2267
+ end
2268
+
2269
+ def f_substring_after(str, sub)
2270
+ str.to_string(self).substring_after sub.to_str
2271
+ end
2272
+
2273
+ def f_substring(str, start, len = nil)
2274
+ len = len.to_number(self) if len
2275
+ str.to_string(self).substring start.to_number(self), len
2276
+ end
2277
+
2278
+ def f_string_length(str = nil)
2279
+ if str then
2280
+ str = str.to_string(self)
2281
+ else
2282
+ str = make_string(@node.string_value)
2283
+ end
2284
+ make_number str.size.to_f
2285
+ end
2286
+
2287
+ def f_normalize_space(str = nil)
2288
+ if str then
2289
+ str = str.to_string(self)
2290
+ else
2291
+ str = make_string(@node.string_value)
2292
+ end
2293
+ str.normalize_space
2294
+ end
2295
+
2296
+ def f_translate(str, from, to)
2297
+ str.to_string(self).translate from.to_str, to.to_str
2298
+ end
2299
+
2300
+
2301
+ def f_boolean(obj)
2302
+ obj.to_boolean self
2303
+ end
2304
+
2305
+ def f_not(bool)
2306
+ make_boolean(!bool.true?)
2307
+ end
2308
+
2309
+ def f_true
2310
+ make_boolean true
2311
+ end
2312
+
2313
+ def f_false
2314
+ make_boolean false
2315
+ end
2316
+
2317
+ def f_lang(str)
2318
+ lang = @visitor.visit(@node).lang
2319
+ make_boolean(lang && /\A#{Regexp.quote(str.to_str)}(?:-|\z)/i =~ lang)
2320
+ end
2321
+
2322
+
2323
+ def f_number(obj = nil)
2324
+ obj = to_nodeset unless obj
2325
+ obj.to_number self
2326
+ end
2327
+
2328
+ def f_sum(nodeset)
2329
+ must_be_nodeset nodeset
2330
+ sum = 0.0
2331
+ nodeset.each { |node|
2332
+ sum += make_string(@visitor.visit(node).string_value).to_f
2333
+ }
2334
+ make_number sum
2335
+ end
2336
+
2337
+ def f_floor(num)
2338
+ num.to_number(self).floor
2339
+ end
2340
+
2341
+ def f_ceiling(num)
2342
+ num.to_number(self).ceil
2343
+ end
2344
+
2345
+ def f_round(num)
2346
+ num.to_number(self).round
2347
+ end
2348
+
2349
+ end
2350
+
2351
+
2352
+ end