65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.58/5 (9投票s)

2011 年 4 月 29 日

CPOL

3分钟阅读

viewsIcon

58341

downloadIcon

2547

本文包含有关如何在 Word 文档中更新图表的信息。

引言

本文包含有关如何以编程方式使用 Open XML 2.0 更新 Word 文档中的图表的信息。

背景

假设您有一个 Word 文档,您想要使用一些新值来更新一个图表。我在 Google 上搜索了一些关于如何执行此操作的示例,但这些文章总是忽略了一个事实,即您需要再次打开 Word 文档,右键单击图表,打开“编辑数据”,然后关闭电子表格才能更新这些值。此应用程序展示了如何自动完成这一切。

使用代码

在 Word 文档中添加图表

  1. 启动 Microsoft Word 2007(或更高版本)。
  2. 导航到“插入”选项卡。
  3. 单击插图框中的“图表”图标。
  4. 对于此示例,通过从列模板中选择它来添加一个三维柱形图。
  5. 这现在将打开一个包含一些默认值的电子表格。关闭此窗口。
  6. 图表现在将出现在 Word 文档中
  7. 保存文档并关闭它。

实现细节

要在 Word 文档中更新图表,您需要

  1. 更新电子表格单元格
  2. 获取 docx 文件中的图表部分
  3. 找到与电子表格单元格相对应的元素
  4. 更新元素
  5. 保存文档

我在某处找到了 UpdateChart 方法和 InsertCellInWorksheet 方法中的代码并使用了它。这些方法可以通过在 Google 中搜索“图表更新”来找到。然后我创建了 ModifyChartSimplifiedModifyChartDetailed 方法来实际更新 Word 文档。 ModifyChartSimplifiedModifyChartDetailed 方法执行完全相同的操作,但它们只是说明了您可以在 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 日 - 创建并发布应用程序
© . All rights reserved.