【问题标题】:Work with checkboxes in docx file with Apache POI使用 Apache POI 处理 docx 文件中的复选框
【发布时间】:2019-11-07 20:07:01
【问题描述】:

你能帮帮我吗? 我需要通过 Apache POI 在我的 MS Word docx 模板中填写复选框。复选框已由 Developer tab->Controls->Checkbox 插入并位于段落内 -> "w:sdt" 标记(不在段落内 -> 运行)。

我试过 paragraph.getCTP().getFldSimpleList() 但它返回 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>

【问题讨论】:

    标签: java checkbox apache-poi docx


    【解决方案1】:

    到目前为止,apache poi 不支持此功能。而且由于它使用来自w14 名称空间的扩展XML,甚至底层的ooxml-schema 类也不支持这一点。这些架构类是从 2007 年发布的 Office Open XMLXML 架构生成的。来自 w14 名称空间的扩展 XML 是后来的,而不是 Office Open XML 的一部分。

    因此,如果要支持该功能,则需要在非常低的级别 XML 级别上工作。但是对于像复选框这样简单的东西,可以在这里作为示例显示。

    以下代码包含W14Checkbox 类的工作草案。这提供了一种静态方法来检查给定的CTSdtRun 是否包含w14:checkbox。如果是这种情况,则可以从该CTSdtRun 创建一个W14Checkbox 对象。该对象然后提供getCheckedsetChecked 方法。

    注意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;
      }
     }
    }
    

    注意:这只是一个工作草案,需要进一步开发以准备好用于生产用途。

    【讨论】:

    • 大家好,我也有类似的问题,但是如果未选中此代码,则选中该框,反之亦然,我需要根据某些条件选中该复选框,例如假设有三个复选框A , B,C 取决于某些条件,我需要检查复选框,但我找不到任何唯一属性,通过它我可以识别它是复选框 A 或 B 或 C
    猜你喜欢
    • 1970-01-01
    • 2020-02-27
    • 2013-02-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-25
    • 1970-01-01
    相关资源
    最近更新 更多