【问题标题】:Should I Convert excel to csv or write htmltable to csv我应该将 excel 转换为 csv 还是将 htmltable 写入 csv
【发布时间】:2015-01-22 18:16:12
【问题描述】:

我的应用程序中有 10 个报告,我让用户导出到 Excel。我从来没有写过 CSV 文件。在我现有的应用程序中,我将存储过程的结果转换为 HTML 表并将其写入 Excel。我的一些存储过程的结果有动态列,所以我使用 dapper。我的新要求是也提供 CSV 导出。

所以我应该先将html数据表转换为excel并将其转换为CSV还是将HTML数据表写入CSV。我不想手动解析,因为有 10 种不同的报告具有不同的列,并且一些报告具有动态列,所以我无法手动解析。

存储的过程返回 Dapper、动态列

EFDbContext db = new EFDbContext();
        var recordDate = StartDate.Date;
        var cnn = new SqlConnection(db.Database.Connection.ConnectionString);
        cnn.Open();
        var p = new DynamicParameters();
        p.Add("@StartDate", StartDate);
        p.Add("@UserRoleID", UserRoleID);
        p.Add("@SelectedSystemIDs", SelectedSystemIDs);
        p.Add("@SelectedPartIDs", SelectedPartIDs);
        p.Add("@SelectedSubSystems", SelectedSubsystems);
        p.Add("@SelectedServiceTypes", SelectedServiceTypes);

    var obs = cnn.Query(sql: "spExportInstrumentConfigAll", param: p, commandType: CommandType.StoredProcedure);

    var dt = ToDataTable(obs);

    return ExportDatatableToHtml(dt);


 public static DataTable ToDataTable(IEnumerable<dynamic> items)
        {
            if (items == null) return null;
            var data = items.ToArray();
            if (data.Length == 0) return null;

            var dt = new DataTable();
            foreach (var pair in ((IDictionary<string, object>)data[0]))
            {
                dt.Columns.Add(pair.Key, (pair.Value ?? string.Empty).GetType());
            }
            foreach (var d in data)
            {
                dt.Rows.Add(((IDictionary<string, object>)d).Values.ToArray());
            }
            return dt;
        }



public static string ExportDatatableToHtml(DataTable dt)
    {
        StringBuilder strHTMLBuilder = new StringBuilder();
        strHTMLBuilder.Append("<html >");
        strHTMLBuilder.Append("<head>");
        strHTMLBuilder.Append("</head>");
        strHTMLBuilder.Append("<body>");
        strHTMLBuilder.Append("<table border='1px' cellpadding='1' cellspacing='1 style='font-family:Garamond; font-size:medium'>");
    strHTMLBuilder.Append("<tr >");
    foreach (DataColumn myColumn in dt.Columns)
    {
        strHTMLBuilder.Append("<td >");
        strHTMLBuilder.Append(myColumn.ColumnName);
        strHTMLBuilder.Append("</td>");

    }
    strHTMLBuilder.Append("</tr>");


    foreach (DataRow myRow in dt.Rows)
    {

        strHTMLBuilder.Append("<tr >");
        foreach (DataColumn myColumn in dt.Columns)
        {
            strHTMLBuilder.Append("<td >");
            strHTMLBuilder.Append(myRow[myColumn.ColumnName].ToString());
            strHTMLBuilder.Append("</td>");

        }
        strHTMLBuilder.Append("</tr>");
    }

    //Close tags.  
    strHTMLBuilder.Append("</table>");
    strHTMLBuilder.Append("</body>");
    strHTMLBuilder.Append("</html>");

    string Htmltext = strHTMLBuilder.ToString();

    return Htmltext;

}

映射到实体的非动态列

    return db.Database.SqlQuery<ServiceEntryPartExportDataRow>("[dbo].[spExportServiceParts] @parm1, @parm2, @parm3, @parm4,@parm5,@parm6",
                new SqlParameter("parm1", StartDate),
                new SqlParameter("parm2", EndDate),
                new SqlParameter("parm3", Reconciled),
                new SqlParameter("parm4", ServiceTypes),
                new SqlParameter("parm5", SelectedSystemIDs),
                new SqlParameter("parm6", UserRoleID)
                ).ToList().ToHTMLTable();

 public static string ToHTMLTable<T>(this IList<T> data)
    {
        PropertyDescriptorCollection props =
            TypeDescriptor.GetProperties(typeof(T));

    StringBuilder builder = new StringBuilder();

    builder.Append("<table border=\"1\">");

    builder.Append("<tr>");

    for (int i = 0; i < props.Count; i++)
    {
        builder.Append("<td>");

        PropertyDescriptor prop = props[i];

        builder.Append(prop.Name);

        builder.Append("</td>");
    }
    builder.Append("</tr>");

    object[] values = new object[props.Count];
    foreach (T item in data)
    {
        builder.Append("<tr>");

        for (int i = 0; i < values.Length; i++)
        {
            builder.Append("<td>");

            builder.Append(props[i].GetValue(item));

            builder.Append("</td>");
        }

        builder.Append("</tr>");

    }

    builder.Append("</table>");
    return "<html><body>" + builder.ToString() + "</body></html";
}

