Create a report in excel 2007 with Open Xml SDK 10
I need a program that send by email some reports each day to a certain number of recipients. The first thing I need to solve is the format of the report, a pdf could be a good thing, but I need to find a library to generate pdf etc etc. The best solution is to use Excel 2007 and send the whole excel file by email. The good thing about excel is that he already possess an incredible number of graph style, and thanks to the open Xml format creating a report is a breeze.
The first step is create a master document, the master document will contain a single row of data, and you can create the graphics the way you like.
Now we only need to modify the file adding real data and updating graphics range to accommodate the new data. My first tentative is to build an ExcelFiller class that can do this for me with simple syntax. You can find the whole file here, you can use as starting point if you need.
|
|
As usual in the constructor you need to copy the original file in another position to be able to modify the document. Then you can call the method FillSheet that return a ExcelFillerSheet, a simple class that is used to phisically do the substitution. In the constructor of ExcelFillerSheet I simply create some Linq 2 XML structure of the basic part of the documetn
|
|
Thanks to the GetStream() methods of the SDK objects I can read the whole xml content in one step, so I first get the WorkBookPart of the whole excel file. In this file there are all the informations on contained sheets, and more. Then I call GetWorksheetByName function to grab the XML content of a worksheet given its name.
|
|
Thanks to Linq 2 XML finding the id of the worksheet is really simple, I look for all descendants nodes named <sheet> (do not forget the namespace), then I filter the only one with the name attribute equal to desidered name and take the Single node. When you have the id of the sheet you can simply use GetPartById to grab a reference to the desidered sheet.
To make the code simple I store all new values in a List<List<Object>> structure, this is not the best option, but it works :D. When you finished to insert data you can call the SaveData routine.
|
|
Modifying the document is a two phase process. In the first part I create a new list of XElement that will be filled with all the rows of the sheet. In line 6 I copy into this array the first X lines of the graph (since I need to open a graph and add data to some other existing data). The next step is creating an XElement for each row you want to insert. In line 3 I used LINQ 2 XML to grab a reference to the <sheetData> node, in line 26 I remove all actual elements (all the rows) and reinsert the new list of row. The final step is grabbing again the stream associated with the worksheet, and this time write down the new content.
The operation is still not completed, if you open the document you can see that new data are there, but the graph still shows old numbers. This happens because the graph stores a reference of the original range of values, you need to update it.
|
|
Now it is finally done. In line 3 I grab the first ChartParts of the worksheet, this because I know that the graphs is the only one included in the worksheet. In the first part I cycle through the elements of type <cat> where categories are stored. The value numRows is passed by the caller, and it is the number of rows you want to include in the graph. in line 15 you can see that I simply change the range of the graph to accommodate new data. Since my graph have two distinct sets of values, in line 18 I select all nodes <val>, then I change the range in line 26, starting from column B. Here it is a simple test.
|
|
If you run it with the original document the result is this.
As you can check all values are inserted correctly, and the graph is updated with the new data.
Some people asked me why I do not use the 2.0 SDK that has some strongly typed classes to manipulate data the answer is. I need to put this code in production and cannot use a CTP library. Moreover using the old 1.0 SDK you have full control over XML data, and there is no limit to the complexity of the documents you can create.
alk.