DocBook is a Ruby gem for parsing, validating, and converting DocBook 5 XML documents into interactive HTML readers and structured JSON. It provides a complete command-line interface and Ruby API for document processing.
Key features:
-
Interactive reader — Self-contained HTML with search, themes, TOC navigation
-
DocBook 5 parsing — Full element support via lutaml-model
-
XInclude resolution — Transparent handling of multi-file documents
-
DocbookMirror JSON — ProseMirror-compatible structured representation
Build an interactive reader from any DocBook XML:
$ docbook build guide.xmlThis produces guide.html in the same directory. Open it in a browser — it works offline with no server required.
Specify a custom output path:
$ docbook build guide.xml -o output.htmlTry the bundled demo:
$ docbook build --demorequire 'docbook'
# Build an interactive reader
Docbook::Output::SinglePage.new(
xml_path: 'guide.xml',
output_path: 'guide.html',
image_search_dirs: ['images/'],
image_strategy: :data_url
).generate
# Export as DocbookMirror JSON
parsed = Docbook::Document.from_xml(File.read('guide.xml'))
json = Docbook::Output::DocbookMirror.new(parsed).to_pretty_json
File.write('guide.json', json)| Command | Description |
|---|---|
|
Build an interactive HTML reader from DocBook XML. Pass |
|
Export as DocbookMirror JSON |
|
Validate DocBook XML against RELAX NG schema |
|
Format/prettify DocBook XML |
Build an interactive HTML reader. The output is a single self-contained file that works offline (CSS, JS, and images are all inlined).
$ docbook build [INPUT] [options]
$ docbook build --demo [options]Options:
-
-o, --output FILE— Output HTML file path (default:<input>.htmlordemo.html) -
--demo— Use the bundled DocBook sample as input (accepts name:xslTNGormodel-flow) -
--image-search-dir DIR— Directories to search for images (default: XML file directory) -
--image-strategy STRATEGY— Image handling:data_url(default),file_url, orrelative -
--title TITLE— Page title (default: derived from document) -
--xinclude/--no-xinclude— Resolve XIncludes (default: true)
Examples:
# Basic (output defaults to book.html)
$ docbook build book.xml
# Custom output path
$ docbook build book.xml -o output.html
# With custom image paths
$ docbook build book.xml --image-search-dir media/ images/
# For web hosting (external image files)
$ docbook build book.xml --image-strategy relative
# Bundled demo
$ docbook build --demo
# Named demo
$ docbook build --demo=model-flowExport DocBook XML as DocbookMirror JSON (ProseMirror-compatible format):
$ docbook export INPUT -o output.json
# Or to stdout
$ docbook export INPUTValidate DocBook XML:
$ docbook validate input.xml
input.xml: valid
# Well-formedness only (no schema)
$ docbook validate --wellformed input.xmlrequire 'docbook'
# Parse a DocBook document (auto-detects article, book, chapter, etc.)
doc = Docbook::Document.from_xml(File.read('guide.xml'))
# With XInclude resolution
xml_string = File.read('main.xml')
resolved = Docbook::XincludeResolver.resolve_string(xml_string, base_path: 'main.xml')
doc = Docbook::Document.from_xml(resolved.to_xml)# Full pipeline: parse + TOC + numbering + index + images + HTML
page = Docbook::Output::SinglePage.new(
xml_path: 'guide.xml',
output_path: 'output/guide.html',
image_search_dirs: ['media/'],
image_strategy: :data_url, # :data_url, :file_url, or :relative
title: "My Document"
)
page.generateThe interactive reader built by docbook build includes:
- Themes
-
Day, Sepia, Night, OLED — all driven by CSS custom properties
- Search
-
Full-text search across headings and content (FlexSearch)
- TOC
-
Collapsible hierarchical table of contents
- Breadcrumb
-
Ancestor chain breadcrumb bar with collapsible chips
- Fonts
-
Sans-serif (Inter) and serif (Merriweather) options
- Navigation
-
Keyboard shortcuts (
/for search,Escto close) -
Clean print stylesheet
The reader’s frontend is a Vue 3 application pre-compiled into frontend/dist/.
cd frontend
npm install
npm run buildAfter building, docbook build automatically includes the compiled assets.
┌─────────────────────────────────────────────────────────────────────────┐
│ DocBook XML (input) │
│ book.xml, article.xml, etc. │
└────────────────────────────────┬────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────────────────────────┐
│ Lutaml::Model (gem) │
│ Serialization Framework │
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ Lutaml::Model::Serializable │ │
│ │ • XML ↔ Ruby object mapping (from_xml / to_xml) │ │
│ │ • Attribute definitions with types │ │
│ │ • mixed_content, map_element, map_attribute │ │
│ │ • Lutaml::Xml::W3c::XmlIdType for xml:id │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ ▲ base class for all element classes │
└──────────────────┼─────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ Docbook Gem (metanorma-docbook) │
│ │
│ ┌──────────────────────────────────────────────────────────────────┐ │
│ │ Docbook::Elements::* (~100+ classes) │ │
│ │ │ │
│ │ Structural: Book, Article, Chapter, Part, Section, Appendix │ │
│ │ Block: Para, FormalPara, BlockQuote, Example │ │
│ │ List: OrderedList, ItemizedList, VariableList │ │
│ │ Inline: Emphasis, Code, Link, Xref, Filename, Command │ │
│ │ Media: MediaObject, ImageObject, ImageData, Figure │ │
│ │ Table: Table, InformalTable, TGroup, Row, Entry │ │
│ │ Admonition: Note, Warning, Caution, Important, Tip │ │
│ │ Reference: RefEntry, RefSection, RefMeta, FieldSynopsis │ │
│ │ ...and more │ │
│ └──────────────────────────────────────────────────────────────────┘ │
│ │
│ Docbook::Document │
│ • Root element dispatcher (from_xml → correct element class) │
│ │
│ ┌────────────────┐ ┌────────────────────┐ ┌───────────────────┐ │
│ │ XInclude │ │ XrefResolver │ │ Services::* │ │
│ │ Resolver │ │ (link resolution)│ │ (helpers) │ │
│ └────────────────┘ └────────────────────┘ └───────────────────┘ │
│ │
│ ┌───────────────────────────────────────────────────────────────────┐ │
│ │ Output Layer │ │
│ │ │ │
│ │ ┌──────────────────┐ ┌──────────────────────────────────────┐ │ │
│ │ │ Output::Single │ │ Output::DocbookMirror │ │ │
│ │ │ Page │ │ │ │ │
│ │ │ │ │ Docbook Element objects → │ │ │
│ │ │ Bundles Vue SPA │ │ ProseMirror-compatible JSON │ │ │
│ │ │ + DocbookMirror │ │ (doc > nodes > text, with marks) │ │ │
│ │ │ into one .html │ │ │ │ │
│ │ └────────┬─────────┘ └──────────────────────────────────────┘ │ │
│ │ │ │ │
│ └───────────┼───────────────────────────────────────────────────────┘ │
│ │ │
│ ┌───────────┼───────────────────────────────────────────────────────┐ │
│ │ ▼ │ │
│ │ ┌─────────────────────────────────────────────────────────────┐ │ │
│ │ │ DocbookMirror (Mirror::Transformer) │ │ │
│ │ │ │ │ │
│ │ │ Converts Docbook Element objects → ProseMirror-compatible │ │ │
│ │ │ JSON document format (doc > nodes > text, with marks) │ │ │
│ │ │ │ │ │
│ │ │ Mirror::Node::Document ──┐ │ │ │
│ │ │ Mirror::Node::Block ────┤ tree structure │ │ │
│ │ │ Mirror::Node::Text ────┤ │ │ │
│ │ │ Mirror::Mark::* ────┘ inline annotations │ │ │
│ │ │ (emphasis, code, link, xref, citation, tag) │ │ │
│ │ └─────────────────────────────────────────────────────────────┘ │ │
│ │ │ │ │ │
│ │ export cmd (JSON) embedded in SinglePage │ │
│ │ │ │ │ │
│ └─────────────────────┼──────────────────────────┼──────────────────┘ │
│ │ │ │
│ ▼ ▼ │
└────────────────────────┼──────────────────────────┼─────────────────────┘
│ │
▼ ▼
┌────────────────────────────────────────────────────────────────────────┐
│ Vue 3 SPA (frontend/dist/) │
│ │
│ Built by Vite → app.iife.js + app.css │
│ Inlined into single-page HTML for file:// protocol support │
│ │
│ ┌──────────────────────────────────────────────────────────────────┐ │
│ │ Pinia Stores │ │
│ │ • documentStore (document data, TOC, numbering) │ │
│ │ • uiStore (sidebar, search, active section state) │ │
│ │ • ebookStore (themes, settings) │ │
│ └──────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────────────────┐ │
│ │ MirrorRenderer.vue + TextRenderer.vue │ │
│ │ Renders DocbookMirror JSON: │ │
│ │ ├─ doc, section, chapter, appendix, part, reference, refentry │ │
│ │ ├─ paragraph, heading, code_block, list, table, blockquote │ │
│ │ ├─ image, admonition, footnote │ │
│ │ └─ text nodes with marks (emphasis, code, link, xref, citation) │ │
│ └──────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────────────────┐ │
│ │ UI Shell │ │
│ │ EbookContainer, AppSidebar, TocTreeItem, EbookTopBar, │ │
│ │ BreadcrumbBar, SearchModal, SettingsPanel, LibraryApp │ │
│ └──────────────────────────────────────────────────────────────────┘ │
│ │
└────────────────────────────────────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────────────────────────┐
│ Interactive HTML Reader │
│ Single .html file (CSS+JS inlined, works via file://) │
│ opened in any browser │
└────────────────────────────────────────────────────────────────────────┘CLI Commands:
docbook build [INPUT] [-o out.html] → SinglePage (Vue SPA bundled)
docbook build --demo → Demo from bundled sample
docbook export INPUT [-o out.json] → DocbookMirror JSON
docbook validate INPUT → RELAX NG schema validationKey relationships:
- Lutaml::Model
-
The foundation — every Docbook::Elements::* class inherits from Lutaml::Model::Serializable, providing XML↔Ruby object serialization.
- DocbookMirror
-
A ProseMirror-compatible intermediate JSON format. The Ruby Mirror::Transformer walks Docbook element objects and produces a {doc: {content: [nodes]}} tree with typed nodes and marks.
- Vue SPA
-
Renders DocbookMirror JSON via MirrorRenderer and TextRenderer components. The data is embedded as window.DOCBOOK_DATA.
- SinglePage
-
Bundles the Vue SPA build artifacts inline into a single HTML file, with DocbookMirror JSON embedded as window.DOCBOOK_DATA for the SPA to consume on load.
Bug reports and pull requests are welcome at https://github.com/metanorma/metanorma-docbook.
Copyright Ribose. MIT License.