Class: Canon::Xml::LineRangeMapper

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

Overview

Maps DOM elements to line ranges in pretty-printed XML

This class builds a mapping between DOM elements and their corresponding line numbers in pretty-printed XML output. This enables line-accurate diff display that can highlight specific elements even when the XML structure is complex.

How it works

  1. Pretty-prints the XML with consistent indentation

  2. Traverses the DOM tree depth-first

  3. For each element, finds its opening and closing tags in the pretty-printed output

  4. Records the line range (start_line..end_line) for that element

  5. Returns a Hash mapping element → LineRange

Usage

mapper = LineRangeMapper.new(indent: 2)
root = Canon::Xml::DataModel.from_xml(xml_string)
line_map = mapper.build_map(root, xml_string)

# Look up line range for an element
range = line_map[element]
puts "Element spans lines #{range.start_line} to #{range.end_line}"

Line Range Format

Each LineRange contains:

  • start_line: First line of the element (0-indexed)

  • end_line: Last line of the element (0-indexed)

  • elem: Reference to the DOM element

Defined Under Namespace

Classes: LineRange

Instance Method Summary collapse

Constructor Details

#initialize(indent: 2) ⇒ LineRangeMapper

Returns a new instance of LineRangeMapper.



51
52
53
54
# File 'lib/canon/xml/line_range_mapper.rb', line 51

def initialize(indent: 2)
  @indent = indent
  @ranges = []
end

Instance Method Details

#build_map(root, xml_string) ⇒ Hash

Build line range map for a DOM tree

Parameters:

Returns:

  • (Hash)

    Map of element => LineRange



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/canon/xml/line_range_mapper.rb', line 61

def build_map(root, xml_string)
  @ranges = []
  @map = {}

  # Pretty-print to get consistent formatting
  pretty_xml = Canon::PrettyPrinter::Xml.new(indent: @indent).format(xml_string)
  @lines = pretty_xml.split("\n")

  # Track current line number
  @current_line = 0

  # Build map recursively
  root.children.each do |child|
    map_node(child)
  end

  @map
end