python-docx Copy Cell

Question:

I need to copy tables’s cell with text and images to another table in another file.

# -*- coding: utf-8 -*-
from docx import Document

oldDocument = Document("d:/first.docx")

newDocument = Document()
temp = oldDocument.tables[9].rows[1].cells[1]
table = newDocument .add_table(rows=1, cols=1)
table.rows[0].cells[0] = temp
newDocument .save("d:/second.docx")

This is example of table

Пример

And this this Error
TypeError: ‘tuple’ object does not support item assignment

Answers:

You can’t simply copy an object from one document to another. python-docx API objects are proxy objects, meaning they are a wrapper around the XML that actually constitutes the paragraph, cell, etc.

You’ll need to read the content from the source document, then create the required structure (like table, cells, paragraphs) in the target document, placing the content where it should go.

You may be able to do something a little fancier if you go down to the lxml layer, perhaps copying the text with all its formatting (superscripts etc.), but that will require digging into the internals and understanding the underlying XML structure. If you search on ‘python-docx workaround function’ you should find some examples to get you started.

Answered By: scanny

For anyone who visits this question while googling, this is actually doable.

First of all, anything from one document can be inserted to the other document preserving the basic styles as described in this GitHub comment. Sample code from there:

def direct_insert(doc_dest, doc_src):
    for p in doc_src.paragraphs:
        inserted_p = doc_dest._body._body._insert_p(p._p)
        if p._p.get_or_add_pPr().numPr:
            inserted_p.style = "ListNumber"

The last two lines are called a "dirty hack" for lists in the above mentioned comment. Thought it does not work pretty well. To make it work with lists one will have to dig a bit deeper. If clause is okay, but to change the style we will refer to this comment in another thread.

Code snippet from there:

from docx import Document
from docx.shared import Inches
from docx.oxml import OxmlElement
from docx.oxml.ns import qn

def create_list(paragraph, list_type):
    p = paragraph._p #access to xml paragraph element
    pPr = p.get_or_add_pPr() #access paragraph properties
    numPr = OxmlElement('w:numPr') #create number properties element
    numId = OxmlElement('w:numId') #create numId element - sets bullet type
    numId.set(qn('w:val'), list_type) #set list type/indentation
    numPr.append(numId) #add bullet type to number properties list
    pPr.append(numPr) #add number properties to paragraph

ordered = "5"
unordered = "1"

document = Document()

paragraph = document.add_paragraph("Hello", "List Paragraph")
create_list(paragraph, unordered)

paragraph = document.add_paragraph("Hello Again", "List Paragraph")
create_list(paragraph, unordered)

paragraph = document.add_paragraph("Goodbye", "List Paragraph")
create_list(paragraph, unordered)

paragraph = document.add_paragraph("Hello", "List Paragraph")
create_list(paragraph, ordered)

paragraph = document.add_paragraph("Hello Again", "List Paragraph")
create_list(paragraph, ordered)

paragraph = document.add_paragraph("Goodbye", "List Paragraph")
create_list(paragraph, ordered)

document.save("bullet list demo.docx")

Credits to berezovskyi and panoptical.


Now given the information from the research above, the code from question should look like:

# -*- coding: utf-8 -*-
from docx import Document

oldDocument = Document("d:/first.docx")

newDocument = Document()
temp = oldDocument.tables[9].rows[1].cells[1]
table = newDocument.add_table(rows=1, cols=1)
for p in temp:
    table.rows[0].cells[0]._element._insert_p(p._p)
newDocument.save("d:/second.docx")

As the original question does not have lists, if clause is not included.

Answered By: DiMithras
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.