xmlparser 0.6.81

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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