Mou*_*nir 2 .net c# asp.net openxml openxml-sdk
我正在尝试使用 OpenXML 将 Word 文件中的合并字段替换为我的数据。
\n\n我认为代码中没有问题,因为有时它在某些模板中工作正常,有时合并字段没有被替换。
\n\n在word模板中插入合并域有问题吗?我不知道出了什么问题。
\n\n下面是我使用的代码:
\n\n public void Fill_Document_Fields(Dictionary<string, string> Fields, string FilePath)\n {\n try\n {\n using (WordprocessingDocument Doc = WordprocessingDocument.Open(FilePath, true))\n {\n foreach (FieldCode field in Doc.MainDocumentPart.RootElement.Descendants<FieldCode>())\n {\n string FieldName =string.Empty;\n try\n {\n FieldName = field.Text.Trim().Split(\' \')[2];\n }\n catch\n {\n FieldName = field.Text.Trim();\n }\n\n\n foreach (Run run in Doc.MainDocumentPart.Document.Descendants<Run>())\n {\n foreach (Text txtFromRun in run.Descendants<Text>().Where(a => a.Text == "\xc2\xab" + FieldName + "\xc2\xbb"))\n {\n string itemValue;\n if (Fields.TryGetValue(txtFromRun.Text, out itemValue))\n {\n txtFromRun.Text = itemValue;\n }\n }\n }\n\n }\n }\n }\n catch \n {\n }\n }\nRun Code Online (Sandbox Code Playgroud)\n
您的代码仅适用于 \'SimpleField\',事实上您的代码根本不正确,因为用您的自定义值替换 \xc2\xabFieldName\xc2\xbb ,您要替换的值也将是合并字段。
\n\n如果你查看文档后面的 xml,你会发现类似于以下内容:
\n\n<w:fldSimple w:instr=" MERGEFIELD TestFoo \\* MERGEFORMAT ">\n <w:r w:rsidR="00C44AC1">\n <w:rPr>\n <w:noProof />\n </w:rPr>\n <w:t>\xc2\xabTestFoo\xc2\xbb</w:t>\n </w:r>\n</w:fldSimple>\nRun Code Online (Sandbox Code Playgroud)\n\n此时,您将元素 \'w:t\' (\xc2\xabTestFoo\xc2\xbb) 替换为您的值 (Foo),结果类似于:
\n\n<w:fldSimple w:instr=" MERGEFIELD TestFoo \\* MERGEFORMAT ">\n <w:r w:rsidR="00C44AC1">\n <w:rPr>\n <w:noProof />\n </w:rPr>\n <w:t>Foo</w:t>\n </w:r>\n</w:fldSimple>\nRun Code Online (Sandbox Code Playgroud)\n\n如您所见,您的值仍在 mergefield 元素内。
\n\n在这种情况下 (SimpleField),您需要找到 \'fldSimple\' 元素并读取 instr 属性,可能使用正则表达式来提取合并字段值。\n当您想用您的值替换合并字段时,您必须将 fldSimple 元素替换为 run 内的文本元素元素。
\n\nmergefield 的第二个实现是 FieldChar。
\n\n<w:r>\n <w:fldChar w:fldCharType="begin" />\n</w:r>\n<w:r>\n <w:instrText xml:space="preserve"> MERGEFIELD TestFoo \\* MERGEFORMAT </w:instrText>\n</w:r>\n<w:r>\n <w:fldChar w:fldCharType="separate" />\n</w:r>\n<w:r w:rsidR="00FA6E12">\n <w:rPr>\n <w:noProof />\n </w:rPr>\n <w:t>\xc2\xabTestFoo\xc2\xbb</w:t>\n</w:r>\n<w:r>\n <w:rPr>\n <w:noProof />\n </w:rPr>\n <w:fldChar w:fldCharType="end" />\n</w:r>\nRun Code Online (Sandbox Code Playgroud)\n\n在这种情况下,您需要找到 fldCharType attr 等于 begin 的 fldChar 元素,您必须迭代所有节点,直到找到 fldCharType attr 值等于 end 为止。
\n\n在“begin”和“end”值之间,您需要查找并读取 instrText 元素内的值。
\n\n当您想要替换值时,必须将“begin”和“end”值之间找到的所有元素替换为 run 元素内的文本元素。
\n\n我认为使用 docx mergefield 会写成 FieldChar,使用 dotx 会写成 SimpleField。
\n\n现在我无法编写代码示例,希望对您有所帮助。
\n\n抱歉我的英语不好,\n再见
\n小智 5
您应该在编辑后保存 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();
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5955 次 |
| 最近记录: |