static void BuildStringOfRow(StringBuilder strBuilder, List<string> lstFields, string strFormat)
{
switch (strFormat)
{
case "XLS":
strBuilder.AppendLine("<Row>");
strBuilder.AppendLine(String.Join("
", lstFields.ToArray()));
strBuilder.AppendLine("</Row>");
break;
case "CSV":
strBuilder.AppendLine(String.Join(",", lstFields.ToArray()));
break;
}
}
static void FormatCellWidth(StringBuilder strBuilder, List<double> colsWidth, string strFormat)
{
var index = 1;
colsWidth.ForEach(p =>
{
switch (strFormat)
{
case "XLS":
strBuilder.AppendLine(string.Format(@"<Column ss:Index='{0}' ss:AutoFitWidth='0' ss:Width='{1}'/>", index, colsWidth[index - 1]));
break;
}
index++;
});
}
static string FormatField(string data, HorizontalAlignment alignment)
{
return FormatField(data, "XLS", false, alignment);
}
static string FormatField(string data, bool isHead)
{
return FormatField(data, "XLS", isHead, HorizontalAlignment.Left);
}
static string FormatField(string data, string format, bool isHead, HorizontalAlignment alignment)
{
//替换< , >否则,导出的Excel打不开
data = data.Replace("<", " <").Replace(">", ">");
switch (format)
{
case "XLS":
if (isHead)
{
return String.Format("<Cell><Data ss:Type="String" + "">{0}</Data></Cell>", data);
//return String.Format("<Cell ss:StyleID="HeaderStyle"><Data ss:Type="String" + "">{0}</Data></Cell>", data);
}
else
{
return String.Format("<Cell><Data ss:Type="String" + "">{0}</Data></Cell>", data);
//return String.Format("<Cell ss:StyleID="" + GetAlignmentType(alignment) + ""><Data ss:Type="String" + "">{0}</Data></Cell>", data);
}
case "CSV":
return String.Format(""{0}"",
data.Replace(""", """"").Replace("
",
"").Replace("
", ""));
}
return data;
}
static string FormatMergeField(string data, string format, HorizontalAlignment alignment, int mergeDownCount)
{
//替换< , >否则,导出的Excel打不开
data = data.Replace("<", " <").Replace(">", ">");
return String.Format("<Cell ss:MergeDown="{1}" ><Data ss:Type="String" + "">{0}</Data></Cell>", data, mergeDownCount);
//return String.Format("<Cell ss:MergeDown="{1}" ss:StyleID="" + GetAlignmentType(alignment) + ""><Data ss:Type="String" + "">{0}</Data></Cell>", data, mergeDownCount);
}
static string FormatFollowMergeField(string data, string format, HorizontalAlignment alignment, int mergeDownIndex)
{
//替换< , >否则,导出的Excel打不开
data = data.Replace("<", " <").Replace(">", ">");
return String.Format("<Cell ss:Index="{1}" ><Data ss:Type="String" + "">{0}</Data></Cell>", data, mergeDownIndex);
//return String.Format("<Cell ss:Index="{1}" ss:StyleID="" + GetAlignmentType(alignment) + ""><Data ss:Type="String" + "">{0}</Data></Cell>", data, mergeDownIndex);
}
static string GetAlignmentType(HorizontalAlignment alignment)
{
switch (alignment)
{
case HorizontalAlignment.Left:
return "CellLeftStyle";
case HorizontalAlignment.Center:
return "CellCenterStyle";
case HorizontalAlignment.Right:
return "CellRightStyle";
default:
return "CellLeftStyle";
}
}
public static Byte[] Export<T>(List<ColumnConfig> columnsConfigs, List<T> data, string mergeByName)
{
//record each row data.
List<string> lstFields = new List<string>();
//temporarily record each column width.
List<double> colsWidth = new List<double>();
//Record final excel xml.
StringBuilder strBuilder = new StringBuilder();
AppendPrefixXml(strBuilder);
var type = typeof(T);
//build excel header
Dictionary<ColumnConfig, PropertyInfo> properties = new Dictionary<ColumnConfig, PropertyInfo>();
foreach (ColumnConfig columnConfig in columnsConfigs)
{
lstFields.Add(FormatField(columnConfig.Name, true));
colsWidth.Add(columnConfig.Width);
if (!properties.ContainsKey(columnConfig))
{
var propertyName = columnConfig.PropertyName;
var property = type.GetProperty(propertyName);
properties.Add(columnConfig, property);
}
}
FormatCellWidth(strBuilder, colsWidth, "XLS");
BuildStringOfRow(strBuilder, lstFields, "XLS");
#region Build excel body
int mergeCount = -1;
int mergeCountCopy = -1;
int columnIndex = 0;
bool isNeedMerge = false;
var megreProperty = type.GetProperty(mergeByName);
Dictionary<string, List<T>> groupData = new Dictionary<string, List<T>>();
string tempSONumber = "-1";
foreach (var item in data)
{
string megreValue = Convert.ToString(megreProperty.GetValue(item, null));
if (tempSONumber != megreValue)
{
tempSONumber = megreValue;
}
if (groupData.ContainsKey(tempSONumber))
{
groupData[tempSONumber].Add(item);
}
else
{
List<T> list = new List<T>();
list.Add(item);
groupData.Add(tempSONumber, list);
}
}
foreach (var item in data)
{
lstFields.Clear();
columnIndex = 0;
if (mergeCount == -1)
{
string megreValue =Convert.ToString(megreProperty.GetValue(item, null));
if (groupData.ContainsKey(megreValue))
{
mergeCount = groupData[megreValue].Count - 1;
}
if (mergeCount > 0)
{
isNeedMerge = true;
mergeCountCopy = mergeCount;
}
else
{
mergeCount = -1;
mergeCountCopy = mergeCount;
isNeedMerge = false;
}
}
foreach (KeyValuePair<ColumnConfig, PropertyInfo> keyValue in properties)
{
columnIndex++;
var value = keyValue.Value.GetValue(item, null);
//drawing first merge data
if (isNeedMerge && mergeCountCopy == mergeCount)
{
if (keyValue.Key.IsMergeDown)
{
lstFields.Add(FormatMergeField(value == null ? string.Empty : value.ToString(), "XLS", keyValue.Key.TextAlign, mergeCount));
}
else
{
lstFields.Add(FormatField(value == null ? string.Empty : value.ToString(), keyValue.Key.TextAlign));
}
}
//drawing follow data
else if (isNeedMerge && mergeCountCopy > 0)
{
if (!keyValue.Key.IsMergeDown)
{
lstFields.Add(FormatFollowMergeField(value == null ? string.Empty : value.ToString(), "XLS", keyValue.Key.TextAlign, columnIndex));
}
}
//drawing normal merge data
else
{
lstFields.Add(FormatField(value == null ? string.Empty : value.ToString(), keyValue.Key.TextAlign));
}
}
if (mergeCount > 0)
{
mergeCount--;
}
else
{
mergeCount = -1;
}
BuildStringOfRow(strBuilder, lstFields, "XLS");
}
#endregion
//build excel footer
AppendPostfixXml(strBuilder);
return System.Text.Encoding.UTF8.GetBytes(strBuilder.ToString());
}
static void AppendPrefixXml(StringBuilder strBuilder)
{
strBuilder.Append("<?xml version="1.0" " +
"encoding="utf-8"?>");
strBuilder.Append("<?mso-application progid" +
"="Excel.Sheet"?>");
strBuilder.Append("<Workbook xmlns="urn:" +
"schemas-microsoft-com:office:spreadsheet" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" xmlns:x="urn:schemas-microsoft-com:office:excel">");
strBuilder.Append("<DocumentProperties " +
"xmlns="urn:schemas-microsoft-com:" +
"office:office">");
strBuilder.Append("<Author>Newegg.com</Author>");
strBuilder.Append("<Created>" +
DateTime.Now.ToLocalTime().ToLongDateString() +
"</Created>");
strBuilder.Append("<LastSaved>" +
DateTime.Now.ToLocalTime().ToLongDateString() +
"</LastSaved>");
strBuilder.Append("<Company>Newegg.com</Company>");
strBuilder.Append("<Version>12.00</Version>");
strBuilder.Append("</DocumentProperties>");
//strBuilder.Append("<Styles>");
//strBuilder.Append("<Style ss:ID="HeaderStyle"><Alignment ss:Vertical="Center" ss:WrapText="1"/>"); strBuilder.Append("<Borders><Border ss:Position="Bottom" ss:LineStyle="Continuous" ss:Weight="1" ss:Color="#FFFFFF"/>");
//strBuilder.Append("<Border ss:Position="Left" ss:LineStyle="Continuous" ss:Weight="1" ss:Color="#FFFFFF"/>");
//strBuilder.Append("<Border ss:Position="Right" ss:LineStyle="Continuous" ss:Weight="1" ss:Color="#FFFFFF"/>");
//strBuilder.Append("<Border ss:Position="Top" ss:LineStyle="Continuous" ss:Weight="1" ss:Color="#FFFFFF"/>");
//strBuilder.Append("</Borders>");
//strBuilder.Append("<Font x:Family="Swiss" ss:Size="12" ss:Color="#FFFFFF" ss:Bold="1"/>");
//strBuilder.Append("<Interior ss:Color="#008000" ss:Pattern="Solid"/>");
//strBuilder.Append("</Style>");
//strBuilder.Append("<Style ss:ID="CellCenterStyle">");
//strBuilder.Append("<Alignment ss:Horizontal="Center" ss:Vertical="Center" ss:WrapText="1"/>");
//strBuilder.Append("<Font x:Family="Swiss" ss:Size="12"/>");
//strBuilder.Append("</Style>");
//strBuilder.Append("<Style ss:ID="CellLeftStyle">");
//strBuilder.Append("<Alignment ss:Horizontal="Left" ss:Vertical="Center" ss:WrapText="1"/>");
//strBuilder.Append("<Font x:Family="Swiss" ss:Size="12"/>");
//strBuilder.Append("</Style>");
//strBuilder.Append("<Style ss:ID="CellRightStyle">");
//strBuilder.Append("<Alignment ss:Horizontal="Right" ss:Vertical="Center" ss:WrapText="1"/>");
//strBuilder.Append("<Font x:Family="Swiss" ss:Size="12"/>");
//strBuilder.Append("</Style>");
//strBuilder.Append("</Styles>");
strBuilder.Append("<Worksheet ss:Name="Export Data" " +
"xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet">");
strBuilder.Append("<Table>");
}
static void AppendPostfixXml(StringBuilder strBuilder)
{
strBuilder.Append("</Table>");
strBuilder.Append("</Worksheet>");
strBuilder.Append("</Workbook>");
}
public static byte[] Zip(byte[] source, string fileName)
{
using (MemoryStream StreamZip = new MemoryStream())
{
using (ZipOutputStream zipFileStream = new ZipOutputStream(StreamZip))
{
zipFileStream.IsStreamOwner = true;
zipFileStream.SetLevel(6);
ZipEntry zipEntry = new ZipEntry(fileName);
zipEntry.DateTime = DateTime.UtcNow;
zipEntry.Size = source.Length;
zipFileStream.PutNextEntry(zipEntry);
zipFileStream.Write(source, 0, source.Length);
zipFileStream.Finish();
StreamZip.Position = 0;
byte[] resultBytes = new byte[StreamZip.Length];
StreamZip.Read(resultBytes, 0, (int)StreamZip.Length);
StreamZip.Seek(0, SeekOrigin.Begin);
return resultBytes;
}
}
}
}
public class ColumnConfig
{
public double Width { get; set; }
public string Name { get; set; }
public string PropertyName { get; set; }
public HorizontalAlignment TextAlign { get; set; }
public bool IsMergeDown { get; set; }
//public string DataType {get;set;}
}
public enum HorizontalAlignment
{
Left,
Right,
Center
}