Skip to content

metanorma/docbook

Repository files navigation

DocBook

Purpose

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

Installation

gem 'docbook'

Or:

$ gem install docbook

Quick start

CLI

Build an interactive reader from any DocBook XML:

$ docbook build guide.xml

This 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.html

Try the bundled demo:

$ docbook build --demo

Ruby API

require '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)

CLI reference

Command Description

build

Build an interactive HTML reader from DocBook XML. Pass --demo for the bundled sample, or --demo=xslTNG / --demo=model-flow.

export

Export as DocbookMirror JSON

validate

Validate DocBook XML against RELAX NG schema

format

Format/prettify DocBook XML

build

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>.html or demo.html)

  • --demo — Use the bundled DocBook sample as input (accepts name: xslTNG or model-flow)

  • --image-search-dir DIR — Directories to search for images (default: XML file directory)

  • --image-strategy STRATEGY — Image handling: data_url (default), file_url, or relative

  • --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-flow

export

Export DocBook XML as DocbookMirror JSON (ProseMirror-compatible format):

$ docbook export INPUT -o output.json

# Or to stdout
$ docbook export INPUT

validate

Validate DocBook XML:

$ docbook validate input.xml
input.xml: valid

# Well-formedness only (no schema)
$ docbook validate --wellformed input.xml

format

Format/prettify DocBook XML:

$ docbook format input.xml -o output.xml

Ruby API

Parsing

require '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)

Building the reader

# 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.generate

Exporting JSON

doc = Docbook::Document.from_xml(File.read('guide.xml'))
mirror = Docbook::Output::DocbookMirror.new(doc)

# Pretty JSON
File.write('guide.json', mirror.to_pretty_json)

# Compact JSON
File.write('guide.json', mirror.to_json)

Reader features

The 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, Esc to close)

Print

Clean print stylesheet

Building the frontend

The reader’s frontend is a Vue 3 application pre-compiled into frontend/dist/.

cd frontend
npm install
npm run build

After building, docbook build automatically includes the compiled assets.

Architecture

┌─────────────────────────────────────────────────────────────────────────┐
│                        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 validation

Key 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.

Contributing

Bug reports and pull requests are welcome at https://github.com/metanorma/metanorma-docbook.

License

Copyright Ribose. MIT License.

About

No description, website, or topics provided.

Resources

Code of conduct

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors