1require 'rexml/validation/validationexception'
2
3module REXML
4  module Validation
5    module Validator
6      NILEVENT = [ nil ]
7      def reset
8        @current = @root
9        @root.reset
10        @root.previous = true
11        @attr_stack = []
12        self
13      end
14      def dump
15        puts @root.inspect
16      end
17      def validate( event )
18        #puts "Current: #@current"
19        #puts "Event: #{event.inspect}"
20        @attr_stack = [] unless defined? @attr_stack
21        match = @current.next(event)
22        raise ValidationException.new( "Validation error.  Expected: "+
23          @current.expected.join( " or " )+" from #{@current.inspect} "+
24          " but got #{Event.new( event[0], event[1] ).inspect}" ) unless match
25        @current = match
26
27        # Check for attributes
28        case event[0]
29        when :start_element
30          #puts "Checking attributes"
31          @attr_stack << event[2]
32          begin
33            sattr = [:start_attribute, nil]
34            eattr = [:end_attribute]
35            text = [:text, nil]
36            k, = event[2].find { |key,value|
37              sattr[1] = key
38              #puts "Looking for #{sattr.inspect}"
39              m = @current.next( sattr )
40              #puts "Got #{m.inspect}"
41              if m
42                # If the state has text children...
43                #puts "Looking for #{eattr.inspect}"
44                #puts "Expect #{m.expected}"
45                if m.matches?( eattr )
46                  #puts "Got end"
47                  @current = m
48                else
49                  #puts "Didn't get end"
50                  text[1] = value
51                  #puts "Looking for #{text.inspect}"
52                  m = m.next( text )
53                  #puts "Got #{m.inspect}"
54                  text[1] = nil
55                  return false unless m
56                  @current = m if m
57                end
58                m = @current.next( eattr )
59                if m
60                  @current = m
61                  true
62                else
63                  false
64                end
65              else
66                false
67              end
68            }
69            event[2].delete(k) if k
70          end while k
71        when :end_element
72          attrs = @attr_stack.pop
73          raise ValidationException.new( "Validation error.  Illegal "+
74            " attributes: #{attrs.inspect}") if attrs.length > 0
75        end
76      end
77    end
78
79    class Event
80      def initialize(event_type, event_arg=nil )
81        @event_type = event_type
82        @event_arg = event_arg
83      end
84
85      attr_reader :event_type
86      attr_accessor :event_arg
87
88      def done?
89        @done
90      end
91
92      def single?
93        return (@event_type != :start_element and @event_type != :start_attribute)
94      end
95
96      def matches?( event )
97        #puts "#@event_type =? #{event[0]} && #@event_arg =? #{event[1]} "
98        return false unless event[0] == @event_type
99        case event[0]
100        when nil
101          return true
102        when :start_element
103          return true if event[1] == @event_arg
104        when :end_element
105          return true
106        when :start_attribute
107          return true if event[1] == @event_arg
108        when :end_attribute
109          return true
110        when :end_document
111          return true
112        when :text
113          return (@event_arg.nil? or @event_arg == event[1])
114=begin
115        when :processing_instruction
116          false
117        when :xmldecl
118          false
119        when :start_doctype
120          false
121        when :end_doctype
122          false
123        when :externalentity
124          false
125        when :elementdecl
126          false
127        when :entity
128          false
129        when :attlistdecl
130          false
131        when :notationdecl
132          false
133        when :end_doctype
134          false
135=end
136        else
137          false
138        end
139      end
140
141      def ==( other )
142        return false unless other.kind_of? Event
143        @event_type == other.event_type and @event_arg == other.event_arg
144      end
145
146      def to_s
147        inspect
148      end
149
150      def inspect
151        "#{@event_type.inspect}( #@event_arg )"
152      end
153    end
154  end
155end
156