docbook 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +5 -0
- data/CLAUDE.md +19 -0
- data/CODE_OF_CONDUCT.md +10 -0
- data/README.adoc +335 -0
- data/Rakefile +12 -0
- data/docs/.lycheeignore +33 -0
- data/docs/Gemfile +10 -0
- data/docs/INDEX.adoc +67 -0
- data/docs/_config.yml +186 -0
- data/docs/advanced/element-classes.adoc +185 -0
- data/docs/advanced/frontend-customization.adoc +193 -0
- data/docs/advanced/index.adoc +14 -0
- data/docs/advanced/templates.adoc +123 -0
- data/docs/features/element-coverage.adoc +373 -0
- data/docs/features/html-output/data-model.adoc +285 -0
- data/docs/features/html-output/directory-mode.adoc +180 -0
- data/docs/features/html-output/index.adoc +90 -0
- data/docs/features/html-output/single-file-mode.adoc +125 -0
- data/docs/features/index-generation.adoc +197 -0
- data/docs/features/index.adoc +63 -0
- data/docs/features/numbering.adoc +183 -0
- data/docs/features/toc-generation.adoc +150 -0
- data/docs/features/xinclude/fragid-schemes.adoc +287 -0
- data/docs/features/xinclude/index.adoc +119 -0
- data/docs/features/xinclude/text-includes.adoc +123 -0
- data/docs/features/xinclude/xml-includes.adoc +167 -0
- data/docs/getting-started/index.adoc +50 -0
- data/docs/getting-started/installation.adoc +113 -0
- data/docs/getting-started/quick-start.adoc +161 -0
- data/docs/guides/converting-article.adoc +188 -0
- data/docs/guides/converting-book.adoc +192 -0
- data/docs/guides/index.adoc +12 -0
- data/docs/guides/roundtrip-testing.adoc +129 -0
- data/docs/interfaces/cli/format-command.adoc +109 -0
- data/docs/interfaces/cli/index.adoc +73 -0
- data/docs/interfaces/cli/roundtrip-command.adoc +125 -0
- data/docs/interfaces/cli/to-html-command.adoc +178 -0
- data/docs/interfaces/cli/validate-command.adoc +104 -0
- data/docs/interfaces/index.adoc +101 -0
- data/docs/interfaces/ruby-api/html-output.adoc +186 -0
- data/docs/interfaces/ruby-api/index.adoc +111 -0
- data/docs/interfaces/ruby-api/parsing.adoc +202 -0
- data/docs/interfaces/ruby-api/xinclude.adoc +162 -0
- data/docs/interfaces/ruby-api/xref-resolution.adoc +156 -0
- data/docs/lychee.toml +42 -0
- data/docs/reference/cli-options.adoc +155 -0
- data/docs/reference/content-block-types.adoc +243 -0
- data/docs/reference/glossary.adoc +119 -0
- data/docs/reference/index.adoc +12 -0
- data/docs/reference/supported-elements.adoc +749 -0
- data/docs/understanding/architecture.adoc +145 -0
- data/docs/understanding/content-pipeline.adoc +102 -0
- data/docs/understanding/data-models.adoc +156 -0
- data/docs/understanding/index.adoc +34 -0
- data/exe/docbook +7 -0
- data/frontend/dist/app.css +1 -0
- data/frontend/dist/app.iife.js +24 -0
- data/frontend/package-lock.json +1445 -0
- data/frontend/package.json +22 -0
- data/frontend/src/App.vue +230 -0
- data/frontend/src/app.ts +8 -0
- data/frontend/src/components/AppSidebar.vue +116 -0
- data/frontend/src/components/AppendixSection.vue +39 -0
- data/frontend/src/components/BlockRenderer.vue +358 -0
- data/frontend/src/components/ChapterSection.vue +32 -0
- data/frontend/src/components/ContentRenderer.vue +13 -0
- data/frontend/src/components/EbookContainer.vue +147 -0
- data/frontend/src/components/EbookTopBar.vue +116 -0
- data/frontend/src/components/PartSection.vue +44 -0
- data/frontend/src/components/ReferenceEntry.vue +80 -0
- data/frontend/src/components/SearchModal.vue +286 -0
- data/frontend/src/components/SectionContent.vue +31 -0
- data/frontend/src/components/SettingsPanel.vue +236 -0
- data/frontend/src/components/TocTreeItem.vue +135 -0
- data/frontend/src/composables/useEbookStore.ts +191 -0
- data/frontend/src/composables/useSearch.ts +249 -0
- data/frontend/src/env.d.ts +7 -0
- data/frontend/src/stores/documentStore.ts +221 -0
- data/frontend/src/stores/uiStore.ts +98 -0
- data/frontend/src/styles.css +253 -0
- data/frontend/tsconfig.json +24 -0
- data/frontend/tsconfig.node.json +11 -0
- data/frontend/vite.config.ts +30 -0
- data/lib/docbook/cli.rb +123 -0
- data/lib/docbook/document.rb +67 -0
- data/lib/docbook/elements/abbrev.rb +16 -0
- data/lib/docbook/elements/acknowledgements.rb +22 -0
- data/lib/docbook/elements/address.rb +18 -0
- data/lib/docbook/elements/alt.rb +16 -0
- data/lib/docbook/elements/annotation.rb +18 -0
- data/lib/docbook/elements/appendix.rb +34 -0
- data/lib/docbook/elements/article.rb +31 -0
- data/lib/docbook/elements/att.rb +15 -0
- data/lib/docbook/elements/attribution.rb +20 -0
- data/lib/docbook/elements/audioobject.rb +18 -0
- data/lib/docbook/elements/author.rb +18 -0
- data/lib/docbook/elements/bibliography.rb +24 -0
- data/lib/docbook/elements/bibliomixed.rb +40 -0
- data/lib/docbook/elements/biblioref.rb +20 -0
- data/lib/docbook/elements/blockquote.rb +26 -0
- data/lib/docbook/elements/book.rb +36 -0
- data/lib/docbook/elements/buildtarget.rb +16 -0
- data/lib/docbook/elements/callout.rb +22 -0
- data/lib/docbook/elements/calloutlist.rb +22 -0
- data/lib/docbook/elements/caution.rb +30 -0
- data/lib/docbook/elements/chapter.rb +62 -0
- data/lib/docbook/elements/citation.rb +16 -0
- data/lib/docbook/elements/citerefentry.rb +26 -0
- data/lib/docbook/elements/citetitle.rb +20 -0
- data/lib/docbook/elements/classname.rb +16 -0
- data/lib/docbook/elements/code.rb +16 -0
- data/lib/docbook/elements/colophon.rb +22 -0
- data/lib/docbook/elements/computeroutput.rb +18 -0
- data/lib/docbook/elements/copyright.rb +17 -0
- data/lib/docbook/elements/danger.rb +28 -0
- data/lib/docbook/elements/date.rb +16 -0
- data/lib/docbook/elements/dedication.rb +22 -0
- data/lib/docbook/elements/dir.rb +16 -0
- data/lib/docbook/elements/emphasis.rb +18 -0
- data/lib/docbook/elements/entry.rb +30 -0
- data/lib/docbook/elements/entrytbl.rb +22 -0
- data/lib/docbook/elements/equation.rb +26 -0
- data/lib/docbook/elements/example.rb +30 -0
- data/lib/docbook/elements/fieldsynopsis.rb +21 -0
- data/lib/docbook/elements/figure.rb +28 -0
- data/lib/docbook/elements/filename.rb +16 -0
- data/lib/docbook/elements/firstname.rb +16 -0
- data/lib/docbook/elements/firstterm.rb +18 -0
- data/lib/docbook/elements/footnote.rb +22 -0
- data/lib/docbook/elements/footnoteref.rb +21 -0
- data/lib/docbook/elements/foreignphrase.rb +18 -0
- data/lib/docbook/elements/formalpara.rb +20 -0
- data/lib/docbook/elements/function.rb +16 -0
- data/lib/docbook/elements/glossary.rb +24 -0
- data/lib/docbook/elements/glossdef.rb +18 -0
- data/lib/docbook/elements/glossentry.rb +26 -0
- data/lib/docbook/elements/glosssee.rb +18 -0
- data/lib/docbook/elements/glossseealso.rb +18 -0
- data/lib/docbook/elements/glossterm.rb +18 -0
- data/lib/docbook/elements/holder.rb +16 -0
- data/lib/docbook/elements/honorific.rb +16 -0
- data/lib/docbook/elements/imagedata.rb +29 -0
- data/lib/docbook/elements/imageobject.rb +22 -0
- data/lib/docbook/elements/important.rb +30 -0
- data/lib/docbook/elements/index.rb +26 -0
- data/lib/docbook/elements/indexdiv.rb +22 -0
- data/lib/docbook/elements/indexentry.rb +22 -0
- data/lib/docbook/elements/indexterm.rb +34 -0
- data/lib/docbook/elements/info.rb +25 -0
- data/lib/docbook/elements/informalexample.rb +24 -0
- data/lib/docbook/elements/informalfigure.rb +20 -0
- data/lib/docbook/elements/inlinemediaobject.rb +22 -0
- data/lib/docbook/elements/itemizedlist.rb +21 -0
- data/lib/docbook/elements/legalnotice.rb +22 -0
- data/lib/docbook/elements/link.rb +26 -0
- data/lib/docbook/elements/listitem.rb +32 -0
- data/lib/docbook/elements/literal.rb +16 -0
- data/lib/docbook/elements/literallayout.rb +22 -0
- data/lib/docbook/elements/mediaobject.rb +26 -0
- data/lib/docbook/elements/msg.rb +20 -0
- data/lib/docbook/elements/msgexplan.rb +22 -0
- data/lib/docbook/elements/msgset.rb +22 -0
- data/lib/docbook/elements/note.rb +30 -0
- data/lib/docbook/elements/orderedlist.rb +23 -0
- data/lib/docbook/elements/orgname.rb +16 -0
- data/lib/docbook/elements/para.rb +61 -0
- data/lib/docbook/elements/paragraph_like.rb +18 -0
- data/lib/docbook/elements/parameter.rb +16 -0
- data/lib/docbook/elements/part.rb +38 -0
- data/lib/docbook/elements/personname.rb +22 -0
- data/lib/docbook/elements/phrase.rb +20 -0
- data/lib/docbook/elements/preface.rb +58 -0
- data/lib/docbook/elements/primary.rb +16 -0
- data/lib/docbook/elements/procedure.rb +24 -0
- data/lib/docbook/elements/productname.rb +18 -0
- data/lib/docbook/elements/productnumber.rb +16 -0
- data/lib/docbook/elements/programlisting.rb +28 -0
- data/lib/docbook/elements/property.rb +16 -0
- data/lib/docbook/elements/pubdate.rb +16 -0
- data/lib/docbook/elements/publishername.rb +16 -0
- data/lib/docbook/elements/quotation.rb +24 -0
- data/lib/docbook/elements/quote.rb +18 -0
- data/lib/docbook/elements/refentry.rb +32 -0
- data/lib/docbook/elements/refentrytitle.rb +16 -0
- data/lib/docbook/elements/reference.rb +26 -0
- data/lib/docbook/elements/refmeta.rb +29 -0
- data/lib/docbook/elements/refmiscinfo.rb +16 -0
- data/lib/docbook/elements/refname.rb +16 -0
- data/lib/docbook/elements/refnamediv.rb +22 -0
- data/lib/docbook/elements/refpurpose.rb +16 -0
- data/lib/docbook/elements/refsect1.rb +22 -0
- data/lib/docbook/elements/refsect2.rb +22 -0
- data/lib/docbook/elements/refsect3.rb +22 -0
- data/lib/docbook/elements/refsection.rb +32 -0
- data/lib/docbook/elements/releaseinfo.rb +16 -0
- data/lib/docbook/elements/remark.rb +20 -0
- data/lib/docbook/elements/replaceable.rb +16 -0
- data/lib/docbook/elements/row.rb +15 -0
- data/lib/docbook/elements/screen.rb +28 -0
- data/lib/docbook/elements/secondary.rb +16 -0
- data/lib/docbook/elements/sect1.rb +26 -0
- data/lib/docbook/elements/sect2.rb +24 -0
- data/lib/docbook/elements/sect3.rb +24 -0
- data/lib/docbook/elements/sect4.rb +24 -0
- data/lib/docbook/elements/sect5.rb +22 -0
- data/lib/docbook/elements/section.rb +66 -0
- data/lib/docbook/elements/see.rb +16 -0
- data/lib/docbook/elements/seealso.rb +18 -0
- data/lib/docbook/elements/set.rb +26 -0
- data/lib/docbook/elements/setindex.rb +24 -0
- data/lib/docbook/elements/sidebar.rb +22 -0
- data/lib/docbook/elements/simplesect.rb +32 -0
- data/lib/docbook/elements/step.rb +26 -0
- data/lib/docbook/elements/substeps.rb +18 -0
- data/lib/docbook/elements/subtitle.rb +16 -0
- data/lib/docbook/elements/surname.rb +16 -0
- data/lib/docbook/elements/table.rb +24 -0
- data/lib/docbook/elements/tag.rb +20 -0
- data/lib/docbook/elements/tbody.rb +15 -0
- data/lib/docbook/elements/term.rb +37 -0
- data/lib/docbook/elements/tertiary.rb +16 -0
- data/lib/docbook/elements/textobject.rb +18 -0
- data/lib/docbook/elements/tfoot.rb +15 -0
- data/lib/docbook/elements/tgroup.rb +21 -0
- data/lib/docbook/elements/thead.rb +15 -0
- data/lib/docbook/elements/tip.rb +30 -0
- data/lib/docbook/elements/title.rb +16 -0
- data/lib/docbook/elements/toc.rb +24 -0
- data/lib/docbook/elements/tocdiv.rb +22 -0
- data/lib/docbook/elements/tocentry.rb +20 -0
- data/lib/docbook/elements/topic.rb +26 -0
- data/lib/docbook/elements/type.rb +16 -0
- data/lib/docbook/elements/uri.rb +16 -0
- data/lib/docbook/elements/userinput.rb +18 -0
- data/lib/docbook/elements/variable.rb +16 -0
- data/lib/docbook/elements/variablelist.rb +19 -0
- data/lib/docbook/elements/varlistentry.rb +17 -0
- data/lib/docbook/elements/version.rb +16 -0
- data/lib/docbook/elements/videoobject.rb +18 -0
- data/lib/docbook/elements/warning.rb +30 -0
- data/lib/docbook/elements/xref.rb +18 -0
- data/lib/docbook/elements/year.rb +16 -0
- data/lib/docbook/elements.rb +204 -0
- data/lib/docbook/models/document_metadata.rb +30 -0
- data/lib/docbook/models/document_root.rb +33 -0
- data/lib/docbook/models/index_entry.rb +28 -0
- data/lib/docbook/models/reading_position.rb +22 -0
- data/lib/docbook/models/section_number.rb +18 -0
- data/lib/docbook/models/section_root.rb +29 -0
- data/lib/docbook/models/toc_node.rb +24 -0
- data/lib/docbook/models.rb +16 -0
- data/lib/docbook/output/data.rb +196 -0
- data/lib/docbook/output/html.rb +1450 -0
- data/lib/docbook/output/index_generator.rb +281 -0
- data/lib/docbook/output.rb +8 -0
- data/lib/docbook/services/document_builder.rb +258 -0
- data/lib/docbook/services/element_to_hash.rb +287 -0
- data/lib/docbook/services/index_generator.rb +134 -0
- data/lib/docbook/services/numbering_service.rb +186 -0
- data/lib/docbook/services/toc_generator.rb +138 -0
- data/lib/docbook/services.rb +14 -0
- data/lib/docbook/templates/document.html.liquid +20 -0
- data/lib/docbook/templates/partials/_head.liquid +39 -0
- data/lib/docbook/templates/partials/_scripts.liquid +10 -0
- data/lib/docbook/version.rb +5 -0
- data/lib/docbook/xinclude_resolver.rb +217 -0
- data/lib/docbook/xref_resolver.rb +78 -0
- data/lib/docbook.rb +17 -0
- data/sig/docbook.rbs +4 -0
- metadata +385 -0
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: default
|
|
3
|
+
title: HTML Output
|
|
4
|
+
parent: Ruby API
|
|
5
|
+
grand_parent: Interfaces
|
|
6
|
+
nav_order: 2
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
== HTML Output
|
|
10
|
+
|
|
11
|
+
The `Docbook::Output::Html` class generates HTML from a parsed DocBook document.
|
|
12
|
+
|
|
13
|
+
=== Constructor
|
|
14
|
+
|
|
15
|
+
[source,ruby]
|
|
16
|
+
----
|
|
17
|
+
html_generator = Docbook::Output::Html.new(
|
|
18
|
+
document, # Parsed DocBook element (required)
|
|
19
|
+
xref_resolver: xref_resolver, # XrefResolver instance (optional)
|
|
20
|
+
output_mode: :single_file, # :single_file or :directory
|
|
21
|
+
base_path: "/path/to/xml/dir", # Base path for image resolution
|
|
22
|
+
output_path: "/path/to/output" # Output directory (required for directory mode)
|
|
23
|
+
)
|
|
24
|
+
----
|
|
25
|
+
|
|
26
|
+
==== Parameters
|
|
27
|
+
|
|
28
|
+
[cols="2,1,5"]
|
|
29
|
+
|===
|
|
30
|
+
| Parameter | Required | Description
|
|
31
|
+
|
|
32
|
+
| `document` | Yes | A parsed DocBook element from `Document.from_xml`
|
|
33
|
+
| `xref_resolver` | No | A `Docbook::XrefResolver` instance (call `resolve!` first). Used to resolve `xref` elements to target titles.
|
|
34
|
+
| `output_mode` | No | `:single_file` (default) or `:directory`. Controls how images and assets are handled.
|
|
35
|
+
| `base_path` | No | Directory containing the source XML file. Used to locate images referenced by relative paths.
|
|
36
|
+
| `output_path` | No | Output directory for directory mode. Required when `output_mode` is `:directory`.
|
|
37
|
+
|===
|
|
38
|
+
|
|
39
|
+
=== Generating HTML
|
|
40
|
+
|
|
41
|
+
Call `to_html` on the generator instance to produce the HTML output:
|
|
42
|
+
|
|
43
|
+
[source,ruby]
|
|
44
|
+
----
|
|
45
|
+
html = html_generator.to_html
|
|
46
|
+
# => "<!DOCTYPE html><html>..." (String)
|
|
47
|
+
----
|
|
48
|
+
|
|
49
|
+
=== Output Modes
|
|
50
|
+
|
|
51
|
+
==== Single-File Mode
|
|
52
|
+
|
|
53
|
+
Produces a self-contained HTML string with all assets embedded:
|
|
54
|
+
|
|
55
|
+
[source,ruby]
|
|
56
|
+
----
|
|
57
|
+
require "docbook"
|
|
58
|
+
|
|
59
|
+
xml_string = File.read("article.xml")
|
|
60
|
+
document = Docbook::Document.from_xml(xml_string)
|
|
61
|
+
xref_resolver = Docbook::XrefResolver.new(document).resolve!
|
|
62
|
+
|
|
63
|
+
html = Docbook::Output::Html.new(
|
|
64
|
+
document,
|
|
65
|
+
xref_resolver: xref_resolver,
|
|
66
|
+
output_mode: :single_file,
|
|
67
|
+
base_path: File.dirname(File.expand_path("article.xml"))
|
|
68
|
+
).to_html
|
|
69
|
+
|
|
70
|
+
File.write("output.html", html)
|
|
71
|
+
----
|
|
72
|
+
|
|
73
|
+
In single-file mode:
|
|
74
|
+
|
|
75
|
+
* CSS and JavaScript are embedded inline in the HTML
|
|
76
|
+
* Images are converted to Base64 data URIs (using the `Marcel` gem for MIME type detection)
|
|
77
|
+
* All content data (TOC, sections, index) is embedded in `<script>` tags as JSON
|
|
78
|
+
* The resulting file is completely self-contained
|
|
79
|
+
|
|
80
|
+
==== Directory Mode
|
|
81
|
+
|
|
82
|
+
Produces an HTML shell plus separate data and asset files:
|
|
83
|
+
|
|
84
|
+
[source,ruby]
|
|
85
|
+
----
|
|
86
|
+
require "docbook"
|
|
87
|
+
require "fileutils"
|
|
88
|
+
|
|
89
|
+
xml_string = File.read("book.xml")
|
|
90
|
+
resolved = Docbook::XIncludeResolver.resolve_string(xml_string, base_path: "book.xml")
|
|
91
|
+
document = Docbook::Document.from_xml(resolved.to_xml)
|
|
92
|
+
xref_resolver = Docbook::XrefResolver.new(document).resolve!
|
|
93
|
+
|
|
94
|
+
output_dir = "/var/www/html/book"
|
|
95
|
+
FileUtils.mkdir_p(output_dir)
|
|
96
|
+
|
|
97
|
+
html = Docbook::Output::Html.new(
|
|
98
|
+
document,
|
|
99
|
+
xref_resolver: xref_resolver,
|
|
100
|
+
output_mode: :directory,
|
|
101
|
+
base_path: File.dirname(File.expand_path("book.xml")),
|
|
102
|
+
output_path: output_dir
|
|
103
|
+
).to_html
|
|
104
|
+
|
|
105
|
+
# The generator writes docbook.data.json to output_path automatically
|
|
106
|
+
# The returned HTML string is the index.html content
|
|
107
|
+
File.write(File.join(output_dir, "index.html"), html)
|
|
108
|
+
----
|
|
109
|
+
|
|
110
|
+
In directory mode, the `to_html` method also writes `docbook.data.json` to the `output_path` directory. The directory structure is:
|
|
111
|
+
|
|
112
|
+
[source]
|
|
113
|
+
----
|
|
114
|
+
output_dir/
|
|
115
|
+
index.html # HTML returned by to_html
|
|
116
|
+
docbook.data.json # Written automatically by to_html
|
|
117
|
+
----
|
|
118
|
+
|
|
119
|
+
[NOTE]
|
|
120
|
+
====
|
|
121
|
+
The CLI's `write_output` method handles copying `app.css` and `app.iife.js` to the `assets/` subdirectory. When using the Ruby API directly, you are responsible for copying the frontend assets if you need them.
|
|
122
|
+
====
|
|
123
|
+
|
|
124
|
+
=== Cross-Reference Resolution
|
|
125
|
+
|
|
126
|
+
The `xref_resolver` parameter is used to resolve `<xref>` elements in the document. When an `xref` element has a `linkend` attribute, the resolver looks up the target element by its `xml:id` and returns the title text:
|
|
127
|
+
|
|
128
|
+
[source,ruby]
|
|
129
|
+
----
|
|
130
|
+
# Without xref_resolver, xref elements display the raw linkend value
|
|
131
|
+
# With xref_resolver, xref elements display the target's title
|
|
132
|
+
xref_resolver = Docbook::XrefResolver.new(document).resolve!
|
|
133
|
+
|
|
134
|
+
html = Docbook::Output::Html.new(
|
|
135
|
+
document,
|
|
136
|
+
xref_resolver: xref_resolver,
|
|
137
|
+
output_mode: :single_file
|
|
138
|
+
).to_html
|
|
139
|
+
----
|
|
140
|
+
|
|
141
|
+
=== Image Handling
|
|
142
|
+
|
|
143
|
+
Images are handled differently based on the output mode:
|
|
144
|
+
|
|
145
|
+
* *Single-file mode:* Images are read from disk, Base64-encoded, and embedded as data URIs
|
|
146
|
+
* *Directory mode:* Images reference their original file paths (relative to the output directory)
|
|
147
|
+
|
|
148
|
+
The `base_path` parameter is used to locate image files on disk. The generator searches the base path and all parent directories to find referenced images. It also checks common prefixes like `resources/` and `../resources/`.
|
|
149
|
+
|
|
150
|
+
=== Generated Data Structure
|
|
151
|
+
|
|
152
|
+
The `to_html` method builds a structured data model internally before rendering. This model includes:
|
|
153
|
+
|
|
154
|
+
[cols="2,5"]
|
|
155
|
+
|===
|
|
156
|
+
| Component | Description
|
|
157
|
+
|
|
158
|
+
| *Title* | The document title extracted from `<info><title>` or the root element's `<title>`
|
|
159
|
+
| *TOC* | Hierarchical table of contents with section IDs, titles, and types
|
|
160
|
+
| *Numbering* | Computed numbering for parts (Roman), chapters (Arabic), appendices (Alpha), and sections (hierarchical)
|
|
161
|
+
| *Content* | Section content organized by section ID, with blocks for paragraphs, code, images, lists, etc.
|
|
162
|
+
| *Index* | Collected `indexterm` elements grouped alphabetically with see/see-also support
|
|
163
|
+
|===
|
|
164
|
+
|
|
165
|
+
=== Supported Content Types
|
|
166
|
+
|
|
167
|
+
The HTML generator processes the following block-level content types from each section:
|
|
168
|
+
|
|
169
|
+
* Paragraphs (`para`, `formalpara`)
|
|
170
|
+
* Code listings (`programlisting`, `screen`, `literallayout`)
|
|
171
|
+
* Images and figures (`mediaobject`, `figure`, `informalfigure`, `inlinemediaobject`)
|
|
172
|
+
* Lists (`orderedlist`, `itemizedlist`, `variablelist`)
|
|
173
|
+
* Admonitions (`note`, `warning`, `caution`, `important`, `tip`, `danger`)
|
|
174
|
+
* Examples (`example`, `informalexample`)
|
|
175
|
+
* Block quotes (`blockquote`)
|
|
176
|
+
* Glossary entries (`glossentry`)
|
|
177
|
+
* Bibliography entries (`bibliomixed`)
|
|
178
|
+
* Reference entries (`refentry`)
|
|
179
|
+
* Index sections (`index`, `setindex`)
|
|
180
|
+
* Nested sections (`section`, `simplesect`)
|
|
181
|
+
|
|
182
|
+
=== See Also
|
|
183
|
+
|
|
184
|
+
* *<<parsing,Parsing Documents>>* -- Parse XML before generating HTML
|
|
185
|
+
* *<<xref-resolution,XRef Resolution>>* -- Resolve cross-references for the HTML generator
|
|
186
|
+
* *<<xinclude,XInclude Resolution>>* -- Resolve XIncludes before parsing
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: default
|
|
3
|
+
title: Ruby API
|
|
4
|
+
parent: Interfaces
|
|
5
|
+
nav_order: 2
|
|
6
|
+
has_children: true
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
== Ruby API
|
|
10
|
+
|
|
11
|
+
The `docbook` gem provides a programmatic Ruby API for parsing, processing, and converting DocBook XML documents. This is the same API that powers the CLI, exposed for direct use in Ruby applications.
|
|
12
|
+
|
|
13
|
+
=== Getting Started
|
|
14
|
+
|
|
15
|
+
Add the gem to your project and require it:
|
|
16
|
+
|
|
17
|
+
[source,ruby]
|
|
18
|
+
----
|
|
19
|
+
require "docbook"
|
|
20
|
+
----
|
|
21
|
+
|
|
22
|
+
All public classes are under the `Docbook` module namespace.
|
|
23
|
+
|
|
24
|
+
=== Core Classes
|
|
25
|
+
|
|
26
|
+
The Ruby API revolves around four core classes:
|
|
27
|
+
|
|
28
|
+
[cols="3,5"]
|
|
29
|
+
|===
|
|
30
|
+
| Class | Purpose
|
|
31
|
+
|
|
32
|
+
| `Docbook::Document` | Entry point for parsing XML strings into typed Ruby element models. Supports 39 root element types.
|
|
33
|
+
| `Docbook::XIncludeResolver` | Resolves `xi:include` elements in XML documents. Must be called *before* parsing with `Document.from_xml`.
|
|
34
|
+
| `Docbook::XrefResolver` | Builds an `xml:id` lookup map from a parsed document and resolves `xref`/`linkend` references to titles.
|
|
35
|
+
| `Docbook::Output::Html` | Generates HTML from a parsed document in single-file or directory mode.
|
|
36
|
+
|===
|
|
37
|
+
|
|
38
|
+
=== Processing Pipeline
|
|
39
|
+
|
|
40
|
+
A typical processing pipeline has four stages:
|
|
41
|
+
|
|
42
|
+
[source,ruby]
|
|
43
|
+
----
|
|
44
|
+
require "docbook"
|
|
45
|
+
|
|
46
|
+
# Stage 1: Read the XML file
|
|
47
|
+
xml_string = File.read("book.xml")
|
|
48
|
+
|
|
49
|
+
# Stage 2: Resolve XIncludes (optional, but usually needed)
|
|
50
|
+
resolved = Docbook::XIncludeResolver.resolve_string(xml_string, base_path: "book.xml")
|
|
51
|
+
|
|
52
|
+
# Stage 3: Parse into Ruby element models
|
|
53
|
+
document = Docbook::Document.from_xml(resolved.to_xml)
|
|
54
|
+
|
|
55
|
+
# Stage 4: Resolve cross-references
|
|
56
|
+
xref_resolver = Docbook::XrefResolver.new(document).resolve!
|
|
57
|
+
|
|
58
|
+
# Stage 5: Generate HTML
|
|
59
|
+
html = Docbook::Output::Html.new(
|
|
60
|
+
document,
|
|
61
|
+
xref_resolver: xref_resolver,
|
|
62
|
+
output_mode: :single_file,
|
|
63
|
+
base_path: File.dirname(File.expand_path("book.xml"))
|
|
64
|
+
).to_html
|
|
65
|
+
|
|
66
|
+
File.write("output.html", html)
|
|
67
|
+
----
|
|
68
|
+
|
|
69
|
+
[TIP]
|
|
70
|
+
====
|
|
71
|
+
Stages 2 and 4 are optional but recommended. XInclude resolution should happen *before* parsing because the parser needs a single, complete XML document. Cross-reference resolution should happen *after* parsing so the resolver can traverse the element tree.
|
|
72
|
+
====
|
|
73
|
+
|
|
74
|
+
=== Error Handling
|
|
75
|
+
|
|
76
|
+
The gem defines a base error class `Docbook::Error` that is raised for invalid input:
|
|
77
|
+
|
|
78
|
+
[source,ruby]
|
|
79
|
+
----
|
|
80
|
+
begin
|
|
81
|
+
Docbook::Document.from_xml("<invalid>not docbook</invalid>")
|
|
82
|
+
rescue Docbook::Error => e
|
|
83
|
+
puts "Parse error: #{e.message}"
|
|
84
|
+
# => "Unsupported DocBook root element: invalid"
|
|
85
|
+
end
|
|
86
|
+
----
|
|
87
|
+
|
|
88
|
+
Common error scenarios:
|
|
89
|
+
|
|
90
|
+
* Empty or invalid XML -- raises `Docbook::Error, "Empty or invalid XML document"`
|
|
91
|
+
* Unsupported root element -- raises `Docbook::Error, "Unsupported DocBook root element: <name>"`
|
|
92
|
+
* Missing file -- raises `Errno::ENOENT` from `File.read`
|
|
93
|
+
|
|
94
|
+
=== Element Models
|
|
95
|
+
|
|
96
|
+
All DocBook elements are modeled as `Lutaml::Model::Serializable` subclasses under the `Docbook::Elements` namespace. These models provide:
|
|
97
|
+
|
|
98
|
+
* *Typed attributes* -- Every XML element maps to a Ruby class with typed attributes (strings, collections, nested models)
|
|
99
|
+
* *Mixed content* -- Elements that support mixed content (text interspersed with child elements) provide an `each_mixed_content` method for traversal
|
|
100
|
+
* *XML round-tripping* -- Models can be serialized back to XML via `to_xml`
|
|
101
|
+
|
|
102
|
+
For example, a `<book>` element is represented as `Docbook::Elements::Book` with attributes for `info`, `part`, `chapter`, `appendix`, `preface`, `bibliography`, `glossary`, and `index`.
|
|
103
|
+
|
|
104
|
+
=== Detailed Documentation
|
|
105
|
+
|
|
106
|
+
Explore each component in detail:
|
|
107
|
+
|
|
108
|
+
* *<<parsing,Parsing Documents>>* -- How to parse XML and access element models
|
|
109
|
+
* *<<html-output,HTML Output>>* -- Generating HTML in single-file and directory modes
|
|
110
|
+
* *<<xinclude,XInclude Resolution>>* -- Resolving `xi:include` elements
|
|
111
|
+
* *<<xref-resolution,XRef Resolution>>* -- Building ID maps and resolving cross-references
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: default
|
|
3
|
+
title: Parsing Documents
|
|
4
|
+
parent: Ruby API
|
|
5
|
+
grand_parent: Interfaces
|
|
6
|
+
nav_order: 1
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
== Parsing Documents
|
|
10
|
+
|
|
11
|
+
The `Docbook::Document` class is the primary entry point for parsing DocBook XML into typed Ruby objects.
|
|
12
|
+
|
|
13
|
+
=== Basic Parsing
|
|
14
|
+
|
|
15
|
+
Use `Document.from_xml` to parse an XML string:
|
|
16
|
+
|
|
17
|
+
[source,ruby]
|
|
18
|
+
----
|
|
19
|
+
require "docbook"
|
|
20
|
+
|
|
21
|
+
xml = <<~XML
|
|
22
|
+
<article xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="sample">
|
|
23
|
+
<info>
|
|
24
|
+
<title>Sample Article</title>
|
|
25
|
+
</info>
|
|
26
|
+
<section xml:id="intro">
|
|
27
|
+
<title>Introduction</title>
|
|
28
|
+
<para>Hello, DocBook world.</para>
|
|
29
|
+
</section>
|
|
30
|
+
</article>
|
|
31
|
+
XML
|
|
32
|
+
|
|
33
|
+
document = Docbook::Document.from_xml(xml)
|
|
34
|
+
# => #<Docbook::Elements::Article:0x0000...>
|
|
35
|
+
----
|
|
36
|
+
|
|
37
|
+
The method returns an instance of the appropriate element class based on the root element name. In this case, it returns a `Docbook::Elements::Article` because the root element is `<article>`.
|
|
38
|
+
|
|
39
|
+
=== Supported Root Elements
|
|
40
|
+
|
|
41
|
+
`Document.from_xml` automatically detects the root element and selects the correct parser. The gem supports 39 root element types:
|
|
42
|
+
|
|
43
|
+
[cols="3,3,3"]
|
|
44
|
+
|===
|
|
45
|
+
| Structural | Sectioning | Reference
|
|
46
|
+
|
|
47
|
+
| `article` | `section` | `refentry`
|
|
48
|
+
| `book` | `sect1` | `reference`
|
|
49
|
+
| `chapter` | `sect2` | `refsection`
|
|
50
|
+
| `appendix` | `sect3` | `refsect1`
|
|
51
|
+
| `preface` | `sect4` | `refsect2`
|
|
52
|
+
| `part` | `sect5` | `refsect3`
|
|
53
|
+
| `set` | `simplesect` |
|
|
54
|
+
| `topic` | `para` |
|
|
55
|
+
|===
|
|
56
|
+
|
|
57
|
+
[cols="3,3,3"]
|
|
58
|
+
|===
|
|
59
|
+
| Front Matter | Back Matter | Other
|
|
60
|
+
|
|
61
|
+
| `dedication` | `bibliography` | `index`
|
|
62
|
+
| `acknowledgements` | `glossary` | `setindex`
|
|
63
|
+
| `colophon` | | `toc`
|
|
64
|
+
|===
|
|
65
|
+
|
|
66
|
+
=== Checking Root Element Support
|
|
67
|
+
|
|
68
|
+
Before parsing, you can check whether a specific root element is supported:
|
|
69
|
+
|
|
70
|
+
[source,ruby]
|
|
71
|
+
----
|
|
72
|
+
# Check if a root element name is supported
|
|
73
|
+
Docbook::Document.supports?("article") # => true
|
|
74
|
+
Docbook::Document.supports?("html") # => false
|
|
75
|
+
|
|
76
|
+
# List all supported root element names
|
|
77
|
+
Docbook::Document.supported_root_elements
|
|
78
|
+
# => ["article", "book", "chapter", "appendix", "preface", "part",
|
|
79
|
+
# "section", "refentry", "bibliography", "glossary", "set",
|
|
80
|
+
# "reference", "topic", "dedication", "acknowledgements",
|
|
81
|
+
# "colophon", "index", "toc", "sect1", "sect2", "sect3",
|
|
82
|
+
# "sect4", "sect5", "refsection", "refsect1", "refsect2",
|
|
83
|
+
# "refsect3", "setindex", "para", "simplesect"]
|
|
84
|
+
----
|
|
85
|
+
|
|
86
|
+
=== Error Handling
|
|
87
|
+
|
|
88
|
+
Parsing errors raise `Docbook::Error`:
|
|
89
|
+
|
|
90
|
+
[source,ruby]
|
|
91
|
+
----
|
|
92
|
+
# Empty XML
|
|
93
|
+
Docbook::Document.from_xml("")
|
|
94
|
+
# => raises Docbook::Error: "Empty or invalid XML document"
|
|
95
|
+
|
|
96
|
+
# Unsupported root element
|
|
97
|
+
Docbook::Document.from_xml("<html><body>Not DocBook</body></html>")
|
|
98
|
+
# => raises Docbook::Error: "Unsupported DocBook root element: html"
|
|
99
|
+
----
|
|
100
|
+
|
|
101
|
+
Always wrap parsing in a rescue block for robust applications:
|
|
102
|
+
|
|
103
|
+
[source,ruby]
|
|
104
|
+
----
|
|
105
|
+
begin
|
|
106
|
+
document = Docbook::Document.from_xml(xml_string)
|
|
107
|
+
rescue Docbook::Error => e
|
|
108
|
+
warn "Failed to parse document: #{e.message}"
|
|
109
|
+
exit 1
|
|
110
|
+
end
|
|
111
|
+
----
|
|
112
|
+
|
|
113
|
+
=== Accessing Parsed Elements
|
|
114
|
+
|
|
115
|
+
Once parsed, the returned object is a fully populated element model. The available attributes depend on the element type:
|
|
116
|
+
|
|
117
|
+
[source,ruby]
|
|
118
|
+
----
|
|
119
|
+
# Parse a book
|
|
120
|
+
document = Docbook::Document.from_xml(book_xml)
|
|
121
|
+
# document is a Docbook::Elements::Book
|
|
122
|
+
|
|
123
|
+
document.xml_id # => "my-book" (the xml:id attribute)
|
|
124
|
+
document.version # => "5.0"
|
|
125
|
+
document.info # => #<Docbook::Elements::Info:...>
|
|
126
|
+
document.info.title # => #<Docbook::Elements::Title:...>
|
|
127
|
+
document.info.title.content # => "My Book Title"
|
|
128
|
+
document.chapter # => [#<Docbook::Elements::Chapter:...>, ...]
|
|
129
|
+
document.appendix # => [#<Docbook::Elements::Appendix:...>, ...]
|
|
130
|
+
document.part # => [#<Docbook::Elements::Part:...>, ...]
|
|
131
|
+
document.preface # => [#<Docbook::Elements::Preface:...>, ...]
|
|
132
|
+
----
|
|
133
|
+
|
|
134
|
+
[source,ruby]
|
|
135
|
+
----
|
|
136
|
+
# Parse an article
|
|
137
|
+
document = Docbook::Document.from_xml(article_xml)
|
|
138
|
+
# document is a Docbook::Elements::Article
|
|
139
|
+
|
|
140
|
+
document.info.title.content # => "Article Title"
|
|
141
|
+
document.section # => [#<Docbook::Elements::Section:...>, ...]
|
|
142
|
+
document.section.first.title # => #<Docbook::Elements::Title:...>
|
|
143
|
+
document.section.first.title.content # => "Introduction"
|
|
144
|
+
----
|
|
145
|
+
|
|
146
|
+
=== Mixed Content Traversal
|
|
147
|
+
|
|
148
|
+
Many DocBook elements support *mixed content* -- a mixture of text strings and child elements. The `each_mixed_content` method yields each child node in document order:
|
|
149
|
+
|
|
150
|
+
[source,ruby]
|
|
151
|
+
----
|
|
152
|
+
section = document.section.first
|
|
153
|
+
section.each_mixed_content do |node|
|
|
154
|
+
case node
|
|
155
|
+
when String
|
|
156
|
+
# Raw text content between elements
|
|
157
|
+
puts "Text: #{node}"
|
|
158
|
+
when Docbook::Elements::Para
|
|
159
|
+
puts "Paragraph: #{node.content}"
|
|
160
|
+
when Docbook::Elements::MediaObject
|
|
161
|
+
puts "Media object"
|
|
162
|
+
when Docbook::Elements::ProgramListing
|
|
163
|
+
puts "Code listing: #{node.content}"
|
|
164
|
+
when Docbook::Elements::OrderedList
|
|
165
|
+
puts "Ordered list"
|
|
166
|
+
# ... many more element types
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
----
|
|
170
|
+
|
|
171
|
+
This is the primary mechanism for traversing element content in the HTML generation pipeline. The `each_mixed_content` method yields both `String` instances (for text nodes) and typed element objects (for child elements).
|
|
172
|
+
|
|
173
|
+
=== File-Based Parsing
|
|
174
|
+
|
|
175
|
+
A complete file-based parsing workflow:
|
|
176
|
+
|
|
177
|
+
[source,ruby]
|
|
178
|
+
----
|
|
179
|
+
require "docbook"
|
|
180
|
+
|
|
181
|
+
# Read the file
|
|
182
|
+
xml_string = File.read("book.xml")
|
|
183
|
+
|
|
184
|
+
# Optionally resolve XIncludes first
|
|
185
|
+
resolved_xml = Docbook::XIncludeResolver.resolve_string(xml_string, base_path: "book.xml")
|
|
186
|
+
|
|
187
|
+
# Parse
|
|
188
|
+
document = Docbook::Document.from_xml(resolved_xml.to_xml)
|
|
189
|
+
|
|
190
|
+
# Work with the parsed document
|
|
191
|
+
puts "Title: #{document.info&.title&.content}"
|
|
192
|
+
puts "Chapters: #{document.chapter&.size || 0}"
|
|
193
|
+
document.chapter&.each do |chapter|
|
|
194
|
+
puts " - #{chapter.title&.content}"
|
|
195
|
+
end
|
|
196
|
+
----
|
|
197
|
+
|
|
198
|
+
=== See Also
|
|
199
|
+
|
|
200
|
+
* *<<html-output,HTML Output>>* -- Convert parsed documents to HTML
|
|
201
|
+
* *<<xinclude,XInclude Resolution>>* -- Resolve XIncludes before parsing
|
|
202
|
+
* *<<xref-resolution,XRef Resolution>>* -- Build cross-reference maps from parsed documents
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: default
|
|
3
|
+
title: XInclude Resolution
|
|
4
|
+
parent: Ruby API
|
|
5
|
+
grand_parent: Interfaces
|
|
6
|
+
nav_order: 3
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
== XInclude Resolution
|
|
10
|
+
|
|
11
|
+
The `Docbook::XIncludeResolver` class resolves http://www.w3.org/2001/XInclude/[XInclude] elements in DocBook XML documents. XInclude resolution must happen *before* parsing with `Document.from_xml`, because the parser needs a single, complete XML document.
|
|
12
|
+
|
|
13
|
+
=== Why Resolve XIncludes First
|
|
14
|
+
|
|
15
|
+
DocBook documents are often modular: a book may include chapters from separate files using `<xi:include>` elements. The `Document.from_xml` parser expects a single XML document with no unresolved XIncludes. The `XIncludeResolver` expands these references to produce a merged document.
|
|
16
|
+
|
|
17
|
+
=== Class Methods
|
|
18
|
+
|
|
19
|
+
The resolver provides two class-level entry points:
|
|
20
|
+
|
|
21
|
+
==== `resolve(doc)`
|
|
22
|
+
|
|
23
|
+
Resolves XIncludes in a Nokogiri document object. Processes `xi:include` elements iteratively to handle nested includes.
|
|
24
|
+
|
|
25
|
+
[source,ruby]
|
|
26
|
+
----
|
|
27
|
+
require "nokogiri"
|
|
28
|
+
require "docbook"
|
|
29
|
+
|
|
30
|
+
doc = Nokogiri::XML(File.read("book.xml"))
|
|
31
|
+
Docbook::XIncludeResolver.resolve(doc)
|
|
32
|
+
# => returns the same Nokogiri document with xi:include elements replaced
|
|
33
|
+
----
|
|
34
|
+
|
|
35
|
+
==== `resolve_string(xml_string, base_path:)`
|
|
36
|
+
|
|
37
|
+
Resolves XIncludes in a raw XML string. This is the most convenient method for most use cases. The `base_path` parameter tells the resolver where to look for included files.
|
|
38
|
+
|
|
39
|
+
[source,ruby]
|
|
40
|
+
----
|
|
41
|
+
require "docbook"
|
|
42
|
+
|
|
43
|
+
xml_string = File.read("book.xml")
|
|
44
|
+
resolved = Docbook::XIncludeResolver.resolve_string(xml_string, base_path: "book.xml")
|
|
45
|
+
resolved.to_xml # => merged XML string with all xi:include expanded
|
|
46
|
+
----
|
|
47
|
+
|
|
48
|
+
[IMPORTANT]
|
|
49
|
+
====
|
|
50
|
+
The `base_path` parameter should be the path to the XML file itself (not just the directory). The resolver extracts the directory from this path to resolve relative `href` attributes in `xi:include` elements.
|
|
51
|
+
====
|
|
52
|
+
|
|
53
|
+
=== Resolution Process
|
|
54
|
+
|
|
55
|
+
The resolver processes XIncludes iteratively:
|
|
56
|
+
|
|
57
|
+
1. Find all `xi:include` elements in the document
|
|
58
|
+
2. For each include, resolve the `href` to a file path relative to the base directory
|
|
59
|
+
3. Replace the `xi:include` element with the included content
|
|
60
|
+
4. Re-scan for any new `xi:include` elements (handles nested includes)
|
|
61
|
+
5. Repeat until no more `xi:include` elements remain
|
|
62
|
+
|
|
63
|
+
This iterative approach ensures that deeply nested includes (file A includes file B, which includes file C) are fully resolved.
|
|
64
|
+
|
|
65
|
+
=== Include Types
|
|
66
|
+
|
|
67
|
+
The resolver handles two types of XIncludes:
|
|
68
|
+
|
|
69
|
+
==== XML Includes (default)
|
|
70
|
+
|
|
71
|
+
Standard XML includes where the `parse` attribute is omitted or set to `"xml"`. The root element of the included file replaces the `xi:include` element:
|
|
72
|
+
|
|
73
|
+
[source,ruby]
|
|
74
|
+
----
|
|
75
|
+
# book.xml contains:
|
|
76
|
+
# <xi:include href="chapters/chapter1.xml"/>
|
|
77
|
+
#
|
|
78
|
+
# After resolution, the <chapter> element from chapter1.xml
|
|
79
|
+
# replaces the xi:include element
|
|
80
|
+
----
|
|
81
|
+
|
|
82
|
+
==== Text Includes
|
|
83
|
+
|
|
84
|
+
Text includes where `parse="text"`. The file contents are included as plain text:
|
|
85
|
+
|
|
86
|
+
[source,ruby]
|
|
87
|
+
----
|
|
88
|
+
# Includes a code snippet as literal text
|
|
89
|
+
# <xi:include href="code/example.rb" parse="text"/>
|
|
90
|
+
----
|
|
91
|
+
|
|
92
|
+
==== Text Includes with Fragid
|
|
93
|
+
|
|
94
|
+
Text includes also support the `fragid` attribute for selecting a subset of the file content. This is an extension based on the DocBook xslTNG specification:
|
|
95
|
+
|
|
96
|
+
* `fragid="line=START,END"` -- Select lines from START to END (RFC 5147 line scheme)
|
|
97
|
+
* `fragid="char=START,END"` -- Select characters from START to END (RFC 5147 char scheme)
|
|
98
|
+
* `fragid="search=#PATTERN#[;after|;before],#STOP#"` -- Select lines matching a literal pattern
|
|
99
|
+
* `fragid="search=/REGEX/,/STOP/"` -- Select lines matching a regex pattern
|
|
100
|
+
|
|
101
|
+
=== Complete Example
|
|
102
|
+
|
|
103
|
+
A full workflow for resolving XIncludes before parsing:
|
|
104
|
+
|
|
105
|
+
[source,ruby]
|
|
106
|
+
----
|
|
107
|
+
require "docbook"
|
|
108
|
+
|
|
109
|
+
# Read the main document
|
|
110
|
+
xml_string = File.read("book.xml")
|
|
111
|
+
|
|
112
|
+
# Resolve all XIncludes
|
|
113
|
+
resolved = Docbook::XIncludeResolver.resolve_string(
|
|
114
|
+
xml_string,
|
|
115
|
+
base_path: "book.xml"
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
# Now parse the merged document
|
|
119
|
+
document = Docbook::Document.from_xml(resolved.to_xml)
|
|
120
|
+
|
|
121
|
+
puts "Chapters: #{document.chapter&.size || 0}"
|
|
122
|
+
document.chapter&.each do |chapter|
|
|
123
|
+
puts " - #{chapter.title&.content}"
|
|
124
|
+
end
|
|
125
|
+
----
|
|
126
|
+
|
|
127
|
+
=== Handling Nested Includes
|
|
128
|
+
|
|
129
|
+
The resolver handles nested includes automatically. Consider this scenario:
|
|
130
|
+
|
|
131
|
+
* `book.xml` includes `part1.xml`
|
|
132
|
+
* `part1.xml` includes `chapter1.xml` and `chapter2.xml`
|
|
133
|
+
|
|
134
|
+
After resolution, all content is merged into a single document:
|
|
135
|
+
|
|
136
|
+
[source,ruby]
|
|
137
|
+
----
|
|
138
|
+
resolved = Docbook::XIncludeResolver.resolve_string(
|
|
139
|
+
File.read("book.xml"),
|
|
140
|
+
base_path: "book.xml"
|
|
141
|
+
)
|
|
142
|
+
# The resolved document contains content from book.xml,
|
|
143
|
+
# part1.xml, chapter1.xml, and chapter2.xml
|
|
144
|
+
----
|
|
145
|
+
|
|
146
|
+
=== Error Handling
|
|
147
|
+
|
|
148
|
+
The resolver is designed to be tolerant of errors:
|
|
149
|
+
|
|
150
|
+
* If a referenced file does not exist, the `xi:include` element is left in place (no error raised)
|
|
151
|
+
* If the resolver encounters an unexpected error during processing, it returns the original document unchanged
|
|
152
|
+
* The resolver uses Nokogiri's `url` attribute to determine the base directory for relative path resolution
|
|
153
|
+
|
|
154
|
+
=== Namespace Handling
|
|
155
|
+
|
|
156
|
+
The resolver ensures that namespace declarations are properly preserved when merging documents. If an included file declares namespaces that are not present in the main document, the resolver adds the namespace declarations to the root element.
|
|
157
|
+
|
|
158
|
+
=== See Also
|
|
159
|
+
|
|
160
|
+
* *<<parsing,Parsing Documents>>* -- Parse resolved XML into element models
|
|
161
|
+
* *<<xref-resolution,XRef Resolution>>* -- Resolve cross-references after parsing
|
|
162
|
+
* *<<html-output,HTML Output>>* -- Generate HTML from parsed documents
|