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,333 @@
1
+ # coding : utf-8
2
+
3
+ require "strscan"
4
+
5
+ require "vcdom/xpath/xpath_expression"
6
+ require "vcdom/xpath/xpath_result"
7
+ require "vcdom/xpath/internal/value"
8
+ require "vcdom/xpath/internal/expr"
9
+ require "vcdom/xpath/internal/command"
10
+
11
+ module VCDOM::XPath::Internal # :nodoc:
12
+
13
+ class Parser # :nodoc: all
14
+
15
+ regexp_str_creating_proc = lambda { |*args|
16
+ args.length == 1 ? [ args[0] ].pack( "U1" ) : [ args[0], 0x2D, args[1] ].pack( "U3" )
17
+ }
18
+
19
+ xml_name_start_char = [
20
+ [ 0xC0, 0xD6 ],
21
+ [ 0xD8, 0xF6 ],
22
+ [ 0xF8, 0x2FF ],
23
+ [ 0x370, 0x37D ],
24
+ [ 0x37F, 0x1FFF ],
25
+ [ 0x200C, 0x200D ],
26
+ [ 0x2070, 0x218F ],
27
+ [ 0x2C00, 0x2FEF ],
28
+ [ 0x3001, 0xD7FF ],
29
+ [ 0xF900, 0xFDCF ],
30
+ [ 0xFDF0, 0xFFFD ],
31
+ [ 0x10000, 0xEFFFF ]
32
+ ].inject( String.new( "_a-zA-Z" ) ) do |s,pair|
33
+ s << regexp_str_creating_proc.call( *pair )
34
+ end
35
+
36
+ xml_name_char = [
37
+ [ 0xB7 ],
38
+ [ 0x0300, 0x036F ],
39
+ [ 0x203F, 0x2040 ]
40
+ ].inject( String.new( xml_name_start_char + "\\-\\.\\d" ) ) do |s,pair|
41
+ s << regexp_str_creating_proc.call( *pair )
42
+ end
43
+
44
+ xml_nc_name = "[#{xml_name_start_char}][#{xml_name_char}]*"
45
+ xml_q_name = "(?:#{xml_nc_name}:)?#{xml_nc_name}"
46
+ xpath_literal = "\"[^\"]*\"|'[^']*'"
47
+ xpath_operator = "\\/?\\/|\\||\\+|\\-|=|\\!=|<=?|>=?"
48
+ xpath_sign = "\\(|\\)|\\[|\\]|\\.\\.?|@|,|::"
49
+ xpath_number = "\\d+(?:\\.\\d*)?|\\.\\d+"
50
+ #xpath_varref = "\\$#{xml_q_name}" # varref は anyname と結合
51
+ xpath_anyname = "(?:#{xml_nc_name}:)?\\*|\\$?#{xml_q_name}"
52
+ #XML_NC_NAME_REGEXP = /#{xml_nc_name}/u
53
+ #XML_Q_NAME_REGEXP = /(?:#{xml_nc_name}:)?#{xml_nc_name}/u
54
+
55
+ xpath_token = xpath_literal + "|" + xpath_number + "|" + xpath_anyname + "|" + xpath_operator + "|" + xpath_sign
56
+
57
+ XML_Q_NAME = /#{xml_q_name}/u
58
+ XPATH_TOKEN_REGEXP = /#{xpath_token}/u
59
+ XPATH_WHITE_SPACE_REGEXP = /[\x20\x0A\x0D\x09]+/u
60
+
61
+ #def next_token()
62
+ # @scanner.skip XPATH_WHITE_SPACE_REGEXP
63
+ # if ( token = @scanner.scan XPATH_TOKEN_REGEXP ).nil? then
64
+ # raise "Invalid XPath expression" unless @scanner.eos?
65
+ # end
66
+ # token
67
+ #end
68
+
69
+ class XPathStringScanner < StringScanner
70
+ XPATH_WHITE_SPACE_REGEXP = /[\x20\x0A\x0D\x09]+/u
71
+ def scan( regexp )
72
+ skip XPATH_WHITE_SPACE_REGEXP
73
+ super( regexp )
74
+ end
75
+ def check( regexp )
76
+ skip XPATH_WHITE_SPACE_REGEXP
77
+ super( regexp )
78
+ end
79
+ end
80
+
81
+ def initialize( xpath_str, ns_resolver )
82
+ @scanner = XPathStringScanner.new( xpath_str )
83
+ @ns_resolver = ns_resolver
84
+ end
85
+
86
+ def parse()
87
+ expr = parse_expr()
88
+ raise "invalid xpath [#{@scanner.rest}]" unless @scanner.eos?
89
+ expr
90
+ end
91
+
92
+ def parse_expr()
93
+ parse_or_expr()
94
+ end
95
+
96
+ def parse_or_expr()
97
+ expr = parse_and_expr()
98
+ if @scanner.check( /or/u ) then
99
+ tmp = expr
100
+ expr = OrExpr.new()
101
+ expr << tmp
102
+ while @scanner.scan( /or/u ) do
103
+ expr << parse_and_expr()
104
+ end
105
+ end
106
+ expr
107
+ end
108
+
109
+ def parse_and_expr()
110
+ expr = parse_equality_expr()
111
+ if token = @scanner.check( /and/u ) then
112
+ tmp = expr
113
+ expr = AndExpr.new()
114
+ expr << tmp
115
+ while @scanner.scan( /and/u ) do
116
+ expr << parse_equality_expr()
117
+ end
118
+ end
119
+ expr
120
+ end
121
+
122
+ def parse_equality_expr()
123
+ expr = VCDOM::XPath::Internal::EqualityExpr.new()
124
+ parse_relational_expr( expr )
125
+ while token = @scanner.scan( /=|\!=/u ) do
126
+ parse_relational_expr( expr )
127
+ expr << VCDOM::XPath::Internal.get_operation_command( token.intern )
128
+ end
129
+ expr
130
+ end
131
+
132
+ def parse_relational_expr( expr )
133
+ parse_additive_expr( expr )
134
+ while token = @scanner.scan( /\<=?|\>=?/u ) do
135
+ parse_additive_expr( expr )
136
+ expr << VCDOM::XPath::Internal.get_operation_command( token.intern )
137
+ end
138
+ end
139
+
140
+ def parse_additive_expr( expr )
141
+ parse_multiplicative_expr( expr )
142
+ while token = @scanner.scan( /\+|\-/u ) do
143
+ parse_multiplicative_expr( expr )
144
+ expr << VCDOM::XPath::Internal.get_operation_command( token.intern )
145
+ end
146
+ end
147
+
148
+ def parse_multiplicative_expr( expr )
149
+ parse_unary_expr( expr )
150
+ while token = @scanner.scan( /\*|div|mod/u ) do
151
+ parse_unary_expr( expr )
152
+ expr << VCDOM::XPath::Internal.get_operation_command( token.intern )
153
+ end
154
+ end
155
+
156
+ def parse_unary_expr( expr )
157
+ num = 0
158
+ while @scanner.scan( /\-/u ) do
159
+ num += 1
160
+ end
161
+ parse_union_expr( expr )
162
+ num.times do
163
+ expr << VCDOM::XPath::Internal.get_operation_command( :"-@" )
164
+ end
165
+ end
166
+
167
+ def parse_union_expr( expr )
168
+ parse_path_expr( expr )
169
+ while @scanner.scan( /\|/u ) do
170
+ parse_path_expr( expr )
171
+ expr << VCDOM::XPath::Internal.get_operation_command( :"|" )
172
+ end
173
+ end
174
+
175
+ XPATH_PATH_EXPR_STARTER_REGEXP = /#{xpath_number}|#{xpath_literal}|#{xpath_anyname}|\/\/?|\.\.?|@|\(/u
176
+ XPATH_VARIABLE_REFERENCE_REGEXP = /\$#{xml_q_name}/u
177
+ XPATH_NUMBER_REGEXP = /#{xpath_number}/u
178
+ XPATH_LITERAL_REGEXP = /#{xpath_literal}/u
179
+ XPATH_NAME_TEST = /(?:#{xml_nc_name}:)?\*|#{xml_q_name}/u
180
+ XPATH_STEP_STARTER_REGEXP = /\*|\.\.?|@|#{xml_q_name}/u
181
+ # VariableReference
182
+ # '(' Expr ')'
183
+ # Literal
184
+ # Number
185
+ # FunctionCall
186
+ def parse_path_expr( expr )
187
+ is_path = false
188
+ if token = @scanner.scan( XPATH_NUMBER_REGEXP ) then
189
+ # Number の場合
190
+ expr << VCDOM::XPath::Internal::NumberValue.new( token.to_f() )
191
+ elsif token = @scanner.scan( XPATH_LITERAL_REGEXP) then
192
+ # Literal の場合
193
+ token[0,1] = ""
194
+ token[-1,1] = ""
195
+ expr << VCDOM::XPath::Internal::StringValue.new( token )
196
+ elsif token = @scanner.scan( XPATH_VARIABLE_REFERENCE_REGEXP ) then
197
+ # VariableReference の場合
198
+ raise "VariableReference is not supported"
199
+ elsif @scanner.scan( /\(/u ) then
200
+ # "(" Expr ")" の場合
201
+ expr << VCDOM::XPath::Internal::ExprEvalCommand.new( parse_expr() )
202
+ raise "invalid xpath expression" unless @scanner.scan( /\)/u )
203
+ else
204
+ # Path or FunctionCall
205
+ pos = @scanner.pos
206
+ is_path = true
207
+ if token = @scanner.scan( XML_Q_NAME ) then
208
+ # FunctionName or AxisName or NameTest or NodeType
209
+ if @scanner.scan( /\(/u ) then
210
+ # FunctionName or NodeType
211
+ case token
212
+ when "comment", "text", "processing-instruction", "node"
213
+ # do nothing
214
+ else
215
+ # FunctionName
216
+ is_path = false
217
+ end
218
+ end
219
+ end
220
+ if is_path then
221
+ # Path
222
+ @scanner.pos = pos
223
+ if token = @scanner.scan( /\/\/?/u ) then
224
+ # "/" or "//"
225
+ expr << VCDOM::XPath::Internal::RootNodeCommand.get_instance()
226
+ if token == "/" then
227
+ # 続く要素がなければここで終了
228
+ return unless @scanner.check( XPATH_STEP_STARTER_REGEXP )
229
+ else # "//"
230
+ expr << VCDOM::XPath::Internal::NodeSelectionCommand.new( :"descendant-or-self", :node, nil, nil, nil )
231
+ end
232
+ else
233
+ expr << VCDOM::XPath::Internal::ContextNodeCommand.get_instance()
234
+ end
235
+ expr << parse_step()
236
+ else
237
+ # FunctionCall
238
+ function_name = token.intern
239
+ arg_exprs = @scanner.check( /\)/u ) ? nil : parse_expr_list()
240
+ raise "invalid xpath [#{@scanner.rest}]" unless @scanner.scan( /\)/u )
241
+ expr << FunctionCallCommand.new( function_name, arg_exprs )
242
+ end
243
+ end
244
+ if not is_path then
245
+ if @scanner.check( /\[/u ) then
246
+ pred_exprs = parse_predicates()
247
+ expr << PredsEvalCommand.new( pred_exprs )
248
+ end
249
+ end
250
+ while token = @scanner.scan( /\/\/?/ ) do
251
+ if token == "//" then
252
+ expr << VCDOM::XPath::Internal::NodeSelectionCommand.new( :"descendant-or-self", :node, nil, nil, nil )
253
+ end
254
+ expr << parse_step()
255
+ end
256
+ end
257
+
258
+ AXIS_NAME_LIST = [ :'ancestor', :'ancestor-or-self', :'attribute', :'child', :'descendant', :'descendant-or-self',
259
+ :'following', :'following-sibling', :'namespace', :'parent', :'preceding', :'preceding-sibling', :'self' ]
260
+ NODE_TYPE_LIST = [ :'comment', :'text', :'processing-instruction', :'node' ]
261
+ def parse_step()
262
+ # "." or ".."
263
+ if @scanner.scan( /\.\./u ) then
264
+ return VCDOM::XPath::Internal::NodeSelectionCommand.new( :parent, :node, nil, nil, nil )
265
+ elsif token = @scanner.scan( /\./u ) then
266
+ return VCDOM::XPath::Internal::NodeSelectionCommand.new( :self, :node, nil, nil, nil )
267
+ end
268
+ # AxisName
269
+ pos = @scanner.pos
270
+ if @scanner.scan( /@/u ) then
271
+ axis_name = :attribute
272
+ elsif token = @scanner.scan( XML_Q_NAME ) then
273
+ if @scanner.scan( /::/u ) then
274
+ axis_name = token.intern
275
+ raise "invalid AxisName [#{axis_name}]" unless AXIS_NAME_LIST.include? axis_name
276
+ else
277
+ axis_name = :child
278
+ @scanner.pos = pos
279
+ end
280
+ else
281
+ axis_name = :child
282
+ end
283
+ # NameTest or NodeType
284
+ if token = @scanner.scan( XPATH_NAME_TEST ) then
285
+ if @scanner.scan( /\(/u ) then
286
+ # NodeType
287
+ node_type = token.intern
288
+ raise "invalid NodeType [#{node_type}]" unless NODE_TYPE_LIST.include? node_type
289
+ node_name = ( node_type == :"processing-instruction" and token = @scanner.scan( XPATH_LITERAL ) ) ? token.intern : nil
290
+ node_ns_uri = nil
291
+ raise "invalid xpath expression" unless @scanner.scan( /\)/u )
292
+ else
293
+ # NameTest
294
+ node_type = :named_node
295
+ name_pair = token.split( /:/u )
296
+ if name_pair.length == 2 then
297
+ node_name = ( name_pair[1] == "*" ) ? nil : name_pair[1].intern
298
+ node_ns_uri = @ns_resolver.lookup_namespace_uri( name_pair[0] )
299
+ node_ns_uri.nil? or node_ns_uri = node_ns_uri.intern
300
+ else
301
+ # length == 1
302
+ node_name = ( name_pair[0] == "*" ) ? nil : name_pair[0].intern
303
+ node_ns_uri = nil
304
+ end
305
+ end
306
+ else
307
+ raise "invalid xpath expression [#{@scanner.rest}]"
308
+ end
309
+ # Predicate
310
+ pred_exprs = @scanner.check( /\[/u ) ? parse_predicates() : nil
311
+ VCDOM::XPath::Internal::NodeSelectionCommand.new( axis_name, node_type, node_ns_uri, node_name, pred_exprs )
312
+ end
313
+
314
+ def parse_expr_list()
315
+ exprs = Array.new()
316
+ exprs << parse_expr()
317
+ while @scanner.scan( /,/u ) do
318
+ exprs << parse_expr()
319
+ end
320
+ exprs
321
+ end
322
+
323
+ def parse_predicates()
324
+ exprs = Array.new()
325
+ while @scanner.scan( /\[/u ) do
326
+ exprs << parse_expr()
327
+ raise "invalid xpath expression" unless @scanner.scan( /\]/u )
328
+ end
329
+ exprs
330
+ end
331
+
332
+ end
333
+ end
@@ -0,0 +1,342 @@
1
+ # coding : utf-8
2
+
3
+ module VCDOM::XPath::Internal # :nodoc:
4
+
5
+ class AbstractValue # :nodoc:
6
+
7
+ def is_value?; true end
8
+ def is_expr?; false end
9
+ def is_command?; false end
10
+
11
+ def to_s()
12
+ "XPathValue(#{value})"
13
+ end
14
+
15
+ def -@(); - self.to_number_value end
16
+ def +( val ); self.to_number_value + val end
17
+ def -( val ); self.to_number_value - val end
18
+ def *( val ); self.to_number_value * val end
19
+ def /( val ); self.to_number_value / val end
20
+ def %( val ); self.to_number_value % val end
21
+
22
+ def |( val )
23
+ raise "User Error : xpath operator \"|\" must operate NodeSet"
24
+ end
25
+
26
+ def ==( val )
27
+ types = [ self.value_type, val.value_type ]
28
+ if types.include? :boolean then
29
+ return val.to_boolean_value.value == self.to_boolean_value.value ? BooleanValue.true : BooleanValue.false
30
+ elsif types.include? :node_set then
31
+ # TODO : node-set が含まれている場合
32
+ val == self
33
+ elsif types.include? :number
34
+ return val.to_number_value.value == self.to_number_value.value ? BooleanValue.true : BooleanValue.false
35
+ else
36
+ return val.to_string_value.value == self.to_string_value.value ? BooleanValue.true : BooleanValue.false
37
+ end
38
+ end
39
+
40
+ def neq?( val )
41
+ if val.value_type == :node_set then
42
+ return val.neq? self
43
+ else
44
+ return ( self == val ? BooleanValue.false : BooleanValue.true )
45
+ end
46
+ end
47
+
48
+ def <=>( val )
49
+ if val.value_type == :node_set then
50
+ return ( val <=> self ) * -1
51
+ else
52
+ return self.to_number_value.value <=> val.to_number_value.value
53
+ end
54
+ end
55
+ def <( val )
56
+ ( self <=> val ) < 0 ? BooleanValue.true : BooleanValue.false
57
+ end
58
+ def <=( val )
59
+ ( self <=> val ) <= 0 ? BooleanValue.true : BooleanValue.false
60
+ end
61
+ def >( val )
62
+ ( self <=> val ) > 0 ? BooleanValue.true : BooleanValue.false
63
+ end
64
+ def >=( val )
65
+ ( self <=> val ) >= 0 ? BooleanValue.true : BooleanValue.false
66
+ end
67
+
68
+ end
69
+
70
+ class NumberValue < AbstractValue # :nodoc:
71
+
72
+ def initialize( val )
73
+ @value = val.to_f
74
+ end
75
+ ##
76
+ # NaN -> "NaN"
77
+ # 正ゼロ, 負ゼロ -> "0"
78
+ # 正の無限大 -> "Infinity"
79
+ # 負の無限大 -> "-Infinity"
80
+ # 数値が整数である場合, 数値は 10 進形式で, 小数点がなく先頭のゼロもない [0-9]+ として表現され,
81
+ # 数値が負である場合には負号 (-) が前につく
82
+ # それ以外 -> 数値は 10 進形式で [0-9]+ "." [0-9]+ として表現され, 数値が負である場合には負号 (-) が前につく
83
+ # 小数点の直前にある必須の数字 1 個を別として, 小数点の前に先頭のゼロがあってはならない.
84
+ # 小数点の後の必須の数字1個を越えてそれ以上の数字は, その数値をその他すべての IEEE 754 数値から一意的に区別するのに
85
+ # 必要な数字がなければならないが, 必要なだけしかあってはならない
86
+ def to_string_value()
87
+ if @value.nan? then
88
+ str = StringValue.new("NaN")
89
+ elsif @value.infinite? == 1 then
90
+ str = StringValue.new("Infinity")
91
+ elsif @value.infinite? == -1 then
92
+ str = StringValue.new("-Infinity")
93
+ elsif @value.zero? then
94
+ str = StringValue.new("0")
95
+ elsif @value.truncate == @value then
96
+ str = StringValue.new(@value.to_i.to_s)
97
+ else
98
+ str = StringValue.new(@value.to_s)
99
+ end
100
+ str
101
+ end
102
+
103
+ def to_number_value()
104
+ self
105
+ end
106
+
107
+ # 数値は、正または負のゼロでなくNaNでもない場合に、かつない場合にのみ、真である。
108
+ def to_boolean_value()
109
+ ( @value.zero? || @value.nan? ) ? BooleanValue.false : BooleanValue.true
110
+ end
111
+
112
+ attr_reader :value
113
+ def value_type; :number end
114
+
115
+ # define operations
116
+
117
+ def -@(); @value = - @value; self end
118
+ def +( val ); NumberValue.new( @value + val.to_number_value.value ) end
119
+ def -( val ); NumberValue.new( @value - val.to_number_value.value ) end
120
+ def *( val ); NumberValue.new( @value * val.to_number_value.value ) end
121
+ def /( val ); NumberValue.new( @value / val.to_number_value.value ) end
122
+ def %( val )
123
+ value1 = val.to_number_value.value
124
+ value1 < 0 && value1 = -value1
125
+ value2 = @value
126
+ if value2 < 0 then
127
+ value2 = - value2
128
+ value2 %= value1
129
+ value2 = - value2
130
+ else
131
+ value2 %= value1
132
+ end
133
+ NumberValue.new( value2 )
134
+ end
135
+
136
+ end
137
+
138
+ class StringValue < AbstractValue # :nodoc:
139
+
140
+ def initialize( val )
141
+ @value = val.to_s
142
+ end
143
+ def to_string_value()
144
+ self
145
+ end
146
+
147
+ # StringValue を NumberValue に変換する
148
+ # オプションの空白にオプションの負号 1 個が続き, [0-9]("." [0-9]*)? | "." [0-9]+ が続いて空白が続いたものからなる文字列は,
149
+ # その文字列が表す数学的値に (IEEE 754 最近接値丸めルールに従い) 最も近い IEEE 754 数値に変換される.
150
+ # その他の文字列はどれも NaN に変換される.
151
+ def to_number_value()
152
+ str = @value.gsub( /[\x20\x09\x0A\x0D]/u, "" )
153
+ if str =~ /\A\-?(?:\d+(?:\.\d*)?|\.\d+)\Z/ then
154
+ # NaN
155
+ return NumberValue.new( str.to_f )
156
+ else
157
+ # NaN
158
+ return NumberValue.new( 0.0 / 0.0 )
159
+ end
160
+ end
161
+
162
+ # 文字列は、その長さが非ゼロである場合に、かつ非ゼロである場合にのみ、真である。
163
+ def to_boolean_value()
164
+ @value.length != 0 ? BooleanValue.true : BooleanValue.false
165
+ end
166
+
167
+ attr_reader :value
168
+ def value_type; :string end
169
+
170
+ end
171
+
172
+ class BooleanValue < AbstractValue # :nodoc:
173
+
174
+ def initialize( val )
175
+ @value = !! val
176
+ end
177
+ def to_string_value()
178
+ @value ? StringValue.new("true") : StringValue.new("false")
179
+ end
180
+
181
+ # convert a BooleanValue object to a NumberValue object.
182
+ # オプションの空白にオプションの負号 1 個が続き, [0-9]("." [0-9]*)? | "." [0-9]+ が続いて空白が続いたものからなる文字列は,
183
+ # その文字列が表す数学的値に (IEEE 754 最近接値丸めルールに従い) 最も近い IEEE 754 数値に変換される.
184
+ # その他の文字列はどれも NaN に変換される.
185
+ def to_number_value()
186
+ @value ? NumberValue.new( 1.0 ) : NumberValue.new( 0.0 )
187
+ end
188
+
189
+ def to_boolean_value()
190
+ self
191
+ end
192
+
193
+ attr_reader :value
194
+ def value_type; :boolean end
195
+
196
+ TRUE = self.new( true )
197
+ FALSE = self.new( false )
198
+ def self.true; TRUE end
199
+ def self.false; FALSE end
200
+
201
+ end
202
+
203
+ class NodeSetValue < AbstractValue # :nodoc:
204
+
205
+ def initialize( *nodes )
206
+ @value = nodes
207
+ end
208
+ def to_string_value()
209
+ # TODO
210
+ raise "NOT SUPPORT"
211
+ end
212
+
213
+ def to_number_value()
214
+ # TODO
215
+ raise "NOT SUPPORT"
216
+ end
217
+
218
+ def to_boolean_value()
219
+ @value.empty? ? BooleanValue.false : BooleanValue.true
220
+ end
221
+
222
+ def []( *args )
223
+ @value.[]( *args )
224
+ end
225
+ def <<( node )
226
+ @value << node
227
+ end
228
+
229
+ def sort( document_order = true )
230
+ # TODO
231
+ #@value.sort! { |a,b|
232
+ #
233
+ # case a. b
234
+ # when :document_position_preceding,
235
+ # when :document_position_following, # a が b より後ろ
236
+ #}
237
+ end
238
+
239
+ def each
240
+ # TODO : ブロックが与えられなかった場合の処理
241
+ @value.each do |v|
242
+ yield v
243
+ end
244
+ end
245
+ def each_with_index
246
+ # TODO : ブロックが与えられなかった場合の処理
247
+ @value.each_with_index do |v,i|
248
+ yield v,i
249
+ end
250
+ end
251
+
252
+ def length
253
+ @value.length
254
+ end
255
+
256
+ attr_reader :value
257
+ def value_type; :node_set end
258
+
259
+ def |( val )
260
+ val.|(self) if val.value_type != :node_set
261
+ @value = @value + val.value
262
+ @value.uniq!
263
+ self
264
+ end
265
+
266
+ # 比較されるべきオブジェクトの双方がノードセットである場合、比較は、2つのノードの文字列値について
267
+ # 比較を実行した結果が真であるようなノードが、1つ目のノードセットと2つ目のノードセットとにある場合に、
268
+ # かつある場合にのみ、真ということになる。比較されるべきオブジェクトの一方がノードセットであり、
269
+ # 他方が数値である場合、比較は、比較されるべき数値と、number 関数を用いてノードの文字列値を数値に変換
270
+ # した結果とについて比較を実行した結果が真であるようなノードが、ノードセットの中にある場合に、かつある
271
+ # 場合にのみ、真ということになる。比較されるべきオブジェクトの一方がノードセットであり、他方が文字列で
272
+ # ある場合、比較は、ノードの文字列値と他方の文字列とについて比較を実行した結果が真であるようなノードが、
273
+ # ノードセットの中にある場合に、かつある場合にのみ、真ということになる。比較されるべきオブジェクトの一方が
274
+ # ノードセットであり、他方がブール値である場合、比較は、ブール値と、boolean 関数を用いてノードセット
275
+ # をブール値に変換した結果とについて比較を実行した結果が真である場合に、かつ真である場合にのみ、真ということになる。
276
+ def ==( val )
277
+ case val.value_type
278
+ when :node_set
279
+ @value.each do |node1|
280
+ str1 = StringValue.new( node1.text_content )
281
+ val.each do |node2|
282
+ return BooleanValue.true if ( str1 == StringValue.new( node2.text_content ) ) == BooleanValue.true
283
+ end
284
+ end
285
+ return BooleanValue.false
286
+ when :number
287
+ # TODO
288
+ raise "NOT SUPPORT"
289
+ when :string
290
+ # TODO
291
+ raise "NOT SUPPORT"
292
+ when :boolean
293
+ return val == self
294
+ end
295
+ end
296
+
297
+ def neq?( val )
298
+ case val.value_type
299
+ when :node_set
300
+ @value.each do |node1|
301
+ str1 = StringValue.new( node1.text_content )
302
+ val.each do |node2|
303
+ return BooleanValue.true if ( str1.neq? StringValue.new( node2.text_content ) ) == BooleanValue.true
304
+ end
305
+ end
306
+ return BooleanValue.false
307
+ when :number
308
+ # TODO
309
+ raise "NOT SUPPORT"
310
+ when :string
311
+ # TODO
312
+ raise "NOT SUPPORT"
313
+ when :boolean
314
+ return val.neq? self
315
+ end
316
+ end
317
+
318
+ def <=>( val )
319
+ # TODO
320
+ case val.value_type
321
+ when :node_set
322
+ @value.each do |node1|
323
+ str1 = StringValue.new( node1.text_content )
324
+ val.each do |node2|
325
+ return BooleanValue.true if ( str1 <=> StringValue.new( node2.text_content ) ) == BooleanValue.true
326
+ end
327
+ end
328
+ return BooleanValue.false
329
+ when :number
330
+ # TODO
331
+ raise "NOT SUPPORT"
332
+ when :string
333
+ # TODO
334
+ raise "NOT SUPPORT"
335
+ when :boolean
336
+ return self.to_boolean_value <=> val
337
+ end
338
+ end
339
+
340
+ end
341
+
342
+ end
@@ -0,0 +1,32 @@
1
+ # coding : utf-8
2
+
3
+ require "vcdom/xpath/xpath_expression"
4
+ require "vcdom/xpath/xpath_ns_resolver"
5
+ require "vcdom/xpath/xpath_result"
6
+ require "vcdom/xpath/internal/parser"
7
+
8
+ module VCDOM::XPath
9
+
10
+ module XPathEvaluatorMod
11
+
12
+ def create_expression( expression, resolver )
13
+ XPathExpression.new( Internal::Parser.new( expression, resolver ).parse() )
14
+ end
15
+
16
+ # Adapts any DOM node to resolve namespaces so that an XPath expression can be easily
17
+ # evaluated relative to the context of the node where it appeared within the document.
18
+ # This adapter works like the DOM Level 3 method lookupNamespaceURI on nodes in resolving
19
+ # the namespaceURI from a given prefix using the current information available in the
20
+ # node's hierarchy at the time lookupNamespaceURI is called. also correctly resolving
21
+ # the implicit xml prefix.
22
+ def create_ns_resolver( node_resolver )
23
+ XPathNSResolver.new( node_resolver )
24
+ end
25
+
26
+ def evaluate( expression, context_node, resolver, type, result = nil )
27
+ return self.create_expression( expression, resolver ).evaluate( context_node, type, result )
28
+ end
29
+
30
+ end
31
+
32
+ end