《C# 根据模版写Excel(Com)一 》 里给出写Excel的主要类
这里给出2个辅助类。
这2个类用来 读Excel模版的xml描述文件
和 写入Excel的sheet 用的
/// <summary> /// 根据数据结果集,修改临时文件内容 /// </summary> /// <param name="ds">要传入到Excel的数据集</param> /// <returns></returns> private void writeExcelContent(Object o) { try { ExcelObj.Visible = false; ExcelDescriptions a = new ExcelDescriptions(); Hashtable templateXml = a.parseXml(templateDiscriptionFilePath); WookSheetWrite wStW = new WookSheetWrite(xSt); wStW.setWorksheet(o, templateXml); ........... }
就是这个 方法里 用到的 2个类
首先是读Excel模版的xml描述文件的类
using System; using System.Data; using System.Configuration; using System.Linq; using System.Xml.Linq; using System.Xml; using System.Collections.Generic; using System.Collections; using System.Reflection; /// <summary> /// 解析Excel模版对应的xml描述文件 /// </summary> public class ExcelDescriptions { /// <summary> /// 解析模版描述文件到 Hashtable /// </summary> /// <param name="descriptionFilePath">解析模版描述文件 全名</param> /// <returns>包含模版描述文件信息的 /// Hashtable: key:字段名 或 类名, /// value:对应模版文件坐标(例如:A1), 或 一个Hashtable /// 当key为类名时, value:为一个Hashtable; /// 这个关系 最多为二层 /// </returns> public Hashtable parseXml(string descriptionFileName) { Hashtable templateXml = new Hashtable(); XmlDocument xmlDoc = new XmlDocument(); try{ //xmlDoc.Load(AppDomain.CurrentDomain.BaseDirectory + "xml/Template1.xml"); xmlDoc.Load(descriptionFileName); } catch(Exception ex){ throw new Exception("没有找到模版描述文件"); } //每个 Excel模版对应一个 描述文件 table节点 是唯一的 XmlNode xn = xmlDoc.SelectSingleNode("table"); XmlNodeList xnl = xn.ChildNodes; //因为只有2层 所以就直接写在这里了 foreach (XmlNode xnf in xnl) { XmlElement xeOuter = (XmlElement)xnf; //map 的key为 字段名, 或类名; // value为 对应的模版的单元格的 坐标. 例如:A1 if (xeOuter.HasChildNodes) { //内层 Hashtable //Hashtable: key:字段名 // value:对应模版文件坐标(例如:A1), //内层Hashtable 不可以再 包含Hashtable Hashtable templateXmlInner = new Hashtable(); XmlNodeList xnlInner = xeOuter.ChildNodes; foreach (XmlNode xnfInner in xnlInner) { XmlElement xeInner = (XmlElement)xnfInner; templateXmlInner.Add(xeInner.GetAttribute("filed").ToString().Trim(), xeInner.GetAttribute("coordinates").ToString().Trim()); } templateXml.Add(xeOuter.GetAttribute("filed").ToString().Trim(), templateXmlInner); } else { templateXml.Add(xeOuter.GetAttribute("filed").ToString().Trim(), xeOuter.GetAttribute("coordinates").ToString().Trim()); } } return templateXml; } }
对应的xml文件, 这个文件是自己定义的
<?xml version="1.0" encoding="utf-8" ?> <table name="User"> <Cell coordinates="A1" filed="name"></Cell> <Cell coordinates="A2" filed="sex"></Cell> <Cell coordinates="B1" filed="age"></Cell> <Cell coordinates="B2" filed="id"></Cell> <Cells filed="car"> <Cell coordinates="B20" filed="id"></Cell> <Cell coordinates="E20" filed="name"></Cell> </Cells> <Cells filed="address"> <Cell coordinates="D37" filed="id"></Cell> <Cell coordinates="D38" filed="name"></Cell> </Cells> </table>
然后是写入Excel文件的类
using System; using System.Data; using System.Configuration; using System.Linq; using System.Web; using System.Web.Security; using Excel = Microsoft.Office.Interop.Excel; using System.Collections; using System.Collections.Generic; using System.Text.RegularExpressions; using System.Reflection; /// <summary> /// 根据模版文件, 描述信息 和 数据集 /// 写Excel 的 sheet /// </summary> public class WookSheetWrite { private object missing = System.Reflection.Missing.Value; //工作Sheet private Excel._Worksheet xSt; public WookSheetWrite(Excel._Worksheet _xSt) { if (_xSt == null) { throw new Exception("目标 Excel 的 sheet对象 为空"); } else { this.xSt = _xSt; } } /// <summary> /// 根据模版, 模版描述文件的 Hashtable, 以及数据对象来填充Excel /// </summary> /// <param name="dataObject">数据集对象, /// 这里的数据集对象 为 linq查出来的实体对象, /// 该实体对象可能包含另外一个或多个实体对象, /// 或 另外一个或多个实体对象的List。 /// </param> /// <param name="templateXml">装载模版描述文件的信息的 Hashtable /// 该Hashtable /// Hashtable: key:字段名 或 类名, /// value:对应模版文件坐标(例如:A1), 或 一个Hashtable /// 当key为类名时, value:为一个Hashtable; /// 这个关系 最多为二层 /// </param> public void setWorksheet(Object dataObject, Hashtable templateXml) { if(dataObject == null) { throw new Exception("数据集对象为空"); } foreach (string filedName in templateXml.Keys) { Object value = templateXml[filedName]; if (value == null) { throw new Exception("指定的数据集的属性:" + filedName + " 为空"); } if (value is Hashtable) { //如果sheet对象里包含 循环结构 //dataObject数据集里 对应的一个List Object innerDataObject = getFiled(dataObject, filedName); if (innerDataObject is IList) { setCells(value, (IList)innerDataObject); //数据集属性类型 为一个List } else { setCells(value, innerDataObject); //数据集属性类型 为一个实体对象 } } else { string coordinates = value.ToString(); string data = getFiled(dataObject, filedName).ToString(); xSt.get_Range(coordinates, missing).Value2 = data; } } } /// <summary> /// 填充一组单元格。这组单元格有如下特征: /// 1,这些单元个的字段组合起来是一个类的属性 /// 2,这些单元个顺序排列在一行里 /// 3, 这些单元个所在行的接下来几行的值,可以通过循环填充 /// </summary> /// <param name="value"> /// Hashtable里指定key对应的 值, 这里仍然是一个Hashtable /// 存放的是,key:特定对象的属性名, value:对应的坐标</param> /// <param name="innerList"> /// 指定数据集对象里包含的IList对象, /// IList里包含的对象就是 value 里的属性对应的对象 /// </param> private void setCells(Object value, IList innerList) { Hashtable templateXmlInner = (Hashtable)value; //循环IList 填充行 for (int i = 0; i < innerList.Count; i++) { Object innerObject = innerList[i]; //循环Hashtable填充单元格组 foreach (string filedNameInner in templateXmlInner.Keys) { string coordinates = templateXmlInner[filedNameInner].ToString(); //对应单元个的行坐标 string innerNum = getRowNo(coordinates); //将行坐标+i返回,第一次为第一行, 第二次为第二行,循环填充 coordinates = coordinates.Replace(innerNum, (int.Parse(innerNum) + i).ToString()); //这里还没有判断 模版预留行数量小于 数据数量的情况 //取得对应单元格的数据 string dataInnert = getFiled(innerObject, filedNameInner).ToString(); xSt.get_Range(coordinates, missing).Value2 = dataInnert; } } } /// <summary> /// 填充一组单元格。这组单元格有如下特征: /// 1,这些单元个的字段组合起来是一个类的属性 /// </summary> /// <param name="value"> /// Hashtable里指定key对应的 值, 这里仍然是一个Hashtable /// 存放的是,key:特定对象的属性名, value:对应的坐标</param> /// <param name="innerDataObject"> /// 指定数据集对象里的 一个数据对象 /// 该对象的属性与Hashtable的key 一一对应 /// </param> private void setCells(Object value, Object innerDataObject) { Hashtable templateXmlInner = (Hashtable)value; //循环Hashtable填充单元格组 foreach (string filedNameInner in templateXmlInner.Keys) { string coordinates = templateXmlInner[filedNameInner].ToString(); string data = getFiled(innerDataObject, filedNameInner).ToString(); xSt.get_Range(coordinates, missing).Value2 = data; } } /// <summary> /// 通过类 和 属性名 得到该类的该属性的值 /// </summary> /// <param name="dataObject">类对象</param> /// <param name="filedName">字符串类型的属性名</param> /// <returns></returns> private Object getFiled(Object dataObject, string filedName) { if (string.IsNullOrEmpty(filedName)) { throw new Exception("属性名为空"); } PropertyInfo field = dataObject.GetType().GetProperty(filedName); if (field == null) { throw new Exception("在类: " + dataObject.GetType().Name.ToString() + " 中不存在名为: " + filedName + " 的属性"); } return field.GetValue(dataObject, null); } /// <summary> /// 取出Excel对应单元格坐标的行号 /// </summary> /// <param name="coordinates">坐标(列:A1)</param> /// <returns>单元个的行坐标</returns> private static string getRowNo(string coordinates) { //取出坐标中的数字 “A1” 中的 “1” if (string.IsNullOrEmpty(coordinates)) { throw new Exception("模版坐标为空"); } Regex rg = new Regex("\\D"); return rg.Replace(coordinates, ""); } }
这样只要有 Excel模版 和 模版描述文件 我们就可以 写Excel文件了
vs2008下测试通过