Using python-docx-template to dynamically create bookmarks and links to them in Word documents

I am using the python-docx-template module to generate docx files from a template.

You can read more about the module here: https://docs-python.ru/packages/modul-python-docx-python/modul-docx-template/

The module contains functionality for inserting external links into the document, but when I needed to create internal links according to the template (to a specific place in the document), there was no such functionality, a search on the net also did not give anything.

Here I propose my own way of inserting bookmarks (bookmarks) and links (hyperlinks) to them using python-docx-template.

Solution

The module includes a RichText() object. The add(string) method of this object creates xml code, which is placed in RichText().xml and then inserted as is into the docx document.

For example:

rt = RichText()
rt.add('TEST')
print(rt.xml)
# <w:r><w:t xml:space="preserve">TEST</w:t></w:r>

I decided to generate it myself and directly put the xml code I need in RichText().xml and it worked.

Below is an example code:

from docxtpl import DocxTemplate, RichText


def add_bookmarks_and_links(data):
    for i, item in enumerate(data['articles']):
        # создаем закладку
        bookmark_name = f'article_{i}'
        bookmark = RichText(item["title"])
        bookmark.xml = f'<w:bookmarkStart w:id="" w:name="{bookmark_name}"/>' + \
                       bookmark.xml + \
                       '<w:bookmarkEnd w:id=""/>'
        item['title_with_bookmark'] = bookmark

        # создаем ссылку на закладку
        hyperlink_start = RichText()
        hyperlink_end = RichText()
        hyperlink_start.xml = f'<w:hyperlink w:anchor="{bookmark_name}" w:history="1">'
        hyperlink_end.xml="</w:hyperlink>"
        item['hyperlink_start'] = hyperlink_start
        item['hyperlink_end'] = hyperlink_end


data = {'report_title': 'Report title',
        'articles': [{'title': 'Title Article 1',
                      'description': 'Description Article 1',
                      'body': 'Body Article 1'},
                     {'title': 'Title Article 2',
                      'description': 'Description Article 2',
                      'body': 'Body Article 2'}
                     ]
        }

template_filename="template.docx"
result_filename="result.docx"

add_bookmarks_and_links(data)
tpl = DocxTemplate(template_filename)
tpl.render(data)
tpl.save(result_filename)

The docx template file looks something like this:

{{ report_title }}
Дайджест
{% for article in articles %}
{{r article.hyperlink_start }}{{ article.title }}{{r article.hyperlink_end }}
{{ article.description }}
{% endfor %}
Полные тексты статей
{% for article in articles %}
{{ article.title_with_bookmark }}
{{ article.description }}
{{ article.body }}
{% endfor %}

As a result of executing the code, we get a document with a section of article digests, with links in the headings that lead to the full texts of the articles:

Similarly, you can insert any other xml code not supported by the python-docx-template module into the template fields.

Thank you for your attention.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *