数据表格转换为HTML表格

49

我有一个问题,希望这里的某个人不介意帮我解决。假设我有三个数据表,每个表都具有以下列:

大小、数量、金额、持续时间

数据表的名称和数值

LivingRoom
================
1
1
1
1
2
2
2
2

BathRoom
================
3
3
3
3
4
4
4
4

BedRoom
=================
5
5
5
5
6
6
6
6

现在我正在尝试构建一个HTML发票,以便我可以循环遍历所有数据表并输出以下基本的HTML输出:

<table>
  <tr>
    <td>Area</td>
  </tr>
  <tr>
    <td>Living Room</td>
  </tr>

  <tr>
    <td>Size</td>
    <td>Quantity</td>
    <td>Amount</td>
    <td>Duration</td>
  </tr>
  <tr>
    <td>1</td>
    <td>1</td>
    <td>1</td>
    <td>1</td>
  </tr>
  <tr>
    <td>2</td>
    <td>2</td>
    <td>2</td>
    <td>2</td>
  </tr>

  <tr>
    <td>Area</td>
  </tr>
  <tr>
    <td>Bathroom</td>
  </tr>

  <tr>
    <td>Size</td>
    <td>Quantity</td>
    <td>Amount</td>
    <td>Duration</td>
  </tr>
  <tr>
    <td>3</td>
    <td>3</td>
    <td>3</td>
    <td>3</td>
  </tr>
  <tr>
    <td>4</td>
    <td>4</td>
    <td>4</td>
    <td>4</td>
  </tr>

  <tr>
    <td>Area</td>
  </tr>
  <tr>
    <td>Bedroom</td>
  </tr>

  <tr>
    <td>Size</td>
    <td>Quantity</td>
    <td>Amount</td>
    <td>Duration</td>
  </tr>
  <tr>
    <td>5</td>
    <td>5</td>
    <td>5</td>
    <td>5</td>
  </tr>
  <tr>
    <td>6</td>
    <td>6</td>
    <td>6</td>
    <td>6</td>
  </tr>
</table>

基本上这个区域会有数据表的名称,然后在每个区域下循环该特定数据表并以该格式输出数据。我无法弄清楚循环逻辑或如何做到这一点,我已经在思考几天了。也许我只是用错误的方式思考,但我确实需要一些帮助。


你考虑过使用 <ListView> 吗? - Amber
但是如果有多个数据表,这样做是否可行?我能否像这样格式化它? - Brad Hazelnut
1
你能把它们合并成一个吗?http://msdn.microsoft.com/zh-cn/library/system.data.datatable.merge.aspx? - Zaki
我不确定您是否可以将所有数据表放入一个列表视图中,但是您应该可以像您所做的那样轻松地进行结构。如果您无法将所有数据表放入一个列表视图中,则可以在表格中放置三个列表视图并相应地填充它们。或者如果它们被分类了,可以使用嵌套的列表视图。 - Amber
10个回答

127

使用这个函数:

    public static string ConvertDataTableToHTML(DataTable dt)
    {
        string html = "<table>";
        //add header row
        html += "<tr>";
        for(int i=0;i<dt.Columns.Count;i++)
            html+="<td>"+dt.Columns[i].ColumnName+"</td>";
        html += "</tr>";
        //add rows
        for (int i = 0; i < dt.Rows.Count; i++)
        {
            html += "<tr>";
            for (int j = 0; j< dt.Columns.Count; j++)
                html += "<td>" + dt.Rows[i][j].ToString() + "</td>";
            html += "</tr>";
        }
        html += "</table>";
        return html;
    }

你如何将这个HTML字符串添加到屏幕上? - Arif YILMAZ
你会如何实现将其添加到DOM中? - LokizFenrir
1
C# ASP支持对实际的HTML控件进行操作,只需包含正确的using语句。using System.Web.UI.HtmlControls; - LokizFenrir
2
我使用了HttpUtility.HtmlEncode和StringBuilder来改进代码。感谢您的回答! - Marquinho Peli
3
可以进一步改进代码,使用foreach而不是普通的for循环来进行第一个循环。可以使用foreach(DataColumn col in dt.Columns),然后只需执行col.ColumnName即可。 - Tot Zam

