python-docx: добавление флажка в .docx не работает


Я хочу добавить XML в свой документ .docx, используя библиотеку python-docx. Я попробовал этот код из stackoverflow, но он не работает, не знаю почему. Я ничего не получаю при открытии docx с помощью LibreOffice и Microsoft Word.

table = document.add_table(rows=1, cols=1)
p = table.cell(0, 0).paragraphs[0]
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'), '0')
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'), '0')
tag.append(end)

Можете вы помочь мне? Большое спасибо
PS: я нашел код здесь


person m0r7y    schedule 19.08.2019    source источник
comment
Лучше, если вы дадите ссылку на сообщение StackOverflow, на основе которого вы это сделали, чтобы мы могли сравнить.   -  person Justin Ezequiel    schedule 19.08.2019
comment
@JustinEzequiel, конечно, позвольте мне отредактировать пост   -  person m0r7y    schedule 19.08.2019
comment
Похоже, вы использовали код из исходного сообщения, которое, по словам ОП, не работает, поэтому в сообщении содержится просьба о помощи. Можете ли вы попробовать функцию addCheckbox в его последующем сообщении?   -  person Justin Ezequiel    schedule 20.08.2019
comment
@JustinEzequiel, это тоже не работает. Итак, я думаю, что этот document.add_paragraph('◻') мне подходит, это просто символ юникода для квадрата, но не настоящий флажок   -  person m0r7y    schedule 20.08.2019


Ответы (1)


Настроив функцию из этого поста SO, я заставил ее работать.

import docx
import random

def addCheckbox(para, box_id, name):
    run = para.add_run()
    tag = run._r
    fld = docx.oxml.shared.OxmlElement('w:fldChar')
    fld.set(docx.oxml.ns.qn('w:fldCharType'), 'begin')

    ffData = docx.oxml.shared.OxmlElement('w:ffData')
    e = docx.oxml.shared.OxmlElement('w:name')
    e.set(docx.oxml.ns.qn('w:val'), 'Check1')
    ffData.append(e)
    ffData.append(docx.oxml.shared.OxmlElement('w:enabled'))
    e = docx.oxml.shared.OxmlElement('w:calcOnExit')
    e.set(docx.oxml.ns.qn('w:val'), '0')
    ffData.append(e)
    e = docx.oxml.shared.OxmlElement('w:checkBox')
    e.append(docx.oxml.shared.OxmlElement('w:sizeAuto'))
    ee = docx.oxml.shared.OxmlElement('w:default')
    ee.set(docx.oxml.ns.qn('w:val'), '0')
    e.append(ee)
    ffData.append(e)

    fld.append(ffData)
    tag.append(fld)

    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)

if __name__ == '__main__':
    document = docx.Document()
    document.add_heading('Document Title', 0)
    p1 = document.add_paragraph('A paragraph with a checkbox ')
    addCheckbox(p1, random.randint(16*1024, 32*1024), 'justinwashere')
    document.save('demo.docx')

Я изменил содержимое его ffData в функции, чтобы оно соответствовало замене XML в его исходном вопросе.

person Justin Ezequiel    schedule 21.08.2019
comment
Спасибо за ваш комментарий. Позвольте мне протестировать его и проголосовать, если он работает. - person m0r7y; 21.08.2019
comment
Извините за ожидание. Я протестировал ваше решение, и оно работает очень хорошо. Большое тебе спасибо - person m0r7y; 23.08.2019