使用docx模块使用Python检查.docx形式的复选框

时间:2017-04-25 19:59:53

标签: python python-2.7 arcgis python-docx

我正在尝试使用Python 2.7的docx模块填写word文档表单。我可以很好地修改文本元素,但我很难弄清楚如何检查是或否复选框。

如何查看表单中的复选框。我尝试了几种不同的方法,但我认为这对我来说不知道docx xml在复选框方面是如何构建的。

我是否可以使用书签属性查找特定复选框并按照下图所示进行检查?

enter image description here

我已将测试表单的副本上传到Google云端硬盘here

2 个答案:

答案 0 :(得分:4)

好的,所以经过多次挫折之后我终于想出了如何查看复选框。复选框元素中有一个元素表示是否选中了该框。我基本上能够使用以下函数创建该元素。

from docx.oxml import OxmlElement
from docx.oxml.ns import qn

def checkedElement():
    elm = OxmlElement('w:checked')
    elm.set(qn('w:val'),"true")
    return elm

我可以使用以下函数找到表格单元格中的所有复选框。由于yes始终是每个单元格中的第一个复选框,因此我可以将yes检查的索引设置为0,将no检查设置为索引1,然后我可以将checked元素附加到checkbox元素中:

def yesNoCheck(yes_no,tableIdx,coords):
    print coords, yes_no
    if yes_no == 'y':
        index = 0
        x = doc.tables[tableIdx].cell(coords[0],coords[1])._element.xpath('.//w:checkBox')
        x[index].append(checkedElement())
    elif yes_no == 'n':
        index = 1
        x = doc.tables[tableIdx].cell(coords[0],coords[1])._element.xpath('.//w:checkBox')
        x[index].append(checkedElement())
    else:
        print "value was neither yes or no"
        pass

这是我到目前为止编写的完整代码。我有一堆重构要做,但它现在很好用。我的.docx模板中有两个表,字典table1和table2包含单元格行和列坐标。该脚本用于使用ESRI的Survey123发布的数据填写所需表格。

from docx import Document
from docx.oxml import OxmlElement
from docx.oxml.ns import qn
from docx.shared import Inches
from docx.enum.text import WD_ALIGN_PARAGRAPH
import arcpy
import datetime
import os

table1 = {
    'BusinessName':[2,3],
    'LicenseNumber':[2,14],
    'OwnerName':[3,3],
    'PhoneNumber':[3,14],
    'BusinessAddress':[4,5],
    'County':[4,14],
    'City':[5,1],
    'St':[5,8],
    'Zip':[5,15],
    'LicenceExpired':[6,1], #CheckBox
    'DateExpired':[6,15],
    'LicenceRenewal':[7,1], #CheckBox
    'NumberDisplayed':[8,1], #CheckBox
    'NameAddDisplayed':[10,1], #CheckBox
    'VehicleInfoMatches':[12,1], #CheckBox
    'DischargeValveCapped':[14,1], #CheckBox
    'DischargeValveCapChained':[15,1], #CheckBox
    'HoseDisinfectCarried':[16,1], #CheckBox
    'VehicleAndTankClean':[17,1], #CheckBox
    'FreeOfLeaks':[18,1] #CheckBox
}

table2 = {
    'LandApplyWaste':[1,1], #Yes/No CheckBox
    'LocationDescriptionAccurate':[6,1], #Yes/No CheckBox
    'LocationDescriptionAccDesc':[6,5], #text
    'Slope':[7,1], #Yes/No CheckBox
    'DistanceNearestResidence':[8,1], #Yes/No CheckBox
    'DistanceNearestWell':[9,1], #Yes/No CheckBox
    'DistanceNearestStreamLakeEtc':[10,1], #Yes/No CheckBox
    'SeptageIncorporated':[11,1], #Yes/No CheckBox
    'InjectedIncorporated':[12,3], #Yes/No CheckBox, dependent on the septage incorporated being yes
    'SeptageStabilized':[13,1], #Yes/No CheckBox
    'HowIsLimeMixed':[14,3], #text dependent on if lime was used
    'ConfiningLayerOrGroundwater':[15,1], #Yes/No CheckBox
    'ConfiningLayerOrGroundwaterDesc':[16,3], #text
    'CropGrown':[17,1], #Yes/No CheckBox
    'CropGrownHowVerified':[19,3], #text
    'LandAppCompliance':[20,1], #Yes/No CheckBox
    'AdditionalComments':[22,3],
    'SignDate':[22,13]
}

