当前位置: 首页 > 面试题库 >

如何使用python-docx将复选框表单插入.docx文件?

衡翰藻
2023-03-14
问题内容

我一直在使用python实现自定义解析器,并使用该解析数据来格式化要在内部分发的word文档。到目前为止,所有格式都非常简单明了,但是我对如何在单个表格单元格中插入复选框感到非常困惑。

我尝试在python-docx中使用python对象函数(使用get_or_add_tcPr()等),这会导致MS
Word在尝试打开文件时引发以下错误:“文件xxxx无法打开,因为内容有问题详细信息:文件已损坏,无法打开”。

经过一段时间的努力,我转向了第二种方法,该方法涉及为输出文档操作word /
document.xml文件。我已经检索出我认为是另存为的复选框的正确xml,replacementXML并将填充文本插入到单元格中,以用作可以搜索和替换的标签searchXML。以下内容似乎在Linux(Fedora
25)环境中使用python运行,但是当我尝试打开文档时word文档显示相同的错误,但是这次文档是可恢复的,并恢复为填充文本。我已经能够将其与手工制作的文档一起使用,并使用一个空的表格单元格,因此,我相信这应该是可能的。注意:我在表格单元格中包含了整个xml元素searchXML变量,但我尝试使用正则表达式并缩短字符串。我不只是使用精确匹配,因为我知道这可能会因单元而异。

searchXML = r'<w:tc><w:tcPr><w:tcW w:type="dxa" w:w="4320"/><w:gridSpan w:val="2"/></w:tcPr><w:p><w:pPr><w:jc w:val="right"/></w:pPr><w:r><w:rPr><w:sz w:val="16"/></w:rPr><w:t>IN_CHECKB</w:t></w:r></w:p></w:tc>'

def addCheckboxes(): 
    os.system("mkdir unzipped")
    os.system("unzip tempdoc.docx -d unzipped/")

    with open('unzipped/word/document.xml', encoding="ISO-8859-1") as file:
        filedata = file.read()

    rep_count = 0
    while re.search(searchXML, filedata):
        filedata = replaceXML(filedata, rep_count)
        rep_count += 1

    with open('unzipped/word/document.xml', 'w') as file:
        file.write(filedata)

    os.system("zip -r ../buildcfg/tempdoc.docx unzipped/*")
    os.system("rm -rf unzipped")

def replaceXML(filedata, rep_count):
    replacementXML = r'<w:tc><w:tcPr><w:tcW w:w="4320" w:type="dxa"/><w:gridSpan w:val="2"/></w:tcPr><w:p w:rsidR="00D2569D" w:rsidRDefault="00FD6FDF"><w:pPr><w:jc w:val="right"/></w:pPr><w:r><w:rPr><w:sz w:val="16"/>
                       </w:rPr><w:fldChar w:fldCharType="begin"><w:ffData><w:name w:val="Check1"/><w:enabled/><w:calcOnExit w:val="0"/><w:checkBox><w:sizeAuto/><w:default w:val="0"/></w:checkBox></w:ffData></w:fldChar>
                       </w:r><w:bookmarkStart w:id="' + rep_count + '" w:name="Check' + rep_count + '"/><w:r><w:rPr><w:sz w:val="16"/></w:rPr><w:instrText xml:space="preserve"> FORMCHECKBOX </w:instrText></w:r><w:r>
                       <w:rPr><w:sz w:val="16"/></w:rPr></w:r><w:r><w:rPr><w:sz w:val="16"/></w:rPr><w:fldChar w:fldCharType="end"/></w:r><w:bookmarkEnd w:id="' + rep_count + '"/></w:p></w:tc>'
    filedata = re.sub(searchXML, replacementXML, filedata, 1)

    rerturn filedata

我有一种强烈的感觉,可以通过python-docx库执行此操作的方法更加简单(而且正确!),但是由于某种原因,我似乎无法正确地做到这一点。

有没有一种方法可以轻松地将复选框字段插入MS Word文档中的表格单元格?如果是的话,我该怎么做?如果不是,是否有比处理.xml文件更好的方法?

更新:我已经能够使用python-docx将XML成功地注入文档中,但是未出现复选框和添加的XML。

我已将以下XML添加到表单元格中:

