问题
could you please help me? I need to fill checkboxes in my MS Word docx template via Apache POI. Checkboxes has been inserted by Developer tab->Controls->Checkbox and located inside paragraph -> "w:sdt" tag (not inside paragraph -> run).
I've tried paragraph.getCTP().getFldSimpleList()
but it returns 0 fields.
So is there another way to get access for checkboxes?
XML part:
<w:p w:rsidR="00C81ACC" w:rsidRDefault="00C81ACC" w:rsidP="004658AE">
<w:pPr>
<w:spacing w:line="276" w:lineRule="auto"/>
<w:ind w:left="383" w:hanging="383"/>
<w:rPr>
<w:rFonts w:ascii="Arial" w:hAnsi="Arial" w:cs="Arial"/>
<w:sz w:val="18"/>
<w:szCs w:val="18"/>
</w:rPr>
</w:pPr>
<w:sdt>
<w:sdtPr>
<w:rPr>
<w:rFonts w:ascii="Arial" w:hAnsi="Arial" w:cs="Arial"/>
<w:sz w:val="18"/>
<w:szCs w:val="18"/>
</w:rPr>
<w:id w:val="615721754"/>
<w14:checkbox>
<w14:checked w14:val="0"/>
<w14:checkedState w14:val="2612" w14:font="MS Gothic"/>
<w14:uncheckedState w14:val="2610" w14:font="MS Gothic"/>
</w14:checkbox>
</w:sdtPr>
<w:sdtContent>
<w:r>
<w:rPr>
<w:rFonts w:ascii="MS Gothic" w:eastAsia="MS Gothic" w:hAnsi="MS Gothic" w:cs="Arial" w:hint="eastAsia"/>
<w:sz w:val="18"/>
<w:szCs w:val="18"/>
</w:rPr>
<w:t>☐</w:t>
</w:r>
</w:sdtContent>
</w:sdt>
<w:r>
<w:rPr>
<w:rFonts w:ascii="Arial" w:hAnsi="Arial" w:cs="Arial"/>
<w:sz w:val="18"/>
<w:szCs w:val="18"/>
</w:rPr>
<w:t xml:space="preserve"> Pass</w:t>
</w:r>
</w:p>
回答1:
This is not supported by apache poi
until now. And since it uses the extended XML
from w14
name space not even the underlying ooxml-schema
classes supports this. Those schema classes were generated from the XML
schemas of Office Open XML
which was published in 2007. The extended XML
from w14
name space is later and not part of Office Open XML
.
So if one wants supporting that then one needs working on very low level XML
level. But for such a simple thing as a checkbox this can be shown here as an example.
The following code contains a working draft of a class W14Checkbox
. This provides a static method to check whether a given CTSdtRun
contains a w14:checkbox
. If that is the case, then a W14Checkbox
object can be created from that CTSdtRun
. This object then provides getChecked
and setChecked
methods.
Note that in setChecked
not only the boolean value w14:checkbox/w14:checked
needs to be set but also the corresponding text value of the CTSdtContentRun
needs to be set. This can be either Unicode Character 'BALLOT BOX' (U+2610) for not checked or Unicode Character 'BALLOT BOX WITH CHECK' (U+2612) for checked.
Complete Example:
import java.io.*;
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
import org.apache.xmlbeans.*;
import javax.xml.namespace.QName;
public class WordFillCheckBox {
public static void main(String[] args) throws Exception {
XWPFDocument document = new XWPFDocument(new FileInputStream("source.docx"));
for (XWPFParagraph paragraph : document.getParagraphs()) { //go through all paragraphs
for (CTSdtRun sdtRun : paragraph.getCTP().getSdtList()) {
if (W14Checkbox.isW14Checkbox(sdtRun)) {
W14Checkbox w14Checkbox = new W14Checkbox(sdtRun);
System.out.println(w14Checkbox.getChecked());
if (w14Checkbox.getChecked()) w14Checkbox.setChecked(false); else w14Checkbox.setChecked(true);
System.out.println(w14Checkbox.getChecked());
}
}
}
FileOutputStream out = new FileOutputStream("result.docx");
document.write(out);
out.close();
document.close();
}
static class W14Checkbox {
CTSdtRun sdtRun = null;
CTSdtContentRun sdtContentRun = null;
XmlObject w14CheckboxChecked = null;
W14Checkbox(CTSdtRun sdtRun) {
this.sdtRun = sdtRun;
this.sdtContentRun = sdtRun.getSdtContent();
String declareNameSpaces = "declare namespace w14='http://schemas.microsoft.com/office/word/2010/wordml'";
XmlObject[] selectedObjects = sdtRun.getSdtPr().selectPath(declareNameSpaces + ".//w14:checkbox/w14:checked");
if (selectedObjects.length > 0) {
this.w14CheckboxChecked = selectedObjects[0];
}
}
CTSdtContentRun getContent() {
return this.sdtContentRun;
}
XmlObject getW14CheckboxChecked() {
return this.w14CheckboxChecked;
}
boolean getChecked() {
XmlCursor cursor = this.w14CheckboxChecked.newCursor();
String val = cursor.getAttributeText(new QName("http://schemas.microsoft.com/office/word/2010/wordml", "val", "w14"));
return "1".equals(val) || "true".equals(val);
}
void setChecked(boolean checked) {
XmlCursor cursor = this.w14CheckboxChecked.newCursor();
String val = (checked)?"1":"0";
cursor.setAttributeText(new QName("http://schemas.microsoft.com/office/word/2010/wordml", "val", "w14"), val);
cursor.dispose();
CTText t = this.sdtContentRun.getRArray(0).getTArray(0);
String content = (checked)?"\u2612":"\u2610";
t.setStringValue(content);
}
static boolean isW14Checkbox(CTSdtRun sdtRun) {
CTSdtPr sdtPr = sdtRun.getSdtPr();
String declareNameSpaces = "declare namespace w14='http://schemas.microsoft.com/office/word/2010/wordml'";
XmlObject[] selectedObjects = sdtPr.selectPath(declareNameSpaces + ".//w14:checkbox");
if (selectedObjects.length > 0) return true;
return false;
}
}
}
Note: This is a working draft only and needs to be further developed to be ready for productive usage.
来源:https://stackoverflow.com/questions/58728103/work-with-checkboxes-in-docx-file-with-apache-poi