If you don't need a Word document at the end of an audit or a project, you're in luck! But if you do need it and love markdown, you've come to the right place.
MDdot generates a Word file from a md file and a docx template.
You: Hey wait a minute! As always, you fix many rules to use it and it is not usable in practice !
Me: Well! No, no and just a little yes.
You have to fill your Word template file with jinja2 variables, but you define the variables!
A hello world?
python mddot -m examples/helloworld.md -d examples/helloworld.docx
- Mk 1.6:
- User:
- Add styles
- Add
_full_xml,_header_xmlendpoint - Add
mditemspython3/jinja2 endpoint for your templates
- Internal
- Fix import
- Remove the unnecessary second rendering which causes some bug. (MDdot is faster !)
- Add a internal dict class to add jinja2 capabilities in templating
- User:
- Mk 1.5:
- User:
- Add syntax highlighting inside code blocks with pygments
- Internal:
- Add getText methods in nodes
- Remove the second rendering
- Remove Images module
- User:
- Mk 1.4:
- User:
- Fix bug if the MD contains jinja2 key-like strings
- Internal:
- Add modules possibilities
- Add Images module
- Add Files class to handle templating processing and cache
- Refactor nodes to remove templating cache
- User:
- Mk 1.3:
- User:
- (BREAKING TEMPLATE) Add
.table(1st table in a part) and.tables(if there are more than 1) endpoint to accessheadersanddata - Fix bug when there 2 parts at same level and with the same name
- (BREAKING TEMPLATE) Add
- User:
- Mk 1.2:
- User:
- Fix image size
- Add a requirement_win64.txt with hash for security
- Internal:
- Text nodes are added as children to paragraph, table or list nodes
- Creation of helpers method inside helpers.py
- Add paragraph in the template cache for each detected jinja2 vars
- User:
- Mk 1.1:
- User:
- Add mddottextcaption, mddottextlink styles
- Add support of paragraph style for xml jinja variables
- Update readme, add example
- Add checkStyle to verify mddot styles inside template (style's type isn't checked)
- Internal:
- Add id for each node
- Add cache for style applied on a jinja2 var.
- User:
- Mk 1.0: Initial release
You can use MDdot inside a virtualenv (or not).
All dependencies are frozen inside the requirement.txt with their sha256 hashes to avoid wrong or malicious packets.
pip install -r requirements.txt
You can find the hashes on pypi.org like for pillow
MDdot is a CLI tool : python mddot -m <your_markdown> -d <your_template> -o <your_destination>
You need help? Try python mddot -h
MDdot uses Jinja2 syntax.
You can find some mddot examples in the example folder
If you want to discover python-docx-template (and Jinja2), try playing with their examples: https://github.com/elapouya/python-docx-template/tree/master/tests
MDdot can use specific word styles for some markdown elements.
You have to follow some rules to get a functional style: a paragraph style (like title) will not work as a character style.
The table describes the style's name and its type :
| Name | Character style | Paragraph style | Tables Style |
|---|---|---|---|
mddottable |
No | Noe | Yes |
mddotheader<X> |
No | Yes | No |
mddotblockcode |
No | Yes | No |
mddottextcaption |
No | Yes | No |
mddottextinlinecode |
Yes | No | No |
mdddottextlink |
Yes | No | No |
Note : for the lvl1 header, mddotheader<X> becomes mddotheader1
If you do not follow these guidelines, your style may not work and the generated document may be corrupted.
MDdot does not provide a default text style as you have only modify your default style in your document.
MDdot styles are not mandatory, as Word uses the default style if it cannot find them.
The heading is the variable name. Each level heading is separated by a ..
All spaces or special characters are removed and the content is lowered: self.id = re.sub(r'[^A-Za-z0-9]+', '', self.content).lower()
Markdown :
# First Heading
## Second HeadingVariable name: firstheading.secondheading:
Append .xml to a variable to "print" content.
This endpoint generates everything (or it should π π π):
- List:
- Bullet list: you need to create the
mddotlistbulletlist style - Ordered List (default choice if the bullet list style is not found): create a list start from 1. It uses the word default-style list.
- Bullet list: you need to create the
- Array: if you want change the default table style, you need to set the table style :
mddottable - Image: use
mddottextcaptionto custom your legend. - Text markdown format:
- Strong :
**amet** - Emphasis :
*consectetur* - Strikethrough :
~~adipiscing elit~~ - InlineCode : Custom the style with
mddottextinlinecode(must be a character style)`Inline Code`
- Strong :
- Link :
(example.com)[example.com]or[](https://www.example.com), usemddottextlinkto custom your links - Code block : MDdot doesn't colorize the code if you add a language. It uses the style
mddotblockcodewhich must be a paragraph style.
This endpoint support paragraph style from your template. If you uses it inside a for loop, you have to use the list representation inside your loop (see the Styling example).
# First Heading
## Second Heading
test
Use {{firstheading.secondheading.xml}} to add test inside your document.
# test
## item 1
### good
test
### bad
test
## item 2
### good
test
### bad
test
Use test[key].good.xml with a paragraph style applied on it :
{% for key, item in test.items() %}
{{ test[key].good.xml }}
{% endfor %}See stylingXml.md and stylingXml.docx for a simple example.
You can use your own table style with .headers and .data endpoint on .table if you want the 1st table in a part or on .tables in a for loop.
Markdown :
## Contacts
| Name | Function | Mail | Phone |
|:------------|:------------|:---------------------|:-----------|
| John Smith | Lorem | john.smith@acme.com | 0123456789 |
| Bob Smith | Ipsum | bob.smith@acme.com | 0123456789 |
| Alice Smith | Consectetur | alice.smith@acme.com | 0123456789 |
## Friends
| Name | *Function* | Mail | Phone |
|:----------|:--------------|:-------------------|:-----------|
| John Doe | Porttitor | john.doe@acme.com | 0123456789 |
| Bob Doe | Sed bibendum | bob.doe@acme.com | 0123456789 |
| Alice Doe | Massa commodo | alice.doe@acme.com | 0123456789 |
| Name | *Function* | Mail | Phone |
|:-------------|:--------------|:-------------------|:-----------|
| John Doe Jr | Porttitor | john.doe@acme.com | 0123456789 |
| Bob Doe Jr | Sed bibendum | bob.doe@acme.com | 0123456789 |
| Alice Doe Jr | Massa commodo | alice.doe@acme.com | 0123456789 |
Docx:
Result:
You will need some variables which you can use everywhere, in a report.
You have to define a list after the heading with the id properties.
The separator between the name and the content is :.
Link, images and styling token isn't supported. Only text.
Code:
- <key> : <content>
Markdown:
# Project
## Properties
- client : ACME
- project_name : ACME Project
- start_date : 01/01/1970
- end_date : 07/01/1970
Jinja2 key:
project.properties.clientproject.properties.project_nameproject.properties.start_dateproject.properties.end_date
All endpoints, which start with _, help to extend the templating capabilities.
There are not returned with the method mditems in your Jinja2/docx template.
The _full_xml endpoint can be used if you want "print" all contents inside elements, his children and the title.
If you want generate a docx file from a template where you have definied only the styles, use {{ _full_xml }}
You can find 2 examples :
- a full document generation (
{{ _full_xml }}) :python.exe -m mddot -m .\examples\project.md -d .\examples\full_xml.docx - a full generation from a lvl2 header (
{{letter.synthesiss._full_xml }}) :python.exe -m mddot -m .\examples\project.md -d .\examples\full_xml.docx
This endpoint is used to created a title from your md header.
{{ letter.synthesis._header_xml}}
MDdot extends the Python dict class to add features inside template.
List of method:
mditems: it's usefull to get only items linked from your markdown files (so you don't get the properties nodes,_full_xmlor_header_xml, etc...)
grep -rn todo .
Docx generation:
Markdown parsing:
Logging:
NightWriter is dual-licensed - Copyright 2021 Titanex
If you want commercialize service which include MDdot, you need a commercial, non-free license. If you want a direct support or specific development, you need a non-free license. Otherwise, NightWriter can be used without charge under the terms of GPLv3.
If want buy a proprietary license, send a mail to titanex@protonmail.com.
A proprietary license brings you some advantages:
- Direct mailing support (creation of templates, module development if needed)
- Bug fixes before GitHub (bug fixes are always released for all in a short time)
- Closed modules
You can support the project by buying πΊ or π» https://www.buymeacoffee.com/titanex
The Word XML is a real π΅.