12
public static string toHTML_Table(DataTable dt)
{
    if (dt.Rows.Count == 0) return ""; // enter code here

    StringBuilder builder = new StringBuilder();
    builder.Append("<html>");
    builder.Append("<head>");
    builder.Append("<title>");
    builder.Append("Page-");
    builder.Append(Guid.NewGuid());
    builder.Append("</title>");
    builder.Append("</head>");
    builder.Append("<body>");
    builder.Append("<table border='1px' cellpadding='5' cellspacing='0' ");
    builder.Append("style='border: solid 1px Silver; font-size: x-small;'>");
    builder.Append("<tr align='left' valign='top'>");
    foreach (DataColumn c in dt.Columns)
    {
        builder.Append("<td align='left' valign='top'><b>");
        builder.Append(c.ColumnName);
        builder.Append("</b></td>");
    }
    builder.Append("</tr>");
    foreach (DataRow r in dt.Rows)
    {
        builder.Append("<tr align='left' valign='top'>");
        foreach (DataColumn c in dt.Columns)
        {
            builder.Append("<td align='left' valign='top'>");
            builder.Append(r[c.ColumnName]);
            builder.Append("</td>");
        }
        builder.Append("</tr>");
    }
    builder.Append("</table>");
    builder.Append("</body>");
    builder.Append("</html>");

    return builder.ToString();
}

2
很适合复制和粘贴,我会添加一些东西: 1)对所有表格值进行HTML编码,例如:builder.Append(System.Web.HttpUtility.HtmlEncode(c.ColumnName))而不是builder.Append(c.ColumnName) 2)将标题指定为函数参数 - sarh
1
我无法理解你的评论 @sarh。 - Suman Banerjee
2
关于第一点:c.ColumnName 可能包含一些需要在 HTML 中进行转义的非法字符。例如,如果将字符串"<"直接放入 HTML 中,这样的 HTML 将会被损坏。应该像"<"一样进行转义。可以使用 System.Web.HttpUtility 来实现此功能。关于第二点-这只是代码声明,我认为最好将所需的标题传递给此方法,而不是使用新 GUID 值生成任意标题。无论如何,您的回答已经+1,因为该答案提供了完整的 HTML,而 StringBuilder 对于这么多字符串修改操作来说比字符串拼接更好。 - sarh
我知道这个问题已经有答案了很长时间,但我们鼓励提供解释清晰的回答,而不仅仅是复制粘贴。 - Malcolm Salvador

10

我见过一些值得注意的解决方案,就像Omer Eldan发布的那样。但是这里提供ASP C#的解决方案。


using System.Data;
using System.Web.UI.HtmlControls;

public static Table DataTableToHTMLTable(DataTable dt, bool includeHeaders)
{
    Table tbl = new Table();
    TableRow tr = null;
    TableCell cell = null;

    int rows = dt.Rows.Count;
    int cols = dt.Columns.Count;

    if (includeHeaders)
    {
        TableHeaderRow htr = new TableHeaderRow();
        TableHeaderCell hcell = null;
        for (int i = 0; i < cols; i++)
        {
            hcell = new TableHeaderCell();
            hcell.Text = dt.Columns[i].ColumnName.ToString();
            htr.Cells.Add(hcell);
        }
        tbl.Rows.Add(htr);
    }

    for (int j = 0; j < rows; j++)
    {
        tr = new TableRow();
        for (int k = 0; k < cols; k++)
        {
            cell = new TableCell();
            cell.Text = dt.Rows[j][k].ToString();
            tr.Cells.Add(cell);
        }
        tbl.Rows.Add(tr);
    }
    return tbl;
}

为什么选择这个解决方案? 因为你可以轻松地将它添加到面板中,如下:

panel.Controls.Add(DataTableToHTMLTable(dtExample,true));

第二个问题,为什么你使用单列的数据表而不是数组?你确定这些数据表是统一的吗?如果数据是不规则的,那就没有用了。如果您确实需要连接这些数据表,有许多 Linq 操作的示例,或者只需使用 (请注意相同名称的列将在 Linq 操作和此解决方案中发生冲突,如果未经处理):

public DataTable joinUniformTable(DataTable dt1, DataTable dt2)
{
    int dt2ColsCount = dt2.Columns.Count;
    int dt1lRowsCount = dt1.Rows.Count;

    DataColumn column;
    for (int i = 0; i < dt2ColsCount; i++)
    {
        column = new DataColumn();
        string colName = dt2.Columns[i].ColumnName;
        System.Type colType = dt2.Columns[i].DataType;
        column.ColumnName = colName;
        column.DataType = colType;
        dt1.Columns.Add(column);

        for (int j = 0; j < dt1lRowsCount; j++)
        {
            dt1.Rows[j][colName] = dt2.Rows[j][colName];
        }
    }
    return dt1;
}

你的解决方案可能看起来像这样:

