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.
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;
}
Having gone through the source code of OpenXML I have found a method that did what I needed. Only it was marked internal and I could not use it in my code.
So I came up with this:
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using System;
internal static class XmlElementHelpers
{
internal static OpenXmlPart GetDocumentPart(this OpenXmlElement xmlElement)
{
if (xmlElement == null)
{
return null;
}
if (xmlElement is Document document)
{
return document.MainDocumentPart;
}
if (xmlElement is Header header)
{
return header.HeaderPart;
}
if (xmlElement is Footer footer)
{
return footer.FooterPart;
}
return GetDocumentPart(xmlElement.Parent);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With