如何使用 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 自己做的,这就是为什么我用同样的方式做的。
希望对您有所帮助!
几天来我一直在努力让它发挥作用,作为最后的手段,我在这里发帖。
背景 - 我正在创建一个 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 自己做的,这就是为什么我用同样的方式做的。
希望对您有所帮助!