summaryrefslogtreecommitdiff
path: root/lib/rexml/validation/validation.rb
blob: 93f5bfb32930c9d2193fe6e6225221b8b449738a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
require 'rexml/validation/validationexception'

module REXML
  module Validation
    module Validator
      NILEVENT = [ nil ]
      def reset
        @current = @root
        @root.reset
        @root.previous = true
        @attr_stack = []
        self
      end
      def dump
        puts @root.inspect
      end
      def validate( event ) 
        #puts "Current: #@current"
        #puts "Event: #{event.inspect}"
        @attr_stack = [] unless defined? @attr_stack
        match = @current.next(event)
        raise ValidationException.new( "Validation error.  Expected: "+
          @current.expected.join( " or " )+" from #{@current.inspect} "+
          " but got #{Event.new( event[0], event[1] ).inspect}" ) unless match
        @current = match

        # Check for attributes
        case event[0]
        when :start_element
          #puts "Checking attributes"
          @attr_stack << event[2]
          begin
            sattr = [:start_attribute, nil]
            eattr = [:end_attribute]
            text = [:text, nil]
            k,v = event[2].find { |key,value| 
              sattr[1] = key
              #puts "Looking for #{sattr.inspect}"
              m = @current.next( sattr )
              #puts "Got #{m.inspect}"
              if m 
                # If the state has text children...
                #puts "Looking for #{eattr.inspect}"
                #puts "Expect #{m.expected}"
                if m.matches?( eattr )
                  #puts "Got end"
                  @current = m
                else
                  #puts "Didn't get end"
                  text[1] = value
                  #puts "Looking for #{text.inspect}"
                  m = m.next( text )
                  #puts "Got #{m.inspect}"
                  text[1] = nil
                  return false unless m
                  @current = m if m
                end
                m = @current.next( eattr )
                if m
                  @current = m
                  true
                else
                  false
                end
              else
                false
              end
            }
            event[2].delete(k) if k
          end while k
        when :end_element
          attrs = @attr_stack.pop
          raise ValidationException.new( "Validation error.  Illegal "+
            " attributes: #{attrs.inspect}") if attrs.length > 0
        end
      end
    end

    class Event
      def initialize(event_type, event_arg=nil )
        @event_type = event_type
        @event_arg = event_arg
      end

      attr_reader :event_type
      attr_accessor :event_arg

      def done?
        @done
      end

      def single?
        return (@event_type != :start_element and @event_type != :start_attribute)
      end

      def matches?( event )
        #puts "#@event_type =? #{event[0]} && #@event_arg =? #{event[1]} "
        return false unless event[0] == @event_type
        case event[0]
        when nil
          return true
        when :start_element
          return true if event[1] == @event_arg
        when :end_element
          return true
        when :start_attribute
          return true if event[1] == @event_arg
        when :end_attribute
          return true
        when :end_document
          return true
        when :text
          return (@event_arg.nil? or @event_arg == event[1])
=begin
        when :processing_instruction
          false
        when :xmldecl
          false
        when :start_doctype
          false
        when :end_doctype
          false
        when :externalentity
          false
        when :elementdecl
          false
        when :entity
          false
        when :attlistdecl
          false
        when :notationdecl
          false
        when :end_doctype
          false
=end
        else
          false
        end
      end

      def ==( other )
        return false unless other.kind_of? Event
        @event_type == other.event_type and @event_arg == other.event_arg
      end

      def to_s
        inspect
      end

      def inspect
        "#{@event_type.inspect}( #@event_arg )"
      end
    end
  end
end