Metanorma Site Generation
Metanorma Site Generation (`metanorma site`)
Introduction
The site subcommand enables you to compile and publish multiple Metanorma documents as a cohesive document site. This functionality is particularly useful for:
- Multiple documents belonging to the same series
- Single documents published to multiple venues
- Multiple parts of a document collection
Commands
Site generation
metanorma site generate [OPTIONS...] [SITE_MANIFEST_FILE]If no SITEMANIFESTFILE is provided, the file metanorma.yml in the current directory is used.
CLI options
-c, --config CONFIG- File path for Metanorma site manifest YAML configuration (Default:
metanorma.ymlin the current directory) (Deprecated: use the SITEMANIFESTFILE argument instead) -o, --output-dir DIR- Directory for generated site output, relative to the current working directory (Default:
_sitein current directory)
[cli-stylesheet]]
-s, --stylesheet FILE- Specify custom stylesheet for HTML output, relative to the current working directory
-t, --template-dir DIR- Specify custom Liquid templates for site design, relative to the current working directory
--output-filename-template TEMPLATE_STRING- Define output filenames using Liquid templating (Uses Relaton model for variable access)
[cli-extensions]]
-x, --extensions FORMATS- Comma-separated list of output formats to generate (e.g.
html,rxl), restricting output to those formats only. Overrides the manifestextensions:key (see manifest-extensions) and any per-collectionformat:. Defaults to all formats the document's flavor supports. --agree-to-terms- Accept third-party licensing terms
--no-agree-to-terms- Reject licensing terms
--skip-agree-to-terms- Skip license agreement prompt
--install-fonts- Install required fonts (Default)
--no-install-fonts- Do not install fonts
--skip-install-fonts- Skip font installation prompt
--continue-without-fonts- Proceed when fonts are missing
--no-continue-without-fonts- Abort when fonts are missing
--skip-continue-without-fonts- Skip missing fonts prompt
-S, --strict- Abort compilation on errors
--no-strict- Continue on errors
--skip-strict- Skip strict mode prompt
Configuration using site manifest
The site generation process can be configured using a site manifest. The site manifest file is a configuration file that is in YAML format:
metanorma:
source:
files: <1>
- doc1.adoc
- "series/*.adoc"
collection:
name: "Site Title" <2>
organization: "Publisher" <3>
template:
path: "templates" <4>
stylesheet: "custom.css" <5>
output_filename: "" <6>
extensions: <7>
- html
- rxlBy default, the file metanorma.yml located in the source directory would be used.
Templates and styling
General
Customization of the site's HTML output is done using Liquid^ templates.
Metanorma uses the template files found in the specified template directory to generate the site's index page and individual document entries.
Template directory structure
The path to the template directory can be specified via the CLI using the -t, --template-dir option, or in the site manifest under the metanorma.template.path key.
If the path is an absolute path, it is used as is.
If it is a relative path, its full path is calculated based on where it is defined.
- If it is defined in the site manifest file, then the path is relative to the directory containing the manifest file.
- If it is defined via the CLI, then the path is relative to the current working directory, i.e., the directory from which the command was run.
- If no manifest file is present, the path is also relative to the current working directory. If a template directory is not specified, the default template directory is used, which is located in the link:{example-template-url}[Relaton CLI repository^]
The template directory must contain:
_index.liquid- Main template for the site's index page
_document.liquid- Template for individual document entries
- CSS stylesheet
- Specify the path to the stylesheet, of which the content can be referenced in templates using the `css` variable.
The path can be specified in the site manifest under the `metanorma.template.stylesheet` key, or via the CLI using the `-s, --stylesheet` option.
Path resolution follows the same rules as the template directory path.
For a more detailed example of what a template directory might look like, see the link:https://github.com/relaton/relaton-cli/tree/1c5170dcefa5692e016f08d80cd29fddd1cc47d4/templates[default templates^] in the Relaton CLI repository^.
Template variables
The index template (_index.liquid) has access to:
title- Collection title from configurationauthor- Collection author/organizationdate- Generation datecss- Stylesheet content [[css-variable]]metanorma_v- Metanorma version (if available)documents- Array of document entries
The document template (e.g., _document.liquid, via the document template variable) has access to:
docid.id- Document identifiertitle- Document titlehtml- HTML URL pathpdf- PDF URL pathdoc- Word document URL pathxml- XML URL pathrxl- Relaton XML URL pathuri- Document URIdoctype.type- Document typeedition.content- Edition informationdocstatus.stage.value- Document stagedocstatus.stage.abbreviation- Abbreviation for the document statusdocstatus.substage.value- Document substagerevdate- Revision dateitems- Array of document items (if applicable, e.g., when the document is itself a collection)
<!-- _index.liquid -->
<!DOCTYPE html>
<html>
<head>
<title>{{ title }}</title>
<style>{{ css }}</style>
</head>
<body>
<h1>{{ title }}</h1>
<div class="documents">
{% render 'document' for documents as document %}
</div>
<footer>Generated: {{ date }}</footer>
</body>
</html>render tag instead of include as this the recommended way to include templates in Liquid. The for parameter allows iteration through the documents collection while maintaining proper variable scoping.<!-- _document.liquid -->
<div class="document">
<h2><a href="{{ document.html }}">{{ document.docid.id }}</a></h2>
<p class="title">{{ document.title }}</p>
<p class="status">Status: {{ document.docstatus.stage }}</p>
{% if document.pdf %}
<a href="{{ document.pdf }}">PDF</a>
{% endif %}
</div>For a more detailed example of what a template might look like, see the link:https://github.com/relaton/relaton-cli/tree/1c5170dcefa5692e016f08d80cd29fddd1cc47d4/templates[default Liquid templates^].
Output filename templates
General
Using Liquid^ templating, Metanorma allows for custom output filenames across all output formats.
For the list of all variables available for filename templates (which is separate from those available in the HTML templates), see the available_variables section.
Default behavior
When an empty string is passed as the template (or when no template is specified), the system generates a normalized version of the document identifier.
For a document with identifier "ISO/IEC FDIS 12345-3", the default output would be:
iso-iec-fdis-12345-3The generated document files would be named accordingly:
_site/
├── index.html
├── documents.xml
└── documents/
├── iso-iec-fdis-12345-3.html
├── iso-iec-fdis-12345-3.doc
├── iso-iec-fdis-12345-3.pdf
├── iso-iec-fdis-12345-3.rxl
└── iso-iec-fdis-12345-3.xmlAvailable variables
Templates can access document metadata through the document object:
docidentifier- Full document identifierlanguage- Document language codeedition- Edition numberdoctype- Document typedocnumber- Document numberpartnumber- Part number (if applicable)
metanorma:
template:
output_filename: "{{ document.docidentifier | downcase | replace: '/' , '-' }}"metanorma:
template:
output_filename: |
{%- if document.doctype == 'international-standard' -%}
iso-
{%- else -%}
std-
{%- endif -%}
{{- document.docnumber -}}
{%- if document.partnumber %}-{{ document.partnumber }}{% endif %}This demonstrates:
- Conditional logic^ based on document type
- Optional part number inclusion
- Multi-line template formatting
- Whitespace trimming^ with
{%-,-%}, and{{-,-}}
- Whitespace trimming^ with
Template filters
Common Liquid filters available:
- `downcase`^
- Convert to lowercase
- `replace`^
- String replacement
- `strip`^
- Remove leading/trailing whitespace
For the full list of available Liquid filters, see Liquid Filters^.
Error handling
- Invalid syntax raises
Liquid::SyntaxError - Missing variables are replaced with empty strings
# Template: "{{ nonexistent }}_{{ document.language }}"
# Result: "_en"Site structure
Generation process
- Scans source directory for Metanorma documents
- Compiles each document with specified options
- Creates site directory structure
- Generates collection index (documents.xml)
- Creates HTML index page
- Copies assets and compiled documents
Output directory structure
_site/ <1>
├── index.html <2>
├── documents.xml <3>
└── documents/ <4>
├── doc1.html
├── doc1.pdf
├── doc1.rxl
├── doc1.xml
├── doc2.html
├── doc2.pdf
├── doc2.rxl
└── doc2.xmlBest practices
- Organize documents in logical directory structures
- Place each document in a separate directory to avoid conflicts.
sources/ ├── doc1/ │ └── main.adoc ├── doc2/ │ └── main.adoc └── doc3/ ├── main.adoc └── annex.adoc - Use consistent naming conventions in templates
- Use the same name for the document template file as the references in the template files.
<!-- _index.liquid --> <1>
...
{% render 'document' for documents as document %} <2>
...
<!-- _document.liquid --> <2> <3>
...
<h1>{{ document.title }}</h1> <3>
...- Include error handling for optional metadata fields
defaultfilter- Use Liquid's `default` filter^ to handle missing metadata fields.
<h1>{{ document.title | default: "Untitled" }}</h1>
- conditional logic
- Use conditional logic to handle optional metadata fields.
{% if document.partnumber %} <p>Part {{ document.partnumber }}</p> {% endif %} - Use whitespace trimming for whitespace-sensitive templates
- This is particularly important when working with output filename templates, which can be sensitive to whitespace. Use Liquid's whitespace control^ to manage whitespace in templates.TIPS: When in doubt, always use whitespace control to ensure consistent filename template rendering.source
metanorma: template: output_filename: | {%- if document.doctype == 'standard' -%} std-{{- document.docnumber -}} {%- else -%} doc-{{- document.docidentifier | downcase -}} {%- endif -%}
Examples
Minimal configuration
Uses the default configuration file (metanorma.yml) in the current directory, and outputs to the default directory (_site).
metanorma site generateBasic site generation (given directory)
Uses the default configuration file (metanorma.yml) in the ./sources directory, and outputs to the specified directory (./output).
metanorma site generate ./sources -o outputBasic site generation (given site manifest file)
Uses the specified configuration file (./sources/project-a/my-manifest.yml), and outputs to the specified directory (./output).
metanorma site generate ./sources/project-a/my-manifest.yml -o outputCustom naming with metadata
Using the CLI:
> metanorma site generate \
--output-filename-template \
"{{ document.docidentifier }}-{{ document.version }}"Alternatively, using the site manifest:
# metanorma.yml
metanorma:
template:
output_filename: "{{document.docidentifier}}-{{document.version}}"Complex configuration
Longer template expressions are best defined in the site manifest, which allows for a more readable multiline format:
metanorma:
source:
files:
- "doc*/main.adoc"
- "collection*/metanorma.yml"
collection:
name: "Technical Documentation"
organization: "Acme Corp."
template:
stylesheet: "assets/stylesheets/site_index.css"
template_dir: "templates"
output_filename: |
{% if document.doctype == 'standard' -%}
std-{{ document.docnumber -}}
{%- else -%}
doc-{{ document.docidentifier | downcase -}}
{%- endif %}CI/CD pipeline
For scripting and automation, use the --agree-to-terms option to bypass the license agreement prompt:
> metanorma site generate --agree-to-termsSee Continuous Integration and Continuous Deployment^ for more detailed examples on how to integrate Metanorma site generation into your CI/CD pipeline.
Next steps
To publish compiled documents as GitHub Releases and aggregate them into an organization portal, see Organization-Scale Publishing Setup.