2023年2月

小孩正处学习新事物的阶段,每天拿着很多卡片来识字识物,甚是有趣。有一天,我突发奇想,如果能用电脑动画来播放一些动画片段来帮助小孩提高记忆,那倒是不错的想法。动画最近肯定是使用Flash来处理了,快捷并且声色俱全,可以提高学习的兴趣。于是着手在Winfrom中嵌入Flash来播放,实现动画的效果,经过一番努力,终于成型,先看看程序的效果。

这个程序和一般操作方式不同,不是直接应用Fash的COM组件进行操作,而是通过接口的晚期绑定来实现对Flash的调用,因此项目工程没有Flash的COM组件的应用的,虽然最终还是需要客户端安装Flash播放器,但是提供了比较好的操作方式,并且这里已经把Fash模块封装成了一个控件,拖拽过来就可以使用了。

使用代码如下所示:

public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void Play()
{
string file = Path.Combine(Application.StartupPath, "demo.swf");
if (File.Exists(file))
{
this.flashPlayer1.LoadMovie(0, file);
}
this.flashPlayer1.Play();
}

private void btnPlay_Click(object sender, EventArgs e)
{
Play();

}

设计时刻的窗体效果如下所示,Flash控件就是一个Panel类型的控件,白色的部分就是。

运行效果就如开始的图片一样,整个控件使用起来非常方便,唯一不足的就是不能控制Flash的停止或者重新播放的操作,Flash一旦开始就没法通过接口来实现控制了,但可以通过Fash控件的菜单进行适度的控制。

本来的构思是在我的网站
http://www.iqidi.com
上部署一系列的宝宝学习题材,然后通过客户端链接网络,获取最新的学习题材链接,在客户端进行播放供天下所有父母的宝宝进行兴趣学习,父母在旁边进行讲解的。 由于时间关系,以及实现对Flash的加密保护处理较为麻烦点,这些东西没能来得及实现暂时搁置,先给大家一个例子尝鲜,呵呵。

例子下载地址:
h
ttp://files.cnblogs.com/wuhuacong/TestFlashPlayer.rar

时光飞逝,生活、工作、业余研究总是在不停忙碌着,转眼快到月底,该月的博客文章任务未完,停顿回忆一下,总结一些经验以及好的东西出来,大家一起分享一下。本文章主要介绍报表的生成,基于Aspose.Cell控件的报表生成。谈到报表,估计大家都有所领悟以及个人的理解,总的来说,一般的报表生成,基本上是基于以下几种方式:一种是基于微软Excel内置的引擎来实现;一种是构造HTML格式的Excle报表;一种是基于控件的方式来处理,基于控件有很多种方式,个人认为比较有名的是Aspose.Cell(收费破解)和NPOI(开源)。

而报表的表现方式大致可以分为两种:

一种是通用的二维表导出的Excel格式,这种方式通过封装一个操作类,传递一个DataTable参数,把数据导出就可以了。这种报表特点是操作方便,通用,能应付一般常用的数据报表,如下所示;

由于这种报表,一般是在一个数据表格中显示,通常的做法是把这个东西做成控件,一个可以解决分页问题,一个可以解决导出、打印问题等,如我的随笔文章《
WinForm界面开发之“分页控件”
》 介绍的解决办法。

当然,也可以把导入导出Excel的操作封装成一个公用的辅助来调用,如我封装的Aspose.Cell的导入导出处理函数如下所示:



代码


public

