您的问题是您的一个(或多个)调用Single()
正在对具有多个元素的序列进行调用。这文档 https://msdn.microsoft.com/en-us/library/vstudio/bb155325%28v=vs.100%29.aspx for Single()
状态(强调我的):
返回序列中唯一的元素,如果不存在则抛出异常恰好有一个元素在序列中。
在您的代码中,这可能会在两种情况之一中发生。第一个是如果您有多个具有相同功能的控件Tag
值,例如,文档中可能有两个标记为“LastName”的控件,这意味着该行
var lastName = mainPart.Document.Body.Descendants<SdtBlock>().Where
(r => r.SdtProperties.GetFirstChild<Tag>().Val == "LastName")
将返回两个元素。
第二个是如果您的内容控件有多个Text
其中的元素在这种情况下这一行
var t = firstName.Descendants<Text>();
将返回多个元素。例如,如果我创建一个内容为“Thisis一个测试”我最终得到了 XML,其中有 4Text
要素:
<w:p w:rsidR="00086A5B" w:rsidRDefault="003515CB">
<w:r>
<w:rPr>
<w:rStyle w:val="PlaceholderText" />
</w:rPr>
<w:t xml:space="preserve">This </w:t>
</w:r>
<w:r>
<w:rPr>
<w:rStyle w:val="PlaceholderText" />
<w:i />
</w:rPr>
<w:t>is</w:t>
</w:r>
<w:r>
<w:rPr>
<w:rStyle w:val="PlaceholderText" />
</w:rPr>
<w:t xml:space="preserve"> </w:t>
</w:r>
<w:r w:rsidR="00E1178E">
<w:rPr>
<w:rStyle w:val="PlaceholderText" />
</w:rPr>
<w:t>a test</w:t>
</w:r>
</w:p>
如何解决第一个问题取决于您是否想要更换all的匹配的Tag
元素或只是一个特定的元素(例如第一个或最后一个)。
如果您只想更换一个,您可以更改呼叫来源Single()
to First()
or Last()
例如,但我想你需要将它们全部替换掉。在这种情况下,您需要循环您想要替换的每个标签名称的每个匹配元素。
删除呼叫Single()
将返回一个IEnumerable<SdtBlock>
您可以迭代替换每一个:
IEnumerable<SdtBlock> firstNameFields = mainPart.Document.Body.Descendants<SdtBlock>().Where
(r => r.SdtProperties.GetFirstChild<Tag>().Val == "FirstName");
foreach (var firstName in firstNameFields)
{
var t = firstName.Descendants<Text>().Single();
t.Text = _firstName;
}
解决第二个问题稍微棘手一些。这easiest我认为解决方案是从内容中删除所有现有段落,然后添加一个包含您希望输出的文本的新段落。
将其分解为一个方法可能是有意义的,因为有很多重复的代码 - 按照这些思路应该可以做到这一点:
private static void ReplaceTags(MainDocumentPart mainPart, string tagName, string tagValue)
{
//grab all the tag fields
IEnumerable<SdtBlock> tagFields = mainPart.Document.Body.Descendants<SdtBlock>().Where
(r => r.SdtProperties.GetFirstChild<Tag>().Val == tagName);
foreach (var field in tagFields)
{
//remove all paragraphs from the content block
field.SdtContentBlock.RemoveAllChildren<Paragraph>();
//create a new paragraph containing a run and a text element
Paragraph newParagraph = new Paragraph();
Run newRun = new Run();
Text newText = new Text(tagValue);
newRun.Append(newText);
newParagraph.Append(newRun);
//add the new paragraph to the content block
field.SdtContentBlock.Append(newParagraph);
}
}
然后可以从您的代码中调用它,如下所示:
using (var wordDoc = WordprocessingDocument.Open(mem, true))
{
var mainPart = wordDoc.MainDocumentPart;
ReplaceTags(mainPart, "FirstName", _firstName);
ReplaceTags(mainPart, "LastName", _lastName);
mainPart.Document.Save();
SaveFileToSp(mem);
}