如何使用 OpenXML 在 Word 文档中设置复选框值

How to set Checkbox value in Word document using OpenXML

几天来我一直在努力让它发挥作用,作为最后的手段,我在这里发帖。

背景 - 我正在创建一个 Web 应用程序,它允许用户将数据输入网页,然后使用占位符将该数据转换为 Microsoft Word 文档。此 Word 文档是一个模板,填充了数据并保存到用户计算机。

已解决的功能 - 我已经设法用用户数据填充所有必需的文本字段。这根本不是问题。我已经创建了一个搜索和替换方法,可以为我完成所有这些工作,所以我不会寻求与此相关的帮助。

问题- 用户在网页上输入的数据中包含几个布尔值。这些布尔值将用于选中或取消选中 Word 文档中的某些复选框。 Word 文档中的每个 Checkbox 都有一个 Bookmark,需要使用它来定位它。我尝试了几种方法来搜索整个 xml Word 文档并更改分配给该特定复选框元素的值。

从 Word 模板中提取的示例 xml

<w:document>
<w:body>        
    <w:tbl>         
        <w:tr>          
            <w:tc>          
                <w:p w:rsidR="007D2E4C" w:rsidRPr="00233E81" w:rsidRDefault="007D2E4C" w:rsidP="007D2E4C">
                    <w:r>   
                        <w:fldChar w:fldCharType="begin">
                            <w:ffData>
                                <w:name w:val="cbxmeal0"/>
                                <w:enabled/>
                                <w:calcOnExit w:val="0"/>
                                <w:checkBox>
                                    <w:sizeAuto/>
                                    <w:default w:val="0"/>
                                </w:checkBox>
                            </w:ffData>
                        </w:fldChar>
                    </w:r>
                    <w:bookmarkStart w:id="10" w:name="cbxmeal0"/>
                    <w:r>
                        <w:rPr>
                            <w:sz w:val="20"/>
                        </w:rPr>
                        <w:instrText xml:space="preserve"> FORMCHECKBOX </w:instrText>
                    </w:r>
                    <w:r w:rsidR="00B128CE">
                        <w:rPr>
                            <w:sz w:val="20"/>
                        </w:rPr>
                    </w:r>
                    <w:r w:rsidR="00B128CE">
                        <w:rPr>
                            <w:sz w:val="20"/>
                        </w:rPr>
                        <w:fldChar w:fldCharType="separate"/>
                    </w:r>
                    <w:r>
                        <w:rPr>
                            <w:sz w:val="20"/>
                        </w:rPr>
                        <w:fldChar w:fldCharType="end"/>
                    </w:r>
                    <w:bookmarkEnd w:id="10"/>
                </w:p>
            </w:tc>
        </w:tr>
    </w:tbl>
</w:body>

以上xml文字是超级简化版,但结构完全一样。一个更简单的结构版本在这里 Document > Body > Table > Table_Row > Table_Cell > Paragraph > Run > Field_Char > Form_Field_Data > Checkbox

下面是我迭代 xml 文本以尝试找到书签和复选框的极其丑陋的方式。注意:我只是打算让它工作,然后我会在以后优化。

            foreach (var table in document.MainDocumentPart.Document.Body.ChildElements.Where(t => t is DocumentFormat.OpenXml.Wordprocessing.Table))
        {
            foreach (var row in table.ChildElements.Where(r => r is DocumentFormat.OpenXml.Wordprocessing.TableRow))
            {
                foreach (var cell in row.ChildElements.Where(c => c is DocumentFormat.OpenXml.Wordprocessing.TableCell))
                {
                    foreach (var paragraph in cell.ChildElements.Where(p => p is DocumentFormat.OpenXml.Wordprocessing.Paragraph))
                    {
                        foreach (var run in paragraph.ChildElements.Where(r => r is DocumentFormat.OpenXml.Wordprocessing.Run))
                        {
                            foreach (var fieldChar in run.ChildElements.Where(fc => fc is DocumentFormat.OpenXml.Wordprocessing.FieldChar))
                            {
                                foreach (var formFieldData in fieldChar.ChildElements)
                                {
                                    foreach (var child in formFieldData.ChildElements)
                                    {
                                        //Check bookmark name
                                        //If bookmark name matches, 
                                        //Set checkbox value to true
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

如果有人可以提供任何帮助,无论是网站地址还是实际代码,那将非常有帮助,因为我对这个任务失去了信心!另外,请原谅我对 LINQ 的使用,因为我使用它的经验很少!

软件 - 我正在使用 Visual Studio 2015、Microsoft Office 2016 和 OpenXML 2.6(我认为)。

这应该对你有帮助。

using (var wordDoc = WordprocessingDocument.Open(@"C:\test\cb\checkbox.docx", true))
{
    MainDocumentPart mainPart = wordDoc.MainDocumentPart;
    var document = mainPart.Document;
    var bookmarks = document.Body.Descendants<BookmarkStart>();

    var myBookmark = bookmarks.First(bms => bms.Name == "cbxmeal0");
    Paragraph paragraph = (Paragraph)myBookmark.Parent;

    Run myCheckbox = (Run)paragraph.Descendants<FieldCode>().First().Parent;
    Run newRun = new Run(@"
<w:r xmlns:w=""http://schemas.openxmlformats.org/wordprocessingml/2006/main"">
    <w:fldChar w:fldCharType=""begin"">
        <w:ffData>
            <w:name w:val=""cbxmeal0"" />
            <w:enabled />
            <w:calcOnExit w:val=""0"" />
            <w:checkBox>
                <w:sizeAuto />
                <w:default w:val=""1"" />
            </w:checkBox>
        </w:ffData>
    </w:fldChar>
</w:r>
");
    paragraph.InsertBefore(newRun, myCheckbox);
}

我已经根据您提供的 XML 创建了一个 Word 文档。前几行只是我放大了包含您的复选框的 运行。

有趣的部分是我创建的 "newRun"。您可以在代码中从 XML 创建它,这是我所做的,但简单地说,它会向您的复选框添加一个 "FieldChar",将其设置为已选中。我不太确定在包含复选框的 运行 之前插入它是否重要,但在我的测试中,这是 Word 自己做的,这就是为什么我用同样的方式做的。

希望对您有所帮助!