panel.Controls.Add(DataTableToHTMLTable(joinUniformTable(joinUniformTable(LivDT,BathDT),BedDT),true));

理解其他内容,享受其中乐趣。


这可能是一个间接的答案,但我相信这些函数将帮助您朝着正确的方向并且在多个项目中使用它们非常强大,如果您发现这有用,请点赞。(如果您想友好一些,也可以分享给您的访客) - LokizFenrir
如果您想将此表呈现为字符串,请使用 https://dev59.com/AEnSa4cB1Zd3GeqPP6qQ#1525087 - Matthew Lock
@MatthewLock 为什么我要将它呈现为字符串?我已经测试过了,这样更高效和语法上更正确。不过还是谢谢你。 - LokizFenrir
2
我想将它保存到一个字符串中,以便插入到HTML电子邮件中。 - Matthew Lock

4
第一个答案是正确的,但如果你有大量的数据(在我的项目中,我有8000行*8列),那么速度会非常慢.... 在C#中使用一个变得如此庞大的字符串是被禁止的。
相反,我使用了一个字符串数组,在最后合并以返回html表格的字符串。此外,我使用了一个linq表达式((from o in row.ItemArray select o.ToString()).ToArray())来连接表中的每个DataRow,而不是再次循环,以尽可能节省时间。
这是我的示例代码:
private string MakeHtmlTable(DataTable data)
{
            string[] table = new string[data.Rows.Count] ;
            long counter = 1;
            foreach (DataRow row in data.Rows)
            {
                table[counter-1] = "<tr><td>" + String.Join("</td><td>", (from o in row.ItemArray select o.ToString()).ToArray()) + "</td></tr>";

                counter+=1;
            }

            return "</br><table>" + String.Join("", table) + "</table>";
}

C# ASP支持对实际的HTML控件进行操作,只需包含正确的using语句。using System.Web.UI.HtmlControls; - LokizFenrir
你的解决方案很好,谢谢。顺便提一下:如果需要的话,可以添加列标题。 - Nicolas
1
好的,抱歉双重评论,但我在写完第一条评论后决定这样做:在foreach循环之前插入以下内容(不要忘记将数组大小增加一!):table[0] = "<tr><th>" + string.Join("</th><th>", (from a_Col in data.Columns.Cast<DataColumn>() select a_Col.ColumnName).ToArray()) + "</th></tr>"; - Nicolas

4

