Module: Arrolio::GenericAdapter::FootnoteExtraction

Included in:
Arrolio::GenericAdapter
Defined in:
lib/arrolio/generic_adapter/footnote_extraction.rb

Overview

Footnote extraction, split from the adapter body (TODO 56 MECE split). Included as a module so the extraction logic stays with its selectors while the adapter class stays lean.

Instance Method Summary collapse

Instance Method Details

#extract_footnotes(root) ⇒ Object

Footnotes come in two shapes: the formatted container (fmt-footnote-container + fmt-fn-body) and the raw marker element () whose body is its own paragraphs. Both register in Document#footnotes, keyed by id; the raw form is what body text and table cells reference.



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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
66
67
# File 'lib/arrolio/generic_adapter/footnote_extraction.rb', line 14

def extract_footnotes(root)
  container_name = selector('footnote_container')
  body_name = selector('footnote_body')
  marker_name = selector('footnote_marker')
  return [] unless marker_name || (container_name && body_name)

  footnotes = []
  ids = []
  # Recursive: footnote containers and raw <fn> markers live at
  # arbitrary depths inside clauses, tables, and terms.
  root.each_recursive do |elem|
    if container_name && elem.name == container_name

    marker = elem.attribute('id')&.value || elem.attribute(marker_name)&.value || ''
    body_elem = find_first(elem, body_name)
    body = []
    if body_elem
      para_name = selector('paragraph')
      each_element(body_elem) do |child|
        next unless child.name == para_name

        body << convert_paragraph(child)
      end
    end
    next if body.empty?

    id = elem.attribute(selector('id_attribute'))&.value
    next if id && ids.include?(id)

    ids << id if id
    footnotes << Content::Footnote.new(
      marker: marker,
      body: body,
      id: id
    )
    elsif marker_name && elem.name == marker_name
      id = elem.attribute('id')&.value ||
           elem.attribute(selector('id_attribute'))&.value
      next if id && ids.include?(id)

      marker = elem.attribute('reference')&.value || id || ''
      body = footnote_body_paragraphs(elem)
      next if body.empty?

      ids << id if id
      footnotes << Content::Footnote.new(
        marker: marker,
        body: body,
        id: id
      )
    end
  end
  footnotes
end

#footnote_body_paragraphs(elem) ⇒ Object



69
70
71
72
73
74
75
76
77
78
# File 'lib/arrolio/generic_adapter/footnote_extraction.rb', line 69

def footnote_body_paragraphs(elem)
  para_name = selector('paragraph')
  paragraphs = []
  each_element(elem) do |child|
    next unless child.name == para_name

    paragraphs << convert_paragraph(child)
  end
  paragraphs
end