Class: Docbook::Mirror::DocbookToMirror
- Inherits:
-
Object
- Object
- Docbook::Mirror::DocbookToMirror
- Defined in:
- lib/docbook/mirror/docbook_to_mirror.rb
Overview
Transforms DocBook element tree into DocbookMirror node tree.
This is the forward direction of the transformation: DocBook XML elements are converted into ProseMirror-style JSON node tree suitable for the Vue frontend's MirrorRenderer.
Uses a HandlerRegistry for dispatch, making it extensible without modifying this class. The default registry maps all built-in DocBook elements to their handlers.
Usage: doc = Docbook::Document.from_xml(xml_string) mirror_doc = DocbookToMirror.new.call(doc)
Instance Attribute Summary collapse
-
#registry ⇒ Object
readonly
Returns the value of attribute registry.
-
#sort_glossary ⇒ Object
readonly
Returns the value of attribute sort_glossary.
-
#xml_id_map ⇒ Object
readonly
Returns the value of attribute xml_id_map.
Instance Method Summary collapse
-
#build_xml_id_map(doc) ⇒ Object
========================================= XML ID Map =========================================.
-
#call(docbook_doc) ⇒ Object
Entry point: Convert DocBook document to DocbookMirror.
- #citetitle_node(element) ⇒ Object
-
#document_node(docbook_doc) ⇒ Object
========================================= Context API — methods available to handlers via context: =========================================.
- #extract_co_markers(element) ⇒ Object
-
#extract_content(element) ⇒ Object
Extract content nodes from an element using the handler registry.
- #extract_text(element) ⇒ Object
- #extract_text_with_callouts(element, co_markers) ⇒ Object
- #flush_footnotes ⇒ Object
-
#initialize(sort_glossary: false, registry: Docbook::Mirror.default_registry) ⇒ DocbookToMirror
constructor
A new instance of DocbookToMirror.
- #link_node(element) ⇒ Object
-
#paragraph_handler(para) ⇒ Object
Paragraph handler used by annotation and others that need paragraph_node directly.
-
#process_inline_content(element) ⇒ Object
========================================= Inline Processing (delegated to Handlers::Inline) =========================================.
-
#register_footnote(element) ⇒ Object
========================================= Footnote Management =========================================.
- #resolve_footnoteref(element) ⇒ Object
- #resolve_title(element) ⇒ Object
-
#text_node(text, marks: []) ⇒ Object
========================================= Shared Helpers (used by handlers via context) =========================================.
Constructor Details
#initialize(sort_glossary: false, registry: Docbook::Mirror.default_registry) ⇒ DocbookToMirror
Returns a new instance of DocbookToMirror.
24 25 26 27 28 29 30 |
# File 'lib/docbook/mirror/docbook_to_mirror.rb', line 24 def initialize(sort_glossary: false, registry: Docbook::Mirror.default_registry) @sort_glossary = sort_glossary @registry = registry @xml_id_map = {} @footnote_counter = 0 @footnotes = [] end |
Instance Attribute Details
#registry ⇒ Object (readonly)
Returns the value of attribute registry.
22 23 24 |
# File 'lib/docbook/mirror/docbook_to_mirror.rb', line 22 def registry @registry end |
#sort_glossary ⇒ Object (readonly)
Returns the value of attribute sort_glossary.
22 23 24 |
# File 'lib/docbook/mirror/docbook_to_mirror.rb', line 22 def sort_glossary @sort_glossary end |
#xml_id_map ⇒ Object (readonly)
Returns the value of attribute xml_id_map.
22 23 24 |
# File 'lib/docbook/mirror/docbook_to_mirror.rb', line 22 def xml_id_map @xml_id_map end |
Instance Method Details
#build_xml_id_map(doc) ⇒ Object
=========================================
XML ID Map
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 |
# File 'lib/docbook/mirror/docbook_to_mirror.rb', line 214 def build_xml_id_map(doc) map = {} doc.each_mixed_content do |node| next if node.is_a?(String) id = node.element_id title = node.resolve_title title = Array(title).join if title map[id] = title if id && !id.empty? && title build_xml_id_map(node).each { |k, v| map[k] = v } end map end |
#call(docbook_doc) ⇒ Object
Entry point: Convert DocBook document to DocbookMirror
33 34 35 36 37 38 |
# File 'lib/docbook/mirror/docbook_to_mirror.rb', line 33 def call(docbook_doc) @xml_id_map = build_xml_id_map(docbook_doc) @footnote_counter = 0 @footnotes = [] document_node(docbook_doc) end |
#citetitle_node(element) ⇒ Object
140 141 142 |
# File 'lib/docbook/mirror/docbook_to_mirror.rb', line 140 def citetitle_node(element) Handlers::Inline.citetitle(element, context: self) end |
#document_node(docbook_doc) ⇒ Object
=========================================
Context API — methods available to handlers via context:
44 45 46 47 48 49 50 51 |
# File 'lib/docbook/mirror/docbook_to_mirror.rb', line 44 def document_node(docbook_doc) title = docbook_doc.resolve_title attrs = { title: title }.compact content = extract_content(docbook_doc) Docbook::Mirror::Node::Document.new(attrs: attrs, content: content) end |
#extract_co_markers(element) ⇒ Object
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/docbook/mirror/docbook_to_mirror.rb', line 103 def extract_co_markers(element) markers = [] counter = 0 element.each_mixed_content do |node| next if node.is_a?(String) next unless node.callout_marker? counter += 1 id = node.xml_id label = node.label || counter.to_s markers << { number: counter, id: id, label: label }.compact end markers end |
#extract_content(element) ⇒ Object
Extract content nodes from an element using the handler registry. Iterates mixed content, dispatching each DocBook element to its registered handler. Unknown elements are silently skipped.
56 57 58 59 60 61 62 63 64 65 66 67 68 |
# File 'lib/docbook/mirror/docbook_to_mirror.rb', line 56 def extract_content(element) content = [] element.each_mixed_content do |node| case node when String next if node.strip.empty? else handle_node(node, content) end end content.compact end |
#extract_text(element) ⇒ Object
91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/docbook/mirror/docbook_to_mirror.rb', line 91 def extract_text(element) texts = [] element.each_mixed_content do |node| if node.is_a?(String) texts << node elsif node.content texts << node.content.join end end texts.join end |
#extract_text_with_callouts(element, co_markers) ⇒ Object
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/docbook/mirror/docbook_to_mirror.rb', line 119 def extract_text_with_callouts(element, co_markers) marker_idx = 0 texts = [] element.each_mixed_content do |node| if node.is_a?(String) texts << node elsif node.callout_marker? marker = co_markers[marker_idx] texts << "(#{marker[:label]})" marker_idx += 1 elsif node.content texts << node.content.join end end texts.join end |
#flush_footnotes ⇒ Object
195 196 197 198 199 200 201 202 203 204 205 206 207 208 |
# File 'lib/docbook/mirror/docbook_to_mirror.rb', line 195 def flush_footnotes return nil if @footnotes.empty? entries = @footnotes.map do |fn| Node.new( type: "footnote_entry", attrs: { id: fn[:id], ref_id: fn[:ref_id], number: fn[:number] }, content: fn[:content], ) end @footnotes = [] Node.new(type: "footnotes", content: entries) end |
#link_node(element) ⇒ Object
136 137 138 |
# File 'lib/docbook/mirror/docbook_to_mirror.rb', line 136 def link_node(element) Handlers::Inline.link(element, context: self) end |
#paragraph_handler(para) ⇒ Object
Paragraph handler used by annotation and others that need paragraph_node directly
79 80 81 |
# File 'lib/docbook/mirror/docbook_to_mirror.rb', line 79 def paragraph_handler(para) Handlers::Paragraph.call(para, context: self) end |
#process_inline_content(element) ⇒ Object
=========================================
Inline Processing (delegated to Handlers::Inline)
74 75 76 |
# File 'lib/docbook/mirror/docbook_to_mirror.rb', line 74 def process_inline_content(element) Handlers::Inline.process(element, context: self) end |
#register_footnote(element) ⇒ Object
=========================================
Footnote Management
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
# File 'lib/docbook/mirror/docbook_to_mirror.rb', line 152 def register_footnote(element) @footnote_counter += 1 num = @footnote_counter fn_id = "fn-#{num}" ref_id = "fn-ref-#{num}" fn_content = if element.para&.any? element.para.filter_map { |p| paragraph_handler(p) } elsif element.content process_inline_content(element) else [text_node(extract_text(element))] end @footnotes << { id: fn_id, ref_id: ref_id, number: num, xml_id: element.xml_id, content: fn_content, } Node.new( type: "footnote_marker", attrs: { id: fn_id, ref_id: ref_id, number: num }, ) end |
#resolve_footnoteref(element) ⇒ Object
180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
# File 'lib/docbook/mirror/docbook_to_mirror.rb', line 180 def resolve_footnoteref(element) linkend = element.linkend ref_fn = @footnotes.find { |fn| fn[:xml_id] == linkend } if linkend if ref_fn Node.new( type: "footnote_marker", attrs: { id: ref_fn[:id], ref_id: "fn-ref-#{ref_fn[:number]}-dup-#{@footnote_counter}", number: ref_fn[:number] }, ) else text_node("[footnote]") end end |
#resolve_title(element) ⇒ Object
144 145 146 |
# File 'lib/docbook/mirror/docbook_to_mirror.rb', line 144 def resolve_title(element) element.resolve_title end |