I'm very close on this.
I'm trying to create a function that will locate and update an embeded chart within a Word document. Ultimately, the document will have sevral charts.
So far, my function can iterate through the document and find a chart (currently there is only one) and plug in some dummy info. It works, however when the document is opened, I get a pop-up complaining that the document is corrupt. I OK past that and a second pop-up asks me if I'd like to recover the document. I OK that and the document then opens and the chart is updated, all as if nothing were wrong.
So it winds up OK, but my users are not going to be happy with the "corrupt file" messages. When they're not happy, no one is happy.
Also, I'm looking for a methodology to find and update a specific chart. Currently I iterate through the document, and if I had to I could live with that but I'd like to implement something a little less fragile.
I was looking at perhaps using the "Title" property on the chart and attempting to have the SDK search for that. I'm a relative newbie to this SDK and can't seem to locate an example of that (or *ANYTHING* for that matter that attempts to find a specific chart in a document).
Here is my code so far. It's just a prototype, so it is maufacturing data for the cells and allthough it is iterating through the document, there is no method yet to target a specific chart:
private void updateChart( WordprocessingDocument doc ) { string rid = null; Stream stream = null; foreach ( Paragraph p in doc.MainDocumentPart.Document.Body.Elements<Paragraph>( ) ) { foreach ( Drawing d in p.Descendants<Drawing>( ) ) { foreach ( ChartReference cr in d.Descendants<ChartReference>( ) ) { rid = cr.Id.Value; ChartPart cp = ( ChartPart )doc.MainDocumentPart.Parts.Where( pt => pt.RelationshipId == rid ).FirstOrDefault( ).OpenXmlPart; foreach ( ExternalData ed in cp.ChartSpace.Elements< ExternalData >( ) ) { string externalDataRID = ed.Id.Value; EmbeddedPackagePart epp = ( EmbeddedPackagePart )cp.Parts.Where( pt => pt.RelationshipId == ed.Id ).FirstOrDefault( ).OpenXmlPart; using ( Stream str = epp.GetStream( ) ) { using ( MemoryStream ms = new MemoryStream( ) ) { CopyStream( str, ms ); using ( SpreadsheetDocument spreadsheetDoc = SpreadsheetDocument.Open( ms, true ) ) { ss.Sheet ws = ( ss.Sheet )spreadsheetDoc.WorkbookPart.Workbook.Sheets.FirstOrDefault( ); string sheetId = ws.Id; WorksheetPart wsp = ( WorksheetPart )spreadsheetDoc.WorkbookPart.Parts.Where( pt => pt.RelationshipId == sheetId ).FirstOrDefault( ).OpenXmlPart; ss.SheetData sd = wsp.Worksheet.Elements<ss.SheetData>( ).FirstOrDefault( ); int ctr = 0; foreach ( ss.Row row in sd.Elements< ss.Row >( ) ) { if ( ctr > 0 && ctr <= 6 ) { ss.CellValue cv0 = row.Elements<ss.Cell>( ).ElementAt( 0 ).Elements<ss.CellValue>( ).FirstOrDefault( ); cv0.Text = _monthsInRange[ ctr - 1 ].startDate.ToString( "MMM-yyyy" ); ss.CellValue cv1 = row.Elements<ss.Cell>( ).ElementAt( 1 ).Elements<ss.CellValue>( ).FirstOrDefault( ); cv1.Text = ( ctr * 10 ).ToString( ); ss.CellValue cv2 = row.Elements<ss.Cell>( ).ElementAt( 2 ).Elements<ss.CellValue>( ).FirstOrDefault( ); cv2.Text = ( ctr * 10 ).ToString( ); ss.CellValue cv3 = row.Elements<ss.Cell>( ).ElementAt( 3 ).Elements<ss.CellValue>( ).FirstOrDefault( ); cv3.Text = ( ctr * 10 ).ToString( ); ss.CellValue cv4 = row.Elements<ss.Cell>( ).ElementAt( 4 ).Elements<ss.CellValue>( ).FirstOrDefault( ); cv4.Text = ( ctr * 10 ).ToString( ); ss.CellValue cv5 = row.Elements<ss.Cell>( ).ElementAt( 5 ).Elements<ss.CellValue>( ).FirstOrDefault( ); cv5.Text = ( ctr * 10 ).ToString( ); }++ctr; } } using ( Stream s = epp.GetStream( ) ) { ms.WriteTo( s ); } } } Chart chart = cp.ChartSpace.Elements<Chart>( ).First( ); Bar3DChart bc = chart.Descendants<DocumentFormat.OpenXml.Drawing.Charts.Bar3DChart>( ).FirstOrDefault( ); if ( bc != null ) { foreach( BarChartSeries bcs in bc.Elements<BarChartSeries>( ) ) { CategoryAxisData cad = bcs.Descendants<CategoryAxisData>( ).FirstOrDefault( ); StringReference sr = cad.Descendants<StringReference>( ).FirstOrDefault( ); StringCache sc = sr.Descendants<StringCache>( ).First( ); int ctr = 0; foreach ( StringPoint sp in sc.Descendants<StringPoint>( ) ) { NumericValue nv = sp.Descendants<NumericValue>( ).First( ); nv.Text = _monthsInRange[ ctr ].startDate.ToString( "MMM-yyyy" );++ctr; } foreach ( Values values in bcs.Descendants<Values>( ) ) { NumberingCache nc = values.Descendants<NumberingCache>( ).First( ); NumericValue nv1 = nc.Elements<NumericPoint>( ).ElementAt( 0 ).Elements<NumericValue>( ).FirstOrDefault( ); nv1.Text = "10"; NumericValue nv2 = nc.Elements<NumericPoint>( ).ElementAt( 1 ).Elements<NumericValue>( ).FirstOrDefault( ); nv2.Text = "20"; NumericValue nv3 = nc.Elements<NumericPoint>( ).ElementAt( 2 ).Elements<NumericValue>( ).FirstOrDefault( ); nv3.Text = "30"; NumericValue nv4 = nc.Elements<NumericPoint>( ).ElementAt( 3 ).Elements<NumericValue>( ).FirstOrDefault( ); nv4.Text = "40"; NumericValue nv5 = nc.Elements<NumericPoint>( ).ElementAt( 4 ).Elements<NumericValue>( ).FirstOrDefault( ); nv5.Text = "50"; NumericValue nv6 = nc.Elements<NumericPoint>( ).ElementAt( 5 ).Elements<NumericValue>( ).FirstOrDefault( ); nv6.Text = "60"; } } } } } } } }
The embedded chart is based off a 5 column (well actually 6 - the first column is row headers) x 6 row spreadsheet.
Any help would be much appreciated.
JP
JP