在 OpenXML 中处理 Word 文档时从 OpenXmlElement 获取 DocumentPart
Get DocumentPart from OpenXmlElement when working with Word document in OpenXML
我正在用 OpenXML API 和 运行 修改一个 docx 模板变成一个问题。
我需要将图像插入特定位置 - 该位置由 Content Controll 元素定义,该元素可以位于文档的主体部分、页眉页脚中。
我正在像这样控制内容:
static IEnumerable<TElement> GetDecendants<TElement>(OpenXmlPart part) where TElement : OpenXmlElement
{
var result = part.RootElement
.Descendants()
.OfType<TElement>();
return result;
}
稍后我需要通过此
将图像插入到文档的正确部分
internal static OpenXmlElement InsertImage(OpenXmlPart documentPart, Stream stream, string fileName, int imageWidth, int imageHeight)
{
// actual implementation that is tested and works
}
现在我的问题是,当我发现需要用图像替换的 ContentControl 元素时,我没有对 documentPart
的引用 - 我只有 SdtRun
或SdtBlock
.
有没有办法从 SdtRun
导航到 documentPart
?我检查了 .Parent
但找不到从 OpenXmlElement
到 OpenXmlPart
的方法 - 它们处于不同的层次结构中。
在浏览了 OpenXML 的源代码后,我发现了一种方法可以满足我的需要。只有它被标记为 internal
,我无法在我的代码中使用它。
所以我想到了这个:
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);
}
}
我推荐以下方法。它使用来自 C# 6 的 Ancestor to avoid recursion and takes advantage of the short-circuiting Null-conditional Operators。
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;
}
我正在用 OpenXML API 和 运行 修改一个 docx 模板变成一个问题。
我需要将图像插入特定位置 - 该位置由 Content Controll 元素定义,该元素可以位于文档的主体部分、页眉页脚中。
我正在像这样控制内容:
static IEnumerable<TElement> GetDecendants<TElement>(OpenXmlPart part) where TElement : OpenXmlElement
{
var result = part.RootElement
.Descendants()
.OfType<TElement>();
return result;
}
稍后我需要通过此
将图像插入到文档的正确部分internal static OpenXmlElement InsertImage(OpenXmlPart documentPart, Stream stream, string fileName, int imageWidth, int imageHeight)
{
// actual implementation that is tested and works
}
现在我的问题是,当我发现需要用图像替换的 ContentControl 元素时,我没有对 documentPart
的引用 - 我只有 SdtRun
或SdtBlock
.
有没有办法从 SdtRun
导航到 documentPart
?我检查了 .Parent
但找不到从 OpenXmlElement
到 OpenXmlPart
的方法 - 它们处于不同的层次结构中。
在浏览了 OpenXML 的源代码后,我发现了一种方法可以满足我的需要。只有它被标记为 internal
,我无法在我的代码中使用它。
所以我想到了这个:
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);
}
}
我推荐以下方法。它使用来自 C# 6 的 Ancestor to avoid recursion and takes advantage of the short-circuiting Null-conditional Operators。
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;
}