Search code examples
c#openxmlopenxml-sdk

Update Content-Control Text in Header and Footer using Open XML SDK


To change the Content-Control Text in the Document Body I'm doing this:

var elements = doc.MainDocumentPart.Document
    .Descendants<SdtElement>()
    .Where(s => s.SdtProperties.ChildElements.Count > 0 && 
                s.SdtProperties.GetFirstChild<Tag>()?.Val == contentControlTag);

foreach (var element in elements)
{
    if (element == null)
    {
        continue;
    }

    var elementText = element.Descendants<Text>();

    if (elementText != null)
    {
        var elementTextValue = elementText.FirstOrDefault();

        if (elementTextValue != null)
        {
            elementTextValue.Text = text;
        }
        elementText.Skip(1).ToList().ForEach(t => t.Remove());
    }
}

Sadly this doesn't change the Header/Footer part.

I want to check each page's header/Footer part for a specific Content-Control-Tag and change its text similar to the code above. How can I achieve this?


Solution

  • The headers and footers aren't in the MainDocumentPart.Document, they are subparts in the HeaderParts and FooterParts collections off the MainDocumentPart. So you'll need to process each part separately. Fortunately, all of the parts share a common base class, OpenXmlPart, so you can put them together into a list and process them in a loop. Since you'll be dealing with the base class, you'll need to use RootElement property instead of Document as a starting point to get the Descendants.

    So the end result would look something like this:

    var partsToUpdate = new List<OpenXmlPart> { doc.MainDocumentPart }
        .Concat(doc.MainDocumentPart.HeaderParts)
        .Concat(doc.MainDocumentPart.FooterParts);
    
    foreach (var part in partsToUpdate)
    {
        var elements = part.RootElement
            .Descendants<SdtElement>()
            .Where(s => s.SdtProperties.ChildElements.Count > 0 &&
                        s.SdtProperties.GetFirstChild<Tag>()?.Val == contentControlTag);
    
        foreach (var element in elements)
        {
            if (element == null)
            {
                continue;
            }
    
            var elementText = element.Descendants<Text>();
    
            if (elementText != null)
            {
                var elementTextValue = elementText.FirstOrDefault();
    
                if (elementTextValue != null)
                {
                    elementTextValue.Text = text;
                }
                elementText.Skip(1).ToList().ForEach(t => t.Remove());
            }
        }
    }