使用 copy.deepcopy 和 python-pptx 向表中添加列会导致单元格属性损坏

问题描述 投票:0回答:3

我正在尝试使用 python-pptx 将一列附加到 PowerPoint 中的表格。许多线程提到了解决方案:

def append_col(prs_obj, sl_i, sh_i):
    # prs_obj is a pptx.Presentation('path') object. 
    # sli_i and sh_i are int indexs to locate a particular table object.

    tab = prs_obj.slides[sl_i].shapes[sh_i].table
    new_col = copy.deepcopy(tab._tbl.tblGrid.gridCol_lst[-1])
    tab._tbl.tblGrid.append(new_col)  # copies last grid element

    for tr in tab._tbl.tr_lst:
        # duplicate last cell of each row
        new_tc = copy.deepcopy(tr.tc_lst[-1])
        tr.append(new_tc)
        cell = _Cell(new_tc, tr.tc_lst)
        cell.text = '--'
    return tab

运行此命令后,当您打开 PowerPoint 时,新列将出现,但它不会包含 cell.text。如果您单击单元格并键入,字母将出现在前一列的单元格中。保存 powerpoint 使您能够像平常一样编辑列,但显然您丢失了单元格文本(和格式)。

问题更新 1 - 以下评论来自 @scanny

对于最简单的情况,一个 (1x3) 表,如下所示: |xx|--|xx| tab._tbl.xml 在附加列之前和之后打印的是:

xml diff 1

xml diff 2

xml diff 3

xml diff 4

问题更新 2 - 来自 @scanny 的评论 我修改了上面的append_col函数,强制从复制的gridCol中删除extLst元素。这解决了在一个单元格中键入内容而文本出现在另一个单元格中的问题。

def append_col(prs_obj, sl_i, sh_i):
    # existing lines removed for brevity

    # New Code

    tblchildren = tab._tbl.getchildren()
        for child in tblchildren:
            if isinstance(child, oxml.table.CT_TableGrid):
                ws = set()
                for j in child:
                    if j.w not in ws:
                        ws.add(j.w)
                    else:
                        for elem in j:
                            j.remove(elem)
    return tab

但是,cell.text(和格式)仍然丢失。此外,手动保存演示文稿会将 tab.xml 对象更改回来。手动打开PowerPoint演示文稿前后的截图为:

AFTER removing extLst, before manual save - xml diff 1

AFTER removing extLst, AFTER manual save - xml diff 2

python powerpoint python-pptx
3个回答
1
投票

如果您认真解决此类问题,则需要针对表的这一方面对 Word XML 进行逆向工程。

首先是表的前后(添加一列)XML 转储,识别 Word 所做的更改,然后复制那些重要的内容(诸如修订号之类的内容可能重要)。

这个过程可以通过一个小例子来简化,例如将 2 x 2 表格转换为 2 x 3 表格。

您可以使用 python-docx XML 元素的

.xml
属性获取 XML,例如:

print(tab._tbl.xml)

您可以比较深度复制结果,然后通过具体差异来开始解释结果不起作用。我希望您会发现表格项目具有唯一的 id,当您复制这些项目时,会发生一些奇怪的事情。


1
投票

在 Scanny 的帮助下,我想出了以下有效的解决方法:

def append_col(prs_obj, sl_i, sh_i):
    tab = prs_obj.slides[sl_i].shapes[sh_i].table
    new_col = copy.deepcopy(tab._tbl.tblGrid.gridCol_lst[-1])
    tab._tbl.tblGrid.append(new_col)  # copies last grid element
    for tr in tab._tbl.tr_lst:
        new_tc = copy.deepcopy(tr.tc_lst[-1])
        tr.tc_lst[-1].addnext(new_tc)
        cell = _Cell(new_tc, tr.tc_lst)
        for paragraph in cell.text_frame.paragraphs:
            for run in paragraph.runs:
                run.text = '--'
    tblchildren = tab._tbl.getchildren()
    for child in tblchildren:
        if isinstance(child, oxml.table.CT_TableGrid):
            ws = set()
            for j in child:
                if j.w not in ws:
                    ws.add(j.w)
                else:
                    # print('j:\n', j.xml)
                    for elem in j:
                            j.remove(elem)
    return tab

0
投票

添加列后,我收到错误“不是合并源单元格;只能拆分合并源单元格”。如果我检查 is_merge_origin 它会返回 False。无法合并或拆分单元格。请帮忙。

© www.soinside.com 2019 - 2024. All rights reserved.