Skip to content

Repository files navigation

mdhtml2docx

Convert MDHTML to Word docx files.

mdhtml renders Markdown to an HTML5 document format shared by format-specific exporters. mdhtml2docx converts its portable core to docx from scratch. It uses fast5ever's mutable WHATWG DOM for input and lxml to generate WordprocessingML.

MDHTML accepts the full HTML vocabulary. This exporter supports the elements and annotations listed below. It preserves the text of unknown inline elements and recurses through block containers. It returns a warning when an unsupported block must become a plain paragraph. HTML parsing and repair belong to mdhtml.

Usage

from mdhtml import md2mdhtml
from mdhtml2docx import mdhtml2docx

html = md2mdhtml(markdown_text)
warnings = mdhtml2docx(html, 'out.docx')

mdhtml2docx takes an MDHTML string, writes a docx, and returns a list of warning strings. It parses strings with mdhtml.mdhtml2dom. Normal HTML5 repair applies; the input need not be well-formed XML.

You can also pass an existing mutable fast5ever DOM:

from mdhtml import mdhtml2dom

document = mdhtml2dom(html)
document.children[0].attrs['custom-style'] = 'Contract Title'
warnings = mdhtml2docx(document, 'out.docx')

Body-position text and phrasing content become implicit Word paragraphs. Whitespace between blocks does not produce content. HTML templates are not rendered.

Supported content

The exporter supports these elements:

  • Headings, paragraphs, block quotes, fenced and indented code blocks, and horizontal rules.
  • Bold, italic, strikethrough, underline (u), highlight, superscript, subscript, inline code, and abbreviations.
  • External links and internal links through bookmarks.
  • Images from local files, embedded with their dimensions. Remote image URLs become links.
  • Bullet and numbered lists, including nesting, start, and task-list checkboxes.
  • Pipe and grid tables, including row and column spans and header rows.
  • Definition lists and footnotes.

A details div becomes its label as a bold line above the body. It does not become a numbered heading or retain its collapsible behavior.

Math spans and blocks become native Word math zones (m:oMath). These contain the source text unchanged, whether TeX, UnicodeMath, or AsciiMath. Math build-up and rendering are left to downstream tools. Pandoc reads the zones back as math.

When fastpylight is installed, code blocks with a language use syntax coloring. Tokens receive Hl* character styles such as Hl Keyword. Their colors come from the reference theme described below. You can restyle them in Word.

Styling

The generated document uses named styles instead of inline formatting. Change the styles to change its appearance.

Markdown headings map to Word styles as follows:

  • h1 uses Title and displays no number. It carries the numbering's invisible level 0, which restarts the count below each title. A file containing several documents can therefore number each from 1.
  • h2 through h6 use Heading 1 through Heading 5.

Prose uses Body Text. The first paragraph after a heading or similar block uses First Paragraph, following Pandoc's convention. Other styles include Quote, Source Code, Verbatim Char, Hyperlink, List Paragraph, Compact for table cells, Definition Term, Definition, caption, and footnote styles. Tables default to Table Grid. The built-in template also provides Borderless Table for signature blocks and other layout tables.

Reference documents and themes

Pass reference='mydoc.docx' to use your own document's styles, as with Pandoc's --reference-doc.

reference also accepts a list. The first entry supplies the document, including page setup, fonts, and base styles. Later entries contribute styles and replace earlier styles with the same name. Each can be another .docx or a fastpylight theme name such as 'dracula'.

The default is the built-in template plus 'github_light'. Pass a reference document without a theme for plain, uncolored code. To write a theme's styles to a standalone docx for inspection or editing, use mdhtml2docx.styles.theme_ref('dracula', 'dracula.docx').

The built-in template is generated by tools/createref.py from a stock Word document. It defines the styles the converter emits and next-paragraph chains for continued editing in Word.

Style annotations and table widths

A custom-style="Name" attribute, written as {custom-style="Name"} in Markdown, applies that style from your reference document. If the style is missing, the converter inserts a stub and returns a warning.

