Class: Canon::Xml::ElementMatcher

Inherits:
Object
  • Object
show all
Defined in:
lib/canon/xml/element_matcher.rb

Overview

Matches XML elements semantically across two DOM trees

This class implements intelligent element matching for XML diffs. Instead of naive line-by-line comparison, it semantically matches elements across documents using identity attributes and structural position.

Matching Strategy

Elements are matched in two passes:

  1. **Identity attribute matching**: Elements with same identity attribute values are matched (e.g., id=“foo” matches id=“foo”)

  2. **Position-based matching**: Remaining elements matched by name and document position

This allows detecting when elements:

  • Move to different positions (matched by ID)

  • Have content changes (matched, diff shows changes)

  • Are added/deleted (no match found)

Identity Attributes

By default, these attributes identify elements:

  • id

  • ref

  • name

  • key

Custom identity attributes can be provided to the constructor.

Usage

matcher = ElementMatcher.new
root1 = Canon::Xml::DataModel.from_xml(xml1)
root2 = Canon::Xml::DataModel.from_xml(xml2)
matches = matcher.match_trees(root1, root2)

matches.each do |match|
  case match.status
  when :matched
    # Elements found in both trees
  when :deleted
    # Element only in first tree
  when :inserted
    # Element only in second tree
  end
end

Defined Under Namespace

Classes: MatchResult

Constant Summary collapse

DEFAULT_IDENTITY_ATTRS =

Default attributes used to identify elements

%w[id ref name key class].freeze

Instance Method Summary collapse

Constructor Details

#initialize(identity_attrs: DEFAULT_IDENTITY_ATTRS) ⇒ ElementMatcher

Returns a new instance of ElementMatcher.



117
118
119
120
# File 'lib/canon/xml/element_matcher.rb', line 117

def initialize(identity_attrs: DEFAULT_IDENTITY_ATTRS)
  @identity_attrs = identity_attrs
  @matches = []
end

Instance Method Details

#match_trees(root1, root2) ⇒ Array<MatchResult>

Match elements between two DOM trees

Parameters:

Returns:



127
128
129
130
131
# File 'lib/canon/xml/element_matcher.rb', line 127

def match_trees(root1, root2)
  @matches = []
  match_children(root1.children, root2.children, [])
  @matches
end