def checkedElement():
    elm = OxmlElement('w:checked')
    elm.set(qn('w:val'),"true")
    return elm

def yesNoCheck(yes_no,tableIdx,coords):
    print coords, yes_no
    if yes_no == 'y':
        index = 0
        x = doc.tables[tableIdx].cell(coords[0],coords[1])._element.xpath('.//w:checkBox')
        x[index].append(checkedElement())
    elif yes_no == 'n':
        index = 1
        x = doc.tables[tableIdx].cell(coords[0],coords[1])._element.xpath('.//w:checkBox')
        x[index].append(checkedElement())
    else:
        print "value was neither yes or no"
        pass

def disposalMethodCheck(method, locationDec):
    vals = {
        'WastewaterTreatmentFacility':[20,1],
        'LandApplication':[22,1],
        'SanitaryLandfill':[24,1],
        'SeptageLagoonOrDryingBed':[26,1]
    }
    if method != None:
        row,col = vals[method]
        checkBoxElm = doc.tables[0].cell(row,col)._element.xpath('.//w:checkBox')[0]
        print "{0} Checked!".format(method)
        checkBoxElm.append(checkedElement())
        editTxt(locationDec,0,[row,6]) 

def editTxt(text, tblIdx, coords, alignment = WD_ALIGN_PARAGRAPH.LEFT, bold=True):
    print text, coords
    field = doc.tables[tblIdx].cell(coords[0],coords[1]).paragraphs[0]
    field.text = text
    field.alignment = alignment
    field.runs[0].font.bold = bold

def addSig(sigJpgPath):
    para = doc.tables[1].row_cells(23)[0].paragraphs[0]
    para.alignment = WD_ALIGN_PARAGRAPH.CENTER
    run = para.add_run()
    run.add_picture(sigJpgPath,width=Inches(1.34),height=Inches(.35))

fc = r"E:\PumperTruckInspectionFeatureClass"
arcpy.MakeFeatureLayer_management (fc, "PumperTruckInspections")
attach = r"PumperTruckInspection__ATTACH" #Where signatures are stored

def rows_as_dicts(cursor):
    colnames = cursor.fields
    for row in cursor:
        yield dict(zip(colnames, row))

def dateString(date):
    if date != None:
        d = date.strftime('%m/%d/%Y')
        return d
    else:
        print "no date"
        return ''

def checkBusName(name):
    if name != None:
        return name
    else:
        return 'unknown'

