使用 Apache POI 处理 docx 文件中的复选框
Work with checkboxes in docx file with Apache POI
你能帮帮我吗?
我需要通过 Apache POI 在我的 MS Word docx 模板中填写复选框。复选框已通过 Developer 选项卡->Controls->Checkbox 插入并位于段落内 -> "w:sdt" 标记(不在段落内 -> 运行)。
我试过 paragraph.getCTP().getFldSimpleList()
但它 returns 0 个字段。
那么还有其他方法可以访问复选框吗?
XML 部分:
<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>
到目前为止,apache poi
不支持此功能。而且由于它使用 w14
名称 space 的扩展 XML
甚至底层 ooxml-schema
classes 也不支持这一点。这些模式 classes 是从 2007 年发布的 Office Open XML
的 XML
模式生成的。来自 w14
名称 space 的扩展 XML
是后来而不是 Office Open XML
.
的一部分
因此,如果想要支持这一点,则需要在非常低的 XML
水平上工作。但是对于像复选框这样简单的东西,可以在这里作为示例显示。
以下代码包含 class W14Checkbox
的工作草案。这提供了一个静态方法来检查给定的 CTSdtRun
是否包含 w14:checkbox
。如果是这种情况,则可以从该 CTSdtRun
创建一个 W14Checkbox
对象。然后该对象提供 getChecked
和 setChecked
方法。
注意,在setChecked
中不仅需要设置布尔值w14:checkbox/w14:checked
,还需要设置CTSdtContentRun
对应的文本值。这可以是未选中的 Unicode 字符 'BALLOT BOX' (U+2610) 或已选中的 Unicode 字符 'BALLOT BOX WITH CHECK' (U+2612)。
完整示例:
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;
}
}
}
注意:这只是一个工作草案,需要进一步开发才能为生产使用做好准备。
你能帮帮我吗? 我需要通过 Apache POI 在我的 MS Word docx 模板中填写复选框。复选框已通过 Developer 选项卡->Controls->Checkbox 插入并位于段落内 -> "w:sdt" 标记(不在段落内 -> 运行)。
我试过 paragraph.getCTP().getFldSimpleList()
但它 returns 0 个字段。
那么还有其他方法可以访问复选框吗?
XML 部分:
<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>
到目前为止,apache poi
不支持此功能。而且由于它使用 w14
名称 space 的扩展 XML
甚至底层 ooxml-schema
classes 也不支持这一点。这些模式 classes 是从 2007 年发布的 Office Open XML
的 XML
模式生成的。来自 w14
名称 space 的扩展 XML
是后来而不是 Office Open XML
.
因此,如果想要支持这一点,则需要在非常低的 XML
水平上工作。但是对于像复选框这样简单的东西,可以在这里作为示例显示。
以下代码包含 class W14Checkbox
的工作草案。这提供了一个静态方法来检查给定的 CTSdtRun
是否包含 w14:checkbox
。如果是这种情况,则可以从该 CTSdtRun
创建一个 W14Checkbox
对象。然后该对象提供 getChecked
和 setChecked
方法。
注意,在setChecked
中不仅需要设置布尔值w14:checkbox/w14:checked
,还需要设置CTSdtContentRun
对应的文本值。这可以是未选中的 Unicode 字符 'BALLOT BOX' (U+2610) 或已选中的 Unicode 字符 'BALLOT BOX WITH CHECK' (U+2612)。
完整示例:
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;
}
}
}
注意:这只是一个工作草案,需要进一步开发才能为生产使用做好准备。