如果有人误入此处,本来是想寻找VB相关信息的(就像我一样,没有输入c#作为搜索词),以下是第一个回答的基本内容:

Public Shared Function ConvertDataTableToHTML(dt As DataTable) As String
    Dim html As String = "<table>"
    html += "<tr>"
    For i As Integer = 0 To dt.Columns.Count - 1
        html += "<td>" + System.Web.HttpUtility.HtmlEncode(dt.Columns(i).ColumnName) + "</td>"
    Next
    html += "</tr>"
    For i As Integer = 0 To dt.Rows.Count - 1
        html += "<tr>"
        For j As Integer = 0 To dt.Columns.Count - 1
            html += "<td>" + System.Web.HttpUtility.HtmlEncode(dt.Rows(i)(j).ToString()) + "</td>"
        Next
        html += "</tr>"
    Next
    html += "</table>"
    Return html
End Function

3

From this link

using System;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.Text;
using System.Xml;

namespace ClientUtil
{
public class DataTableUtil
{

public static string DataTableToXmlString(DataTable dtData)
{
if (dtData == null || dtData.Columns.Count == 0)
return (string) null;
DataColumn[] primaryKey = dtData.PrimaryKey;
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append(“<TABLE>”);
stringBuilder.Append(“<TR>”);
foreach (DataColumn dataColumn in (InternalDataCollectionBase) dtData.Columns)
{
if (DataTableUtil.IsPrimaryKey(dataColumn.ColumnName, primaryKey))
stringBuilder.Append(“<TH IsPK=’true’ ColType='”).Append(Convert.ToString(dataColumn.DataType == typeof (object) ? (object) typeof (string) : (object) dataColumn.DataType)).Append(“‘>”).Append(dataColumn.ColumnName.Replace(“&”, “”)).Append(“</TH>”);
else
stringBuilder.Append(“<TH IsPK=’false’ ColType='”).Append(Convert.ToString(dataColumn.DataType == typeof (object) ? (object) typeof (string) : (object) dataColumn.DataType)).Append(“‘>”).Append(dataColumn.ColumnName.Replace(“&”, “”)).Append(“</TH>”);
}
stringBuilder.Append(“</TR>”);
int num1 = 0;
foreach (DataRow dataRow in (InternalDataCollectionBase) dtData.Rows)
{
stringBuilder.Append(“<TR>”);
int num2 = 0;
foreach (DataColumn dataColumn in (InternalDataCollectionBase) dtData.Columns)
{
string str = Convert.IsDBNull(dataRow[dataColumn.ColumnName]) ? (string) null : Convert.ToString(dataRow[dataColumn.ColumnName]).Replace(“<“, “&lt;”).Replace(“>”, “&gt;”).Replace(“\””, “&quot;”).Replace(“‘”, “&apos;”).Replace(“&”, “&amp;”);
if (!string.IsNullOrEmpty(str))
stringBuilder.Append(“<TD>”).Append(str).Append(“</TD>”);
else
stringBuilder.Append(“<TD>”).Append(“</TD>”);
++num2;
}
stringBuilder.Append(“</TR>”);
++num1;
}
stringBuilder.Append(“</TABLE>”);
return ((object) stringBuilder).ToString();
}

protected static bool IsPrimaryKey(string ColumnName, DataColumn[] PKs)
{
if (PKs == null || string.IsNullOrEmpty(ColumnName))
return false;
foreach (DataColumn dataColumn in PKs)
{
if (dataColumn.ColumnName.ToLower().Trim() == ColumnName.ToLower().Trim())
return true;
}
return false;
}

public static DataTable XmlStringToDataTable(string XmlData)
{
DataTable dataTable = (DataTable) null;
IList<DataColumn> list = (IList<DataColumn>) new List<DataColumn>();
if (string.IsNullOrEmpty(XmlData))
return (DataTable) null;
XmlDocument xmlDocument1 = new XmlDocument();
xmlDocument1.PreserveWhitespace = true;
XmlDocument xmlDocument2 = xmlDocument1;
xmlDocument2.LoadXml(XmlData);
XmlNode xmlNode1 = xmlDocument2.SelectSingleNode(“/TABLE”);
if (xmlNode1 != null)
{
dataTable = new DataTable();
int num = 0;
foreach (XmlNode xmlNode2 in xmlNode1.SelectNodes(“TR”))
{
if (num == 0)
{
foreach (XmlNode xmlNode3 in xmlNode2.SelectNodes(“TH”))
{
bool result = false;
string str = xmlNode3.Attributes[“IsPK”].Value;
if (!string.IsNullOrEmpty(str))
{
if (!bool.TryParse(str, out result))
result = false;
}
else
result = false;
Type type = Type.GetType(xmlNode3.Attributes[“ColType”].Value);
DataColumn column = new DataColumn(xmlNode3.InnerText, type);
if (result)
list.Add(column);
if (!dataTable.Columns.Contains(column.ColumnName))
dataTable.Columns.Add(column);
}
if (list.Count > 0)
{
DataColumn[] dataColumnArray = new DataColumn[list.Count];
for (int index = 0; index < list.Count; ++index)
dataColumnArray[index] = list[index];
dataTable.PrimaryKey = dataColumnArray;
}
}
else
{
DataRow row = dataTable.NewRow();
int index = 0;
foreach (XmlNode xmlNode3 in xmlNode2.SelectNodes(“TD”))
{
Type dataType = dataTable.Columns[index].DataType;
string s = xmlNode3.InnerText;
if (!string.IsNullOrEmpty(s))
{
try
{
s = s.Replace(“&lt;”, “<“);
s = s.Replace(“&gt;”, “>”);
s = s.Replace(“&quot;”, “\””);
s = s.Replace(“&apos;”, “‘”);
s = s.Replace(“&amp;”, “&”);
row[index] = Convert.ChangeType((object) s, dataType);
}
catch
{
if (dataType == typeof (DateTime))
row[index] = (object) DateTime.ParseExact(s, “yyyyMMdd”, (IFormatProvider) CultureInfo.InvariantCulture);
}
}
else
row[index] = Convert.DBNull;
++index;
}
dataTable.Rows.Add(row);
}
++num;
}
}
return dataTable;
}
}
}

2

如果有人仍在寻找一个避免(在某种程度上)使用硬编码字符串的解决方案,您可以使用HtmlTextWriter Nuget包:

// NOTE: dt is the `DataTable` type object
StringBuilder sbControlHtml = new StringBuilder();
using (StringWriter stringWriter = new StringWriter())
{
    using HtmlTextWriter htmlWriter = new HtmlTextWriter(stringWriter);
    htmlWriter.RenderBeginTag(HtmlTextWriterTag.Table);

    // add header row
    htmlWriter.RenderBeginTag(HtmlTextWriterTag.Tr);
    foreach(DataColumn col in dt.Columns)
    {
        htmlWriter.RenderBeginTag(HtmlTextWriterTag.Td);
        htmlWriter.Write(col.ColumnName);
        htmlWriter.RenderEndTag();
    }
    htmlWriter.RenderEndTag();

    // add rows
    foreach(DataRow row in dt.Rows)
    {
        htmlWriter.RenderBeginTag(HtmlTextWriterTag.Tr);
        foreach(DataColumn col in dt.Columns)
        {
            htmlWriter.RenderBeginTag(HtmlTextWriterTag.Td);
            htmlWriter.Write(row[col].ToString());
            htmlWriter.RenderEndTag();
        }
        htmlWriter.RenderEndTag();
    }
    
    htmlWriter.RenderEndTag();
    sbControlHtml.Append(stringWriter.ToString());
}

这个库的好处是支持 .Net Standard。在我的情况下,我需要一个 .Net Core 的替代方案来替换只能在 .Net Framework 上使用的 HtmlTextWriter。我将这段代码放到 .Net Standard 项目中,然后从 .Net Core 项目中引用它。

1
如果您正在使用Web Forms,则GridView非常适用于此。
代码看起来有点像这样。
aspx页面。
<asp:GridView ID="GridView1" runat="server" DataKeyNames="Name,Size,Quantity,Amount,Duration"></asp:GridView>

你可以手动输入数据,也可以在代码中使用源代码方法。
public class Room
{
    public string Name
    public double Size {get; set;}
    public int Quantity {get; set;}
    public double Amount {get; set;}
    public int Duration {get; set;}
}

protected void Page_Load(object sender, EventArgs e)
{
    if(!IsPostBack)//this is so you can keep any data you want for the list
    {
        List<Room> rooms=new List<Room>();
        //then use the rooms.Add() to add the rooms you need.
        GridView1.DataSource=rooms
        GridView1.Databind()
    }
}

个人而言,我更喜欢MVC4,因为客户端代码比Web Forms轻。它类似于上面的示例,但你使用视图和控制器代替类。
视图如下所示。
@model YourProject.Model.IEnumerable<Room>

<table>
    <th>
        <td>@Html.LabelFor(model => model.Name)</td>
        <td>@Html.LabelFor(model => model.Size)</td>
        <td>@Html.LabelFor(model => model.Quantity)</td>
        <td>@Html.LabelFor(model => model.Amount)</td>
        <td>@Html.LabelFor(model => model.Duration)</td>
   </th>
foreach(item in model)
{
    <tr>
        <td>@model.Name</td>
        <td>@model.Size</td>
        <td>@model.Quantity</td>
        <td>@model.Amount</td>
        <td>@model.Duration</td>
   </tr>
}
</table>

控制器可能看起来像这样。
public ActionResult Index()
{
    List<Room> rooms=new List<Room>();
    //again add the items you need

    return View(rooms);
}

希望这有所帮助 :)

1
也许在MVC4中,WebGrid可以是另一种选择。 - Jon

0

由于我在其他答案中没有看到这个,而且它更高效(代码行数和速度),所以这里提供一个使用StringBuilder和lambda函数的VB.NET解决方案,使用String.Join代替列的For循环。

Dim sb As New StringBuilder
sb.Append("<table>")
sb.Append("<tr>" & String.Join("", dt.Columns.OfType(Of DataColumn)().Select(Function(x) "<th>" & x.ColumnName & "</th>").ToArray()) & "</tr>")
For Each row As DataRow In dt.Rows
    sb.Append("<tr>" & String.Join("", row.ItemArray.Select(Function(f) "<td>" & f.ToString() & "</td>")) & "</tr>")
Next
sb.Append("</table>")

您可以很容易地添加自己的样式。


-1
根据我的理解,您需要使用asp.net和c#将3个表的数据显示在一个html表中。
我认为最好的方法是创建一个包含3个DataTable对象的数据集。
在页面加载时,直接将该数据集绑定到GriView。

也许您可以添加一个代码示例,因为这个答案相当模糊。 - Eric Hauenstein
以下是向数据集添加数据表的示例。http://msdn.microsoft.com/en-us/library/aeskbwf7(v=vs.110).aspx 用于将数据集绑定到GridView的方法:https://dev59.com/jWgu5IYBdhLWcg3wv5mm - Socialwebi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接