使用以下语法查找合并字段时遇到问题
foreach (var field in docx.MainDocumentPart.Document.Descendants<SimpleField>())
{
}
有时上面的代码可以工作并找出合并字段,有时它只显示 null
问题是 word 可以将合并字段实现为 SimpleField 或 FieldChar。SimpleField 元素包含合并字段的所有详细信息,对于 FieldChar,它有一个 begin 元素,后跟字段代码、带有运行的段落和用于存储字段显示值的文本,最后是合并字段 end 元素。开始和结束之间的所有元素都属于合并字段。
合并字段实现为 FieldChar
<w:r>
<w:fldChar w:fldCharType="begin" />
</w:r>
<w:r>
<w:instrText xml:space="preserve"> MERGEFIELD AnotherBodyField \* MERGEFORMAT </w:instrText>
</w:r>
<w:r>
<w:fldChar w:fldCharType="separate" />
</w:r>
<w:r w:rsidR="003A6EEC">
<w:rPr>
<w:noProof />
</w:rPr>
<w:t>«AnotherBodyField»</w:t>
</w:r>
<w:r>
<w:rPr>
<w:noProof />
</w:rPr>
<w:fldChar w:fldCharType="end" />
</w:r>
合并字段实现为 SimpleField
<w:fldSimple w:instr=" MERGEFIELD TestMergField \* MERGEFORMAT ">
<w:r w:rsidR="00C44AC1">
<w:rPr>
<w:noProof />
</w:rPr>
<w:t>«TestMergField»</w:t>
</w:r>
</w:fldSimple>
SimpleField 对象包含所有合并字段内容,所以这段代码就可以了。var simpleMergeField = documentProcessor.MainDocumentPart.Document.Body.Descendants();
对于 FieldChar,您需要注意 FieldCharValues.Begin、FieldCharValues.Separate 和 FieldCharValues.End。两者之间的每个元素都包含在合并字段内容中。
请验证您的合并字段是否存在文档的哪个部分。它可能存在于页眉或页脚部分。您可以通过制作 xml 包来找出这一点。检查每个页眉、页脚 xml。
您可以使用以下语句遍历页眉部分和页脚部分
foreach (var header in docx.MainDocumentPart.Headerparts)
{
foreach (var field in header.RootElement.Descendants<SimpleField>())
{
}
}
foreach (var footerin docx.MainDocumentPart.FooterParts)
{
foreach (var field in footer.RootElement.Descendants<SimpleField>())
{
}
}
多年后,总结上面的 2 个答案,创建按名称查找所有合并字段的代码解决方案:
var splitter = new[] { ' ', '"' };
const string mergefield = "MERGEFIELD";
var mergeFields = mainPart.HeaderParts.Cast<OpenXmlPart>()
.Concat(mainPart.FooterParts.Cast<OpenXmlPart>())
.Concat(new OpenXmlPart[] { mainPart })
.SelectMany(x => x.RootElement.Descendants<SimpleField>().Select(sf => new { text = sf.Instruction.Value, el = (OpenXmlElement)sf })
.Concat(x.RootElement.Descendants<FieldCode>().Select(fc=> new { text = fc.Text, el = (OpenXmlElement)fc})))
.Select(a => new { words = a.text.Split(splitter, StringSplitOptions.RemoveEmptyEntries), el = a.el })
.Where(a => mergefield.Equals(a.words.FirstOrDefault(), StringComparison.OrdinalIgnoreCase))
.ToLookup(k => string.Join(" ",k.words.Skip(1).TakeWhile(i=>i!= "\\*")), v => v.el);