我正在尝试使用OpenXML用我的数据替换word文件中的合并字段。
我认为代码中没有问题,因为有时它在一些模板中工作得很好,有时合并字段没有被替换。
在word模板中插入Mergefield有问题吗?我不知道问题出在哪里。
下面是我使用的代码:
public void Fill_Document_Fields(Dictionary<string, string> Fields, string FilePath)
{
try
{
using (WordprocessingDocument Doc = WordprocessingDocument.Open(FilePath, true))
{
foreach (FieldCode field in Doc.MainDocumentPart.RootElement.Descendants<FieldCode>())
{
string FieldName =string.Empty;
try
{
FieldName = field.Text.Trim().Split(' ')[2];
}
catch
{
FieldName = field.Text.Trim();
}
foreach (Run run in Doc.MainDocumentPart.Document.Descendants<Run>())
{
foreach (Text txtFromRun in run.Descendants<Text>().Where(a => a.Text == "«" + FieldName + "»"))
{
string itemValue;
if (Fields.TryGetValue(txtFromRun.Text, out itemValue))
{
txtFromRun.Text = itemValue;
}
}
}
}
}
}
catch
{
}
}发布于 2017-05-29 04:30:10
您的代码只能与“SimpleField”一起使用,实际上您的代码根本不正确,因为用您的自定义值替换«FieldName»,您要替换的值也将是一个合并字段。
如果您查看文档背后的xml,您可以看到类似于以下内容:
<w:fldSimple w:instr=" MERGEFIELD TestFoo \* MERGEFORMAT ">
<w:r w:rsidR="00C44AC1">
<w:rPr>
<w:noProof />
</w:rPr>
<w:t>«TestFoo»</w:t>
</w:r>
</w:fldSimple>此时,您将元素'w:t‘(«TestFoo»)替换为您的值(Foo),结果如下:
<w:fldSimple w:instr=" MERGEFIELD TestFoo \* MERGEFORMAT ">
<w:r w:rsidR="00C44AC1">
<w:rPr>
<w:noProof />
</w:rPr>
<w:t>Foo</w:t>
</w:r>
</w:fldSimple>如您所见,您的值仍然在mergefield元素中。
在本例中(SimpleField),您需要找到'fldSimple‘元素并读取instr属性,可能使用正则表达式来提取合并字段的值。当你想用你的值替换mergefield时,你必须用run元素中的文本元素替换fldSimple元素。
mergefield的第二个实现是FieldChar。
<w:r>
<w:fldChar w:fldCharType="begin" />
</w:r>
<w:r>
<w:instrText xml:space="preserve"> MERGEFIELD TestFoo \* MERGEFORMAT </w:instrText>
</w:r>
<w:r>
<w:fldChar w:fldCharType="separate" />
</w:r>
<w:r w:rsidR="00FA6E12">
<w:rPr>
<w:noProof />
</w:rPr>
<w:t>«TestFoo»</w:t>
</w:r>
<w:r>
<w:rPr>
<w:noProof />
</w:rPr>
<w:fldChar w:fldCharType="end" />
</w:r>在这种情况下,您需要找到fldCharType attr等于begin的fldChar元素,您必须迭代所有节点,直到找到fldCharType attr等于end。
在'begin‘和'end’值之间,您需要在instrText元素中查找和读取值。
当你想要替换你的值时,你必须用run元素中的文本元素替换在'begin‘和'end’值之间找到的所有元素。
我认为使用docx合并字段被写成FieldChar,而使用dotx被写成SimpleField。
现在我不会写示例代码了,希望对大家有所帮助。
对不起,我的英语,再见
发布于 2020-04-07 04:34:00
您应该在编辑word文档后将其保存,因此在停止使用WordprocessingDocument.Open之前,只需关闭该文档(请参阅下面的示例)。
您可以在这里找到GetMergeFields()的一个很好的实现:https://github.com/frankfajardo/OpenXmlWordHelper
我是这样做的:
// get a memory stream for the bytes
using MemoryStream templateFileStream = this.GetMemoryStream(templateFileBytes);
// open template file from Memory Stream
using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(templateFileStream, true))
{
var mergeFields = wordDoc.GetMergeFields().ToList();
foreach (var mergeField in mergeFields)
{
mergeField.ReplaceWithText(*replacementText*);
}
// This is required to save and flush the merged word document to the memory stream
wordDoc.Close();
// get the new merged document stream before it is closed and disposed
mergedDocumentBytes = templateFileStream.ToArray();
} https://stackoverflow.com/questions/37518114
复制相似问题