Class: Canon::Comparison::XmlComparatorHelpers::AttributeFilter
- Inherits:
-
Object
- Object
- Canon::Comparison::XmlComparatorHelpers::AttributeFilter
- Defined in:
- lib/canon/comparison/xml_comparator/attribute_filter.rb
Overview
Attribute filtering logic Handles filtering of attributes based on options and match settings
Class Method Summary collapse
-
.expanded_attribute_name(attr) ⇒ Object
Expanded attribute key: "namespace-urilocal-name", or the bare local name when the attribute is in no namespace.
-
.filter(attributes, opts) ⇒ Hash
Filter attributes based on options.
-
.filter_array_attributes(attributes, opts, match_opts, filtered) ⇒ Object
Filter array-format attributes (Canon::Xml::Node).
-
.filter_hash_attributes(attributes, opts, match_opts, filtered) ⇒ Object
Filter hash-format attributes (Nokogiri/Moxml).
-
.ignore_by_content?(value, opts) ⇒ Boolean
Check if attribute should be ignored by content.
-
.ignore_by_name?(name, opts) ⇒ Boolean
Check if attribute should be ignored by name.
- .namespace_declaration?(attr_name) ⇒ Boolean
-
.normalize_attribute_pair(key, val) ⇒ Array<String, String>
Normalize attribute key-value pair from different formats.
Class Method Details
.expanded_attribute_name(attr) ⇒ Object
Expanded attribute key: "namespace-urilocal-name", or the bare local name when the attribute is in no namespace. Prefixed-but-unresolvable attributes (namespace-invalid documents — an undeclared prefix has no expanded name) fall back to the local name: recovery comparison cannot do better.
72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/canon/comparison/xml_comparator/attribute_filter.rb', line 72 def self.(attr) case attr when Canon::Xml::Nodes::AttributeNode uri = attr.namespace_uri attr.prefix when defined?(Nokogiri) && Nokogiri::XML::Attr uri = attr.namespace&.href attr.namespace&.prefix else uri = attr.namespace_uri nil end uri && !uri.empty? ? "{#{uri}}#{attr.name}" : attr.name end |
.filter(attributes, opts) ⇒ Hash
Filter attributes based on options
14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
# File 'lib/canon/comparison/xml_comparator/attribute_filter.rb', line 14 def self.filter(attributes, opts) filtered = {} match_opts = opts[:match_opts] # Handle Canon::Xml::Node attribute format (array of AttributeNode) if attributes.is_a?(Array) filter_array_attributes(attributes, opts, match_opts, filtered) else # Handle Nokogiri and Moxml attribute formats (Hash-like) filter_hash_attributes(attributes, opts, match_opts, filtered) end filtered end |
.filter_array_attributes(attributes, opts, match_opts, filtered) ⇒ Object
Filter array-format attributes (Canon::Xml::Node)
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 |
# File 'lib/canon/comparison/xml_comparator/attribute_filter.rb', line 35 def self.filter_array_attributes(attributes, opts, match_opts, filtered) attributes.each do |attr| # Expanded name (XML Namespaces 1.0 §5.2/§5.3): an # unprefixed attribute is in NO namespace — {no-ns}srsName # and {uri}srsName are different attributes, and two # prefixes bound to the same URI are the same attribute. # Local-name keys conflated qualified with unqualified # attributes whenever the prefix matched the element's # (issue #155). name = (attr) value = attr.value # Skip namespace declarations - they're handled separately next if namespace_declaration?(attr.name) # Skip if attribute name should be ignored — by local name # (user-facing list) or expanded key, so ignore lists keep # working against both forms. next if ignore_by_name?(attr.name, opts) || ignore_by_name?(name, opts) # Skip if attribute content should be ignored next if ignore_by_content?(value, opts) # Apply match options for attribute values behavior = match_opts[:attribute_values] || :strict value = MatchOptions.process_attribute_value(value, behavior) filtered[name] = value end end |
.filter_hash_attributes(attributes, opts, match_opts, filtered) ⇒ Object
Filter hash-format attributes (Nokogiri/Moxml)
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/canon/comparison/xml_comparator/attribute_filter.rb', line 93 def self.filter_hash_attributes(attributes, opts, match_opts, filtered) attributes.each do |key, val| # Normalize key and value name, value = normalize_attribute_pair(key, val) # Skip namespace declarations - they're handled separately next if namespace_declaration?(name) # Skip if attribute name should be ignored next if ignore_by_name?(name, opts) # Skip if attribute content should be ignored next if ignore_by_content?(value, opts) # Apply match options for attribute values behavior = match_opts[:attribute_values] || :strict value = MatchOptions.process_attribute_value(value, behavior) filtered[name] = value end end |
.ignore_by_content?(value, opts) ⇒ Boolean
Check if attribute should be ignored by content
146 147 148 149 150 |
# File 'lib/canon/comparison/xml_comparator/attribute_filter.rb', line 146 def self.ignore_by_content?(value, opts) opts[:ignore_attr_content].any? do |pattern| value.to_s.include?(pattern) end end |
.ignore_by_name?(name, opts) ⇒ Boolean
Check if attribute should be ignored by name
137 138 139 |
# File 'lib/canon/comparison/xml_comparator/attribute_filter.rb', line 137 def self.ignore_by_name?(name, opts) opts[:ignore_attrs_by_name].any? { |pattern| name.include?(pattern) } end |
.namespace_declaration?(attr_name) ⇒ Boolean
152 153 154 |
# File 'lib/canon/comparison/xml_comparator/attribute_filter.rb', line 152 def self.namespace_declaration?(attr_name) Canon::Xml::NamespaceHelper.namespace_declaration?(attr_name) end |
.normalize_attribute_pair(key, val) ⇒ Array<String, String>
Normalize attribute key-value pair from different formats
120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/canon/comparison/xml_comparator/attribute_filter.rb', line 120 def self.normalize_attribute_pair(key, val) if key.is_a?(String) name = key value = val.is_a?(String) ? val : val.value else name = key.name value = key.value end [name, value] end |