vcdom 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,73 @@
1
+ # coding : utf-8
2
+
3
+ module VCDOM
4
+ module XPath
5
+
6
+ module Evaluative
7
+
8
+ def create_expression( expression, resolver )
9
+ end
10
+
11
+ def create_ns_resolver( node_resolver )
12
+ end
13
+
14
+ def evaluate( expression, context_node, resolver, type, result )
15
+ self.create_expression( expression, resolver ).evaluate( context_node, type, result )
16
+ end
17
+
18
+ end
19
+
20
+ class Expression
21
+ def evaluate( context_node, type, result )
22
+ end
23
+ end
24
+
25
+ class NSResolver
26
+ def lookup_namespace_uri( prefix )
27
+ end
28
+ end
29
+
30
+ class XPathResult
31
+ # XPathResultType
32
+ ANY_TYPE = 0
33
+ NUMBER_TYPE = 1
34
+ STRING_TYPE = 2
35
+ BOOLEAN_TYPE = 3
36
+ UNORDERED_NODE_ITERATOR_TYPE = 4
37
+ ORDERED_NODE_ITERATOR_TYPE = 5
38
+ UNORDERED_NODE_SNAPSHOT_TYPE = 6
39
+ ORDERED_NODE_SNAPSHOT_TYPE = 7
40
+ ANY_UNORDERED_NODE_TYPE = 8
41
+ FIRST_ORDERED_NODE_TYPE = 9
42
+
43
+ def result_type
44
+ end
45
+ def number_value
46
+ end
47
+ def string_value
48
+ end
49
+
50
+ def boolean_value
51
+ end
52
+
53
+ def single_node_value
54
+ end
55
+ def invalid_iterator_state
56
+ end
57
+ def snapshot_length
58
+ end
59
+
60
+ def iterate_next()
61
+ end
62
+ def snapshot_item( index )
63
+ end
64
+ end
65
+
66
+ class Namespace < Node
67
+ XPATH_NAMESPACE_NODE = 13
68
+ def owner_element
69
+ end
70
+ end
71
+
72
+ end
73
+ end
@@ -0,0 +1,121 @@
1
+ # coding : utf-8
2
+
3
+ module VCDOM::XPath::Internal # :nodoc:
4
+
5
+ class AbstractCommand # :nodoc:
6
+ def is_value?; false end
7
+ def is_expr?; false end
8
+ def is_command?; true end
9
+
10
+ def to_s()
11
+ "XPathCommand(#{command_type})"
12
+ end
13
+
14
+ end
15
+
16
+ class AbstractOperationCommand < AbstractCommand # :nodoc:
17
+ def initialize( operation_name )
18
+ @operation_name = operation_name
19
+ end
20
+ attr_reader :operation_name
21
+
22
+ def to_s()
23
+ "XPathCommand(#{command_type}, #{operation_name})"
24
+ end
25
+ end
26
+
27
+ class OperationUnaryCommand < AbstractOperationCommand # :nodoc:
28
+ def command_type; :operation_unary end
29
+ end
30
+
31
+ class OperationBinaryCommand < AbstractOperationCommand # :nodoc:
32
+ def command_type; :operation_binary end
33
+ end
34
+
35
+ @operation_unary_commands = {
36
+ :"-@" => OperationUnaryCommand.new( :"-@" ),
37
+ :"+" => OperationBinaryCommand.new( :"+" ),
38
+ :"-" => OperationBinaryCommand.new( :"-" ),
39
+ :"*" => OperationBinaryCommand.new( :"*" ),
40
+ :"div" => OperationBinaryCommand.new( :"/" ),
41
+ :"mod" => OperationBinaryCommand.new( :"%" ),
42
+ :"=" => OperationBinaryCommand.new( :"==" ),
43
+ :"!=" => OperationBinaryCommand.new( :"neq?" ),
44
+ :"<" => OperationBinaryCommand.new( :"<" ),
45
+ :"<=" => OperationBinaryCommand.new( :"<=" ),
46
+ :">" => OperationBinaryCommand.new( :">" ),
47
+ :">=" => OperationBinaryCommand.new( :">=" ),
48
+ :"|" => OperationBinaryCommand.new( :"|" ),
49
+ }
50
+ def self.get_operation_command( name )
51
+ if @operation_unary_commands.include? name
52
+ return @operation_unary_commands[name]
53
+ else
54
+ raise "NOT SUPPORTED"
55
+ end
56
+ end
57
+
58
+ class ContextNodeCommand < AbstractCommand # :nodoc:
59
+ def initialize(); end
60
+ def command_type; :context_node end
61
+ @@instance = self.new()
62
+ def self.get_instance
63
+ @@instance
64
+ end
65
+ end
66
+
67
+ class RootNodeCommand < AbstractCommand # :nodoc:
68
+ def initialize(); end
69
+ def command_type; :root_node end
70
+ @@instance = self.new()
71
+ def self.get_instance
72
+ @@instance
73
+ end
74
+ end
75
+
76
+ class NodeSelectionCommand < AbstractCommand # :nodoc:
77
+ def initialize( axis, node_type, node_ns_uri, node_name, pred_exprs )
78
+ @axis = axis
79
+ @node_type = node_type
80
+ @node_ns_uri = node_ns_uri
81
+ @node_name = node_name
82
+ @pred_exprs = pred_exprs
83
+ end
84
+ def command_type; :node_selection end
85
+ attr_reader :axis
86
+ attr_reader :node_type
87
+ attr_reader :node_ns_uri
88
+ attr_reader :node_name
89
+ attr_reader :pred_exprs
90
+ end
91
+
92
+ class ExprEvalCommand < AbstractCommand # :nodoc:
93
+ def initialize( expr )
94
+ @expr = expr
95
+ end
96
+ attr_reader :expr
97
+ def command_type; :expr_eval end
98
+ end
99
+
100
+ class FunctionCallCommand < AbstractCommand # :nodoc:
101
+ EMPTY_ARGS = Array.new().freeze()
102
+ def initialize( name, arg_exprs )
103
+ @function_name = name
104
+ @function_args = arg_exprs # nil �܂���
105
+ end
106
+ attr_reader :function_name
107
+ def function_args
108
+ @function_args.nil? ? EMPTY_ARGS : @function_args
109
+ end
110
+ def command_type; :function_call end
111
+ end
112
+
113
+ class PredsEvalCommand < AbstractCommand # :nodoc:
114
+ def initialize( exprs )
115
+ @exprs = exprs
116
+ end
117
+ attr_reader :exprs
118
+ def command_type; :preds_eval end
119
+ end
120
+
121
+ end
@@ -0,0 +1,307 @@
1
+ # coding : utf-8
2
+
3
+ require "vcdom/xpath/internal/value"
4
+
5
+ module VCDOM::XPath::Internal # :nodoc:
6
+
7
+ class Evaluator # :nodoc:
8
+
9
+ def context_node; @context_node_stack[-1] end
10
+ def context_size; @context_size_stack[-1] end
11
+ def context_position; @context_pos_stack[-1] end
12
+
13
+ def change_context_node_and_position( context_node, position, &block )
14
+ @context_node_stack.push context_node
15
+ @context_pos_stack.push position
16
+ block.call
17
+ @context_pos_stack.pop
18
+ @context_node_stack.pop
19
+ end
20
+ def change_context_size( size, &block )
21
+ @context_size_stack.push size
22
+ block.call
23
+ @context_size_stack.pop
24
+ end
25
+
26
+ def evaluate_expr( expr )
27
+ # TODO
28
+ case expr.expr_type
29
+ when :or_expr
30
+ return evaluate_or_expr( expr )
31
+ when :and_expr
32
+ return evaluate_and_expr( expr )
33
+ when :equality_expr
34
+ return evaluate_equality_expr( expr )
35
+ else
36
+ raise "INTERNAL ERROR"
37
+ end
38
+ end
39
+
40
+ def evaluate_or_expr( expr )
41
+ # TODO
42
+ raise "NOT STILL BE SUPPORTED"
43
+ end
44
+
45
+ def evaluate_and_expr( expr )
46
+ # TODO
47
+ raise "NOT STILL BE SUPPORTED"
48
+ end
49
+
50
+ def evaluate_equality_expr( expr )
51
+ # TODO
52
+ val_stack = Array.new()
53
+ expr.each do |e|
54
+ if e.is_value? or e.is_expr? then
55
+ val_stack.push e
56
+ else
57
+ case e.command_type
58
+ when :operation_unary
59
+ operand = val_stack.pop
60
+ val_stack.push operand.send( e.operation_name )
61
+ when :operation_binary
62
+ operand2 = val_stack.pop
63
+ operand1 = val_stack.pop
64
+ val_stack.push operand1.send( e.operation_name, operand2 )
65
+ when :expr_eval
66
+ val_stack.push evaluate_expr( e.expr )
67
+ when :function_call
68
+ args = Array.new()
69
+ e.function_args.each do |arg_expr|
70
+ args << evaluate_expr( arg_expr )
71
+ end
72
+ val_stack.push( call_function( e.function_name, args ) )
73
+ when :node_selection
74
+ target = val_stack.pop
75
+ val_stack.push evaluate_node_selection( target, e )
76
+ when :preds_eval
77
+ target = val_stack.pop
78
+ val_stack.push evaluate_preds( target, e.exprs )
79
+ when :context_node
80
+ val_stack.push create_node_set_value( context_node )
81
+ when :root_node
82
+ # TODO : context_node.class::DOCUMENT_NODE を書き換え
83
+ root_node = ( context_node.node_type == context_node.class::DOCUMENT_NODE ? context_node : context_node.owner_document )
84
+ val_stack.push create_node_set_value( root_node )
85
+ else
86
+ raise "NOT SUPPORTED"
87
+ end
88
+ end
89
+ end
90
+ raise "INTERNAL ERROR" if val_stack.length != 1
91
+ return val_stack.pop
92
+ end
93
+
94
+ def call_function( name, args )
95
+ args.each do |a|
96
+ raise "USER ERROR" unless a.is_value?
97
+ end
98
+ send( "_xpath_#{name}".intern, *args )
99
+ end
100
+
101
+ NODE_SELECTION_BY_AXIS_PROCS = {
102
+ :'self' => lambda { |c_node, new_nodes|
103
+ new_nodes << c_node
104
+ },
105
+ :'child' => lambda { |c_node, new_nodes|
106
+ c_node.each_child_node { |n| new_nodes << n }
107
+ },
108
+ :'parent' => lambda { |c_node, new_nodes|
109
+ if c_node.node_type == c_node.class::ATTRIBUTE_NODE then # TODO
110
+ new_nodes << c_node.owner_element if c_node.owner_element
111
+ elsif c_node.node_type == :xpath_namespace_node then
112
+ raise "NOT SUPPORTED"
113
+ else
114
+ new_nodes << c_node.parent_node if c_node.parent_node
115
+ end
116
+ },
117
+ :'descendant' => lambda { |c_node, new_nodes|
118
+ node = c_node.first_child
119
+ if node then
120
+ while not node.equal? c_node do
121
+ new_nodes << node
122
+ if node.first_child then
123
+ node = node.first_child
124
+ elsif node.next_sibling
125
+ node = node.next_sibling
126
+ else
127
+ # TODO
128
+ node = node.parent_node
129
+ while not node.equal? c_node do
130
+ if node.next_sibling then
131
+ node = node.next_sibling
132
+ break
133
+ else
134
+ node = node.parent_node
135
+ end
136
+ end
137
+ end
138
+ end
139
+ end
140
+ },
141
+ :'descendant-or-self' => lambda { |c_node, new_nodes|
142
+ new_nodes << c_node
143
+ NODE_SELECTION_BY_AXIS_PROCS[:"descendant"].call( c_node, new_nodes )
144
+ },
145
+ :'ancestor' => lambda { |c_node, new_nodes|
146
+ node = c_node.parent_node
147
+ while node do
148
+ new_nodes << node
149
+ node = node.parent_node
150
+ end
151
+ },
152
+ :'ancestor-or-self' => lambda { |c_node, new_nodes|
153
+ new_nodes << c_node
154
+ NODE_SELECTION_BY_AXIS_PROCS[:"ancestor"].call( c_node, new_nodes )
155
+ },
156
+ :'following' => lambda { |c_node, new_nodes|
157
+ raise "NOT SUPPORTED"
158
+ },
159
+ :'following-sibling' => lambda { |c_node, new_nodes|
160
+ raise "NOT SUPPORTED"
161
+ },
162
+ :'preceding' => lambda { |c_node, new_nodes|
163
+ raise "NOT SUPPORTED"
164
+ },
165
+ :'preceding-sibling' => lambda { |c_node, new_nodes|
166
+ raise "NOT SUPPORTED"
167
+ },
168
+ :'attribute' => lambda { |c_node, new_nodes|
169
+ if c_node.attributes then
170
+ c_node.attributes.each do |n|
171
+ if n.namespace_uri != "http://www.w3.org/2000/xmlns/" then
172
+ new_nodes << n
173
+ end
174
+ end
175
+ end
176
+ },
177
+ :'namespace' => lambda { |c_node, new_nodes|
178
+ raise "NOT SUPPORTED"
179
+ },
180
+ }
181
+
182
+ def evaluate_node_selection( nodes, cmd )
183
+ # cmd.pred_exprs は nil の可能性あり
184
+ # cmd.node_test_name も nil の可能性あり
185
+ # cmd.node_test_type は :any, :, :processing-instruction など
186
+ new_nodes = Array.new()
187
+ nodes.each do |c_node|
188
+ c_nodes = Array.new()
189
+ # TODO : 軸によって対象となるノードを集める
190
+ if ( node_selection_by_axis_proc = NODE_SELECTION_BY_AXIS_PROCS[ cmd.axis ] ).nil? then
191
+ raise "invalid axis [#{cmd.axis}]"
192
+ end
193
+ node_selection_by_axis_proc.call( c_node, c_nodes )
194
+ # type, name, ns url によって絞り込む
195
+ c_nodes = evaluate_node_selection_sub( c_nodes, cmd )
196
+ # TODO : 軸によって順序を変更?
197
+ if cmd.pred_exprs then
198
+ cmd.pred_exprs.each do |expr|
199
+ c_nodes = evaluate_pred_internal( c_nodes, expr )
200
+ end
201
+ end
202
+ new_nodes.concat c_nodes
203
+ end
204
+ new_nodes.uniq!
205
+ create_node_set_value( *new_nodes )
206
+ end
207
+
208
+ def evaluate_node_selection_sub( nodes, cmd )
209
+ # node_type での絞り込み
210
+ case cmd.node_type
211
+ when :node
212
+ # do nothing
213
+ when :named_node
214
+ case cmd.axis
215
+ when :attribute
216
+ raise "NOT SUPPORTED"
217
+ when :namespace
218
+ raise "NOT SUPPORTED"
219
+ else
220
+ expected_type = VCDOM::Node::ELEMENT_NODE # TODO : change
221
+ end
222
+ nodes = nodes.inject( Array.new() ) do |arr,n|
223
+ arr << n if n.node_type == expected_type
224
+ end
225
+ else
226
+ raise "NOT SUPPORTED"
227
+ end
228
+ new_nodes = Array.new()
229
+ # node_ns_url での絞り込み # node_name での絞り込み
230
+ if cmd.node_ns_uri.nil? then #and cmd.node_name.nil? then
231
+ if cmd.node_name.nil? then
232
+ new_nodes = nodes
233
+ else
234
+ nodes.each do |n|
235
+ new_nodes << n if n.namespace_uri.nil? and ( n.local_name || n.node_name ) == cmd.node_name.to_s
236
+ end
237
+ end
238
+ else
239
+ nodes.each do |n|
240
+ new_nodes << n if n.namespace_uri == cmd.node_ns_uri.to_s and n.local_name == cmd.node_name.to_s
241
+ end
242
+ end
243
+ new_nodes
244
+ end
245
+
246
+ def evaluate_preds( nodes, exprs )
247
+ raise "User Error?" if nodes.value_type != :node_set
248
+ # TODO
249
+ nodes.sort()
250
+ nodes = nodes.value
251
+ exprs.each do |expr|
252
+ nodes = evaluate_pred_internal( nodes, expr )
253
+ end
254
+ create_node_set_value( *nodes )
255
+ end
256
+
257
+ # evaluate_preds および evaluate_node_selection から呼び出される
258
+ def evaluate_pred_internal( nodes, expr )
259
+ new_nodes = Array.new()
260
+ change_context_size( nodes.length ) do
261
+ nodes.each_with_index do |node,i|
262
+ change_context_node_and_position( node, i+1 ) do
263
+ res = evaluate_expr( expr )
264
+ if ( res.value_type == :number and res.value == context_position ) or
265
+ ( res.value_type != :number and res.to_boolean_value.value ) then
266
+ new_nodes << node
267
+ end
268
+ end
269
+ end
270
+ end
271
+ new_nodes
272
+ end
273
+
274
+ def create_number_value( num )
275
+ NumberValue.new( num.to_f )
276
+ end
277
+ def create_boolean_value( bool )
278
+ bool ? BooleanValue::TRUE : BooleanValue::FALSE
279
+ end
280
+ def create_string_value( str )
281
+ StringValue.new( str )
282
+ end
283
+ def create_node_set_value( *nodes )
284
+ NodeSetValue.new( *nodes )
285
+ end
286
+
287
+ def initialize( context_node )
288
+ ( @context_node_stack = Array.new() ).push context_node
289
+ ( @context_size_stack = Array.new() ).push 1
290
+ ( @context_pos_stack = Array.new() ).push 1
291
+ end
292
+
293
+ def self.set_xpath_function( name, func )
294
+ define_method "_xpath_#{name}".intern, func
295
+ end
296
+
297
+ end
298
+
299
+ # setting xpath functions
300
+ Evaluator.set_xpath_function( :position, lambda { || create_number_value( context_position ) } )
301
+ Evaluator.set_xpath_function( :true, lambda { || create_boolean_value( true ) } )
302
+ Evaluator.set_xpath_function( :false, lambda { || create_boolean_value( false ) } )
303
+ Evaluator.set_xpath_function( :string, lambda { |*args|
304
+ raise "ERROR" if args.length > 2
305
+ ( args.length == 0 ? NodeSetValue.new( context_node ) : args[0] ).to_string_value } )
306
+
307
+ end
@@ -0,0 +1,35 @@
1
+ # coding : utf-8
2
+
3
+ module VCDOM::XPath::Internal # :nodoc:
4
+
5
+ class AbstractExpr < Array # :nodoc:
6
+ def initialize( *expr_elems )
7
+ expr_elems.each do |e|
8
+ self << e
9
+ end
10
+ end
11
+
12
+ def is_value?; false end
13
+ def is_expr?; true end
14
+ def is_command?; false end
15
+ end
16
+
17
+ class OrExpr < AbstractExpr # :nodoc:
18
+ def expr_type
19
+ :or_expr
20
+ end
21
+ end
22
+
23
+ class AndExpr < AbstractExpr # :nodoc:
24
+ def expr_type
25
+ :and_expr
26
+ end
27
+ end
28
+
29
+ class EqualityExpr < AbstractExpr # :nodoc:
30
+ def expr_type
31
+ :equality_expr
32
+ end
33
+ end
34
+
35
+ end