当前代码发送到 Excel

return new PostActionResult(htmlTable, "ServiceEntryHistory", submit);

public PostActionResult(string htmlTable, string typeName, string submit) { this.htmlTable = htmlTable; this.typeName = typeName; this.submit = submit; }
        public PostActionResult(DataTable dataTable, string typeName, string submit) { this.dataTable = dataTable; this.typeName = typeName; this.submit = submit; }

        public override void ExecuteResult(ControllerContext context)
        {
            if (submit == "Excel")
            {
                ExcelHelpers.ExportToExcel(context.HttpContext, typeName, htmlTable);
            }
            if (submit == "CSV")
            {
                ExcelHelpers.ExportToExcelCSV(context.HttpContext, typeName, htmlTable);

            }
        }

  public static void ExportToExcel(HttpContextBase httpBase, string fileNamePrefix, string table)
        {
            string TimeStamp = DateTime.Now.ToLocalTime().ToString();
            string fileName = string.Format("attachment;filename={0}_{1}.xls", fileNamePrefix, TimeStamp);
            httpBase.Response.ClearHeaders();
            httpBase.Response.ClearContent();
            httpBase.Response.Clear();
            httpBase.Response.AddHeader("content-disposition", fileName);
            httpBase.Response.ContentType = "application/vnd.ms-excel";
            httpBase.Response.Write(table);
            httpBase.Response.End();
        }

【问题讨论】:

  • 实际的结构化数据在哪里?将记录集合导出到 CSV 相当简单。它基本上是一个循环和一个字符串生成器。 “动态列”不是问题。如果您有列名,则将它们打印为文件的第一行。如果不这样做,则只需打印其他内容(例如 Column{0} 带有递增的整数)。
  • 您在 ASP.NET 环境中使用 Office Interop,即bad idea。您应该停止这样做,并使用能够在不依赖 Interop 的情况下生成所需的本机 Excel 文件的库。如果你搜索“c# generate excel file”,你应该会得到很多有用的库。
  • @David 我发布了我的整个代码。对于具有动态列输出的报告,我使用 dapper,对于具有非动态列的报告,我映射了实体
  • @user721:构建 CSV 的代码与构建 HTML 表的代码几乎相同。您只能使用逗号、引号(特别是对于其中带有逗号的值)和回车符来代替 HTML 标记。除此之外,结构完全相同。事实上,CSV 与 HTML 是模板方法模式的经典示例。

标签: c# asp.net sql-server-2008 asp.net-mvc-3


【解决方案1】:

您已经有了从数据构建 HTML 表格的代码。构建 CSV 几乎相同。为简洁起见,让我们简化 HTML 表格伪代码

builder.Append("<table>");

// header
builder.Append("<tr>");
foreach (var column in columns)
    builder.Append("<th>" + column.name + "</th>");
builder.Append("</tr>");

// rows
foreach (var row in rows)
{
    builder.Append("<tr>");
    foreach (var column in row.columns)
        builder.Append("<td>" + column.value + "</td>");
    builder.Append("</tr>");
}

builder.Append("</table>");

构建 CSV 的结构完全相同:

// header
foreach (var column in columns)
    builder.Append("\"" + column.name + "\",");
// there's now an extra comma at the end.  remove it, or use a
// different method to have built the row, such as string.Join.

// rows
foreach (var row in rows)
{
    foreach (var column in row.columns)
        builder.Append("\"" + column.value + "\",");
    // there's now an extra comma at the end.  remove it, or use a
    // different method to have built the row, such as string.Join.
    builder.Append(Environment.NewLine);
}

请记住,这是徒手的伪代码,您可以使用一些清理方法。您还可以检查列类型以确定是否需要那些转义引号,因为数字类型不需要它们。但关键是结构是一样的。 CSV 是文本,就像 HTML 是文本一样。只是价值观不同而已。

旁注:这实际上是Template Method Pattern 的经典示例。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-07-02
    • 2014-11-19
    • 2012-10-10
    • 2016-11-30
    • 1970-01-01
    • 1970-01-01
    • 2012-04-24
    • 2015-01-07
    相关资源
    最近更新 更多