Metanorma
On this page

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.yml in 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: _site in 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 manifest extensions: key (see manifest-extensions) and any per-collection format:. 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
    - rxl

By 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
Note
The name of this file actually depends on how it is referenced in the index template. See official documentation on include^ (which is being deprecated) and render^ for more information.
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 configuration
  • author - Collection author/organization
  • date - Generation date
  • css - 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 identifier
  • title - Document title
  • html - HTML URL path
  • pdf - PDF URL path
  • doc - Word document URL path
  • xml - XML URL path
  • rxl - Relaton XML URL path
  • uri - Document URI
  • doctype.type - Document type
  • edition.content - Edition information
  • docstatus.stage.value - Document stage
  • docstatus.stage.abbreviation - Abbreviation for the document status
  • docstatus.substage.value - Document substage
  • revdate - Revision date
  • items - Array of document items (if applicable, e.g., when the document is itself a collection)
Example `_index.liquid` templatesource
<!-- _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>
Note
The example uses the 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.
Example `__document_.liquid` templatesource
<!-- _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.

Example

For a document with identifier "ISO/IEC FDIS 12345-3", the default output would be:

iso-iec-fdis-12345-3

The 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.xml

Available variables

Templates can access document metadata through the document object:

  • docidentifier - Full document identifier
  • language - Document language code
  • edition - Edition number
  • doctype - Document type
  • docnumber - Document number
  • partnumber - Part number (if applicable)
Example using liquid filterssource
metanorma:
  template:
    output_filename: "{{ document.docidentifier | downcase | replace: '/' , '-' }}"
Example using conditionalssource
metanorma:
  template:
    output_filename: |
      {%- if document.doctype == 'international-standard' -%}
        iso-
      {%- else -%}
        std-
      {%- endif -%}
      {{- document.docnumber -}}
      {%- if document.partnumber %}-{{ document.partnumber }}{% endif %}

This demonstrates:

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
Example with missing variable:source
# Template: "{{ nonexistent }}_{{ document.language }}"
# Result: "_en"

Site structure

Generation process

  1. Scans source directory for Metanorma documents
  2. Compiles each document with specified options
  3. Creates site directory structure
  4. Generates collection index (documents.xml)
  5. Creates HTML index page
  6. 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.xml

Best 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
default filter
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 generate

Basic 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 output

Basic 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 output

Custom 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-terms

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