Class: SvgConform::Requirements::BaseRequirement
- Inherits:
-
Lutaml::Model::Serializable
- Object
- Lutaml::Model::Serializable
- SvgConform::Requirements::BaseRequirement
- Includes:
- Interfaces::RequirementInterface, NodeHelpers
- Defined in:
- lib/svg_conform/requirements/base_requirement.rb
Overview
Base class for all validation requirements
Validation modes
Requirements support two validation modes:
DOM validation (remediation mode)
Used when the full document is available and remediation is needed.
Requirements implement validate_document to traverse the document once.
requirement.validate_document(document, context)
SAX validation (streaming mode)
Used for memory-efficient streaming validation without loading the full document. Requirements implement either immediate or deferred validation patterns.
Immediate validation (14 requirements)
Validates as it encounters each node during SAX parsing.
No state is needed - validation is complete after validate_sax_element returns.
def validate_sax_element(element, context)
# Immediate validation logic
context.add_error(...) if invalid
end
Requirements using immediate validation:
- AllowedElementsRequirement
- FontFamilyRequirement
- ColorRestrictionsRequirement
- ViewboxRequiredRequirement
- NamespaceRequirement
- IdCollectionRequirement
- StylePromotionRequirement
- NoExternalImagesRequirement
- NoExternalFontsRequirement
- NamespaceAttributesRequirement
- ForbiddenContentRequirement
- StyleRequirement
- LinkValidationRequirement (registers to ReferenceManifest)
Deferred validation (3 requirements)
Collects data during SAX parsing and validates at document end. Requires a nested State class to store collected data.
class State
attr_accessor :collected_data
def initialize
@collected_data = []
end
end
def needs_deferred_validation?
true
end
def collect_sax_data(element, context)
state = context.state_for(self)
state.collected_data << extract_data(element)
end
def validate_sax_complete(context)
state = context.state_for(self)
# Validate collected data
end
Requirements using deferred validation:
- IdReferenceRequirement (needs forward references to IDs)
- InvalidIdReferencesRequirement (needs to collect IDs first)
- NoExternalCssRequirement (needs to check style elements)
State management
Requirements needing deferred validation must define a nested State class.
The ValidationContext manages state instances per requirement via state_for:
state = context.state_for(self) # Returns State instance for this requirement
Each validation gets a fresh state instance, preventing state pollution when reusing the same profile for multiple validations.
Direct Known Subclasses
AllowedElementsRequirement, ColorRestrictionsRequirement, FontFamilyRequirement, ForbiddenContentRequirement, IdCollectionRequirement, IdReferenceRequirement, InvalidIdReferencesRequirement, LinkValidationRequirement, NamespaceAttributesRequirement, NamespaceRequirement, NoExternalCssRequirement, NoExternalFontsRequirement, NoExternalImagesRequirement, StylePromotionRequirement, StyleRequirement, TextAsPathRequirement, ViewboxRequiredRequirement
Instance Method Summary collapse
-
#check(node, context) ⇒ Object
Main validation method - must be implemented by subclasses.
-
#collect_sax_data(element, context) ⇒ Object
Called for each element to collect data for deferred validation Override in subclasses that need to collect data.
-
#get_attributes(node) ⇒ Object
Helper method to get all attributes Note: Other attribute helpers are included via NodeHelpers module.
-
#needs_deferred_validation? ⇒ Boolean
Indicates if requirement needs deferred validation Override to return true for requirements that need forward references.
-
#should_check_node?(node, context = nil) ⇒ Boolean
Determine if this requirement should check a specific node.
-
#skip_attribute_validation?(node_or_element, context) ⇒ Boolean
Shared helper for skipping attribute validation on structurally invalid nodes Used by both DOM and SAX validation.
- #to_s ⇒ Object
-
#validate_document(document, context) ⇒ Object
Validate the entire document (called once per requirement).
-
#validate_sax_complete(context) ⇒ Object
Called at end of document for deferred validation Override in subclasses that need full document data.
-
#validate_sax_element(element, context) ⇒ Object
Called for each element during SAX parsing Override in subclasses for immediate validation.
Methods included from Interfaces::RequirementInterface
Methods included from NodeHelpers
#element?, #get_attribute, #has_attribute?, #remove_attribute, #set_attribute, #text?
Instance Method Details
#check(node, context) ⇒ Object
Main validation method - must be implemented by subclasses
109 110 111 |
# File 'lib/svg_conform/requirements/base_requirement.rb', line 109 def check(node, context) raise NotImplementedError, "Subclasses must implement #check" end |
#collect_sax_data(element, context) ⇒ Object
Called for each element to collect data for deferred validation Override in subclasses that need to collect data
131 132 133 |
# File 'lib/svg_conform/requirements/base_requirement.rb', line 131 def collect_sax_data(element, context) # Default: no data collection end |
#get_attributes(node) ⇒ Object
Helper method to get all attributes Note: Other attribute helpers are included via NodeHelpers module
159 160 161 162 163 164 165 166 167 |
# File 'lib/svg_conform/requirements/base_requirement.rb', line 159 def get_attributes(node) return {} unless node.respond_to?(:attributes) attrs = node.attributes || [] # Convert array of Moxml::Attribute objects to hash attrs.to_h do |attr| [attr.name, attr.value] end end |
#needs_deferred_validation? ⇒ Boolean
Indicates if requirement needs deferred validation Override to return true for requirements that need forward references
143 144 145 |
# File 'lib/svg_conform/requirements/base_requirement.rb', line 143 def needs_deferred_validation? false end |
#should_check_node?(node, context = nil) ⇒ Boolean
Determine if this requirement should check a specific node
148 149 150 151 152 153 154 155 |
# File 'lib/svg_conform/requirements/base_requirement.rb', line 148 def should_check_node?(node, context = nil) return false unless node.respond_to?(:name) && node.respond_to?(:attributes) # Skip structurally invalid nodes (and their children are automatically skipped by marking the parent) return false if context&.node_structurally_invalid?(node) true end |
#skip_attribute_validation?(node_or_element, context) ⇒ Boolean
Shared helper for skipping attribute validation on structurally invalid nodes Used by both DOM and SAX validation
171 172 173 174 175 176 177 178 179 180 181 |
# File 'lib/svg_conform/requirements/base_requirement.rb', line 171 def skip_attribute_validation?(node_or_element, context) # For DOM mode, also check if it's an element return true if element?(node_or_element) && context.node_structurally_invalid?(node_or_element) # For SAX mode (ElementProxy always has this method) if node_or_element.respond_to?(:path_id) return context.node_structurally_invalid?(node_or_element) end false end |
#to_s ⇒ Object
183 184 185 |
# File 'lib/svg_conform/requirements/base_requirement.rb', line 183 def to_s "#{@id}: #{@description}" end |
#validate_document(document, context) ⇒ Object
Validate the entire document (called once per requirement)
114 115 116 117 118 |
# File 'lib/svg_conform/requirements/base_requirement.rb', line 114 def validate_document(document, context) document.traverse do |node| check(node, context) if should_check_node?(node, context) end end |
#validate_sax_complete(context) ⇒ Object
Called at end of document for deferred validation Override in subclasses that need full document data
137 138 139 |
# File 'lib/svg_conform/requirements/base_requirement.rb', line 137 def validate_sax_complete(context) # Default: no deferred validation end |
#validate_sax_element(element, context) ⇒ Object
Called for each element during SAX parsing Override in subclasses for immediate validation
124 125 126 127 |
# File 'lib/svg_conform/requirements/base_requirement.rb', line 124 def validate_sax_element(element, context) # Default: Empty - subclasses must override for SAX support # Cannot call check() here as it's abstract end |