I have asked a related question in this form.The problem is I can only change the data in Chart.xml but can't change the data in .xlsx file related to the chart.xml.
the code is :
//-----------------------------------------------------------------------
// This application was created by Imran Mohamed on April 28, 2011
// It programmaticallly updates a chart inside a Word Document
// This code is licensed under the Code Project Open License CPOL
//-----------------------------------------------------------------------
namespace chartUpdate
{
#region Directives
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Text;
using System.Xml.XPath;
using System.IO.Packaging;
using System.Reflection;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Drawing.Charts;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
using DocumentFormat.OpenXml.Wordprocessing;
#endregion
/// <summary>
/// Class for updating and resizing images in an Image Placeholder
/// </summary>
public class ChartUpdate
{
#region Private Fields
/// <summary>
/// Contains the word processing document
/// </summary>
private WordprocessingDocument wordProcessingDocument;
/// <summary>
/// Contains the main document part
/// </summary>
private MainDocumentPart mainDocPart;
#endregion
#region Public Methods
#region OpenTheDocuemnt
/// <summary>
/// Open an Word XML document
/// </summary>
/// <param name="docname">name of the document to be opened</param>
public void OpenTheDocuemnt(string docname)
{
// open the word docx
wordProcessingDocument = WordprocessingDocument.Open(docname, true);
// get the Main Document part
mainDocPart = wordProcessingDocument.MainDocumentPart;
}
#endregion
#region CloseTheDocument
/// <summary>
/// Close the document
/// </summary>
public void CloseTheDocument()
{
wordProcessingDocument.Close();
}
#endregion
#region UpdateChart
/// <summary>
/// Updates the Chart in a word docuemnt.
/// </summary>
/// <param name="cellColumn">Corresponds to the Column that needs to be modified</param>
/// <param name="intRow">Corresponds to the Row that needs to be modified</param>
/// <param name="newValue">New value of the pointed cell</param>
/// <param name="axisValue">Is the new value an Axis Value?</param>
public void UpdateChart(string cellColumn, uint intRow, string newValue, bool axisValue)
{
// Gets the Chart stream
Stream stream = this.wordProcessingDocument.MainDocumentPart.ChartParts.First().EmbeddedPackagePart.GetStream();
// Open the internal spreadsheet doc for the chart
using (SpreadsheetDocument wordSSDoc = SpreadsheetDocument.Open(stream, true))
{
// Navigate to the sheet where the chart data is located
WorkbookPart workBookPart = wordSSDoc.WorkbookPart;
Sheet theSheet = workBookPart.Workbook.Descendants<Sheet>().
Where(s => s.Name == "Sheet1").FirstOrDefault();
if (theSheet != null)
{
Worksheet ws = ((WorksheetPart)workBookPart.GetPartById(theSheet.Id)).Worksheet;
// Get the cell which needs to be updated
Cell theCell = InsertCellInWorksheet(cellColumn, intRow, ws);
// Update the cell value
theCell.CellValue = new CellValue(newValue);
if (axisValue)
{
// We are updating the Series text
theCell.DataType = new EnumValue<CellValues>(CellValues.String);
}
else
{
// We are updating a numeric chart value
theCell.DataType = new EnumValue<CellValues>(CellValues.Number);
}
// Either one of these methods work. It is just to illustrate the different elements that the OpenXML goes through
//this.ModifyChartDetailed(cellColumn, intRow, newValue, axisValue);
this.ModifyChartSimplified(cellColumn, intRow, newValue, axisValue);
ws.Save();
}
}
}
#endregion
#endregion
#region Private Methods
#region InsertCellInWorksheet
/// <summary>
/// Gets the cell where the updated value is going to be placed
/// </summary>
/// <param name="columnName">Corresponds to the Column that needs to be modified</param>
/// <param name="rowIndex">Corresponds to the Row that needs to be modified</param>
/// <param name="worksheet">WorkSheet to update</param>
/// <returns> The cell where the new value is going to get updated to</returns>
private static Cell InsertCellInWorksheet(string columnName, uint rowIndex, Worksheet worksheet)
{
SheetData sheetData = worksheet.GetFirstChild<SheetData>();
string cellReference = columnName + rowIndex;
Row row;
if (sheetData.Elements<Row>().Where(r => r.RowIndex == rowIndex).Count() != 0)
{
row = sheetData.Elements<Row>().Where(r => r.RowIndex == rowIndex).First();
}
else
{
row = new Row() { RowIndex = rowIndex };
sheetData.Append(row);
}
if (row.Elements<Cell>().Where(c => c.CellReference.Value == columnName + rowIndex).Count() > 0)
{
return row.Elements<Cell>().Where(c => c.CellReference.Value == cellReference).First();
}
else
{
Cell refCell = null;
foreach (Cell cell in row.Elements<Cell>())
{
if (string.Compare(cell.CellReference.Value, cellReference, true) > 0)
{
refCell = cell;
break;
}
}
Cell newCell = new Cell() { CellReference = cellReference };
row.InsertBefore(newCell, refCell);
worksheet.Save();
return newCell;
}
}
#endregion
#region ModifyChartDetailed
/// <summary>
/// Updates the Cached Chart data in the Word document file
/// </summary>
/// <param name="cellColumn">Corresponds to the Column that needs to be modified</param>
/// <param name="intRow">Corresponds to the Row that needs to be modified</param>
/// <param name="cellValue">New value of the pointed cell</param>
/// <param name="axisValue">Is the new value an Axis Value?</param>
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;
}
}
#endregion
#region ModifyChartSimplified
/// <summary>
/// Updates the Cached Chart data in the Word document file
/// </summary>
/// <param name="cellColumn">Corresponds to the Column that needs to be modified</param>
/// <param name="intRow">Corresponds to the Row that needs to be modified</param>
/// <param name="cellValue">New value of the pointed cell</param>
/// <param name="axisValue">Is the new value an Axis Value?</param>
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;
}
}
#endregion
#endregion
}
class Program
{
static void Main(string[] args)
{
ChartUpdate u = new ChartUpdate();
// copy the word doc so you can see the difference between the two
File.Delete("test1.docx");
File.Copy("test.docx", "test1.docx");
u.OpenTheDocuemnt("test1.docx");
u.UpdateChart("B", 2, "20", false);
u.UpdateChart("A", 2, "test", true);
u.CloseTheDocument();
}
}
}
In Word , when I have a right mouse click on the chart Which I have changed the data by above codes,and then select the "edit data" item . The strangest thing
happened: The chart data changed suddenly! the data was same to the xlsx file's data! So I think I must change the data either in chart.xml or in .xlsx file,is it? And how can I do that?
赵召