C# 根据模版写Excel(Com)二

《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下测试通过

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值