Class: SvgConform::SaxValidationHandler
- Inherits:
-
Nokogiri::XML::SAX::Document
- Object
- Nokogiri::XML::SAX::Document
- SvgConform::SaxValidationHandler
- Defined in:
- lib/svg_conform/sax_validation_handler.rb
Overview
SAX event handler for streaming SVG validation Processes XML events and dispatches to requirements
Requirement classification
The handler classifies requirements into two categories:
-
Immediate validation requirements (14) - validate during parsing
- These requirements implement
validate_sax_elementand validate each element as it is encountered - No state is maintained between elements
- These requirements implement
-
Deferred validation requirements (3) - collect data, validate at end
- These requirements implement
collect_sax_dataandvalidate_sax_complete - State is stored in requirement-specific State classes via
context.state_for - Validation happens after parsing is complete, when all data is available
- These requirements implement
State management
Each handler instance has its own cache and fresh requirement instances, ensuring no state leakage between validations.
Profile reuse for multiple validations:
- Profile is created once with requirement instances (configuration from YAML)
- Each validation creates a fresh SaxValidationHandler with fresh ValidationContext
- ValidationContext creates fresh State instances for deferred requirements
- No state pollution occurs across validations
Instance Attribute Summary collapse
-
#context ⇒ Object
readonly
Returns the value of attribute context.
-
#result ⇒ Object
readonly
Get result (will be nil until end_document called).
Instance Method Summary collapse
-
#add_parse_error(error) ⇒ Object
Handle parse errors.
-
#characters(string) ⇒ Object
SAX Event: Text content.
-
#end_document ⇒ Object
SAX Event: Document complete.
-
#end_element(_name) ⇒ Object
SAX Event: Element end tag.
-
#error(error_message) ⇒ Object
SAX Event: Parse error.
-
#initialize(profile) ⇒ SaxValidationHandler
constructor
A new instance of SaxValidationHandler.
-
#start_document ⇒ Object
SAX Event: Document start.
-
#start_element(name, attributes = []) ⇒ Object
SAX Event: Element start tag.
-
#warning(warning_message) ⇒ Object
SAX Event: Warning.
Constructor Details
#initialize(profile) ⇒ SaxValidationHandler
Returns a new instance of SaxValidationHandler.
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/svg_conform/sax_validation_handler.rb', line 44 def initialize(profile) @profile = profile @element_stack = [] # Track parent-child hierarchy @path_stack = [] # Current element path @position_counters = [] # Stack of sibling counters per level @parse_errors = [] @result = nil # Will be set in end_document # Create instance-level cache (no shared state between handlers) @classification_cache = ClassificationCache.new # Use profile requirements directly (config is stateless) # Validation state lives in context, not in requirements @requirements = @profile.requirements || [] # Create validation context (without document reference for SAX) @context = create_sax_context # Classify requirements into immediate vs deferred (use instance cache) @immediate_requirements, @deferred_requirements = classify_requirements_with_cache end |
Instance Attribute Details
#context ⇒ Object (readonly)
Returns the value of attribute context.
42 43 44 |
# File 'lib/svg_conform/sax_validation_handler.rb', line 42 def context @context end |
#result ⇒ Object (readonly)
Get result (will be nil until end_document called)
157 158 159 |
# File 'lib/svg_conform/sax_validation_handler.rb', line 157 def result @result end |
Instance Method Details
#add_parse_error(error) ⇒ Object
Handle parse errors
147 148 149 150 151 152 153 154 |
# File 'lib/svg_conform/sax_validation_handler.rb', line 147 def add_parse_error(error) @context.add_error( node: nil, message: "Parse error: #{error.}", requirement_id: "parse_error", severity: :error, ) end |
#characters(string) ⇒ Object
SAX Event: Text content
119 120 121 122 123 |
# File 'lib/svg_conform/sax_validation_handler.rb', line 119 def characters(string) return if @element_stack.empty? @element_stack.last.text_content << string end |
#end_document ⇒ Object
SAX Event: Document complete
126 127 128 129 130 131 132 133 134 |
# File 'lib/svg_conform/sax_validation_handler.rb', line 126 def end_document # Run deferred validation @deferred_requirements.each do |req| req.validate_sax_complete(@context) end # Create result @result = ValidationResult.new(nil, @profile, @context) end |
#end_element(_name) ⇒ Object
SAX Event: Element end tag
112 113 114 115 116 |
# File 'lib/svg_conform/sax_validation_handler.rb', line 112 def end_element(_name) @element_stack.pop @path_stack.pop @position_counters.pop end |
#error(error_message) ⇒ Object
SAX Event: Parse error
137 138 139 |
# File 'lib/svg_conform/sax_validation_handler.rb', line 137 def error() @parse_errors << end |
#start_document ⇒ Object
SAX Event: Document start
67 68 69 70 71 |
# File 'lib/svg_conform/sax_validation_handler.rb', line 67 def start_document # No need to reset state - each validation has fresh requirement instances # Initialize root level counters @position_counters.push({}) end |
#start_element(name, attributes = []) ⇒ Object
SAX Event: Element start tag
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 |
# File 'lib/svg_conform/sax_validation_handler.rb', line 74 def start_element(name, attributes = []) attrs = attributes.to_h # Calculate position among siblings at current level current_counters = @position_counters.last || {} current_counters[name] ||= 0 current_counters[name] += 1 position = current_counters[name] # Build element proxy element = ElementProxy.new( name: name, attributes: attrs, position: position, path: @path_stack.dup, parent: @element_stack.last, ) # Push to stacks @element_stack.push(element) @path_stack.push("#{name}[#{position}]") @position_counters.push({}) # New level for this element's children # Validate with immediate requirements @immediate_requirements.each do |req| req.validate_sax_element(element, @context) end # Deferred requirements may need to collect data @deferred_requirements.each do |req| if req.respond_to?(:collect_sax_data) req.collect_sax_data(element, @context) end end end |
#warning(warning_message) ⇒ Object
SAX Event: Warning
142 143 144 |
# File 'lib/svg_conform/sax_validation_handler.rb', line 142 def warning() # Can log warnings if needed end |