Search code examples
c#ms-wordopenxmlopenxml-sdk

Get DocumentPart from OpenXmlElement when working with Word document in OpenXML


I'm modifying a docx template with OpenXML API and run into a problem.

I need to insert an image into a certain place - that place is defined by a Content Controll element that can be in the main part of document, header of footer.

I'm getting content controll like this:

static IEnumerable<TElement> GetDecendants<TElement>(OpenXmlPart part) where TElement : OpenXmlElement
{
    var result = part.RootElement
        .Descendants()
        .OfType<TElement>();

    return result;
}

Later down the pipeline I need to insert an image to the correct part of the document via this

internal static OpenXmlElement InsertImage(OpenXmlPart documentPart, Stream stream, string fileName, int imageWidth, int imageHeight)
{
    // actual implementation that is tested and works
}

Now my problem is that when I discover a ContentControl element that needs to be replaced by an image, I don't have a reference to documentPart - I only have reference so SdtRun or SdtBlock.

Is there a way to navigate to documentPart from SdtRun? I've checked .Parent but could not find a way to go from OpenXmlElement to OpenXmlPart - these are in different hierarchies.


Solution

  • I recommend the below method. It uses Ancestor to avoid recursion and takes advantage of the short-circuiting Null-conditional Operators from C# 6.

        internal static OpenXmlPart GetMainDocumentPart(OpenXmlElement xmlElement)
        {
            return
            xmlElement?.Ancestors<Document>()?.FirstOrDefault()?.MainDocumentPart as OpenXmlPart ??
            xmlElement?.Ancestors<Footer>()?.FirstOrDefault()?.FooterPart as OpenXmlPart ??
            xmlElement?.Ancestors<Header>()?.FirstOrDefault()?.HeaderPart as OpenXmlPart;
        }