OpenXML如何将文本插入到Word 2007内容控件中

3

我正在学习OpenXML。已经花了很多时间搜索如何在C#中将文本插入内容控件。

我有一个模板文档,其中包含两个控件“Name”和“Age”。我可以找到它们,但是我无法在它们中添加文本。我尝试了很多方法,但都没有成功。

        byte[] templateBytes = System.IO.File.ReadAllBytes(fileName);
        using (MemoryStream templateStream = new MemoryStream())
        {
            templateStream.Write(templateBytes, 0, (int)templateBytes.Length);

            using (WordprocessingDocument outDoc = WordprocessingDocument.Open(templateStream, true))
            {
                MainDocumentPart mainPart = outDoc.MainDocumentPart;

                foreach (SdtElement sdt in mainPart.Document.Descendants<SdtElement>().ToList())
                {
                    SdtAlias alias = sdt.Descendants<SdtAlias>().FirstOrDefault();

                    if (alias != null)
                    {
                        string sdtTitle = alias.Val.Value;

                        switch (sdtTitle)
                        {
                            case "Name":
                                // ¿Qué?
                                break;
                            case "Age":
                                // ¿Qué?
                                break;
                        }
                    }
                }

                outDoc.ChangeDocumentType(DocumentFormat.OpenXml.WordprocessingDocumentType.Document);
            }

            using (FileStream fileStream = new FileStream(savePath, System.IO.FileMode.CreateNew))
            {
                templateStream.WriteTo(fileStream);
            }
        }

非常感谢您的帮助。

谢谢,

Tim。

编辑--

感谢您的回复。根据您的建议,我尝试使用生产力工具进行转换和钻取以查找要更新的子元素。您能否告诉我为什么这段代码根本没有写入任何内容?

        foreach (SdtElement sdt in mainPart.Document.Descendants<SdtElement>().ToList())
                {
                    SdtAlias alias = sdt.Descendants<SdtAlias>().FirstOrDefault();

                    if (alias != null)
                    {
                        SdtRun xRun = (SdtRun)sdt;
                        SdtContentRun xContentRun = xRun.Descendants<SdtContentRun>().FirstOrDefault();
                        Run xRun = xContentRun.Descendants<Run>().FirstOrDefault();
                        Text xText = xRun.Descendants<Text>().FirstOrDefault();

                        string sdtTitle = alias.Val.Value;

                        switch (sdtTitle)
                        {
                            case "Name":
                                xText.Text = "Whatever";                  
                                break;
                            case "Age":                    
                                xText.Text = "69";
                                break;
                        }
                    }     
                }

你好,你的代码中xRun被声明了两次,所以Visual Studio编译失败了。这里是更改后的代码: [code]Run xRun2 = xContentRun.Descendants<Run>().FirstOrDefault();[/code] - Nolmë Informatique
4个回答

7
你需要将SdtElement转换为其对应的类型,才能访问其内容子节点。
例如,如果它是一个SdtBlock:
    ((SdtBlock)sdt).SdtContentBlock

然后你可以向其中添加内容(例如添加子元素)。

来自MSDN,继承层次结构:

 DocumentFormat.OpenXml.Wordprocessing.SdtElement
     DocumentFormat.OpenXml.Wordprocessing.SdtBlock
     DocumentFormat.OpenXml.Wordprocessing.SdtCell
     DocumentFormat.OpenXml.Wordprocessing.SdtRow
     DocumentFormat.OpenXml.Wordprocessing.SdtRun
     DocumentFormat.OpenXml.Wordprocessing.SdtRunRuby

1

如果有人想要VB格式的代码来执行键/值字典数组的直接查找/替换操作...

            Using document As WordprocessingDocument = WordprocessingDocument.Open(cls_sNewFilename, True)
                Dim mainPart As MainDocumentPart = document.MainDocumentPart
                Dim body As Body = mainPart.Document.Body

                'if custom xml content exists, delete it first
                mainPart.DeleteParts(Of CustomXmlPart)(mainPart.CustomXmlParts)

                For Each sdt As SdtElement In body.Descendants(Of SdtElement)().ToList()
                    Dim [alias] As SdtAlias = sdt.Descendants(Of SdtAlias)().FirstOrDefault()

                    If [alias] IsNot Nothing Then

                        If sdt.ToString() = "DocumentFormat.OpenXml.Wordprocessing.SdtRun" Then
                            Dim xStdRun As SdtRun = DirectCast(sdt, SdtRun)
                            Dim xStdContentRun As SdtContentRun = xStdRun.Descendants(Of SdtContentRun)().FirstOrDefault()
                            Dim xRun As Run = xStdContentRun.Descendants(Of Run)().FirstOrDefault()
                            Dim xText As Text = xRun.Descendants(Of Text)().FirstOrDefault()
                            Dim sdtTitle As String = [alias].Val.Value

                            xText.Text = dictReplacements.Item(sdtTitle)

                        ElseIf sdt.ToString() = "DocumentFormat.OpenXml.Wordprocessing.SdtBlock" Then
                            Dim xStdBlock As SdtBlock = DirectCast(sdt, SdtBlock)
                            Dim xStdContentBlock As SdtContentBlock = xStdBlock.Descendants(Of SdtContentBlock)().FirstOrDefault()
                            Dim xRun As Run = xStdContentBlock.Descendants(Of Run)().FirstOrDefault()
                            Dim xText As Text = xStdContentBlock.Descendants(Of Text)().FirstOrDefault()
                            Dim sdtTitle As String = [alias].Val.Value

                            xText.Text = dictReplacements.Item(sdtTitle)
                        End If
                    End If
                Next

                mainPart.Document.Save()
                document.Close()
            End Using

由于某些原因,最后一部分似乎是 sdtBlock 而不是 sdtRun,因此需要使用 ElseIf..!


1
经过多个小时的痛苦,我终于解决了它。
问题出在两个地方: 1)我需要在其中添加一个mainPart.Document.Save();命令。 2)我使用Content Control Toolkit添加了一个customXmlPart。因此,我认为这个customxml部分覆盖了我用代码添加的文本,因为当我回到内容控制工具包并删除xml部分时,它就起作用了。
再次感谢plutext给我提供解决方案!

0

顺便说一下,在 foreach 之前添加以下代码行将自动清除任何现有的自定义 xml:

mainPart.DeleteParts<CustomXmlPart>(mainPart.CustomXmlParts);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接