<w:tc>
  <w:tcPr>
    <w:tcW w:type="dxa" w:w="4320"/>
    <w:gridSpan w:val="2"/>
  </w:tcPr>
  <w:p>
    <w:r>
      <w:bookmarkStart w:id="0" w:name="testName">
        <w:complexType w:name="CT_FFCheckBox">
          <w:sequence>
            <w:choice>
              <w:element w:name="size" w:type="CT_HpsMeasure"/>
              <w:element w:name="sizeAuto" w:type="CT_OnOff"/>
            </w:choice>
            <w:element w:name="default" w:type="CT_OnOff" w:minOccurs="0"/>
            <w:element w:name="checked" w:type="CT_OnOff" w:minOccurs="0"/>
          </w:sequence>
        </w:complexType>
      </w:bookmarkStart>
      <w:bookmarkEnd w:id="0" w:name="testName"/>
    </w:r>
  </w:p>
</w:tc>

通过使用以下python-docx代码:

run = p.add_run()
tag = run._r
start = docx.oxml.shared.OxmlElement('w:bookmarkStart')
start.set(docx.oxml.ns.qn('w:id'), '0')
start.set(docx.oxml.ns.qn('w:name'), n)
tag.append(start)

ctype = docx.oxml.OxmlElement('w:complexType')
ctype.set(docx.oxml.ns.qn('w:name'), 'CT_FFCheckBox')
seq = docx.oxml.OxmlElement('w:sequence')
choice = docx.oxml.OxmlElement('w:choice')
el = docx.oxml.OxmlElement('w:element')
el.set(docx.oxml.ns.qn('w:name'), 'size')
el.set(docx.oxml.ns.qn('w:type'), 'CT_HpsMeasure')
el2 = docx.oxml.OxmlElement('w:element')
el2.set(docx.oxml.ns.qn('w:name'), 'sizeAuto')
el2.set(docx.oxml.ns.qn('w:type'), 'CT_OnOff')

choice.append(el)
choice.append(el2)

el3 = docx.oxml.OxmlElement('w:element')
el3.set(docx.oxml.ns.qn('w:name'), 'default')
el3.set(docx.oxml.ns.qn('w:type'), 'CT_OnOff')
el3.set(docx.oxml.ns.qn('w:minOccurs'), '0')
el4 = docx.oxml.OxmlElement('w:element')
el4.set(docx.oxml.ns.qn('w:name'), 'checked')
el4.set(docx.oxml.ns.qn('w:type'), 'CT_OnOff')
el4.set(docx.oxml.ns.qn('w:minOccurs'), '0')

seq.append(choice)
seq.append(el3)
seq.append(el4)

ctype.append(seq)
start.append(ctype)

end = docx.oxml.shared.OxmlElement('w:bookmarkEnd')
end.set(docx.oxml.ns.qn('w:id'), '0')
end.set(docx.oxml.ns.qn('w:name'), n)
tag.append(end)

似乎找不到找到未反映在输出文档中的XML的原因,但是会根据我发现的内容进行更新。


问题答案:

经过@scanny的大量挖掘和帮助,我终于能够完成此任务。

可以python-docx使用以下功能将复选框插入任何段落。我将复选框插入表中的特定单元格。

