1
require "rexml/validation/validation"
2
require "rexml/parsers/baseparser"
38
EMPTY = Event.new( nil )
39
TEXT = [:start_element, "text"]
40
attr_accessor :current
42
attr_reader :references
46
parser = REXML::Parsers::BaseParser.new( source )
50
@root = @current = Sequence.new(self)
59
when "element", "attribute", "text", "value"
62
states << Optional.new( self )
63
states[-2] << states[-1]
65
states << Choice.new( self )
66
states[-2] << states[-1]
68
states << OneOrMore.new( self )
69
states[-2] << states[-1]
71
states << ZeroOrMore.new( self )
72
states[-2] << states[-1]
74
states << Sequence.new( self )
75
states[-2] << states[-1]
77
states << Interleave.new( self )
78
states[-2] << states[-1]
80
states << Interleave.new( self )
81
states[-2] << states[-1]
84
states << [ event[2]["name"] ]
86
states[-1] << Ref.new( event[2]["name"] )
88
states << AnyName.new( self )
89
states[-2] << states[-1]
103
when "element", "attribute"
105
when "zeroOrMore", "oneOrMore", "choice", "optional",
106
"interleave", "group", "mixed"
110
@references[ ref.shift ] = ref
118
end while event[0] != :end_document
127
def initialize( context )
131
@count = context.count += 1
132
@references = context.references
137
return if @current == 0
139
@events.each {|s| s.reset if s.kind_of? State }
142
def previous=( previous )
143
@previous << previous
147
#print "In next with #{event.inspect}. "
148
#puts "Next (#@current) is #{@events[@current]}"
150
return @previous.pop.next( event ) if @events[@current].nil?
151
expand_ref_in( @events, @current ) if @events[@current].class == Ref
152
if ( @events[@current].kind_of? State )
154
@events[@current-1].previous = self
155
return @events[@current-1].next( event )
157
#puts "Current isn't a state"
158
if ( @events[@current].matches?(event) )
160
if @events[@current].nil?
161
#puts "#{inspect[0,5]} 1RETURNING #{@previous.inspect[0,5]}"
163
elsif @events[@current].kind_of? State
165
#puts "#{inspect[0,5]} 2RETURNING (#{@current-1}) #{@events[@current-1].inspect[0,5]}; on return, next is #{@events[@current]}"
166
@events[@current-1].previous = self
167
return @events[@current-1]
169
#puts "#{inspect[0,5]} RETURNING self w/ next(#@current) = #{@events[@current]}"
179
self.class.name =~ /(?:::)(\w)\w+$/
181
#self.class.name =~ /(?:::)(\w+)$/
186
"< #{to_s} #{@events.collect{|e|
187
pre = e == @events[@current] ? '#' : ''
188
pre + e.inspect unless self == e
193
return [@events[@current]]
197
add_event_to_arry( @events, event )
202
def expand_ref_in( arry, ind )
204
@references[ arry[ind].to_s ].each{ |evt|
205
add_event_to_arry(new_events,evt)
207
arry[ind,1] = new_events
210
def add_event_to_arry( arry, evt )
211
evt = generate_event( evt )
212
if evt.kind_of? String
213
arry[-1].event_arg = evt if arry[-1].kind_of? Event and @value
220
def generate_event( event )
221
return event if event.kind_of? State or event.class == Ref
229
arg = event[2]["name"]
231
evt = :start_attribute
232
arg = event[2]["name"]
242
return Event.new( event[0] )
243
else # then :end_element
251
return Event.new( evt, arg )
256
class Sequence < State
258
@events[@current].matches?( event )
263
class Optional < State
268
@prior = @previous.pop
269
return @prior.next( event )
275
@events[@current].matches?(event) ||
276
(@current == 0 and @previous[-1].matches?(event))
280
return [ @prior.expected, @events[0] ].flatten if @current == 0
281
return [@events[@current]]
286
class ZeroOrMore < Optional
288
expand_ref_in( @events, @current ) if @events[@current].class == Ref
289
if ( @events[@current].matches?(event) )
291
if @events[@current].nil?
294
elsif @events[@current].kind_of? State
296
@events[@current-1].previous = self
297
return @events[@current-1]
302
@prior = @previous.pop
303
return @prior.next( event ) if @current == 0
309
return [ @prior.expected, @events[0] ].flatten if @current == 0
310
return [@events[@current]]
315
class OneOrMore < State
316
def initialize context
327
expand_ref_in( @events, @current ) if @events[@current].class == Ref
328
if ( @events[@current].matches?(event) )
331
if @events[@current].nil?
334
elsif @events[@current].kind_of? State
336
@events[@current-1].previous = self
337
return @events[@current-1]
342
return @previous.pop.next( event ) if @current == 0 and @ord > 0
347
def matches?( event )
348
@events[@current].matches?(event) ||
349
(@current == 0 and @ord > 0 and @previous[-1].matches?(event))
353
if @current == 0 and @ord > 0
354
return [@previous[-1].expected, @events[0]].flatten
356
return [@events[@current]]
363
def initialize context
371
@choices.each { |c| c.each { |s| s.reset if s.kind_of? State } }
375
add_event_to_arry( @choices, event )
379
# Make the choice if we haven't
381
c = 0 ; max = @choices.size
383
if @choices[c][0].class == Ref
384
expand_ref_in( @choices[c], 0 )
385
@choices += @choices[c]
386
@choices.delete( @choices[c] )
392
@events = @choices.find { |evt| evt[0].matches? event }
393
# Remove the references
396
#puts "In next with #{event.inspect}."
397
#puts "events is #{@events.inspect}"
402
#puts "current = #@current"
406
def matches?( event )
407
return @events[@current].matches?( event ) if @events.size > 0
408
!@choices.find{|evt| evt[0].matches?(event)}.nil?
412
#puts "IN CHOICE EXPECTED"
413
#puts "EVENTS = #{@events.inspect}"
414
return [@events[@current]] if @events.size > 0
415
return @choices.collect do |x|
416
if x[0].kind_of? State
425
"< #{to_s} #{@choices.collect{|e| e.collect{|f|f.to_s}.join(', ')}.join(' or ')} >"
429
def add_event_to_arry( arry, evt )
430
if evt.kind_of? State or evt.class == Ref
432
elsif evt[0] == :text
434
arry[-1][-1].kind_of?( Event ) and
435
arry[-1][-1].event_type == :text and @value
437
arry[-1][-1].event_arg = evt[1]
441
arry << [] if evt[0] == :start_element
442
arry[-1] << generate_event( evt )
448
class Interleave < Choice
449
def initialize context
458
def next_current( event )
460
c = 0 ; max = @choices.size
462
if @choices[c][0].class == Ref
463
expand_ref_in( @choices[c], 0 )
464
@choices += @choices[c]
465
@choices.delete( @choices[c] )
471
@events = @choices[@choice..-1].find { |evt| evt[0].matches? event }
474
# reorder the choices
475
old = @choices[@choice]
476
idx = @choices.index( @events )
477
@choices[@choice] = @events
482
#puts "In next with #{event.inspect}."
483
#puts "events is #{@events.inspect}"
484
@events = [] unless @events
489
# Find the next series
490
next_current(event) unless @events[@current]
491
return nil unless @events[@current]
493
expand_ref_in( @events, @current ) if @events[@current].class == Ref
494
#puts "In next with #{event.inspect}."
495
#puts "Next (#@current) is #{@events[@current]}"
496
if ( @events[@current].kind_of? State )
498
@events[@current-1].previous = self
499
return @events[@current-1].next( event )
501
#puts "Current isn't a state"
502
return @previous.pop.next( event ) if @events[@current].nil?
503
if ( @events[@current].matches?(event) )
505
if @events[@current].nil?
506
#puts "#{inspect[0,5]} 1RETURNING self" unless @choices[@choice].nil?
507
return self unless @choices[@choice].nil?
508
#puts "#{inspect[0,5]} 1RETURNING #{@previous[-1].inspect[0,5]}"
510
elsif @events[@current].kind_of? State
512
#puts "#{inspect[0,5]} 2RETURNING (#{@current-1}) #{@events[@current-1].inspect[0,5]}; on return, next is #{@events[@current]}"
513
@events[@current-1].previous = self
514
return @events[@current-1]
516
#puts "#{inspect[0,5]} RETURNING self w/ next(#@current) = #{@events[@current]}"
524
def matches?( event )
525
return @events[@current].matches?( event ) if @events[@current]
526
!@choices[@choice..-1].find{|evt| evt[0].matches?(event)}.nil?
530
#puts "IN CHOICE EXPECTED"
531
#puts "EVENTS = #{@events.inspect}"
532
return [@events[@current]] if @events[@current]
533
return @choices[@choice..-1].collect do |x|
534
if x[0].kind_of? State
543
"< #{to_s} #{@choices.collect{|e| e.collect{|f|f.to_s}.join(', ')}.join(' and ')} >"