Skip to content

Instantly share code, notes, and snippets.

@louwersj
Created May 5, 2023 08:23
Show Gist options
  • Save louwersj/74a8c059a391689dee0954dcbd9cdfbd to your computer and use it in GitHub Desktop.
Save louwersj/74a8c059a391689dee0954dcbd9cdfbd to your computer and use it in GitHub Desktop.
Example code to show how XML data can be infused into a docx template based upon Jinja2.
# Example code to show how XML data can be infused into a docx template based upon Jinja2.
import sys
import uuid
import xml.etree.cElementTree as ET
from docxtpl import DocxTemplate
xmlStructure = ("input_data.xml")
def getTemplate (name):
'''
Function is used to retrieve the word .docx template. the template will be retrieved based upon the variable name
provided to the function. In this example we will retrieve the template from local disk. In a more production like
environment the template will have to be retrieved (most likely) from an external location...possibly via https
:param name:
:return:
'''
try:
templatePath = "./templates/{}".format(name)
retreivedTemplate = DocxTemplate(templatePath)
except IOError as e:
# handle the exception
print(f"Error opening template file: {e}")
return retreivedTemplate
def getXmlRoot (name):
'''
Used to retrieve the XML file and get the root element. In this example we load the .xml structure from a local
file. In other situations you might need to get this via a https call or it is send to the code as part of the
invocation call. the xml root should be retruned as xml.etree.ElementTree.Element variable to the calling logic
:param name:
:return: xml.etree.ElementTree.Element
'''
try:
xmlTree = ET.parse(name)
xmlRoot = xmlTree.getroot()
except FileNotFoundError as e:
print(f"Error: {e}. The XML file does not exist.")
sys.exit(1)
except ET.ParseError as e:
print(f"Error: {e}. Failed to parse the XML file.")
sys.exit(1)
except Exception as e:
print(f"Error: {e}.")
sys.exit(1)
return xmlRoot
def createContextStruct(xmlInput):
'''
Used to build a context structure based upon the XML input file. The context structure needs to be a simple K/V like
structure where K equals the Jinja variable names in the word template. In this example we extract the K/V values
from everything within <variables> in the main XML input file. In a specific situation you might want/need to change
this.
:param xmlInput:
:return:
'''
context = {}
for var in xmlInput.iter():
if var.tag != "output_data" and var.tag != "variables":
context[var.tag] = var.text
return context
if __name__ == '__main__':
# get the XML data using the getXmlRoot function
try:
xmlContent = getXmlRoot(xmlStructure)
except AttributeError as e:
# handle the exception
print(f"Error reading the the XML data when calling the getXmlRoot function : {e}")
sys.exit(1)
# get the word template name form the XML file.
try:
templateName = (xmlContent.find("template")).text
except Exception as e:
# handle the exception
print(f"Error reading the template name from the XML file: {e}")
sys.exit(1)
# get the word template name form the XML file.
try:
docTemplate = getTemplate(templateName)
except Exception as e:
# handle the exception
print(f"Error unable to get the document template using the getTemplate function: {e}")
sys.exit(1)
# create a context structure which will hold a K/V list in a dict for all variables in the word template.
try:
context = createContextStruct(xmlContent)
except Exception as e:
# handle the excpetion
print(f"Error, unable to create context by using createContextStruct {e}")
sys.exit(1)
docTemplate.render(context)
outputName = ("./{}.docx").format(str(uuid.uuid4()))
docTemplate.save(outputName)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment