问题检索内容控制与Open XML SDK(Problems retrieving content

2019-10-22 05:54发布

我正在开发一个解决方案,将产生字的文件。 字文档已定义的内容控件模板文件的基础上产生的。 一切都为我工作很好,当我只有一个在我的模板内容控制,但更多的内容控制扩展模板文档后,我得到异常。 好像我没有找到的内容控制。

这是我的方法:

private void CreateReport(File file)

    {
        var byteArray = file.OpenBinary();
        using (var mem = new MemoryStream())
        {
            mem.Write(byteArray, 0, byteArray.Length);
            try
            {
                using (var wordDoc = WordprocessingDocument.Open(mem, true))
                {
                    var mainPart = wordDoc.MainDocumentPart;

                    var firstName = mainPart.Document.Body.Descendants<SdtBlock>().Where
                        (r => r.SdtProperties.GetFirstChild<Tag>().Val == "FirstName").Single();
                    var t = firstName.Descendants<Text>().Single();
                    t.Text = _firstName;

                     var lastName = mainPart.Document.Body.Descendants<SdtBlock>().Where
                        (r => r.SdtProperties.GetFirstChild<Tag>().Val == "LastName").Single();
                     var t2= lastName.Descendants<Text>().Single();
                     t2.Text = _lastName;

                    mainPart.Document.Save();
                    SaveFileToSp(mem);
                }

            }
            catch (FileFormatException)
            {
            }
        }
    }

这是例外,我得到:

“System.InvalidOperationException”类型的异常出现在System.Core.dll但在用户代码中没有处理。 的InnerException:空

我如何能写出寻找更好的控制方法,为我任何提示?

Answer 1:

你的问题是,您的来电中的一个(或多个) Single()被调用在具有多个元素的序列。 该文档的Single()国家(重点煤矿):

返回序列中的唯一元素,如果有序列中的一个元素是不是抛出异常。

在你的代码这可以在两种情况之一发生。 第一个是,如果你有相同的多个控制Tag的值,例如,你可能有一个标有“姓”的文档中两个控制这将意味着这条线

var lastName = mainPart.Document.Body.Descendants<SdtBlock>().Where
                    (r => r.SdtProperties.GetFirstChild<Tag>().Val == "LastName")

将返回两个元素。

第二个是,如果你的内容的控制有一个以上的Text在这种情况下,该行元素在里面

var t = firstName.Descendants<Text>();

将返回多个元素。 例如,如果我创建与内容“这一个测试”我结束了XML具有4个的控制Text元素:

<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>

如何避开第一个问题取决于你是否要替换所有匹配的Tag内容,或只是一个特定的一个(如第一个或最后一个)。

如果您要更换只有一个你可以改变从呼叫Single()First()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;
}

要解决的第二个问题是稍微棘手。 在我看来, 最简单的解决方案是从内容删除所有现有的段落,然后添加一个新的使用要输出的文本。

打破这一点成为可能的方法是有道理的,因为是有大量重复的代码 - 沿着这些线路应该这样做的东西:

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);
}


Answer 2:

我觉得你的Single()方法导致异常。

当你有只有一个内容控制, Single()可以得到唯一可用的元素。 但是,当你展开内容的控制,你的Single()方法会导致InvalidOperationException ,因为序列中的一个以上的元素是。 如果是这样的情况下,尽量循环代码,并采取一个元素在同一时间。



文章来源: Problems retrieving content controls with Open XML sdk