with arcpy.da.SearchCursor(fc, '*') as sc:
    for row in rows_as_dicts(sc):
        doc = Document(r"path\to\TEMPLATE.docx")

        t = datetime.datetime.now().strftime('%Y-%m-%d')
        newDocName = checkBusName(row['BusinessName']) + t + '.docx'


        editTxt(row['BusinessName'],0,table1['BusinessName'])
        editTxt(row['LicenseNumber'],0,table1['LicenseNumber'])
        editTxt(row['OwnerName'],0,table1['OwnerName'])
        editTxt(row['PhoneNumber'],0,table1['PhoneNumber'])
        editTxt(row['BusinessAddress'],0,table1['BusinessAddress'])
        editTxt(row['County'],0,table1['County']) 
        editTxt(row['City'],0,table1['City'])
        editTxt(row['St'],0,table1['St'])
        editTxt(row['Zip'],0,table1['Zip'])
        editTxt(dateString(row['DateExpired']),0,table1['DateExpired'])
        yesNoCheck(row['LicenceExpired'],0, table1['LicenceExpired'])

        yesNoCheck(row['LicenceRenewal'],0, table1['LicenceRenewal'])
        yesNoCheck(row['NumberDisplayed'],0, table1['NumberDisplayed'])
        yesNoCheck(row['NameAddDisplayed'],0, table1['NameAddDisplayed'])
        yesNoCheck(row['VehicleInfoMatches'],0, table1['VehicleInfoMatches'])
        yesNoCheck(row['DischargeValveCapped'],0, table1['DischargeValveCapped'])
        yesNoCheck(row['DischargeValveCapChained'],0, table1['DischargeValveCapChained'])
        yesNoCheck(row['HoseDisinfectCarried'],0, table1['HoseDisinfectCarried'])
        yesNoCheck(row['VehicleAndTankClean'],0, table1['VehicleAndTankClean'])
        yesNoCheck(row['FreeOfLeaks'],0, table1['FreeOfLeaks'])
        disposalMethodCheck(row['DisposalMethod'],row['DisposalLocation'])
        if row['DisposalMethod'] == 'LandApplication':
            yesNoCheck(row['LandApplyWaste'],1,table2['LandApplyWaste'])
            yesNoCheck(row['LocationDescriptionAccurate'],1,table2['LocationDescriptionAccurate'])
            editTxt(row['LocationDescriptionAccDesc'],1,table2['LocationDescriptionAccDesc'])
            yesNoCheck(row['Slope'],1,table2['Slope'])
            yesNoCheck(row['DistanceNearestResidence'],1,table2['DistanceNearestResidence'])

            yesNoCheck(row['DistanceNearestWell'],1,table2['DistanceNearestWell'])
            yesNoCheck(row['DistanceNearestStreamLakeEtc'],1,table2['DistanceNearestStreamLakeEtc'])
            yesNoCheck(row['SeptageIncorporated'],1,table2['SeptageIncorporated'])
            yesNoCheck(row['InjectedIncorporated'],1,table2['InjectedIncorporated']) #might need a new method since its not yes/no
            yesNoCheck(row['SeptageStabilized'],1,table2['SeptageStabilized'])
            editTxt(row['HowIsLimeMixed'],1,table2['HowIsLimeMixed'])
            yesNoCheck(row['ConfiningLayerOrGroundwater'],1,table2['ConfiningLayerOrGroundwater'])
            editTxt(row['ConfiningLayerOrGroundwaterDescript'],1,table2['ConfiningLayerOrGroundwaterDescript'])
            yesNoCheck(row['CropGrown'],1,table2['CropGrown'])
            editTxt(row['CropGrownHowVerified'],1,table2['CropGrownHowVerified'])
            yesNoCheck(row['LandAppCompliance'],1,table2['LandAppCompliance'])
        editTxt(row['AdditionalComments'],1,table2['AdditionalComments'],bold=False)
        where = "REL_GLOBALID = '{0}'".format(row['GlobalID'])
        from pprint import pprint
        with arcpy.da.SearchCursor(attach,['DATA', 'ATT_NAME', 'ATTACHMENTID'],where_clause=where) as cursor:
            for r in rows_as_dicts(cursor):
                pprint(r)
                name = r['ATT_NAME']
                attachment = r['DATA']
                if name.split('_')[0] == 'InspectorSignature':
                    imagePath = os.path.join(name.split('_')[0] + "_" + )
                    open(("sig.jpeg"), 'wb').write(attachment.tobytes())
                    addSig("sig.jpeg")

                    break

        editTxt(dateString(row['SignDate']),1,table2['SignDate'],alignment = WD_ALIGN_PARAGRAPH.CENTER,bold=False)
        doc.save(newDocName)
        del doc

答案 1 :(得分:1)

我刚刚在word中创建了一个复选框,然后重新创建了xml代码。在函数中编译整个,你只需要将段落作为参数传递。

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


def addCheckedbox(para, box_id, name):

    run = para.add_run()
    tag = run._r
    start = docx.oxml.shared.OxmlElement('w:bookmarkStart')
    start.set(docx.oxml.ns.qn('w:id'), str(box_id - 1))
    start.set(docx.oxml.ns.qn('w:name'), "_GoBack")

    run2 = para.add_run()
    tag2 = run2._r
    fld = docx.oxml.shared.OxmlElement('w:fldChar')
    fld.set(docx.oxml.ns.qn('w:fldCharType'), 'begin')


    checker = docx.oxml.shared.OxmlElement('w:checkBox')
    sizer = docx.oxml.shared.OxmlElement('w:sizeAuto')
    checkValue = docx.oxml.shared.OxmlElement('w:default')
    checkValue.set(docx.oxml.ns.qn('w:val'), '1')
    checker.append(sizer)
    checker.append(checkValue)
    start.append(checker)    
    tag.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