def addCheckbox(para, box_id, name):

  run = para.add_run()
  tag = run._r
  fldchar = docx.oxml.shared.OxmlElement('w:fldChar')
  fldchar.set(docx.oxml.ns.qn('w:fldCharType'), 'begin')

  ffdata = docx.oxml.shared.OxmlElement('w:ffData')
  name = docx.oxml.shared.OxmlElement('w:name')
  name.set(docx.oxml.ns.qn('w:val'), cb_name)
  enabled = docx.oxml.shared.OxmlElement('w:enabled')
  calconexit = docx.oxml.shared.OxmlElement('w:calcOnExit')
  calconexit.set(docx.oxml.ns.qn('w:val'), '0')

  checkbox = docx.oxml.shared.OxmlElement('w:checkBox')
  sizeauto = docx.oxml.shared.OxmlElement('w:sizeAuto')
  default = docx.oxml.shared.OxmlElement('w:default')

  if checked:
    default.set(docx.oxml.ns.qn('w:val'), '1')
  else:
    default.set(docx.oxml.ns.qn('w:val'), '0')

  checkbox.append(sizeauto)
  checkbox.append(default)
  ffdata.append(name)
  ffdata.append(enabled)
  ffdata.append(calconexit)
  ffdata.append(checkbox)
  fldchar.append(ffdata)
  tag.append(fldchar)

  run2 = para.add_run()
  tag2 = run2._r
  start = docx.oxml.shared.OxmlElement('w:bookmarkStart')
  start.set(docx.oxml.ns.qn('w:id'), str(box_id))
  start.set(docx.oxml.ns.qn('w:name'), name)
  tag2.append(start)

  run3 = para.add_run()
  tag3 = run3._r
  instr = docx.oxml.OxmlElement('w:instrText')
  instr.text = 'FORMCHECKBOX'
  tag3.append(instr)

  run4 = para.add_run()
  tag4 = run4._r
  fld2 = docx.oxml.shared.OxmlElement('w:fldChar')
  fld2.set(docx.oxml.ns.qn('w:fldCharType'), 'end')
  tag4.append(fld2)

  run5 = para.add_run()
  tag5 = run5._r
  end = docx.oxml.shared.OxmlElement('w:bookmarkEnd')
  end.set(docx.oxml.ns.qn('w:id'), str(box_id))
  end.set(docx.oxml.ns.qn('w:name'), name)
  tag5.append(end)

  return

fldData.text对象似乎是随机的,但是是从生成的XML中带一个带有现有复选框的Word文档中提取的。如果不设置此文本,该功能将失败。我还没有确认,但是我听说过一种情况,开发人员可以随意更改字符串,但是一旦保存,它将恢复为原始生成的值。



 类似资料:
  • 我试图读取一堆格式相同的word docx文件,并将数据提取到数据库中。我对文本没有任何问题,但我在与复选框作斗争。我需要说的是,我是docx4j的新手,但已经在这个问题上挣扎了四天了。我真的很重视一些帮助/帮助/建议。 结果是: 现在,我已经为包含一个难以捉摸的复选框的单元格添加了mainDocumentPart.getXML()的输出。我在那里看不到任何东西告诉我价值。谁能告诉我我错过了什么吗

  • 您好,我正在尝试将一个表从一个docx文件复制到另一个docx文件,但实际情况是,该表的值在新文档中的表下方和表外部被复制(请参见下面的图片) Talbe在新的docx里 正如您所见,表的值被复制到表的外部。我使用的是Libre Office,ApachePOI版本3.17,我的电脑运行的是Ubuntu 16.04 我用来执行复制的代码如下

  • 我正在尝试拆分一个word文档,该文档如下所示: 1.0列表项 1.1列表项 1.2列表项 2.0列表项 它存储在docx中,我正在使用python-docx尝试解析它。不幸的是,它在开始时失去了所有的编号。我试图识别每个有序列表项的开始。 python-docx库也允许我访问样式,但是我不知道如何确定样式是否是列表样式。 到目前为止,我一直在处理函数和检查输出,但标准格式类似于: 我一直在使用它

  • Python DocX目前是Python OpenXML的一部分,你可以用它打开Word 2007及以后的文档,而用它保存的文档可以在Microsoft Office 2007/2010, Microsoft Mac Office 2008, Google Docs, OpenOffice.org 3, and Apple iWork 08中打开。 示例: from docx import Doc

  • 需要一些快速帮助。我正在尝试编写一个java程序来生成一个报告。我在一个docx文件中有报告模板。 我想要做的是,使用该docx文件作为模板,将数据多次放入其中,用于各种记录,并将其写入一个新的docx文件。主要的事情是我想维护docx文件中内容的格式和缩进。它们是子弹数据。这就是问题所在。 下面是处理上述操作的代码段, 如果可以请引导。多谢.

  • 我正在努力寻找用Python将PDF文件转换为.docx文件的方法。 我见过其他与此相关的帖子,但在我的情况下,它们似乎都不正常。 我特别使用 这给了我输出[1],但在我的文件夹中找不到任何.docx文档。 我已经安装了LibreOffice 5.3。 有什么线索吗? 提前谢谢你!