A plain class such as {.note} applies a style only when the reference document defines one named note. Otherwise it is ignored. Both annotations also work on tables. A named table style replaces Table Grid.

Tables can mix fixed and proportional column widths. Add an attribute list after the table: {: colwidths="10em 2fr 1fr"}. Lengths fix a column's width. The fr values divide the remaining width proportionally, as in CSS grid.

Raw docx

The converter accepts MDHTML raw data with data-format="docx":

<script type="application/vnd.mdhtml.raw" data-format="docx"></script>

A ```{=docx} fenced block in Markdown, or inline code followed by {=docx}, produces this element. The payload is parsed as WordprocessingML and inserted verbatim. Block payloads contain elements such as w:p or w:tbl. Inline payloads contain elements such as w:r. The prefixes w, r, wp, a, pic, and m are predeclared.

Payload encoding follows these rules:

  • No data-encoding: use the literal payload.
  • data-encoding="html": perform one character-reference decoding pass.
  • data-encoding="base64": decode a base64-encoded UTF-8 payload.

Malformed payloads and unknown encodings are dropped with a warning. Raw data for other formats is skipped silently.

For example, insert a page break with:

```{=docx}
<w:p><w:r><w:br w:type="page"/></w:r></w:p>
```

Cross-references

Markdown references such as [@sec-payment] become live Word REF fields. MDHTML represents them as a elements with data-ref.

The default field is REF <bookmark> \w \h. It displays the full-context paragraph number, such as "3.(c)(iii)", as a hyperlink. The converter sets updateFields in settings.xml so Word refreshes fields on open.

The leaf, rel, text, and page tokens select other fields. The independent bare token suppresses the prefix word. Unknown or conflicting tokens are conversion errors.

Prefixes and groups

The reference type is the part of the target id before its first -. It determines the word before the number. The built-in sec type uses Section or Sections. Add types with reftypes=dict(exh=('Exhibit', 'Exhibits')).

Use [Clause @sec-x] to override the word for one reference, or [-@sec-x] to suppress it.

Grouped references use a span with data-refs. They render as "Sections 3.1 and 4.2", with one field per number. Groups never collapse into static ranges such as "3.1-3.3", whose meaning could change when a clause is inserted.

A missing target id raises a conversion error. A reference type with no defined prefix also raises when a prefix is required. A lawyer's document must not open showing "Error! Reference source not found."

Heading numbering

Number fields require numbered headings. If your reference docx already numbers its heading styles, the converter leaves that numbering unchanged.

Otherwise, select a scheme with number_headings:

  • 'legal' uses 1. / (a) / (i) numbering.
  • 'decimal' uses 1. / 1.1. / 1.1.1. numbering.
  • A {lvlText: numFmt} dictionary supplies a custom scheme, with one entry per heading level from h1 down. Level 0 is the h1 title with an empty lvlText. %2 is the h2 counter.

The named schemes come from mdhtml's SCHEMES. The custom dictionary uses the same format as mdhtml.

A reference-list entry ending in .xml can also supply styles and numbering. It contains raw w:style, w:abstractNum, and w:num elements. The converter remaps their ids to avoid collisions.

Figures and tables

Figures and captioned tables use live SEQ fields. A figure's caption appears below its image as "Figure 1: caption", using the caption style. A table's caption appears above it as "Table 1: caption".

When the element has an id, the converter bookmarks its label and number. [@fig-plot] inserts "Figure 1" from that bookmark without adding another prefix. A second, number-only bookmark supplies the bare number for references such as [-@tbl-stages].

fig and tbl are built-in reference types alongside sec. Their labels come from the same reftypes table. Same-type groups pluralize once. Mixed-type groups use each item's singular prefix, as in "Figure 1 and Table 2".

Reference targets must be headings, paragraphs, figures, or tables with ids. A reference to anything else raises a conversion error.

Validation

The test suite checks docx containers, CRCs, and XML, validates against the ECMA-376 schemas with lxml, and performs semantic round trips through Pandoc's independent docx reader. Periodic acceptance runs open documents in Microsoft Word through AppleScript.

About

XHTML to docx conversion

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages