我们知道,搜索引擎最擅长处理的就是文本,而Excel中的内容并不是以文本方式存储的。那么如果想要搜索引擎爬虫能够抓取到Excel中的内容是比较困难的,除非搜索引擎爬虫对Excel格式进行专门的处理。那么有没有办法解决此问题呢?有,通过NPOI将Excel内容文本化!
如下,有这样一张Excel,如果想让它被搜索引擎收录,常用的方式是以HTML形式展现,但将一个个这样的Excel手工做成HTML页面显然比较麻烦。接下来,我们将提供一种方案,自动将Excel中的内容以HTML形式展现。
其实基本思想也很简单,就是通过NPOI读取每个Cell中的内容,然后以HTML的形式输出。但要保证输出的HTML页面布局与Excel中的一致,还有点小技巧。下面是构造Table的代码:
protected String excelContent;
protected void Page_Load( object sender, EventArgs e)
{
HSSFWorkbook wb = new HSSFWorkbook( new FileStream(Server.MapPath( " App_Data/quotation.xls " ), FileMode.Open));
sht = wb.GetSheet( " Sheet1 " );
// 取行Excel的最大行数
int rowsCount = sht.PhysicalNumberOfRows;
// 为保证Table布局与Excel一样,这里应该取所有行中的最大列数(需要遍历整个Sheet)。
// 为少一交全Excel遍历,提高性能,我们可以人为把第0行的列数调整至所有行中的最大列数。
int colsCount = sht.GetRow( 0 ).PhysicalNumberOfCells;
int colSpan;
int rowSpan;
bool isByRowMerged;
StringBuilder table = new StringBuilder(rowsCount * 32 );
table.Append( " <table border='1px'> " );
for ( int rowIndex = 0 ; rowIndex < rowsCount; rowIndex ++ )
{
table.Append( " <tr> " );
for ( int colIndex = 0 ; colIndex < colsCount; colIndex ++ )
{
GetTdMergedInfo(rowIndex, colIndex, out colSpan, out rowSpan, out isByRowMerged);
// 如果已经被行合并包含进去了就不输出TD了。
// 注意被合并的行或列不输出的处理方式不一样,见下面一处的注释说明了列合并后不输出TD的处理方式。
if (isByRowMerged)
{
continue ;
}
table.Append( " <td " );
if (colSpan > 1 )
table.Append( string .Format( " colSpan={0} " , colSpan));
if (rowSpan > 1 )
table.Append( string .Format( " rowSpan={0} " , rowSpan));
table.Append( " > " );
table.Append(sht.GetRow(rowIndex).GetCell(colIndex));
// 列被合并之后此行将少输出colSpan-1个TD。
if (colSpan > 1 )
colIndex += colSpan - 1 ;
table.Append( " </td> " );
}
table.Append( " </tr> " );
}
table.Append( " </table> " );
this .excelContent = table.ToString();
}
其中用到的GetTdMergedInfo方法代码如下:
/// 获取Table某个TD合并的列数和行数等信息。与Excel中对应Cell的合并行数和列数一致。
/// </summary>
/// <param name="rowIndex"> 行号 </param>
/// <param name="colIndex"> 列号 </param>
/// <param name="colspan"> TD中需要合并的行数 </param>
/// <param name="rowspan"> TD中需要合并的列数 </param>
/// <param name="rowspan"> 此单元格是否被某个行合并包含在内。如果被包含在内,将不输出TD。 </param>
/// <returns></returns>
private void GetTdMergedInfo( int rowIndex, int colIndex, out int colspan, out int rowspan, out bool isByRowMerged)
{
colspan = 1 ;
rowspan = 1 ;
isByRowMerged = false ;
int regionsCuont = sht.NumMergedRegions;
Region region;
for ( int i = 0 ; i < regionsCuont; i ++ )
{
region = sht.GetMergedRegionAt(i);
if (region.RowFrom == rowIndex && region.ColumnFrom == colIndex)
{
colspan = region.ColumnTo - region.ColumnFrom + 1 ;
rowspan = region.RowTo - region.RowFrom + 1 ;
return ;
}
else if (rowIndex > region.RowFrom && rowIndex <= region.RowTo && colIndex >= region.ColumnFrom && colIndex <= region.ColumnTo)
{
isByRowMerged = true ;
}
}
}
最后在apsx页面中输出构建好的Table:
执行效果如下:
我们发现,与Excel中的布局完全一样(这里没有处理单元格的样式,只处理了内容,有兴趣的读者也可以将Excel中单元格的样式也应用在HTML中)。这里为保证布局一致,主要是将Excel中的Region信息解析成Table的colSpan和rowSpan属性,如果对这两个属性不太了解,可以结合以下代码和示例加以了解:
< tr >
< td colspan ="2" rowspan ="2" > 0,0 </ td >
< td > 0,3 </ td >
</ tr >
< tr >
< td > 1,3 </ td >
</ tr >
< tr >
< td rowspan ="2" > 2,0 </ td >
< td colspan ="2" > 2,1 </ td >
</ tr >
< tr >
< td > 3,1 </ td >
< td > 3,2 </ td >
</ tr >
</ table >
以上HTML代码对应的Table展现为: