iulica / docx-mailmerge

Mail merge for Office Open XML (docx) files without the need for Microsoft Office Word.
MIT License
55 stars 7 forks source link

Merge_Templates #6

Closed omar-haikal closed 2 years ago

omar-haikal commented 2 years ago

Merge Templates Request

Issue Description

I am currently trying to merge a document that contains multiple pages. The second page contains a table composed of two rows with different mailmerge fields on each row. I am trying to have this table repeated for my dataframe.

The issue that arises when using the merge templates method is that the entire document is repeated for every dataframe row. I have also attempted to use the merge table function, but because of the anchor input and my table hanging different mailmerge fields in each row, this is not resulting in the correct output.

iulica commented 2 years ago

Could you create a simple example that shows your issue?

Are you able to mailmerge the document using Microsoft Word?

omar-haikal commented 2 years ago

@iulica ,Thank you for your quick response. Please find a simple example for this issue

Sample Data

image

The first paragraph should not be repeated, only the table below should be repeated

Result with merge_templates

from mailmerge import MailMerge
with MailMerge('sample.docx') as doc:
    doc.merge_templates([{'name':'Mark','job':'Software Engineer','nationality':'Canadian'}, 
    {'name':'Jacob','job':'Engineer','nationality':'Swedish'}],'textWrapping_break')
    doc.write('output.docx')

Output

image

Ideal Output

image

iulica commented 2 years ago

I do not believe this is possible, even with the Microsoft Word Mailmerge. Merge Table functionality would not work as the duplication is done at row level. What I would suggest is to split the template document into 2 parts. The one fixed that contains the first page, that doesn't need to be repeated, and a second document with the table, that need to be repeated. Then, you can mail merge them independently (I don't know if the first page has fields or not), and then join them together into the final word document. (you can use python-docx for this) It's slightly more complicated but you can manage an automated script.

omar-haikal commented 2 years ago

@iulica Thank you for your response. I have thought about this solution as well, and while it is not completely ideal, I will see to its implementation.

As a side note, is there any possibility that this can be done with the merge_rows method. Based on my understanding, the anchor specifies the first column where the merge field occurs. Would it be possible to input a list of anchors, so that two or more rows of the table are in each iteration of the method. I have tried looking at the source code, but I guess I am not at the level where I can implement this change on my own

I have attempted to do something similar by using the merge_rows method two. Here is the code:

from mailmerge import MailMerge
with MailMerge('sample.docx', remove_empty_tables=True) as doc:
    doc.merge_rows('name',[{'name':'Mark','job':'Software Engineer'},{'name':'Jacob','job':'Engineer'}])
    doc.merge_rows('nationality',[{'nationality':'Canadian'},{'nationality':'Swedish'}])
    doc.write('output.docx')

image

iulica commented 2 years ago

merge_rows and also merge/merge_templates when you give a list as a value to one field, can be used to expand multiple tables. But they are expanded separately and you will get something like this: table: row1 value1 row1 value2 row1 ... value n row2 value1 ... row2 value n

I see your updated answer and it's exactly this

iulica commented 2 years ago

I will think about a solution like this, maybe to include several rows instead of just one row. Will come back with an answer

omar-haikal commented 2 years ago

Thank you so much

iulica commented 2 years ago

I got another idea that might work. Can you just make one table with one row and one column, and inside that one row create another table that looks like yours. This might give you the needed result.

image

The merge_rows call needs to change as well: doc.merge_rows('name',[ {'name':'Mark','job':'Software Engineer', 'nationality':'Canadian'}, {'name':'Jacob','job':'Engineer', 'nationality':'Swedish'}])

omar-haikal commented 2 years ago

Genius Solution! It is working as intended

image

Thank you so much for assisting on this issue, you have saved me a lot of lines of code