OpenXML insert text into content control Word 2007
I am learning OpenXML. I have been looking for hours trying to find how to do a simple task: insert text into a content control in c#.
I have a template document with two controls "Name" and "Age." I can find them well enough, but I just cannot add text in them. I've tried a number of things, all to no avail.
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);
}
}
All help greatly appreciated.
Cheers,
Tim.
EDIT --
Thanks for the response. Taking you开发者_运维百科r advice, I've attempted to cast and drilled down with the productivity tool to find the child elements to update. Could you tell me if you can see why this code is simply not writing anything to the document?
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;
}
}
}
You need to cast your SdtElement to whatever it is, in order to get at its content child.
For example, if its an SdtBlock:
((SdtBlock)sdt).SdtContentBlock
Then you can add stuff (eg add children) to that.
From MSDN, the inheritance hierarchy:
DocumentFormat.OpenXml.Wordprocessing.SdtElement
DocumentFormat.OpenXml.Wordprocessing.SdtBlock
DocumentFormat.OpenXml.Wordprocessing.SdtCell
DocumentFormat.OpenXml.Wordprocessing.SdtRow
DocumentFormat.OpenXml.Wordprocessing.SdtRun
DocumentFormat.OpenXml.Wordprocessing.SdtRunRuby
After many hours of pain, I solved it.
Two things were the problem: 1) I needed a mainPart.Document.Save(); command in there. 2) I had added a customXmlPart with the Content Control Toolkit. So I assume that this customxml part was overriding the text I was adding with the code, because when I went back into the content control toolkit and deleted the xml part, it worked.
Thanks again plutext for putting me onto the solution!
Anyone wanting the code in VB format to do a straight find/replace of a key/value dictionary array...
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
for some reason the last part seems to be sdtBlock instead of sdtRun hence the ElseIf..!
By the way, adding the following line of code before the foreach will automatically clean out any existing custom xml:
mainPart.DeleteParts<CustomXmlPart>(mainPart.CustomXmlParts);
精彩评论