class
AsposeExcelTools
{


public

static

bool
DataTableToExcel(DataTable datatable,
string
filepath,
out

string
error)
{
error

=

""
;

try

{

if
(datatable
==

null
)
{
error

=

"
DataTableToExcel:datatable 为空
"
;

return

false
;
}

Aspose.Cells.Workbook workbook

=

new
Aspose.Cells.Workbook();
Aspose.Cells.Worksheet sheet

=
workbook.Worksheets[
0
];
Aspose.Cells.Cells cells

=
sheet.Cells;


int
nRow
=

0
;

foreach
(DataRow row
in
datatable.Rows)
{
nRow

++
;

try

{

for
(
int
i
=

0
; i
<
datatable.Columns.Count; i
++
)
{

if
(row[i].GetType().ToString()
==

"
System.Drawing.Bitmap
"
)
{

//
------插入图片数据-------


System.Drawing.Image image
=
(System.Drawing.Image)row[i];
MemoryStream mstream

=

new
MemoryStream();
image.Save(mstream, System.Drawing.Imaging.ImageFormat.Jpeg);
sheet.Pictures.Add(nRow, i, mstream);
}

else

{
cells[nRow, i].PutValue(row[i]);
}
}
}

catch
(System.Exception e)
{
error

=
error
+

"
DataTableToExcel:
"

+
e.Message;
}
}

workbook.Save(filepath);

return

true
;
}

catch
(System.Exception e)
{
error

=
error
+

"
DataTableToExcel:
"

+
e.Message;

return

false
;
}
}


public

static

bool
DataTableToExcel2(DataTable datatable,
string
filepath,
out

string
error)
{
error

=

""
;
Aspose.Cells.Workbook wb

=

new
Aspose.Cells.Workbook();


try

{

if
(datatable
==

null
)
{
error

=

"
DataTableToExcel:datatable 为空
"
;

return

false
;
}


//
为单元格添加样式


Aspose.Cells.Style style
=
wb.Styles[wb.Styles.Add()];

//
设置居中


style.HorizontalAlignment
=
Aspose.Cells.TextAlignmentType.Center;

//
设置背景颜色


style.ForegroundColor
=
System.Drawing.Color.FromArgb(
153
,
204
,
0
);
style.Pattern

=
BackgroundType.Solid;
style.Font.IsBold

=

true
;


int
rowIndex
=

0
;

for
(
int
i
=

0
; i
<
datatable.Columns.Count; i
++
)
{
DataColumn col

=
datatable.Columns[i];

string
columnName
=
col.Caption
??
col.ColumnName;
wb.Worksheets[

0
].Cells[rowIndex, i].PutValue(columnName);
wb.Worksheets[

0
].Cells[rowIndex, i].Style
=
style;
}
rowIndex

++
;


foreach
(DataRow row
in
datatable.Rows)
{

for
(
int
i
=

0
; i
<
datatable.Columns.Count; i
++
)
{
wb.Worksheets[

0
].Cells[rowIndex, i].PutValue(row[i].ToString());
}
rowIndex

++
;
}


for
(
int
k
=

0
; k
<
datatable.Columns.Count; k
++
)
{
wb.Worksheets[

0
].AutoFitColumn(k,
0
,
150
);
}
wb.Worksheets[

0
].FreezePanes(
1
,
0
,
1
, datatable.Columns.Count);
wb.Save(filepath);

return

true
;
}

catch
(Exception e)
{
error

=
error
+

"
DataTableToExcel:
"

+
e.Message;

return

false
;
}

}


///

<summary>


///
Excel文件转换为DataTable.

///

</summary>


///

<param name="filepath">
Excel文件的全路径
</param>


///

<param name="datatable">
DataTable:返回值
</param>


///

<param name="error">
错误信息:返回错误信息,没有错误返回""
</param>


///

<returns>
true:函数正确执行 false:函数执行错误
</returns>



public

static

bool
ExcelFileToDataTable(
string
filepath,
out
DataTable datatable,
out

string
error)
{
error

=

""
;
datatable

=

null
;

try

{

if
(File.Exists(filepath)
==

false
)
{
error

=

"
文件不存在
"
;
datatable

=

null
;

return

false
;
}
Aspose.Cells.Workbook workbook

=

new
Aspose.Cells.Workbook();
workbook.Open(filepath);
Aspose.Cells.Worksheet worksheet

=
workbook.Worksheets[
0
];
datatable

=
worksheet.Cells.ExportDataTable(
0
,
0
, worksheet.Cells.MaxRow
+

1
, worksheet.Cells.MaxColumn
+

1
);

//
-------------图片处理-------------


Aspose.Cells.Pictures pictures
=
worksheet.Pictures;

if
(pictures.Count
>

0
)
{

string
error2
=

""
;

if
(InsertPicturesIntoDataTable(pictures, datatable,
out
datatable,
out
error2)
==

false
)
{
error

=
error
+
error2;
}
}

return

true
;
}

catch
(System.Exception e)
{
error

=
e.Message;

return

false
;
}

}




public

static

bool
ExcelFileToLists(
string
filepath,
out
IList[] lists,
out

string
error)
{
error

=

""
;
lists

=

null
;
DataTable datatable

=

new
DataTable();
IList list

=

new
ArrayList();
Pictures[] pictures;

if
(ExcelFileToDataTable(filepath,
out
datatable,
out
error)
&&
GetPicturesFromExcelFile(filepath,
out
pictures,
out
error))
{
lists

=

new
ArrayList[datatable.Rows.Count];

//
------------DataTable转换成IList[]--------------

//
数据



int
nRow
=

0
;

foreach
(DataRow row
in
datatable.Rows)
{
lists[nRow]

=

new
ArrayList(datatable.Columns.Count);

for
(
int
i
=

0
; i
<=
datatable.Columns.Count
-

1
; i
++
)
{
lists[nRow].Add(row[i]);
}
nRow

++
;
}

//
图片



for
(
int
i
=

0
; i
<
pictures.Length; i
++
)
{

foreach
(Picture picture
in
pictures[i])
{

try

{

//
----把图片转换成System.Drawing.Image----

//
MemoryStream mstream = new MemoryStream();

//
mstream.Write(picture.Data, 0, picture.Data.Length);

//
System.Drawing.Image image = System.Drawing.Image.FromStream(mstream);

//
----Image放入IList------

//
图片有可能越界



if
(picture.UpperLeftRow
<=
datatable.Rows.Count
&&
picture.UpperLeftColumn
<=
datatable.Columns.Count)
{
lists[picture.UpperLeftRow][picture.UpperLeftColumn]

=
picture.Data;
}

}

catch
(System.Exception e)
{
error

=
error
+
e.Message;
}

}
}

}

else

{


return

false
;
}

return

true
;
}


public

static

bool
ListsToExcelFile(
string
filepath, IList[] lists,
out

string
error)
{
error

=

""
;

//
----------Aspose变量初始化----------------


Aspose.Cells.Workbook workbook
=

new
Aspose.Cells.Workbook();
Aspose.Cells.Worksheet sheet

=
workbook.Worksheets[
0
];
Aspose.Cells.Cells cells

=
sheet.Cells;

//
-------------输入数据-------------



int
nRow
=

0
;
sheet.Pictures.Clear();
cells.Clear();

foreach
(IList list
in
lists)
{


for
(
int
i
=

0
; i
<=
list.Count
-

1
; i
++
)
{

try

{
System.Console.WriteLine(i.ToString()

+

"

"

+
list[i].GetType());

if
(list[i].GetType().ToString()
==

"
System.Drawing.Bitmap
"
)
{

//
插入图片数据


System.Drawing.Image image
=
(System.Drawing.Image)list[i];

MemoryStream mstream

=

new
MemoryStream();

image.Save(mstream, System.Drawing.Imaging.ImageFormat.Jpeg);

sheet.Pictures.Add(nRow, i, mstream);
}

else

{
cells[nRow, i].PutValue(list[i]);
}
}

catch
(System.Exception e)
{
error

=
error
+
e.Message;
}

}

nRow

++
;
}

//
-------------保存-------------


workbook.Save(filepath);


return

true
;
}

这样封装了Aspose.Cell的操作,每次生成Excel文件或者导入Excel内容,就非常方便,只需要如下调用方式即可完成:


private

void
button1_Click(
object
sender, EventArgs e)
{
DataTable dt

=
CreateTable(
"
测试1,测试2,Test1,Test2
"
,
"
testTable
"
);

for
(
int
i
=

0
; i
<

100
; i
++
)
{
DataRow dr

=
dt.NewRow();

for
(
int
j
=

0
; j
<
dt.Columns.Count; j
++
)
{
dr[j]

=
i.ToString();
}
dt.Rows.Add(dr);
}


string
outError
=

""
;

string
fileName
=

@"
C:\test.xls
"
;
AsposeExcelTools.DataTableToExcel2(dt, fileName,

out
outError);



if
(
!
string
.IsNullOrEmpty(outError))
{
MessageBox.Show(outError);
}

else

{
Process.Start(fileName);
}
}



public
DataTable CreateTable(
string
nameString,
string
tableName)
{

string
[] nameArray
=
nameString.Split(
new

char
[] {
'
,
'
,
'
;
'
});
List

<
string
>
nameList
=

new
List
<
string
>
();

foreach
(
string
item
in
nameArray)
{

if
(
!
string
.IsNullOrEmpty(item))
{
nameList.Add(item);
}
}


return
CreateTable(nameList, tableName);
}

另外一种是以Excel文件作为模板,然后填入必要的内容,形成比较综合性,复杂性较高的报表,这种报表一般比较专业、比较规范好看,在一些特殊的场合,必须使用这些固定格式的报表,如下所示:

或者这样的报表格式

这些报表,基本上就是用到了变量、函数等的概念才能处理好这些数据,如上面的出库单,里面的成本中心、部门、库房编号等,这些通过变量绑定应该就可以了,而里面的列表,则可以通过集合绑定实现,Aspose.Cell控件功能非常强大,很好支持这些操作,下面一步步介绍该控件制作这类报表的实现代码。

Aspose.Cell控件支持多种参数变量的绑定操作,如支持DataSet、Datatable、IList集合,实体类集合、类对象等。

DataSet ds
=
LoadDataSet();
//
使用DataSet对象


List
<
Customers
>
entity
=
GetCustomers();
//
使用实体类对象


DataTable dt
=
GetCustomersTable();
//
使用DataTable对象


//
创建一个workbookdesigner对象


WorkbookDesigner designer
=

new
WorkbookDesigner();


//
制定报表模板



string
path
=
System.IO.Path.Combine(Application.StartupPath,
"
SmartMarkerDesigner.xls
"
);
designer.Open(path);


//
设置DataSet对象

//
designer.SetDataSource(ds);


//
设置实体类对象

//
designer.SetDataSource("Customers", entity);




//
设置Datatable对象

designer.SetDataSource(dt);
designer.SetDataSource(ds.Tables[

"
Order Details
"
]);


//
设置变量对象


designer.SetDataSource(
"
Variable
"
,
"
Single Variable
"
);

//
设置集合变量


designer.SetDataSource(
"
MultiVariable
"
,
new

string
[] {
"
Variable 1
"
,
"
Variable 2
"
,
"
Variable 3
"
});

//
设置集合变量


designer.SetDataSource(
"
MultiVariable2
"
,
new

string
[] {
"
Skip 1
"
,
"
Skip 2
"
,
"
Skip 3
"
});


//根据数据源处理生成报表内容


designer.Process();


//
保存Excel文件



string
fileToSave
=
System.IO.Path.Combine(Application.StartupPath,
"
SmartMarker.xls
"
);

if
(File.Exists(fileToSave))
{
File.Delete(fileToSave);
}

designer.Save(fileToSave, FileFormatType.Excel2003);

//打开Excel文件

Process.Start(fileToSave);

以上的代码说明了改控件支持的各种参数变量,我们先看看报表的模板,然后看看报表的生成内容,对比一下就更直观了。

报表1模板如下所示(其中通过引用集合的对象是通过&=来引用,对象的属性或者列名,通过如&=Customer.City方式引用,非常直观方便:


报表1生成的效果如下所示(Customers可以使DataTable对象,也可以List<Customer>实体对象集合。

报表2的模板如下所示,对象也可以通过&=[Order Detail]方式引用,另外模板支持一些参数,其中{r}为当行的变量,翻译到实际的报表可能就是C4*D4这样的格式了,其中两个&=表示动态公式引用,区别于普通的变量和字符,如&=&=C{r}*D{r}后者汇总函数&=&=Sum(C{r}:D{r})等等。

报表2的生成效果如下所示

报表3的模板如下所示,这个报表模板使用了对象变量,对象变量引用方式如&=$Variable这样格式,比集合对象或者DataTable对象多了一个$符号,其中集合支持一些遍历参数,如Skip,Horiontal等等。

报表3的生成效果如下所示

综上所述,模板报表的变量绑定方式有以下几种方式:

&=DataSource.FieldName

&=[Data Source].[Field Name]
&=$VariableName
&=$VariableArray
&==DynamicFormula
&=&=RepeatDynamicFormula

另外,模板报表支持一些参数进行辅助使用,如下所示:

noadd
适应数据而不添加额外的行(不知道是不是这样表达)
skip:n
每行记录跳过的数量,n=1代表依次遍历N=2则跳一个遍历
ascending:n / descending:n
排序数据供. 如果n=1,那么该列就是排序的第一个关键字,例子: &=Table1.Field3(ascending:1)
horizontal
默认是上下垂直方式输出,如果设置为horizontal,则是横着输出内容,见上面的例子

动态公式变量

另外,上面模板中看到&=&=C{r}*D{r}这样的动态公式,用于对列的应用,动态公式支持下面的引用变量:

{r}
- 当前行变量

{2}, {-1}
- 当前行的偏移位置

如果要汇总一些行列,可以使用&=&=Sum(C{r}:F{r})这样的动态变量来实现。

那如果是对同一列,不同行的字段进行汇总呢?,那样就更方便,不用这么复杂了,你只要使用普通的汇总函数如=Sum(C3:C4)这样的格式,就可以了,如果行动态增加,Excel会自动调整Sum函数里面的行列引用了,可能最后输出会变为=Sum(C3:C11)这样了。

汇总格式变量

可以通过
group:normal/merge/repeat
来控制汇总合并等格式的输出,如使用两者的例子:

&=Customers.CustomerID(group:merge)

&=Employees.EmployeeID(group:normal,skip:1)

出来的报表如下所示:





subtotalN函数

分别代表1=AVERAGE, 2=COUNT,3=COUNTA, 4=MAX, 5=MIN,...9=SUM等等

该函数是用来执行一系列汇总计算的函数,N从
1~11
subtotalN:Ref,其中Ref代表汇总的指定列

例如,&=Products.Units(subtotal9:Products.ProductID) 表示基于Units列进行数据汇总统计,统计到ProductID上来。

例如,&=Table1.ColumnD(subtotal9:Table1.ColumnA&Table1.ColumnB) ,则表示基于ColumnD列进行汇总统计,统计到ColumnA和ColumnB的分组条件上。

本篇由于篇幅原因,介绍到这里,下篇继续探讨基于模板生成的报表内容,包括利用对象动态创建行列以及公式,使用Style等方面,并结合实际复杂的报表例子,对基于Aspose.Cell报表内容进行进一步的实战分析探讨。

应读者要求,放上一个操作例子:
https://files.cnblogs.com/wuhuacong/TestAposeCell.rar

继续在上篇《
使用Aspose.Cell控件实现Excel高难度报表的生成(一)
》随笔基础上,研究探讨基于模板的Aspose.cell报表实现,其中提到了下面两种报表的界面,如下所示:

或者这样的报表格式


首先来分析第一种报表,这个其实还是比较固定的二维表,我们只要绑定相关的信息即可,设计模板如下所示:


实际生成的报表如下所示:

实现的代码其实不复杂,如下所示:


private
DataTable GetTable(
string
sql)

{
Database db

=
DatabaseFactory.CreateDatabase();
DbCommand command

=
db.GetSqlStringCommand(sql);

return
db.ExecuteDataSet(command).Tables[
0
];
}

private

void
btnAllMonthReport_Click(
object
sender, EventArgs e)
{

string
sql
=

@"
Select [LastCount] as LC, [LastMoney] as LM, [CurrentInCount] as CIC, [CurrentInMoney] as CIM,
[CurrentOutCount] as COC, [CurrentOutMoney] as COM, [CurrentCount] as CC, [CurrentMoney] as CM,
YearMonth,ItemName
from TB_ReportMonthCheckOut

"
;
DataTable dtBigType

=
GetTable(sql
+

"
where ReportType =3
"
);
dtBigType.TableName

=

"
BigType
"
;

if
(dtBigType.Rows.Count
==

0
)

return
;

DataTable dtItemType

=
GetTable(sql
+

"
where ReportType =3
"
);
dtItemType.TableName

=

"
ItemType
"
;

WorkbookDesigner designer

=

new
WorkbookDesigner();

string
path
=
System.IO.Path.Combine(Application.StartupPath,
"
Report2-1.xls
"
);
designer.Open(path);
designer.SetDataSource(dtBigType);
designer.SetDataSource(dtItemType);
designer.SetDataSource(

"
YearMonth
"
, dtBigType.Rows[
0
][
"
YearMonth
"
].ToString());
designer.Process();


//
Save the excel file



string
fileToSave
=
FileDialogHelper.SaveExcel();

if
(File.Exists(fileToSave))
{
File.Delete(fileToSave);
}
designer.Save(fileToSave, FileFormatType.Excel2003);
Process.Start(fileToSave);
}


通过绑定两个不同的DataTable对象,然后引用他的属性即可,行会自动增加以适应实际的数据,并且对象变量&=$YearMonth也正常显示了,注意一点就是,所有使用变量的地方,都必须在一个独立的Excel单元格中,否则不能解析出来。另外上图的红色圆圈里面表示,汇总的函数,会自动根据行列的增加,自动调整引用,这真是我们需要的。

出库单的实现也差不多,实现代码如下所示:


string
TakeOutBill
=
Path.Combine(Application.StartupPath,
"
TakeOutBill.xls
"
);
WorkbookDesigner designer

=

new
WorkbookDesigner();
designer.Open(TakeOutBill);
designer.SetDataSource(

"
TakeOutDate
"
, DateTime.Now.ToString(
"
yyyy-MM-dd
"
));
designer.SetDataSource(

"
WareHouse
"
,
this
.txtWareHouse.Text);
designer.SetDataSource(

"
Manager
"
,
this
.txtCreator.Text);
designer.SetDataSource(

"
CostCenter
"
,
this
.txtCostCenter.Text);
designer.SetDataSource(

"
Dept
"
,
this
.txtDept.Text);


string
columns
=

"
Start|int,ItemNo,ItemName,Specification,Unit,Price|decimal,Count|int
"
;
DataTable dt

=
DataTableHelper.CreateTable(columns);
dt.TableName

=

"
Detail
"
;
DataRow row

=

null
;

for
(
int
i
=

0
; i
<

this
.lvwDetail.Items.Count; i
++
)
{
PurchaseDetailInfo info

=

this
.lvwDetail.Items[i].Tag
as
PurchaseDetailInfo;

if
(info
!=

null
)
{
row

=
dt.NewRow();
row[

"
Start
"
]
=
(i
+

1
);
row[

"
ItemNo
"
]
=
info.ItemNo;
row[

"
ItemName
"
]
=
info.ItemName;
row[

"
Specification
"
]
=
info.Specification;
row[

"
Unit
"
]
=
info.Unit;
row[

"
Price
"
]
=
info.Price;
row[

"
Count
"
]
=
Math.Abs(info.Quantity);
dt.Rows.Add(row);
}
}
designer.SetDataSource(dt);
designer.Process();

string
fileToSave
=
FileDialogHelper.SaveExcel();

if
(File.Exists(fileToSave))
{
File.Delete(fileToSave);
}
designer.Save(fileToSave, FileFormatType.Excel2003);
Process.Start(fileToSave);


以上报表,其实实现思路基本都差不多,相对来时,还是比较容易的,接下来设计一个比较困难的报表,需要结合Aspose.Cell一些对象来动态创建行列,并设置单元格的变量,然后填入相应的对象构造报表,另外还需要注意单元格格式的变化,如下所示的这种报表

这个报表初看没有太多特别的地方,难点就是他的第一行列也是变化的,因此不能通过普通的方式构建二维表,然后绑定数据源的方式,要先加载模板文件,然后操作Excel对象,把第一行的各列头部补齐,然后给下一行各单元格填入对象公式,如&=BigType.DeptName 和&=BigType.TotalMoney等内容,实现的代码如下所示:


string
sql
=

@"
Select [YearMonth], [DeptName], [ItemType], [TotalMoney]
from TB_ReportDeptCost

"
;
DataTable dt

=
GetTable(sql);

if
(dt.Rows.Count
==

0
)

return
;

List

<
string
>
itemTypeList
=

new
List
<
string
>
();
List

<
string
>
partList
=

new
List
<
string
>
();

foreach
(DataRow row
in
dt.Rows)
{

string
itemType
=
row[
"
ItemType
"
].ToString();

if
(
!
itemTypeList.Contains(itemType))
{
itemTypeList.Add(itemType);
}


string
part
=
row[
"
DeptName
"
].ToString();

if
(
!
partList.Contains(part))
{
partList.Add(part);
}
}


string
columnString
=

"
DeptName
"
;

for
(
int
i
=

0
; i
<
itemTypeList.Count; i
++
)
{
columnString

+=

string
.Format(
"
,TotalMoney{0}|decimal
"
, i);
}
DataTable dtBigType

=
DataTableHelper.CreateTable(columnString);
dtBigType.TableName

=

"
BigType
"
;

foreach
(
string
part
in
partList)
{
DataRow row

=
dtBigType.NewRow();
row[

"
DeptName
"
]
=
part;

for
(
int
i
=

0
; i
<
itemTypeList.Count; i
++
)
{

string
itemType
=
itemTypeList[i];
DataRow[] rowSelect

=
dt.Select(
string
.Format(
"
DeptName='{0}' AND ItemType='{1}'
"
, part, itemType));

if
(rowSelect.Length
>

0
)
{
row[

"
TotalMoney
"

+
i.ToString()]
=
rowSelect[
0
][
"
TotalMoney
"
];
}
}
dtBigType.Rows.Add(row);
}

WorkbookDesigner designer

=

new
WorkbookDesigner();

string
path
=
System.IO.Path.Combine(Application.StartupPath,
"
Report1.xls
"
);
designer.Open(path);

Aspose.Cells.Worksheet w

=
designer.Workbook.Worksheets[
0
];

//
先设置标题项目:如大修件,日常备件等



int
rowIndex
=

2
;
//
第三行为标题


Aspose.Cells.Style style
=
w.Cells[rowIndex
+

1
,
1
].Style;
//
继承数字栏目的样式


style.Number
=

4
;
//
对应格式是#,##0.00


Aspose.Cells.Style boldStyle
=
w.Cells[rowIndex,
0
].Style;
//
继承开始栏目的样式



for
(
int
i
=

0
; i
<
itemTypeList.Count; i
++
)
{
w.Cells[rowIndex, i

+

1
].PutValue(itemTypeList[i]);
w.Cells[rowIndex, i

+

1
].Style
=
boldStyle;
w.Cells[rowIndex

+

1
, i
+

1
].PutValue(
"
&=BigType.TotalMoney
"

+
i.ToString());
w.Cells[rowIndex

+

1
, i
+

1
].Style
=
style;
}


//
添加合计行


w.Cells[rowIndex, itemTypeList.Count
+

1
].PutValue(
"
合计
"
);
w.Cells[rowIndex, itemTypeList.Count

+

1
].Style
=
boldStyle;
w.Cells[rowIndex

+

1
, itemTypeList.Count
+

1
].PutValue(
string
.Format(
"
&=&=SUM(B{{r}}:{0}{{r}})
"
, GetChar(itemTypeList.Count
+

1
)));
w.Cells[rowIndex

+

1
, itemTypeList.Count
+

1
].Style
=
style;

designer.SetDataSource(dtBigType);
designer.SetDataSource(

"
YearMonth
"
, dt.Rows[
0
][
"
YearMonth
"
].ToString());
designer.Process();


//
Save the excel file



string
fileToSave
=
FileDialogHelper.SaveExcel();

if
(File.Exists(fileToSave))
{
File.Delete(fileToSave);
}
designer.Save(fileToSave, FileFormatType.Excel2003);
Process.Start(fileToSave);

jquery-easyui是一个基于jquery的图形界面插件,利用easyui可以创建很多好看的网页界面效果,easyui的相关地址是:http://jquery-easyui.wikidot.com/; easyui的中文文档地址是:http://www.easyui.net/,本人也利用easeyUI在做一些页面效果。由于我很喜欢那种弹出的对话框界面,因此在界面中应用了Dialog类来处理一些确认的信息,但在利用中发现,弹出的对话框,不能再继续执行asp.net按钮的后台响应代码。界面如下所示。

操作是在按钮提交后,弹出一个对话框层,用来确认流程的信息,不过奇怪的是里面原本是asp.net图片服务器控件却不能提交了,无法触发后台按钮,其中页面的代码如下所示,注意如果要对话框默认开始不显示出来,通过设置closed:true,属性即可。

<
script
language
="javascript"
>

$(

function
(){

var
dlg
=
jQuery(
"
#dd
"
).dialog({
draggable:

true
,
resizable:

true
,
closed:

true
,
show:

'
Transfer
'
,
hide:

'
Transfer
'
,
autoOpen:

false
,
width:

600
,
minHeight:

10
,
minwidth:

10

});


});


function
open1(){
$(

'
#dd
'
).dialog(
'
open
'
);
}

function
close1(){
$(

'
#dd
'
).dialog(
'
close
'
);
}


</
script
>

对应的弹出层内容如下所示:


<
div
id
="dd"
title
="处理流程"
icon
="icon-save"
style
="overflow:auto;padding:10px;"
>


<
table
width
="100%"
cellpadding
="0"
cellspacing
="1"
border
="0"
id
="Table1"
>


<
tr
>


<
td
>


<
asp:DataGrid
ID
="dg"
runat
="server"
Width
="100%"
CssClass
="dg"
AutoGenerateColumns
="False"

PageSize

="20"
AllowSorting
="True"
DataKeyField
="ID"
Height
="0px"
OnItemDataBound
="dg_ItemDataBound"
>


<
EditItemStyle
CssClass
="EditItem"
></
EditItemStyle
>


<
AlternatingItemStyle
CssClass
="AlternatingItem"
></
AlternatingItemStyle
>


<
ItemStyle
CssClass
="Item"
></
ItemStyle
>


<
HeaderStyle
CssClass
="Header"
></
HeaderStyle
>


<
FooterStyle
CssClass
="Footer"
></
FooterStyle
>


<
Columns
>


<
asp:TemplateColumn
HeaderText
="ID"
Visible
="false"
>


<
ItemTemplate
>


<
asp:Label
ID
="lblId"
runat
="server"
Text
='<%#
DataBinder.Eval(Container, "DataItem.id") %
>
'>
</
asp:Label
>


</
ItemTemplate
>


</
asp:TemplateColumn
>


<
asp:TemplateColumn
HeaderText
="序号"
>


<
ItemTemplate
>


<
asp:Label
ID
="lblOrderbyId"
runat
="server"
Text
='<%#
DataBinder.Eval(Container, "DataItem.OrderbyId") %
>
'>
</
asp:Label
>


</
ItemTemplate
>


</
asp:TemplateColumn
>


<
asp:TemplateColumn
HeaderText
="处理类型"
>


<
ItemTemplate
>


<
asp:Label
ID
="lblproctype"
runat
="server"
Text
='<%#
DataBinder.Eval(Container, "DataItem.proctype") %
>
'>
</
asp:Label
>


</
ItemTemplate
>


</
asp:TemplateColumn
>


<
asp:TemplateColumn
HeaderText
="流程名称"
>


<
ItemTemplate
>


<
asp:Label
ID
="lblflowname"
runat
="server"
Text
='<%#
DataBinder.Eval(Container, "DataItem.flowname") %
>
'>
</
asp:Label
>


</
ItemTemplate
>


</
asp:TemplateColumn
>


<
asp:TemplateColumn
HeaderText
="流程处理人"
>


<
ItemTemplate
>


<
asp:Label
ID
="lblproc_user"
runat
="server"
Text
='<%#
DataBinder.Eval(Container, "DataItem.procuser") %
>
'>
</
asp:Label
>


<
asp:DropDownList
ID
="ddlproc_user"
runat
="server"
Visible
="false"

/>


</
ItemTemplate
>


</
asp:TemplateColumn
>


<
asp:TemplateColumn
HeaderText
="流程步骤描述"
>


<
ItemTemplate
>


<
asp:Label
ID
="lblmayaddflow"
runat
="server"
Text
='<%#
DataBinder.Eval(Container, "DataItem.flownote") %
>
'>
</
asp:Label
>


</
ItemTemplate
>


</
asp:TemplateColumn
>


</
Columns
>


</
asp:DataGrid
>


</
td
>


</
tr
>


</
table
>



<
table
class
="formitem_pagestyle"
cellspacing
="0"
cellpadding
="0"
border
="0"
style
="width: 100%;
border-collapse: collapse;"

>


<
tr
>


<
td
class
="pagebutton"
align
="right"
style
="height: 30px; width: 100%;"
>


<
asp:ImageButton
ID
="imgbtnOK"
runat
="server"
ImageUrl
="~/Themes/Default/btn_savetobox.gif"

OnClick

="imgbtnOK_Click"

/>
&nbsp;


<
img
src
="http://www.cnblogs.com/Themes/Default/btn_close.gif"
border
="0"
onclick
="close1()"
/>


</
td
>


</
tr
>


</
table
>


</
div
>


<
br
/><
br
/>


<
div
align
="center"
>


<
img
src
="http://www.cnblogs.com/Themes/Default/btn_savetobox.gif"
border
="0"
onclick
="open1()"
/>


<
asp:ImageButton
ID
="imgbtnBack"
runat
="server"
ImageUrl
="~/Themes/Default/btn_back.gif"

CausesValidation

="false"
OnClick
="imgbtnBack_Click"

/>


</
div
>

搜索相关问题发现,其中主要问题是出在:JQuery会把Dialog的元素append到Body里面,而不是form里面。研究了页面源码后发现,jQuery UI Dialog控件初始化时动态生成的HTML元素被添加到页面的尾部、form元素的后面,而原始的Dialog模板部分(其内包含表单元素)也被移到了 动态生成的HTML元素内。也就是说,原先在form内的表单在Dialog初始化后就被移到form外了,这就导致了Dialog模板内表单全部失效。

解决方法是增加一行代码即可:dlg.parent().appendTo(jQuery("form:first"));

也就是修改开始部分创建对话框的脚本即可:


<
script
language
="javascript"
>

$(

function
(){

var
dlg
=
jQuery(
"
#dd
"
).dialog({
draggable:

true
,
resizable:

true
,
closed:

true
,
show:

'
Transfer
'
,
hide:

'
Transfer
'
,
autoOpen:

false
,
width:

600
,
minHeight:

10
,
minwidth:

10

});
dlg.parent().appendTo(jQuery(

"
form:first
"
));
});


function
open1(){
$(

'
#dd
'
).dialog(
'
open
'
);
}

function
close1(){
$(

'
#dd
'
).dialog(
'
close
'
);
}

</
script
>

另外你也可以通过这种方法来处理该问题:

$('#dialog_link').click(function () {

$('#dialog').dialog('open');

$('#dialog').parent().appendTo($("form:first"))

return false;

});

上述的解决问题详细可以参考老外的一篇问题回复文章:
JQuery UI Dialog with Asp .NET button postback..

新浪博客,网易博客,都是博客中的佼佼者,其中网易提供的圈子信息,更胜一筹,使得一般用户能够通过访问圈子进入相关的群组,或者获取相关圈子用户的信息等,以实现各种精准营销的目的。虽然新浪遮遮掩掩不提供圈子的相关信息,相对而言,网易博客提供圈子,能够使得更多的人、更多的程序支持,推高博客的知名度及实用性。网易博客可以通过地址
http://q.163.com/
访问,它是经过两级分类的,如下所示。

点击分类进入即可查看到每个子分类都有很多圈子,圈子累死QQ的群组,是某一兴趣团体的博客,里面收集很多相关的资料及信息,如下所示:

这里不关心圈子的有哪些宝贵学习资料,我更关心的是这些圈子的用户如何采集出来,由于用户都是网易的用户,因此他们一个账户就会对应一个账号,有163.com,163.net,yeah.net,126.com等等的,我们先看看圈子的用户信息是如何显示的。

我们看到上图里面圈子的信息是一个列表,有的圈子多,有的圈子少,不过他们的名称中都会关联一个博客地址的,由于博客地址和邮件地址有一一对应关系,因此可以获取对应的邮件信息,这就是我们所要的重要信息。

下面用一个程序来介绍如何采集圈子的分类、圈子数据以及圈子用户资料信息,测试的程序如下所示:

下面我们来看看按钮”刷新分类数据“的实现代码,主要是获取圈子大类、圈子子类以及保存数据操作,代码如下所示:


private

void
btnRefreshCategory_Click(
object
sender, EventArgs e)
{

string
url
=

"
http://q.163.com/
"
;

string
mainTypeReg
=

"
<div\\s*style=\"font-size:14px;\"><b><a\\s*?href=\"(?<value>.*?)\">(?<key>.*?)</a></b></div>
"
;

string
subTypeReg
=

"
<div\\s*class=\"left\"><a\\s*href=\"(?<value>.*?)\">(?<key>.*?)</a></div>
"
;


#region
取得大类


httpHelper.Encoding

=
Encoding.Default;

string
content
=
httpHelper.GetHtml(url);
Regex re

=

new
Regex(mainTypeReg, RegexOptions.IgnoreCase
|
RegexOptions.Singleline
|
RegexOptions.IgnorePatternWhitespace);
Match mc

=
re.Match(content);
Dictionary

<
string
,
string
>
typeDict
=

new
Dictionary
<
string
,
string
>
();

if
(mc.Success)
{
MatchCollection mcs

=
re.Matches(content);

foreach
(Match me
in
mcs)
{

string
strKey
=
me.Groups[
"
key
"
].Value;

string
strValue
=
me.Groups[
"
value
"
].Value;

//
截取连接前面部分作为大类标识



string
newValue
=
strValue.TrimEnd(
'
/
'
);

int
eIndex
=
newValue.LastIndexOf(
'
/
'
);
newValue

=
newValue.Substring(
0
, eIndex)
+

"
/
"
;


if
(
!
typeDict.ContainsKey(strKey))
{
typeDict.Add(strKey, newValue);
}
}
}

#endregion



#region
取得子类

Dictionary

<
string
, CircleSubTypeInfo
>
circleDict
=

new
Dictionary
<
string
, CircleSubTypeInfo
>
();
re

=

new
Regex(subTypeReg, RegexOptions.IgnoreCase
|
RegexOptions.Singleline
|
RegexOptions.IgnorePatternWhitespace);
mc

=
re.Match(content);

if
(mc.Success)
{
MatchCollection mcs

=
re.Matches(content);

foreach
(Match me
in
mcs)
{

string
strKey
=
me.Groups[
"
key
"
].Value;

string
strValue
=
me.Groups[
"
value
"
].Value;

//
截取连接前面部分作为大类标识



string
typeValue
=
strValue.TrimEnd(
'
/
'
);

int
eIndex
=
typeValue.LastIndexOf(
'
/
'
);
typeValue

=
typeValue.Substring(
0
, eIndex)
+

"
/
"
;


if
(
!
circleDict.ContainsKey(strKey))
{
CircleSubTypeInfo info

=

new
CircleSubTypeInfo();
info.Name

=
strKey;
info.LinkUrl

=
strValue;
info.TypeUrlValue

=
typeValue;

circleDict.Add(strKey, info);
}
}
}

#endregion




#region
保存数据

Database db

=
DatabaseFactory.CreateDatabase();
DbCommand command

=

null
;

string
sql
=

""
;


foreach
(
string
key
in
typeDict.Keys)
{
sql

=

string
.Format(
"
Insert into CircleType(TypeName, TypeValue) values('{0}', '{1}')
"
, key, typeDict[key]);
command

=
db.GetSqlStringCommand(sql);
db.ExecuteNonQuery(command);
}


foreach
(
string
key
in
circleDict.Keys)
{
CircleSubTypeInfo info

=
circleDict[key];
sql

=

string
.Format(
"
Insert into CircleSubType(SubTypeName, LinkUrl, TypeUrlValue) values('{0}', '{1}', '{2}')
"
, info.Name, info.LinkUrl, info.TypeUrlValue);
command

=
db.GetSqlStringCommand(sql);
db.ExecuteNonQuery(command);
}

#endregion



this
.lblTips.Text
=

"
获取分类操作完成
"
;

}


其中主要是采用了正则表达式来对获取的内容进行处理,然后整理出来相关的分类数据放到数据库中,以便获取圈子用户信息作准备。

有了圈子分类信息,我们第二步骤就是看如何获取圈子数据,然后才能通过圈子的唯一ID获取圈子的用户资料,这步也是必须的,获取圈子资料是比较复杂的,需要组装较多的参数获取资料,部分代码如下所示。


foreach
(
string
key
in
urlDict.Keys)
{

string
keyNumberReg
=

"
/mapCircleList/(?<d1>[1-9]\\d*)/(?<d2>[1-9]\\d*)*/(?<d3>[1-9]\\d*)/
"
;
Regex re

=

new
Regex(keyNumberReg, RegexOptions.IgnoreCase
|
RegexOptions.Singleline
|
RegexOptions.IgnorePatternWhitespace);

LogTextHelper.WriteLine(

string
.Format(
"
正在处理类型:{0}
"
, urlDict[key]));
cookie

=

new
System.Net.CookieContainer();


string
urlKey
=
key;
Match mc

=
re.Match(urlKey);

string
d1
=
mc.Groups[
"
d1
"
].Value;

string
d2
=
mc.Groups[
"
d2
"
].Value;

string
d3
=
mc.Groups[
"
d3
"
].Value;

int
pageSize
=

30
;

urlKey

=
urlKey.Trim(
'
/
'
);
//
清除前后的/字符



string
url
=

"
http://q.163.com/dwr/call/plaincall/CircleMainpageBean.getCircleByType2IdInMemberOrder.dwr
"
;

//
string refUrl = "
http://q.163.com/mapCircleList/2/11/48/?fromCircleCircleMap
";



string
refUrl
=

string
.Format(
"
http://q.163.com/{0}/?fromCircleCircleMap
"
, urlKey);

#region
内容正则表达式

StringBuilder circleReg

=

new
StringBuilder();
circleReg.Append(

"
s[0-9]\\d*.circleId=(?<circleId>[0-9]\\d*[^;])
"
);
circleReg.Append(

"
.*?s[0-9]\\d*.circleType1Str=\"(?<circleType1Str>.*?)\"
"
);
circleReg.Append(

"
.*?s[0-9]\\d*.circleType2Str=\"(?<circleType2Str>.*?)\"
"
);
circleReg.Append(

"
.*?s[0-9]\\d*.createDateStr=\"(?<createDateStr>.*?)\"
"
);
circleReg.Append(

"
.*?s[0-9]\\d*.creatorId=(?<creatorId>[0-9]\\d*[^;])
"
);
circleReg.Append(

"
.*?s[0-9]\\d*.creatorName=\"(?<creatorName>.*?)\"
"
);
circleReg.Append(

"
.*?s[0-9]\\d*.creatorSpaceUrl=\"(?<creatorSpaceUrl>.*?)\"
"
);
circleReg.Append(

"
.*?s[0-9]\\d*.description=\"(?<description>.*?)\"
"
);
circleReg.Append(

"
.*?s[0-9]\\d*.joinDeclaration=\"(?<joinDeclaration>.*?)\"
"
);
circleReg.Append(

"
.*?s[0-9]\\d*.linkImgUrl=\"(?<linkImgUrl>.*?)\"
"
);
circleReg.Append(

"
.*?s[0-9]\\d*.memberNum=(?<memberNum>[0-9]\\d*[^;])
"
);
circleReg.Append(

"
.*?s[0-9]\\d*.name=\"(?<name>.*?)\"
"
);
circleReg.Append(

"
.*?s[0-9]\\d*.urlName=\"(?<urlName>.*?)\"
"
);
circleReg.Append(
"
.*?s[0-9]\\d*.visitNum=(?<visitNum>[0-9]\\d*[^;])
"
);


通过组装参数数据,然后获取页面数据,对页面数据进行分析即可,主要代码如下所示:

if
(mc.Success)
{

string
message
=

string
.Format(
"
正在处理类型{0}:{1}, 第{2}次数据, 共处理了{3}
"
, urlDict[key], url, i
+

1
, j);
CallCtrlWithThreadSafety.SetText(

this
.lblTips, message,
this
);
Application.DoEvents();
Thread.Sleep(

10
);

MatchCollection mcs

=
re.Matches(content);

foreach
(Match me
in
mcs)
{

#region
MyRegion

j

++
;


int
memberNum
=

0
;

try

{
memberNum

=
Convert.ToInt32(me.Groups[
"
memberNum
"
].Value);
}

catch
{ }

if
(memberNum
<

50
)
{
flag

=

false
;

break
;
}


sql

=

string
.Format(
@"
insert into Circle(circleId,circleType1Str,circleType2Str,createDateStr,creatorId,
creatorName,creatorSpaceUrl,description,joinDeclaration,linkImgUrl,memberNum,name2,urlName,SubTypeName)
values('{0}','{1}','{2}','{3}','{4}','{5}','{6}','{7}','{8}','{9}','{10}','{11}','{12}','{13}')

"
, me.Groups[
"
circleId
"
].Value,
UnicodeHelper.UnicodeToString(me.Groups[

"
circleType1Str
"
].Value.Replace(
"
'
"
,
""
)), UnicodeHelper.UnicodeToString(me.Groups[
"
circleType2Str
"
].Value.Replace(
"
'
"
,
""
)),
me.Groups[

"
createDateStr
"
].Value, me.Groups[
"
creatorId
"
].Value, UnicodeHelper.UnicodeToString(me.Groups[
"
creatorName
"
].Value),
me.Groups[

"
creatorSpaceUrl
"
].Value, UnicodeHelper.UnicodeToString(me.Groups[
"
description
"
].Value.Replace(
"
'
"
,
""
)), UnicodeHelper.UnicodeToString(me.Groups[
"
joinDeclaration
"
].Value.Replace(
"
'
"
,
""
)),
me.Groups[

"
linkImgUrl
"
].Value, me.Groups[
"
memberNum
"
].Value, UnicodeHelper.UnicodeToString(me.Groups[
"
name
"
].Value.Replace(
"
'
"
,
""
)), me.Groups[
"
urlName
"
].Value, urlDict[key]);
command

=
db.GetSqlStringCommand(sql);

try

{
db.ExecuteNonQuery(command);
}

catch
(Exception ex)
{
LogTextHelper.WriteLine(sql);
LogTextHelper.WriteLine(ex.ToString());
}

message

=

string
.Format(
"
正在处理{0}:{1} 正在写入数据{2}次
"
, urlDict[key], url, j);
CallCtrlWithThreadSafety.SetText(

this
.lblTips, message,
this
);
Application.DoEvents();
Thread.Sleep(

10
);


#endregion

}
}

else

{
flag

=

false
;
//
没有匹配就停止



break
;
}

}

构造获取圈子用户信息也是比较复杂的一个过程,需要组装更多的参数来获取相关的数据,部分主要实现代码如下所示:

httpHelper
=

new
HttpHelper();
httpHelper.Encoding

=
Encoding.Default;
cookie

=

new
CookieContainer();
Regex re

=

null
;
Match mc

=

null
;

int
pageSize
=

30
;

string
url
=

"
http://q.163.com/dwr/call/plaincall/CircleBean.getNewCircleUsers.dwr
"
;


foreach
(
string
key
in
circlelDict.Keys)
{

string
circleId
=
key;

string
urlName
=
circlelDict[key];



string
refUrl
=

string
.Format(
"
http://q.163.com/{0}/members/
"
, urlName);


#region
内容正则表达式

StringBuilder circleReg

=

new
StringBuilder();
circleReg.Append(

"
s[0-9]\\d*.ageStr=\"(?<ageStr>.*?)\"
"
);
circleReg.Append(

"
.*?s[0-9]\\d*.city=\"(?<city>.*?[^;])\"
"
);
circleReg.Append(

"
.*?s[0-9]\\d*.hometownCity=(\"(?<hometownCity>.*?[^;])\"|(?<hometownCity>null))
"
);
circleReg.Append(

"
.*?s[0-9]\\d*.hometownProvince=(\"(?<hometownProvince>.*?)\"|(?<hometownProvince>null))
"
);
circleReg.Append(

"
.*?s[0-9]\\d*.name=(\"(?<name>.*?)\"|(?<name>null))
"
);
circleReg.Append(

"
.*?s[0-9]\\d*.nickname=(\"(?<nickname>.*?)\"|(?<nickname>null))
"
);
circleReg.Append(

"
.*?s[0-9]\\d*.profileImage140=\"(?<profileImage140>.*?)\"
"
);
circleReg.Append(

"
.*?s[0-9]\\d*.profileImage60=\"(?<profileImage60>.*?)\"
"
);
circleReg.Append(

"
.*?s[0-9]\\d*.province=\"(?<province>.*?)\"
"
);
circleReg.Append(

"
.*?s[0-9]\\d*.qq=(\"(?<qq>.*?)\"|(?<qq>null))
"
);
circleReg.Append(

"
.*?s[0-9]\\d*.realName=(\"(?<realName>.*?)\"|(?<realName>null))
"
);
circleReg.Append(

"
.*?s[0-9]\\d*.spaceName=(\"(?<spaceName>.*?)\"|(?<spaceName>null))
"
);
circleReg.Append(

"
.*?s[0-9]\\d*.userId=(?<userId>[0-9]\\d*[^;])
"
);
circleReg.Append(

"
.*?s[0-9]\\d*.userName=\"(?<userName>.*?)\"
"
);

#endregion



bool
flag
=

true
;

int
i
=

0
;

int
j
=

0
;
List

<
CircleMemberInfo
>
entityList
=

new
List
<
CircleMemberInfo
>
();

while
(flag)
{

#region
构造提交参数

StringBuilder sb

=

new
StringBuilder();
sb.AppendFormat(

"
callCount=1
"
);
sb.AppendFormat(

"
&page=/{0}/members/
"
, urlName);
sb.AppendFormat(

"
&httpSessionId=
"
);
sb.AppendFormat(

"
&scriptSessionId=D4DAC4AD9C3BF9B71C82802BDDBA0C25369
"
);
sb.AppendFormat(

"
&c0-scriptName=CircleBean
"
);
sb.AppendFormat(

"
&c0-methodName=getNewCircleUsers
"
);
sb.AppendFormat(

"
&c0-id=0
"
);
//
保留字符


sb.AppendFormat(
"
&c0-param0=number:{0}
"
, circleId);
//
11


sb.AppendFormat(
"
&c0-param1=number:{0}
"
, pageSize);
//
数量


sb.AppendFormat(
"
&c0-param2=number:{0}
"
, pageSize
*
i);
//
0,30,60


sb.AppendFormat(
"
&c0-param3=boolean:true
"
);
sb.AppendFormat(

"
&batchId={0}
"
, i);

i
++
;

#endregion


然后我们通过代码来获取页面数据了,实现代码如下:

string
content
=

""
;

try

{
httpHelper.ContentType

=

"
text/plain
"
;
content

=
httpHelper.GetHtml(url, cookie, sb.ToString(),
true
, refUrl);
re

=

new
Regex(circleReg.ToString(), RegexOptions.IgnoreCase
|
RegexOptions.Singleline
|
RegexOptions.IgnorePatternWhitespace);
mc

=
re.Match(content);
}

catch
(Exception ex)
{
LogTextHelper.WriteLine(ex.ToString());

break
;

}


然后我们就开始用正则表达式来分析返回的数据,以便显示或者添加到数据库中,以供他用,代码实现如下所示:、

MatchCollection mcs
=
re.Matches(content);

foreach
(Match me
in
mcs)
{

#region
MyRegion

j

++
;


sql

=

string
.Format(
@"
insert into CircleMember(userId,userName,realName,nickname,circleId)
values('{0}','{1}','{2}','{3}','{4}')

"
, me.Groups[
"
userId
"
].Value, httpHelper.RemoveHtml(UnicodeHelper.UnicodeToString(me.Groups[
"
userName
"
].Value)),
httpHelper.RemoveHtml(UnicodeHelper.UnicodeToString(me.Groups[

"
realName
"
].Value.Replace(
"
'
"
,
""
))), httpHelper.RemoveHtml(UnicodeHelper.UnicodeToString(me.Groups[
"
nickname
"
].Value.Replace(
"
'
"
,
""
))), circleId);
command

=
db.GetSqlStringCommand(sql);

try

{
db.ExecuteNonQuery(command);
}

catch
(Exception ex)
{
LogTextHelper.WriteLine(sql);
LogTextHelper.WriteLine(ex.ToString());
}

message

=

string
.Format(
"
正在处理{0} 正在写入数据{1}次
"
, urlName, j);
CallCtrlWithThreadSafety.SetText(

this
.lblTips, message,
this
);
Application.DoEvents();
Thread.Sleep(

10
);

#endregion

}


以上就是获取数据的一个完整的过程,其中涉及到获取圈子大类、圈子分类、圈子信息,以及最终获取圈子的用户信息,其中较为详细的介绍了各种数据的正则分析过程,如果您有这方面的应用,一个可以参考下面的代码,第二个也可以参考我的软件《 易博搜搜 》,其中就涉及到了网易博客圈子的邮件采集,如下所示。


该软件除了可以采集网易博客圈子用户的邮件信息,给营销推广人提供资料外,还可以利用网易博客的找朋友模块,获取相关的用户数据信息,当然也是可以转换为邮件地址信息的了,如下所示。

以上对网易博客的应用的代码实现以及一个较为综合的软件产品介绍,希望能带给大家更多的启示和知识了解。