使用 OpenXML 更新 Word 文档中的图表






4.58/5 (9投票s)
本文包含有关如何在 Word 文档中更新图表的信息。
引言
本文包含有关如何以编程方式使用 Open XML 2.0 更新 Word 文档中的图表的信息。
背景
假设您有一个 Word 文档,您想要使用一些新值来更新一个图表。我在 Google 上搜索了一些关于如何执行此操作的示例,但这些文章总是忽略了一个事实,即您需要再次打开 Word 文档,右键单击图表,打开“编辑数据”,然后关闭电子表格才能更新这些值。此应用程序展示了如何自动完成这一切。
使用代码
在 Word 文档中添加图表
- 启动 Microsoft Word 2007(或更高版本)。
- 导航到“插入”选项卡。
- 单击插图框中的“图表”图标。
- 对于此示例,通过从列模板中选择它来添加一个三维柱形图。
- 这现在将打开一个包含一些默认值的电子表格。关闭此窗口。
- 图表现在将出现在 Word 文档中
- 保存文档并关闭它。
实现细节
要在 Word 文档中更新图表,您需要
- 更新电子表格单元格
- 获取 docx 文件中的图表部分
- 找到与电子表格单元格相对应的元素
- 更新元素
- 保存文档
我在某处找到了 UpdateChart
方法和 InsertCellInWorksheet
方法中的代码并使用了它。这些方法可以通过在 Google 中搜索“图表更新”来找到。然后我创建了 ModifyChartSimplified
和 ModifyChartDetailed
方法来实际更新 Word 文档。 ModifyChartSimplified
和 ModifyChartDetailed
方法执行完全相同的操作,但它们只是说明了您可以在 Word 文档文件中导航 XML 元素的方式。
如果您在 Deflector 工具中打开 Word 文档,然后单击 /word/document.xml 下的“图表”元素,您可以进一步向下钻取,并查看存储图表数据的 XML 数据。
下面我只展示了存储在文档文件中的“系列 1”XML 数据
<c:chartSpace xmlns:c="http://schemas.openxmlformats.org/drawingml/2006/chart"
xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
<c:date1904 val="1" />
<c:lang val="en-US" />
<c:chart>
<c:view3D>
<c:perspective val="30" />
</c:view3D>
<c:plotArea>
<c:layout />
<c:bar3DChart>
<c:barDir val="col" />
<c:grouping val="clustered" />
<c:ser>
<c:idx val="0" />
<c:order val="0" />
<c:tx>
<c:strRef>
<c:f>Sheet1!$B$1</c:f>
<c:strCache>
<c:ptCount val="1" />
<c:pt idx="0">
<c:v>Series 1</c:v>
</c:pt>
</c:strCache>
</c:strRef>
</c:tx>
<c:cat>
<c:strRef>
<c:f>Sheet1!$A$2:$A$5</c:f>
<c:strCache>
<c:ptCount val="4" />
<c:pt idx="0">
<c:v>Category 1</c:v>
</c:pt>
<c:pt idx="1">
<c:v>Category 2</c:v>
</c:pt>
<c:pt idx="2">
<c:v>Category 3</c:v>
</c:pt>
<c:pt idx="3">
<c:v>Category 4</c:v>
</c:pt>
</c:strCache>
</c:strRef>
</c:cat>
<c:val>
<c:numRef>
<c:f>Sheet1!$B$2:$B$5</c:f>
<c:numCache>
<c:formatCode>General</c:formatCode>
<c:ptCount val="4" />
<c:pt idx="0">
<c:v>4.3</c:v>
</c:pt>
<c:pt idx="1">
<c:v>2.5</c:v>
</c:pt>
<c:pt idx="2">
<c:v>3.5</c:v>
</c:pt>
<c:pt idx="3">
<c:v>4.5</c:v>
</c:pt>
</c:numCache>
</c:numRef>
</c:val>
</c:ser>
如果您查看我的 ModifiedDetailed
方法,您可以看到我基本上钻取了每个元素并获取了下一个元素。 这对于学习 OpenXML 格式来说是一个很好的练习。
private void ModifyChartDetailed
(string cellColumn, uint intRow, string cellValue, bool axisValue)
{
try
{
ChartPart c_p = this.mainDocPart.ChartParts.FirstOrDefault();
Chart chart = c_p.ChartSpace.Descendants<Chart>().FirstOrDefault();
PlotArea p_c = chart.PlotArea;
Bar3DChart b3d = p_c.Descendants<Bar3DChart>().FirstOrDefault();
BarChartSeries bs1 = b3d.Descendants<BarChartSeries>().Where(s =>
string.Compare(s.InnerText, "Sheet1!$" + cellColumn + "$1", true) > 0).First();
if (axisValue)
{
CategoryAxisData v1 = bs1.Descendants<CategoryAxisData>().FirstOrDefault();
StringReference sr = v1.Descendants<StringReference>().First();
StringCache sc = sr.Descendants<StringCache>().First();
StringPoint sp = sc.Descendants<StringPoint>().First();
NumericValue nv = sp.Descendants<NumericValue>().First();
nv.Text = cellValue;
}
else
{
DocumentFormat.OpenXml.Drawing.Charts.Values v1 = bs1.Descendants;
DocumentFormat.OpenXml.Drawing.Charts.Values>().FirstOrDefault();
NumberReference nr = v1.Descendants<NumberReference>().First();
NumberingCache nc = nr.Descendants<NumberingCache>().First();
NumericPoint np = nc.Descendants<NumericPoint>().ElementAt((int)intRow - 2);
NumericValue nv = np.Descendants<NumericValue>().First();
nv.Text = cellValue;
}
}
catch
{
// Chart Element is not in a recognizable format.
// Most likely the defined Chart is incorrect. Ignore the chart creation.
return;
}
}
在 ModifyChartSimplified
中,我只转到我知道我需要的元素并直接更新它们。
private void ModifyChartSimplified
(string cellColumn, uint intRow, string cellValue, bool axisValue)
{
try
{
ChartPart c_p = this.mainDocPart.ChartParts.FirstOrDefault();
BarChartSeries bs1 = c_p.ChartSpace.Descendants<BarChartSeries>().Where
(s => string.Compare(s.InnerText, "Sheet1!$" +
cellColumn + "$1", true) > 0).First();
if (axisValue)
{
NumericValue nv1 = bs1.Descendants<NumericValue>().First();
nv1.Text = cellValue;
}
else
{
DocumentFormat.OpenXml.Drawing.Charts.Values v1 =
bs1.Descendants<DocumentFormat.OpenXml.Drawing.Charts.Values>().FirstOrDefault();
NumericPoint np = v1.Descendants<NumericPoint>().ElementAt((int)intRow - 2);
NumericValue nv = np.Descendants<NumericValue>().First();
nv.Text = cellValue;
}
}
catch
{
// Chart Element is not in a recognizable format.
// Most likely the defined Chart is incorrect. Ignore the chart creation.
return;
}
}
关注点
使用 Deflector 工具确实帮助我很多,让我了解 OpenXML SDK 的工作原理。一开始它可能看起来令人难以承受,但它值得研究。
请随时评论本文以进行改进和批评。当我在 Google 上搜索如何在图像占位符中插入图片时,我发现许多文章使用直接 XML 来查找更新的位置。我认为一定有一种更简单的方法,只需使用 OpenXML 本身,令我欣慰的是,确实如此。
历史
- V1 - 2011 年 4 月 28 日 - 创建并发布应用程序