代码拉取完成,页面将自动刷新
同步操作将从 Sunday/代码片段 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using NPOI.HSSF.UserModel;
using NPOI.POIFS.FileSystem;
using NPOI.SS.Converter;
using NPOI.SS.Format;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
namespace BoYuan.Framework.Uitility
{
public partial class NPOIHelper
{
//参考 https://www.cnblogs.com/zhj11226/p/8649497.html
/// <summary>
/// excel转html 相关。常用语模版打印相关
/// </summary>
public class EXCELTOHTML
{
private IWorkbook wb = null;
private const String DEFAULTS_CLASS = "excelDefaults";
private const String COL_HEAD_CLASS = "colHeader";
private const String ROW_HEAD_CLASS = "rowHeader";
private const int IDX_TABLE_WIDTH = -2;
private const int IDX_HEADER_COL_WIDTH = -1;
private int firstColumn;
private int endColumn;
private bool gotBounds;
private readonly List<KeyValuePair<HorizontalAlignment, string>> HALIGN = new List<KeyValuePair<HorizontalAlignment, string>>()
{
new KeyValuePair<HorizontalAlignment, string>(HorizontalAlignment.Left, "left"),
new KeyValuePair<HorizontalAlignment, string>(HorizontalAlignment.Center, "center"),
new KeyValuePair<HorizontalAlignment, string>(HorizontalAlignment.Right, "right"),
new KeyValuePair<HorizontalAlignment, string>(HorizontalAlignment.Fill, "left"),
new KeyValuePair<HorizontalAlignment, string>(HorizontalAlignment.Justify, "left"),
new KeyValuePair<HorizontalAlignment, string>(HorizontalAlignment.CenterSelection, "center"),
new KeyValuePair<HorizontalAlignment, string>(HorizontalAlignment.General, "left")
};
private readonly List<KeyValuePair<VerticalAlignment, string>> VALIGN = new List<KeyValuePair<VerticalAlignment, string>>()
{
new KeyValuePair<VerticalAlignment, string>(VerticalAlignment.Bottom, "bottom"),
new KeyValuePair<VerticalAlignment, string>(VerticalAlignment.Center, "middle"),
new KeyValuePair<VerticalAlignment, string>(VerticalAlignment.Top, "top")
};
private readonly List<KeyValuePair<BorderStyle, string>> BORDER = new List<KeyValuePair<BorderStyle, string>>()
{
new KeyValuePair<BorderStyle, string>(BorderStyle.DashDot, "dashed 1pt"),
new KeyValuePair<BorderStyle, string>(BorderStyle.DashDotDot, "dashed 1pt"),
new KeyValuePair<BorderStyle, string>(BorderStyle.Dashed, "dashed 1pt"),
new KeyValuePair<BorderStyle, string>(BorderStyle.Dotted, "dotted 1pt"),
new KeyValuePair<BorderStyle, string>(BorderStyle.Double, "double 3pt"),
new KeyValuePair<BorderStyle, string>(BorderStyle.Hair, "dashed 1px"),
new KeyValuePair<BorderStyle, string>(BorderStyle.Medium, "solid 2pt"),
new KeyValuePair<BorderStyle, string>(BorderStyle.MediumDashDot, "dashed 2pt"),
new KeyValuePair<BorderStyle, string>(BorderStyle.MediumDashDotDot, "dashed 2pt"),
new KeyValuePair<BorderStyle, string>(BorderStyle.MediumDashed, "dashed 2pt"),
new KeyValuePair<BorderStyle, string>(BorderStyle.None, "none"),
new KeyValuePair<BorderStyle, string>(BorderStyle.SlantedDashDot, "dashed 2pt"),
new KeyValuePair<BorderStyle, string>(BorderStyle.Thick, "solid 3pt"),
new KeyValuePair<BorderStyle, string>(BorderStyle.Thin, "solid 1pt")
};
public EXCELTOHTML(IWorkbook wb)
{
this.wb = wb;
}
public EXCELTOHTML(string path)
{
if (UploadFileCommand.GetFileExtension(path) == "xlsx")
{
this.wb = new XSSFWorkbook(path);
}
else
{
using (var inputfs = new FileStream(path, FileMode.Open, FileAccess.Read))
{
NPOIFSFileSystem fs = new NPOIFSFileSystem(inputfs);
this.wb = new HSSFWorkbook(fs.Root, true);
}
}
}
//方法一样式和效果比较好。
#region 方法一
//参考 https://www.cnblogs.com/GoCircle/p/6248375.html
/// <summary>
/// npoi默认方法 excel转html
/// </summary>
/// <param name="OutputColumnHeaders">输出行头</param>
/// <param name="OutputRowNumbers">输行号</param>
/// <param name="OutputHiddenColumns"></param>
/// <param name="OutputHiddenRows"></param>
/// <param name="OutputLeadingSpacesAsNonBreaking"></param>
/// <param name="UseDivsToSpan"></param>
/// <returns></returns>
public string ExcelToHtml(bool OutputColumnHeaders = true,
bool OutputRowNumbers = true,
bool OutputHiddenColumns = false,
bool OutputHiddenRows = false,
bool OutputLeadingSpacesAsNonBreaking = true,
bool UseDivsToSpan = true)
{
ExcelToHtmlConverter excelToHtmlConverter = new ExcelToHtmlConverter();
// 设置输出参数
excelToHtmlConverter.OutputColumnHeaders = OutputColumnHeaders ;
excelToHtmlConverter.OutputHiddenColumns = OutputHiddenColumns ;
excelToHtmlConverter.OutputHiddenRows = OutputHiddenRows ;
excelToHtmlConverter.OutputLeadingSpacesAsNonBreaking = OutputLeadingSpacesAsNonBreaking;
excelToHtmlConverter.OutputRowNumbers = OutputRowNumbers ;
excelToHtmlConverter.UseDivsToSpan = UseDivsToSpan ;
// 处理的Excel文件
excelToHtmlConverter.ProcessWorkbook(wb);
//添加表格样式
excelToHtmlConverter.Document.InnerXml =
excelToHtmlConverter.Document.InnerXml.Insert(
excelToHtmlConverter.Document.InnerXml.IndexOf("<head>", 0) + 6,
@"<style>table, td, th{border:1px solid green;}th{background-color:green;color:white;}</style>"
);
//方法一
return excelToHtmlConverter.Document.InnerXml;
}
#endregion
#region 方法二
public string ToHtml(int sheetIndex = 0, bool completeHtmls = true, bool needTitle = true)
{
return ToHtml(wb.GetSheetName(sheetIndex), completeHtmls, needTitle);
}
public string ToHtml(string sheetName, bool completeHtmls = true, bool needTitle = true)
{
StringBuilder sbRet = new StringBuilder();
if (completeHtmls)
{
sbRet.Append("<?xml version=\"1.0\" encoding=\"iso-8859-1\" ?>\n");
sbRet.Append("<html>\n");
sbRet.Append("<head>\n");
}
sbRet.Append(GetInlineStyle());
if (completeHtmls)
{
sbRet.Append("</head>\n");
sbRet.Append("<body>\n");
}
sbRet.Append(GetSheets(sheetName, needTitle));
if (completeHtmls)
{
sbRet.Append("</body>\n");
sbRet.Append("</html>\n");
}
return sbRet.ToString();
}
private string GetSheets(string sheetName, bool needTitle)
{
StringBuilder sbRet = new StringBuilder();
ISheet sheet = wb.GetSheet(sheetName);
sbRet.Append(GetSheet(sheet, needTitle));
return sbRet.ToString();
}
private string GetSheet(ISheet sheet, bool needTitle)
{
StringBuilder sbRet = new StringBuilder();
List<KeyValuePair<int, int>> widths = computeWidths(sheet);
int tableWidth = widths.First(o => o.Key == IDX_TABLE_WIDTH).Value;
sbRet.AppendFormat("<table class={0} cellspacing=\"0\" cellpadding=\"0\" style=\"width:{1}px;\">\n", DEFAULTS_CLASS, tableWidth);
sbRet.Append(GetCols(widths, needTitle));
sbRet.Append(GetSheetContent(sheet, needTitle));
sbRet.Append("</table>\n");
return sbRet.ToString();
}
private string GetColumnHeads()
{
StringBuilder sbRet = new StringBuilder();
sbRet.AppendFormat("<thead>\n");
sbRet.AppendFormat(" <tr class={0}>\n", COL_HEAD_CLASS);
sbRet.AppendFormat(" <th class={0}>◊</th>\n", COL_HEAD_CLASS);
//noinspection UnusedDeclaration
for (int i = firstColumn; i < endColumn; i++)
{
StringBuilder colName = new StringBuilder();
int cnum = i;
do
{
colName.Insert(0, (char)('A' + cnum % 26));
cnum /= 26;
} while (cnum > 0);
sbRet.AppendFormat(" <th class={0}>{1}</th>\n", COL_HEAD_CLASS, colName);
}
sbRet.Append(" </tr>\n");
sbRet.Append("</thead>\n");
return sbRet.ToString();
}
private string GetSheetContent(ISheet sheet, bool needTitle)
{
StringBuilder sbRet = new StringBuilder();
if (needTitle)
{
sbRet.Append(GetColumnHeads());
}
sbRet.AppendFormat("<tbody>\n");
IEnumerator rows = sheet.GetRowEnumerator();
while (rows.MoveNext())
{
IRow row = (IRow)rows.Current;
sbRet.AppendFormat(" <tr>\n");
if (needTitle)
{
sbRet.AppendFormat(" <td class={0}>{1}</td>\n", ROW_HEAD_CLASS, row.RowNum + 1);
}
StringBuilder sbTemp = new StringBuilder();
int mergeCnt = 0;
ICell preCell = null;
ICell cell = null;
for (int i = firstColumn; i < endColumn; i++)
{
String content = " ";
String attrs = "";
ICellStyle style = null;
bool isMerge = false;
if (i >= row.FirstCellNum && i < row.LastCellNum)
{
cell = row.GetCell(i);
if (cell != null)
{
isMerge = cell.IsMergedCell;
style = cell.CellStyle;
attrs = tagStyle(cell, style);
//Set the value that is rendered for the cell
//also applies the format
MyCellFormat cf = MyCellFormat.GetInstance(style.GetDataFormatString());
CellFormatResult result = cf.Apply(cell);
content = result.Text; //never null
if (string.IsNullOrEmpty(content))
{
content = " ";
}
}
}
if (isMerge && content == " ")
{
/*
* 因为 NPOI 返回的 cell 没有 mergeCnt 属性,只有一个 IsMergedCell 属性
* 如果有5个单元格,后面四个单元格合并成一个大单元格
* 它返回的其实还是5个单元格,IsMergedCell 分别是: false,true,true,true,true
* 上头这种情况还算好,我们好歹还能猜到后面四个单元格是合并单元格
*
* 但是如果第一个单独,后面四个每两个合并呢?
* TMD返回的还是5个单元格,IsMergedCell 仍然是: false,true,true,true,true
* 所以这里是有问题的,我没法知道后面的四个单元格是四个合并成一个呢,还是两个两个的分别合并
* 这个是没办法的,除非从NPOI的源代码里头去解决这个问题,介于上班呢,要求的是出结果,所以公司是
* 不太会允许我去干这种投入产出比较差的事情的,所以这个问题我采用了一个成本比较低的办法来绕开
*
* 办法就是我们在定义模板的时候,可以通过为每一个合并单元格添加内容来避免。
* 比如说 cell1(内容), cell2,cell3(内容), cell4,cell5(内容)
* 这样的话我就能知道 cell1 IsMergedCell = false 是一个独立的单元格
* cell2, cell3, cell4, cell5 的 IsMergedCell 虽然都是 true, 但是因为 cell4 这个位置有内容了,
* 那我就晓得 cell2 和 cell3 是合并的, cell4 和 cell5 也是合并的。
*
* 当然这里还会有个小小的问题,如果 cell4, cell5 里头是一个会被替换掉的内容,也即 $[字段] 这样的东西
* 如果实际的内容为 null 那么 cell4, cell5 合并单元格的内容也就是 null 了,这又回到了之前的问题了,
* 所以此处要求定义模板的时候 $[内容] 后面加一个空格,这样在生成 html 的时候,其实是不影响打印效果的。
* 也即 “$[] ”注意双引号里头的 “]”后头有个空格
*/
if (mergeCnt == 1 && preCell != null && preCell.IsMergedCell == false)
{
sbTemp.AppendFormat(" <td class={0} {1}{3}>{2}</td>\n", styleName(style), attrs, content, (isMerge) ? " colspan=\"1\"" : "");
}
else
{
mergeCnt++;
}
}
else
{
sbTemp.Replace("colspan=\"1\"", string.Format("colspan=\"{0}\"", mergeCnt));
mergeCnt = 1;
sbTemp.AppendFormat(" <td class={0} {1}{3}>{2}</td>\n", styleName(style), attrs, content, (isMerge) ? " colspan=\"1\"" : "");
}
preCell = cell;
}
sbRet.Append(sbTemp.Replace("colspan=\"1\"", string.Format("colspan=\"{0}\"", mergeCnt)).ToString());
sbRet.AppendFormat(" </tr>\n");
}
sbRet.AppendFormat("</tbody>\n");
return sbRet.ToString();
}
private String tagStyle(ICell cell, ICellStyle style)
{
if (style.Alignment == HorizontalAlignment.General)
{
switch (ultimateCellType(cell))
{
case CellType.String:
return "style=\"text-align: left;\"";
case CellType.Boolean:
case CellType.Error:
return "style=\"text-align: center;\"";
case CellType.Numeric:
default:
// "right" is the default
break;
}
}
return "";
}
private static CellType ultimateCellType(ICell c)
{
CellType type = c.CellType;
if (type == CellType.Formula)
{
type = c.CachedFormulaResultType;
}
return type;
}
private string GetCols(List<KeyValuePair<int, int>> widths, bool needTitle)
{
StringBuilder sbRet = new StringBuilder();
if (needTitle)
{
int headerColWidth = widths.First(o => o.Key == IDX_HEADER_COL_WIDTH).Value;
sbRet.AppendFormat("<col style=\"width:{0}px\"/>\n", headerColWidth);
}
for (int i = firstColumn; i < endColumn; i++)
{
int colWidth = widths.First(o => o.Key == i).Value;
sbRet.AppendFormat("<col style=\"width:{0}px;\"/>\n", colWidth);
}
return sbRet.ToString();
}
private List<KeyValuePair<int, int>> computeWidths(ISheet sheet)
{
List<KeyValuePair<int, int>> ret = new List<KeyValuePair<int, int>>();
int tableWidth = 0;
ensureColumnBounds(sheet);
// compute width of the header column
int lastRowNum = sheet.LastRowNum;
int headerCharCount = lastRowNum.ToString().Length;
int headerColWidth = widthToPixels((headerCharCount + 1) * 256);
ret.Add(new KeyValuePair<int, int>(IDX_HEADER_COL_WIDTH, headerColWidth));
tableWidth += headerColWidth;
for (int i = firstColumn; i < endColumn; i++)
{
int colWidth = widthToPixels(sheet.GetColumnWidth(i));
ret.Add(new KeyValuePair<int, int>(i, colWidth));
tableWidth += colWidth;
}
ret.Add(new KeyValuePair<int, int>(IDX_TABLE_WIDTH, tableWidth));
return ret;
}
private int widthToPixels(double widthUnits)
{
return (int)(Math.Round(widthUnits * 9 / 256));
}
private void ensureColumnBounds(ISheet sheet)
{
if (gotBounds) return;
IEnumerator iter = sheet.GetRowEnumerator();
if (iter.MoveNext()) firstColumn = 0;
else firstColumn = int.MaxValue;
endColumn = 0;
iter.Reset();
while (iter.MoveNext())
{
IRow row = (IRow)iter.Current;
short firstCell = row.FirstCellNum;
if (firstCell >= 0)
{
firstColumn = Math.Min(firstColumn, firstCell);
endColumn = Math.Max(endColumn, row.LastCellNum);
}
}
gotBounds = true;
}
private string GetInlineStyle()
{
StringBuilder sbRet = new StringBuilder();
sbRet.Append("<style type=\"text/css\">\n");
sbRet.Append(GetStyles());
sbRet.Append("</style>\n");
return sbRet.ToString();
}
private string GetStyles()
{
StringBuilder sbRet = new StringBuilder();
HashSet<ICellStyle> seen = new HashSet<ICellStyle>();
for (int i = 0; i < wb.NumberOfSheets; i++)
{
ISheet sheet = wb.GetSheetAt(i);
IEnumerator rows = sheet.GetRowEnumerator();
while (rows.MoveNext())
{
IRow row = (IRow)rows.Current;
foreach (ICell cell in row)
{
ICellStyle style = cell.CellStyle;
if (!seen.Contains(style))
{
sbRet.Append(GetStyle(style));
seen.Add(style);
}
}
}
}
return sbRet.ToString();
}
private string GetStyle(ICellStyle style)
{
StringBuilder sbRet = new StringBuilder();
sbRet.AppendFormat(".{0} .{1} {{\n", DEFAULTS_CLASS, styleName(style));
sbRet.Append(styleContents(style));
sbRet.Append("}\n");
return sbRet.ToString();
}
private string styleContents(ICellStyle style)
{
StringBuilder sbRet = new StringBuilder();
sbRet.Append(styleOut("text-align", style.Alignment));
sbRet.Append(styleOut("vertical-align", style.VerticalAlignment));
sbRet.Append(fontStyle(style));
sbRet.Append(borderStyles(style));
sbRet.Append(colorStyles(style));
return sbRet.ToString();
}
private string colorStyles(ICellStyle style)
{
StringBuilder sbRet = new StringBuilder();
//sbRet.Append("还未实现!");
return sbRet.ToString();
}
private string borderStyles(ICellStyle style)
{
StringBuilder sbRet = new StringBuilder();
sbRet.Append(styleOut("border-left", style.BorderLeft));
/*
* NPOI有BUG,合并单元格的 border-right 永远都是 None
* 我们可以通过设置合并单元格后边那个单元格的左边框的解决
* 如果当前合并单元格已经合并到最后一列了,我们就只能再加一列了,为了不影响打印效果
* 这最后加的这一列在设置好左边框后,需要把宽度设置得很小,比如说0.1这样
*/
sbRet.Append(styleOut("border-right", style.BorderRight));
sbRet.Append(styleOut("border-top", style.BorderTop));
sbRet.Append(styleOut("border-bottom", style.BorderBottom));
return sbRet.ToString();
}
private string fontStyle(ICellStyle style)
{
StringBuilder sbRet = new StringBuilder();
IFont font = style.GetFont(wb);
if (font.Boldweight == 0)
{
sbRet.Append(" font-weight: bold;\n");
}
if (font.IsItalic)
{
sbRet.Append(" font-style: italic;\n");
}
double fontheight = font.FontHeight / 10 - 10;
if (fontheight == 9)
{
//fix for stupid ol Windows
fontheight = 10;
}
sbRet.AppendFormat(" font-size: {0}pt;\n", fontheight);
return sbRet.ToString();
}
private string styleOut(string k, HorizontalAlignment p)
{
return k + ":" + HALIGN.First(o => o.Key == p).Value + ";\n";
}
private string styleOut(string k, VerticalAlignment p)
{
return k + ":" + VALIGN.First(o => o.Key == p).Value + ";\n";
}
private string styleOut(string k, BorderStyle p)
{
return k + ":" + BORDER.First(o => o.Key == p).Value + ";\n";
}
private string styleName(ICellStyle style)
{
if (style == null)
{
style = wb.GetCellStyleAt((short)0);
}
StringBuilder sb = new StringBuilder();
sb.AppendFormat("style_{0}", style.Index);
return sb.ToString();
}
}
/// <summary>
/// 这个东西是为了解决 NPOI CellFormat 的BUG而存在的。
/// 它在读取 日期格式 的时候有时候会报错。
/// </summary>
public class MyCellFormat
{
private CellFormat cellformat = null;
private MyCellFormat(string format)
{
this.cellformat = CellFormat.GetInstance(format);
}
public static MyCellFormat GetInstance(string format)
{
return new MyCellFormat(format);
}
public CellFormatResult Apply(ICell cell)
{
try
{
return cellformat.Apply(cell);
}
catch (Exception)
{
var formatStr = cell.CellStyle.GetDataFormatString();
var mc = new Regex(@"(yy|M|d|H|s|ms)").Match(formatStr);
/*
* 目前全部不能正常转换的日期格式都转换成 yyyy - MM - dd 的形式
* 比如说:【[$-F800]dddd\,\ mmmm\ dd\,\ yyyy】这个格式
* 稍微 google 了下( https://msdn.microsoft.com/en-us/library/dd318693(VS.85).aspx)
* 这个字符串 0x0800 表示 [System default locale language]
* 因时间关系,只能干完手头的活之后再慢慢研究了。
*/
if (mc.Success)
{
return CellFormat.GetInstance("yyyy-MM-dd").Apply(cell);
}
else return cellformat.Apply(cell.ToString() + "<!-- This is the bug of NPOI, Maybe you should modify the file which name is \"MyCellFormat.cs\" -->");
}
}
public CellFormatResult Apply(Object v)
{
return cellformat.Apply(v);
}
#endregion
}
}
}
/* //https://www.jb51.net/office/word/67360.html
打印页边距设定为 0mm 时,网页内最大元素的分辨率:794×1123
<div style="width:794px;height:1123px;border:1px solid #000000;"> </div>
打印页边距设定为 5mm 时,网页内最大元素的分辨率:756×1086
<div style="width:756px;height:1086px;border:1px solid #000000;"> </div>
打印页边距设定为 19.05mm 时,网页内最大元素的分辨率:649×978
<div style="width:649px;height:978px;border:1px solid #000000;"> </div>
*/
/*
调用示例:
NPOIHelper.EXCELTOHTML exceltohtml=new NPOIHelper.EXCELTOHTML(Server.MapPath("~/1.xlsx"));
string html=exceltohtml.ToHtml(0);//方法二
eth.ExcelToHtml();//方法一
*/
/* js相关,去掉双线。别忘记引用jquery
<script>
var table = $("table.excelDefautls");
$("#container").width(table.width());
$("td").css("word-break", "break-all");
//去除两个相邻单元格的双线
var trs = table.find("tr");
trs.each(function(idxTr, elTr) {
$(elTr).find("td").each(function(idxTd, elTd) {
if (idxTd != 0) {
var lptd = $(elTd).prev(); //左边单元格
//左右两个单元格中间有两条线,去掉一条
if (lptd.css("border-right-style") != "none" && $(elTd).css("border-right-style") != "none") {
lptd.css("border-right", "none");
}
}
if (idxTr != 0) {
var vptd = $(elTr).prev().find("td:eq(" + idxTd + ")"); //上边单元格
//上下两个单元格中间有两条线,去掉一条
if (vptd.css("border-botton-style") != "none" && $(elTd).css("border-top-style") != "none") {
vptd.css("border-botton", "none");
}
}
});
})
</script>
*/
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。