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

时间:2010-09-28 05:45:41

标签: c# ms-word openxml

我正在学习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);
            }
        }

所有人都非常感谢。

干杯,

编辑 -

感谢您的回复。根据您的建议,我尝试使用生产力工具进行投射和挖掘,以找到要更新的子元素。你能否告诉我你是否能看出为什么这段代码根本没有在文档中写任何内容?

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

4 个答案:

答案 0 :(得分:6)

你需要将你的SdtElement转换为它的内容,以便获得它的内容。

例如,如果它是一个SdtBlock:

    ((SdtBlock)sdt).SdtContentBlock

然后你可以添加东西(例如添加孩子)。

From 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 :(得分:1)

经过几个小时的痛苦,我解决了它。

问题有两个: 1)我需要一个mainPart.Document.Save();命令在那里。 2)我添加了一个带有Content Control Toolkit的customXmlPart。所以我假设这个customxml部分覆盖了我在代码中添加的文本,因为当我回到内容控制工具包并删除了xml部分时,它起作用了。

再次感谢插件让我加入解决方案!

答案 2 :(得分: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 ..!

答案 3 :(得分:0)

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

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