开发B/S结构的应用程序最头疼的问题可能就是报表打印了,而很多B/S结构的应用程序常常需要完成非常复杂的报表打印任务。更加郁闷的是,很多报表在使用的的时候还要求将数据输入到数据库中。
此主题相关图片如下:
添加一个解析器,使用正则表达式,把参数字符串提取出来
现在是呈现报表和保存报表数据的时候了
方案原理
其实原理很简单,通过XML强大的自定义功能,进行格式解析,我们便能方便的自定义出我们所有需要的格式控制标签,在服务器端进行动态编码后通过WEB服务器传到客户端,然后在客户端打印出我们需要的报表。
感谢卢彦的利用XML实现通用WEB报表打印(http://www.yesky.com/20030214/1652186.shtml),所以遵循他的精神,不敢独享
工作流程
工作流程
服务器的工作流程为:
1. 根据报表类型读取xml模板。
2. 根据报表id读取数据库(如果采用orm的话,也可以是持久对象)的数据。
3. 对xml模板进行数据解析。
4. 构造html标签,并赋值 。
5.用户在客户端进行数据输入或者选择打印
6用户提交后,根据xml模板,对返回值进行解析,将数据保存。
安全性
由于采用的是普通WEB服务器传送数据,因此可以直接采用SSL安全套接字等已经成熟的WEB加密技术,保证了传输的安全性。
由于采用的是80端口,不需要再另外新增加专用端口,减少了安全漏洞的可能性,同时还能方便的穿过双方的的网络防火墙等保护设备。
格式定义
为了能自己控制打印的格式,我们定义了下列的格式标签
标签应用示例:
<?
xmlversion="1.0"encoding="utf-8"
?>
< doc >
< pagesetting >
< paperwidth > 800 </ paperwidth >
< paperheight > 600 </ paperheight >
< pageleft > 0 </ pageleft >
< pageright > 0 </ pageright >
< pagetop > 0 </ pagetop >
< pagebottom > 0 </ pagebottom >
</ pagesetting >
< data >
< DataClass > XReport.ReportDocument, XReport </ DataClass >
< get > GetData </ get >
< set > SetData </ set >
</ data >
< report >
< reporthead >
< rowheight ="20" ></ row >
< rowheight ="40" >
< textalign ="center" fontsize ="12pt" > 通用报表 </ text >
</ row >
< rowheight ="20" >
< textalign ="center" fontsize ="10pt" > ([$Eval(get(year),set(year)),Format(align(center),size(50))$]年[$Eval(get(month),set(month))$]月) </ text >
</ row >
< rowheight ="16" >
< textalign ="set" x ="0" y ="0" fontsize ="9pt" > 填报单位: [$Eval(get(dw),set(dw)),Format(align(center),size(50))$] </ text >
< textalign ="set" x ="325" y ="0" fontsize ="9pt" > 文 号: 报字[1999]7号 </ text >
</ row >
< rowheight ="18" ></ row >
</ reporthead >
< reporttablepagesize ="20" >
< columnscolumnsize ="11" >
< columnkey ="c1" align ="center" > [$Eval(get(DataItem.#c1)),Format(align(center),size(100%))$] </ column >
< columnkey ="c2" align ="right" > [$Eval(get(DataItem.#c2),set(DataItem.#c2)),Format(align(right),size(100%))$] </ column >
< columnkey ="c3" align ="right" > [$Eval(get(DataItem.#c3),set(DataItem.#c3)),Format(align(right),size(100%))$] </ column >
< columnkey ="c4" align ="right" > [$Eval(get(DataItem.#c4),set(DataItem.#c4)),Format(align(right),size(100%))$] </ column >
< columnkey ="c5" align ="right" > [$Eval(get(DataItem.#c5),set(DataItem.#c5)),Format(align(right),size(100%))$] </ column >
< columnkey ="c6" align ="right" > [$Eval(get(DataItem.#c6),set(DataItem.#c6)),Format(align(right),size(100%))$] </ column >
< columnkey ="c7" align ="right" > [$Eval(get(DataItem.#c7),set(DataItem.#c7)),Format(align(right),size(100%))$] </ column >
< columnkey ="c8" align ="right" > [$Eval(get(DataItem.#c8),set(DataItem.#c8)),Format(align(right),size(100%))$] </ column >
< columnkey ="c9" align ="right" > [$Eval(get(DataItem.#c9),set(DataItem.#c9)),Format(align(right),size(100%))$] </ column >
< columnkey ="c10" align ="right" > [$Eval(get(DataItem.#c10),set(DataItem.#c10)),Format(align(right),size(100%))$] </ column >
< columnkey ="c11" align ="right" > [$Eval(get(DataItem.#c11),set(DataItem.#c11)),Format(align(right),size(100%))$] </ column >
</ columns >
< rows >
< rowkey ="r1" fontsize ="9pt" align ="center" >
< cellrowspan ="2" colspan ="1" > 项目 </ cell >
< cellrowspan ="1" colspan ="2" > 项目 </ cell >
< cellrowspan ="2" colspan ="1" > 项目 </ cell >
< cellrowspan ="2" colspan ="1" > 项目/n(个) </ cell >
< cellrowspan ="2" colspan ="1" > 项目 </ cell >
< cellrowspan ="1" colspan ="4" > 项目 </ cell >
< cellrowspan ="2" colspan ="1" > 项目/n(元) </ cell >
</ row >
< rowkey ="r2" fontsize ="9pt" align ="center" >
< cellrowspan ="1" colspan ="1" > 县/n(市)(个) </ cell >
< cellrowspan ="1" colspan ="1" > 乡/n(镇)(个) </ cell >
< cellrowspan ="1" colspan ="1" > 总计/n(人) </ cell >
< cellrowspan ="1" colspan ="1" > 项目/n(人) </ cell >
< cellrowspan ="1" colspan ="1" > 项目/n(人) </ cell >
< cellrowspan ="1" colspan ="1" > 项目/n(人) </ cell >
</ row >
< rowkey ="r3" fontsize ="9pt" align ="center" >
< cellrowspan ="1" colspan ="1" > 1 </ cell >
< cellrowspan ="1" colspan ="1" > 2 </ cell >
< cellrowspan ="1" colspan ="1" > 3 </ cell >
< cellrowspan ="1" colspan ="1" > 4 </ cell >
< cellrowspan ="1" colspan ="1" > 5 </ cell >
< cellrowspan ="1" colspan ="1" > 6 </ cell >
< cellrowspan ="1" colspan ="1" > 7 </ cell >
< cellrowspan ="1" colspan ="1" > 8 </ cell >
< cellrowspan ="1" colspan ="1" > 9 </ cell >
< cellrowspan ="1" colspan ="1" > 10 </ cell >
< cellrowspan ="1" colspan ="1" > 11 </ cell >
</ row >
</ rows >
</ reporttable >
< reportfoot >
< rowheight ="20" >
< textalign ="set" x ="0" y ="0" fontsize ="9pt" > 单位负责人:[$Eval(get(fzr),set(fzr)),Format(align(center),size(50))$] </ text >
< textalign ="set" x ="80" y ="0" fontsize ="9pt" > 统计负责人:[$Eval(get(tjr),set(tjr)),Format(align(center),size(50))$] </ text >
< textalign ="set" x ="140" y ="0" fontsize ="9pt" > 填报人:[$Eval(get(tbr),set(tbr)),Format(align(center),size(50))$] </ text >
< textalign ="set" x ="200" y ="0" fontsize ="9pt" > 报出日期:[$Eval(get(tbyear),set(tbyear)),Format(align(center),size(50))$]年 </ text >
</ row >
</ reportfoot >
< calcus >
< calcu > [% #r20c2$ = parseValue(#r4c2$,1) * parseValue(#r5c2$,1) + parseValue(#r6c2$,0) + parseValue(#r7c2$,0) %] </ calcu >
< calcu > [% #r20c3$ = parseValue(#r4c3$,0) + parseValue(#r5c3$,0) + parseValue(#r6c3$,0) + parseValue(#r7c3$,0) %] </ calcu >
< calcu > [% #r20c4$ = parseValue(#r4c4$,0) + parseValue(#r5c4$,0) + parseValue(#r6c4$,0) + parseValue(#r7c4$,0) %] </ calcu >
</ calcus >
</ report >
</ doc >
< doc >
< pagesetting >
< paperwidth > 800 </ paperwidth >
< paperheight > 600 </ paperheight >
< pageleft > 0 </ pageleft >
< pageright > 0 </ pageright >
< pagetop > 0 </ pagetop >
< pagebottom > 0 </ pagebottom >
</ pagesetting >
< data >
< DataClass > XReport.ReportDocument, XReport </ DataClass >
< get > GetData </ get >
< set > SetData </ set >
</ data >
< report >
< reporthead >
< rowheight ="20" ></ row >
< rowheight ="40" >
< textalign ="center" fontsize ="12pt" > 通用报表 </ text >
</ row >
< rowheight ="20" >
< textalign ="center" fontsize ="10pt" > ([$Eval(get(year),set(year)),Format(align(center),size(50))$]年[$Eval(get(month),set(month))$]月) </ text >
</ row >
< rowheight ="16" >
< textalign ="set" x ="0" y ="0" fontsize ="9pt" > 填报单位: [$Eval(get(dw),set(dw)),Format(align(center),size(50))$] </ text >
< textalign ="set" x ="325" y ="0" fontsize ="9pt" > 文 号: 报字[1999]7号 </ text >
</ row >
< rowheight ="18" ></ row >
</ reporthead >
< reporttablepagesize ="20" >
< columnscolumnsize ="11" >
< columnkey ="c1" align ="center" > [$Eval(get(DataItem.#c1)),Format(align(center),size(100%))$] </ column >
< columnkey ="c2" align ="right" > [$Eval(get(DataItem.#c2),set(DataItem.#c2)),Format(align(right),size(100%))$] </ column >
< columnkey ="c3" align ="right" > [$Eval(get(DataItem.#c3),set(DataItem.#c3)),Format(align(right),size(100%))$] </ column >
< columnkey ="c4" align ="right" > [$Eval(get(DataItem.#c4),set(DataItem.#c4)),Format(align(right),size(100%))$] </ column >
< columnkey ="c5" align ="right" > [$Eval(get(DataItem.#c5),set(DataItem.#c5)),Format(align(right),size(100%))$] </ column >
< columnkey ="c6" align ="right" > [$Eval(get(DataItem.#c6),set(DataItem.#c6)),Format(align(right),size(100%))$] </ column >
< columnkey ="c7" align ="right" > [$Eval(get(DataItem.#c7),set(DataItem.#c7)),Format(align(right),size(100%))$] </ column >
< columnkey ="c8" align ="right" > [$Eval(get(DataItem.#c8),set(DataItem.#c8)),Format(align(right),size(100%))$] </ column >
< columnkey ="c9" align ="right" > [$Eval(get(DataItem.#c9),set(DataItem.#c9)),Format(align(right),size(100%))$] </ column >
< columnkey ="c10" align ="right" > [$Eval(get(DataItem.#c10),set(DataItem.#c10)),Format(align(right),size(100%))$] </ column >
< columnkey ="c11" align ="right" > [$Eval(get(DataItem.#c11),set(DataItem.#c11)),Format(align(right),size(100%))$] </ column >
</ columns >
< rows >
< rowkey ="r1" fontsize ="9pt" align ="center" >
< cellrowspan ="2" colspan ="1" > 项目 </ cell >
< cellrowspan ="1" colspan ="2" > 项目 </ cell >
< cellrowspan ="2" colspan ="1" > 项目 </ cell >
< cellrowspan ="2" colspan ="1" > 项目/n(个) </ cell >
< cellrowspan ="2" colspan ="1" > 项目 </ cell >
< cellrowspan ="1" colspan ="4" > 项目 </ cell >
< cellrowspan ="2" colspan ="1" > 项目/n(元) </ cell >
</ row >
< rowkey ="r2" fontsize ="9pt" align ="center" >
< cellrowspan ="1" colspan ="1" > 县/n(市)(个) </ cell >
< cellrowspan ="1" colspan ="1" > 乡/n(镇)(个) </ cell >
< cellrowspan ="1" colspan ="1" > 总计/n(人) </ cell >
< cellrowspan ="1" colspan ="1" > 项目/n(人) </ cell >
< cellrowspan ="1" colspan ="1" > 项目/n(人) </ cell >
< cellrowspan ="1" colspan ="1" > 项目/n(人) </ cell >
</ row >
< rowkey ="r3" fontsize ="9pt" align ="center" >
< cellrowspan ="1" colspan ="1" > 1 </ cell >
< cellrowspan ="1" colspan ="1" > 2 </ cell >
< cellrowspan ="1" colspan ="1" > 3 </ cell >
< cellrowspan ="1" colspan ="1" > 4 </ cell >
< cellrowspan ="1" colspan ="1" > 5 </ cell >
< cellrowspan ="1" colspan ="1" > 6 </ cell >
< cellrowspan ="1" colspan ="1" > 7 </ cell >
< cellrowspan ="1" colspan ="1" > 8 </ cell >
< cellrowspan ="1" colspan ="1" > 9 </ cell >
< cellrowspan ="1" colspan ="1" > 10 </ cell >
< cellrowspan ="1" colspan ="1" > 11 </ cell >
</ row >
</ rows >
</ reporttable >
< reportfoot >
< rowheight ="20" >
< textalign ="set" x ="0" y ="0" fontsize ="9pt" > 单位负责人:[$Eval(get(fzr),set(fzr)),Format(align(center),size(50))$] </ text >
< textalign ="set" x ="80" y ="0" fontsize ="9pt" > 统计负责人:[$Eval(get(tjr),set(tjr)),Format(align(center),size(50))$] </ text >
< textalign ="set" x ="140" y ="0" fontsize ="9pt" > 填报人:[$Eval(get(tbr),set(tbr)),Format(align(center),size(50))$] </ text >
< textalign ="set" x ="200" y ="0" fontsize ="9pt" > 报出日期:[$Eval(get(tbyear),set(tbyear)),Format(align(center),size(50))$]年 </ text >
</ row >
</ reportfoot >
< calcus >
< calcu > [% #r20c2$ = parseValue(#r4c2$,1) * parseValue(#r5c2$,1) + parseValue(#r6c2$,0) + parseValue(#r7c2$,0) %] </ calcu >
< calcu > [% #r20c3$ = parseValue(#r4c3$,0) + parseValue(#r5c3$,0) + parseValue(#r6c3$,0) + parseValue(#r7c3$,0) %] </ calcu >
< calcu > [% #r20c4$ = parseValue(#r4c4$,0) + parseValue(#r5c4$,0) + parseValue(#r6c4$,0) + parseValue(#r7c4$,0) %] </ calcu >
</ calcus >
</ report >
</ doc >
注意事项:
a) 字符编码应该为UTF-8,否则会出现编码错误问题。
b) 应该严格按照XML规定的格式来生成文件,否则XML解析器将不会予以解析。
2. 客户端
效果示例图
打印预览
.Net Web控件方案的实现和扩充
软件原理:
该软件的原理其实很简单,就是要方便的解析出定义好的XML格式标记,解读出文件中标记的参数定义,构造出html标签。
针对大多数报表的功能需要,我只定义了两种格式标签:文本(text)和表格(table),它们的具体属性定义和另外一些设置性的标签定义请参考前文,这里再补充一幅结构图帮助读者理解。如下所示:
此主题相关图片如下:
<
doc
>根节点
|
<
pagesetting
>
页面设置
|
<
data
>
报表数据
|
<
report
>
报表格式
|
<
row
>
行
|
<
text
>
文本
|
<
reportfoot
>
页脚
|
<
reporthead
>
表头
|
<
calcus
>
报表计算
计算
|
<
columns
>
列
|
<
rows
>
行
|
<reporttable>
表格
|
结构设计:
为了描述所有的样式标记,我先定义了一个抽象基类
ReportElement
,它拥有一个虚拟方法Draw,然后对应表格和文本,从
ReportElement
派生出三个子类,分别是
Report
Table和
Report
Text,
ReportRow
,我还创建了一个
ReportParser
类用来解析不同的样式标记.
代码实现:
然后为项目添加一个PrintElement的新类,代码如下:
namespace
XReport
{
/**////<summary>
/// 报表成员
///</summary>
public class ReportElement
{
public ReportElement()
{
}
/**////<summary>
/// 绘制报表成员
///</summary>
///<param name="parent"></param>
///<returns></returns>
public virtual bool Draw(System.Web.UI.HtmlControls.HtmlControl parent)
{
return false;
}
}
该类中只有一个虚拟方法Draw,注意它规定需要返回一个bool值,这个值的作用是用来指示标签是否在页内打印完毕。
{
/**////<summary>
/// 报表成员
///</summary>
public class ReportElement
{
public ReportElement()
{
}
/**////<summary>
/// 绘制报表成员
///</summary>
///<param name="parent"></param>
///<returns></returns>
public virtual bool Draw(System.Web.UI.HtmlControls.HtmlControl parent)
{
return false;
}
}
该类中只有一个虚拟方法Draw,注意它规定需要返回一个bool值,这个值的作用是用来指示标签是否在页内打印完毕。
然后再添一个
ReportText
的新类,代码如下:
using
System.Xml;
using System.Drawing;
using System.Web;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Collections;
namespace XReport
{
/**////<summary>
/// 文本
///</summary>
public class ReportText : ReportElement
{
private XmlNode text;
/**////<summary>
/// 构造器
///</summary>
///<param name="x"></param>
///<param name="d"></param>
public ReportText(XmlNode x)
{
text = x;
}
/**////<summary>
/// 绘制报表成员
///</summary>
///<param name="parent"></param>
///<returns></returns>
public override bool Draw(System.Web.UI.HtmlControls.HtmlControl parent)
{
HtmlContainerControl c = new HtmlGenericControl("span");//添加显示控件
c.Style.Add("Font-size",text.Attributes["fontsize"].InnerText);//显示字体
//设置显示位置
if(text.Attributes["align"].InnerText != "set")
{
//设置对齐方式
c.Style.Add("width","100%");
c.Style.Add("TEXT-ALIGN",text.Attributes["align"].InnerText);
}
else
{
//流对齐,及设置在流中的位置
c.Style.Add("POSITION","relative");
c.Style.Add("left",text.Attributes["x"].InnerText);
}
string shtml = Encode(text.InnerText);//显示内容
c.InnerHtml = shtml;//转换参数
parent.Controls.Add(c);//将控件放入控父件中
return true;
}
}
}
using System.Drawing;
using System.Web;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Collections;
namespace XReport
{
/**////<summary>
/// 文本
///</summary>
public class ReportText : ReportElement
{
private XmlNode text;
/**////<summary>
/// 构造器
///</summary>
///<param name="x"></param>
///<param name="d"></param>
public ReportText(XmlNode x)
{
text = x;
}
/**////<summary>
/// 绘制报表成员
///</summary>
///<param name="parent"></param>
///<returns></returns>
public override bool Draw(System.Web.UI.HtmlControls.HtmlControl parent)
{
HtmlContainerControl c = new HtmlGenericControl("span");//添加显示控件
c.Style.Add("Font-size",text.Attributes["fontsize"].InnerText);//显示字体
//设置显示位置
if(text.Attributes["align"].InnerText != "set")
{
//设置对齐方式
c.Style.Add("width","100%");
c.Style.Add("TEXT-ALIGN",text.Attributes["align"].InnerText);
}
else
{
//流对齐,及设置在流中的位置
c.Style.Add("POSITION","relative");
c.Style.Add("left",text.Attributes["x"].InnerText);
}
string shtml = Encode(text.InnerText);//显示内容
c.InnerHtml = shtml;//转换参数
parent.Controls.Add(c);//将控件放入控父件中
return true;
}
}
}
添加一个解析器,使用正则表达式,把参数字符串提取出来
using
System;
using System.Xml;
using System.Collections;
using System.Text.RegularExpressions;
namespace XReport
{
/**////<summary>
/// 报表成员解析器
///</summary>
public class ReportParser
{
/**////<summary>
/// 构造器
///</summary>
public ReportParser()
{
}
/**////<summary>
/// 解析器
///</summary>
///<param name="s">带格式字符串</param>
///<returns></returns>
public ArrayList Parser(string s)
{
ArrayList list = new ArrayList();
string soure = s;
//表达式解析
string regStr = @"/[/$(?<eval>.*?)/$/]";
Regex r = new Regex(regStr);
MatchCollection mc = r.Matches(soure);
foreach (Match m in mc)
{
//表达式
string eval = string.Format("[${0}$]",m.Groups["eval"].Value);
list.Add(eval);
}
return list;
}
/**////<summary>
/// 解析器
///</summary>
///<param name="s">带格式字符串</param>
///<returns></returns>
public ArrayList ParserClient(string s)
{
ArrayList list = new ArrayList();
string soure = s;
//表达式解析
string regStr = @"/[/%(?<eval>.*?)/%/]";
Regex r = new Regex(regStr);
MatchCollection mc = r.Matches(soure);
foreach (Match m in mc)
{
//表达式
string eval = m.Groups["eval"].Value;
list.Add(eval);
}
return list;
}
/**////<summary>
/// 取得参数字符串中的值get(key)
///</summary>
///<param name="eval">参数字符串</param>
///<returns>key</returns>
public string GetKey(string eval,string Name)
{
Regex rg = new Regex(string.Format(@"{0}/((?<g>.*?)/)",Name));
if(!rg.IsMatch(eval))
return null;
else
return rg.Match(eval).Groups["g"].Value;
}
}//class
}
using System.Xml;
using System.Collections;
using System.Text.RegularExpressions;
namespace XReport
{
/**////<summary>
/// 报表成员解析器
///</summary>
public class ReportParser
{
/**////<summary>
/// 构造器
///</summary>
public ReportParser()
{
}
/**////<summary>
/// 解析器
///</summary>
///<param name="s">带格式字符串</param>
///<returns></returns>
public ArrayList Parser(string s)
{
ArrayList list = new ArrayList();
string soure = s;
//表达式解析
string regStr = @"/[/$(?<eval>.*?)/$/]";
Regex r = new Regex(regStr);
MatchCollection mc = r.Matches(soure);
foreach (Match m in mc)
{
//表达式
string eval = string.Format("[${0}$]",m.Groups["eval"].Value);
list.Add(eval);
}
return list;
}
/**////<summary>
/// 解析器
///</summary>
///<param name="s">带格式字符串</param>
///<returns></returns>
public ArrayList ParserClient(string s)
{
ArrayList list = new ArrayList();
string soure = s;
//表达式解析
string regStr = @"/[/%(?<eval>.*?)/%/]";
Regex r = new Regex(regStr);
MatchCollection mc = r.Matches(soure);
foreach (Match m in mc)
{
//表达式
string eval = m.Groups["eval"].Value;
list.Add(eval);
}
return list;
}
/**////<summary>
/// 取得参数字符串中的值get(key)
///</summary>
///<param name="eval">参数字符串</param>
///<returns>key</returns>
public string GetKey(string eval,string Name)
{
Regex rg = new Regex(string.Format(@"{0}/((?<g>.*?)/)",Name));
if(!rg.IsMatch(eval))
return null;
else
return rg.Match(eval).Groups["g"].Value;
}
}//class
}
找一个hashtable用来传递报表的临时值。这样就不用关心数据的名称及出现的具体位置了。
using
System;
using System.Xml;
using System.Reflection;
using System.Collections;
namespace XReport
{
/**////<summary>
/// 报表数据
///</summary>
public class ReportData
{
/**////<summary>
/// 利用hash表保存数据
///</summary>
private Hashtable data;
/**////<summary>
/// 构造器
///</summary>
public ReportData()
{
data = new Hashtable();
}
/**////<summary>
/// 添加一条数据
///</summary>
///<param name="key">关键字</param>
///<param name="o">对象</param>
public void Add(string key,object o)
{
data.Add(key,o);
}
/**////<summary>
/// 删除一个对象
///</summary>
///<param name="key">关键字</param>
public void Delete(string key)
{
data.Remove(key);
}
/**////<summary>
/// 取得报表数据
///</summary>
///<param name="element">xml节点(doc/data)</param>
///<param name="ReportID">报表id</param>
///<returns></returns>
public static ReportData GetReportData(XmlNode element,string ReportID)
{
//该报表的数据管理类
string dataClass = ReportElement.GetChildNode(element,"DataClass").InnerText;
string method = ReportElement.GetChildNode(element,"get").InnerText;
Type t = Type.GetType(dataClass);
//数据方法
BindingFlags flags = BindingFlags.InvokeMethod|BindingFlags.Instance|BindingFlags.Public|BindingFlags.Static;
//设置参数
Object[] args = new Object[] {ReportID};
//调用方法,返回报表数据
return (ReportData)t.InvokeMember(method,flags,null,null,args);
}
/**////<summary>
/// 设置报表数据
///</summary>
///<param name="element">xml节点(doc/data)</param>
///<param name="ReportID">报表id</param>
///<returns></returns>
public static object SetReportData(XmlNode element,ReportData data,string ReportID)
{
//该报表的数据管理类
string dataClass = ReportElement.GetChildNode(element,"DataClass").InnerText;
string method = ReportElement.GetChildNode(element,"set").InnerText;
Type t = Type.GetType(dataClass);
//数据方法
BindingFlags flags = BindingFlags.InvokeMethod|BindingFlags.Instance|BindingFlags.Public|BindingFlags.Static;
//设置参数
Object[] args = new Object[] {data,ReportID};
//调用方法,返回报表数据
return t.InvokeMember(method,flags,null,null,args);
}
/**////<summary>
/// 取得数据
///</summary>
///<param name="key">关键字</param>
///<returns></returns>
public object Get(string key)
{
return data[key];
}
}
}
using System.Xml;
using System.Reflection;
using System.Collections;
namespace XReport
{
/**////<summary>
/// 报表数据
///</summary>
public class ReportData
{
/**////<summary>
/// 利用hash表保存数据
///</summary>
private Hashtable data;
/**////<summary>
/// 构造器
///</summary>
public ReportData()
{
data = new Hashtable();
}
/**////<summary>
/// 添加一条数据
///</summary>
///<param name="key">关键字</param>
///<param name="o">对象</param>
public void Add(string key,object o)
{
data.Add(key,o);
}
/**////<summary>
/// 删除一个对象
///</summary>
///<param name="key">关键字</param>
public void Delete(string key)
{
data.Remove(key);
}
/**////<summary>
/// 取得报表数据
///</summary>
///<param name="element">xml节点(doc/data)</param>
///<param name="ReportID">报表id</param>
///<returns></returns>
public static ReportData GetReportData(XmlNode element,string ReportID)
{
//该报表的数据管理类
string dataClass = ReportElement.GetChildNode(element,"DataClass").InnerText;
string method = ReportElement.GetChildNode(element,"get").InnerText;
Type t = Type.GetType(dataClass);
//数据方法
BindingFlags flags = BindingFlags.InvokeMethod|BindingFlags.Instance|BindingFlags.Public|BindingFlags.Static;
//设置参数
Object[] args = new Object[] {ReportID};
//调用方法,返回报表数据
return (ReportData)t.InvokeMember(method,flags,null,null,args);
}
/**////<summary>
/// 设置报表数据
///</summary>
///<param name="element">xml节点(doc/data)</param>
///<param name="ReportID">报表id</param>
///<returns></returns>
public static object SetReportData(XmlNode element,ReportData data,string ReportID)
{
//该报表的数据管理类
string dataClass = ReportElement.GetChildNode(element,"DataClass").InnerText;
string method = ReportElement.GetChildNode(element,"set").InnerText;
Type t = Type.GetType(dataClass);
//数据方法
BindingFlags flags = BindingFlags.InvokeMethod|BindingFlags.Instance|BindingFlags.Public|BindingFlags.Static;
//设置参数
Object[] args = new Object[] {data,ReportID};
//调用方法,返回报表数据
return t.InvokeMember(method,flags,null,null,args);
}
/**////<summary>
/// 取得数据
///</summary>
///<param name="key">关键字</param>
///<returns></returns>
public object Get(string key)
{
return data[key];
}
}
}
现在是呈现报表和保存报表数据的时候了
using
System;
using System.Xml;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Collections;
using System.Web.UI.HtmlControls;
namespace XReport
{
/**////<summary>
/// 报表文档
///</summary>
public class ReportDocument
{
private XmlDocument doc ;
private HtmlControl _Canvas;
private string xmlPath;
ReportData data;
/**////<summary>
/// 画布
///</summary>
public HtmlControl Canvas
{
get{return _Canvas;}
set{_Canvas = value;}
}
/**////<summary>
/// 构造器
///</summary>
///<param name="path">xml定义文件路径</param>
public ReportDocument(string path)
{
xmlPath = path;
doc = new XmlDocument();
doc.Load(path);
}
初始化画布(用于容纳报表)#region 初始化画布(用于容纳报表)
/**////<summary>
/// 初始化画布(用于容纳报表)
///</summary>
private void InitCanvas()
{
XmlNode xRoot = ReportElement.GetChildNode(doc,"doc");
XmlNode xPageSetting = ReportElement.GetChildNode(xRoot,"pagesetting");
XmlNode xReport = ReportElement.GetChildNode(xRoot,"report");
XmlNode xReportHead = ReportElement.GetChildNode(xReport,"reporthead");
XmlNode xReportFoot = ReportElement.GetChildNode(xReport,"reportfoot");
XmlNode xReportTable = ReportElement.GetChildNode(xReport,"reporttable");
//设置报表格式
_Canvas = new System.Web.UI.HtmlControls.HtmlGenericControl("DIV");
_Canvas.Style.Add("width",ReportElement.GetChildNode(xPageSetting,"paperwidth").InnerText);
_Canvas.Style.Add("heiht",ReportElement.GetChildNode(xPageSetting,"paperheight").InnerText);
_Canvas.Style.Add("OVERFLOW","hidden");
//绘制页头
foreach(XmlNode xNode in xReportHead.ChildNodes)
{
ReportRow rw = new ReportRow(xNode);
rw.Draw(_Canvas);
}
//绘制表格
ReportTable rt = new ReportTable(xReportTable);
rt.Draw(_Canvas);
//绘制页脚
foreach(XmlNode xNode in xReportFoot.ChildNodes)
{
ReportRow rw = new ReportRow(xNode);
rw.Draw(_Canvas);
}
HtmlContainerControl c = new HtmlGenericControl("script");//添加客户端计算脚本
c.InnerText = ParseClientScript();
_Canvas.Controls.Add(c);
}
#endregion
输出报表对象及报表所包含的值#region 输出报表对象及报表所包含的值
/**////<summary>
/// 输出报表对象
///</summary>
///<returns></returns>
public System.Web.UI.Control WriteReport()
{
//读取报表数据
XmlNode xRoot = ReportElement.GetChildNode(doc,"doc");
XmlNode xData = ReportElement.GetChildNode(xRoot,"data");
data = ReportData.GetReportData(xData,"12345");
InitCanvas();
parserCanvas(_Canvas);
return _Canvas;
}
/**////<summary>
/// 解析客户端脚本(动态计算用)
///</summary>
private string ParseClientScript()
{
XmlNode xRoot = ReportElement.GetChildNode(doc,"doc");
XmlNode xReport = ReportElement.GetChildNode(xRoot,"report");
XmlNode xCalcus = ReportElement.GetChildNode(xReport,"calcus");//计算节点
//报表解析器
ReportParser rp = new ReportParser();
ArrayList list = rp.ParserClient(xCalcus.InnerXml);
StringBuilder sb = new StringBuilder();
sb.Append(" function calcus(){/n");
for(int i = 0 ;i< list.Count;i ++)
{
string eval = (string)list[i];
eval = eval.Replace("#","document.all['txt_");
eval = eval.Replace("$","'].value");
sb.Append(eval);
sb.Append(";/n");
}
sb.Append("}/n");
sb.Append(" window.onload = calcus;/n");
sb.Append(" document.onkeyup = calcus;/n");
sb.Append("function parseValue(v,def){/n");
sb.Append(" if(isNaN(parseFloat(v)))/n");
sb.Append(" return def;/n");
sb.Append(" else/n");
sb.Append(" return parseFloat(v);/n");
sb.Append("}/n");
return sb.ToString();
}
/**////<summary>
/// 解析画布中的参数
///</summary>
///<param name="c"></param>
private void parserCanvas(Control c)
{
HtmlContainerControl cc = c as HtmlContainerControl;
if(cc!=null &&( cc.TagName.ToLower() == "td" || cc.TagName.ToLower() == "span"))
cc.InnerHtml = Parser(cc.InnerHtml);
foreach(Control fc in c.Controls)
{
parserCanvas(fc);
}
}
/**////<summary>
/// 解析参数
///</summary>
///<param name="s"></param>
///<returns></returns>
private string Parser(string s)
{
string soure = s;
//取得参数
ReportParser rp = new ReportParser();
ArrayList evalList = rp.Parser(s);
for(int i = 0; i< evalList.Count;i ++)
{
string eval = (string)evalList[i];
//get关键字
string getkey = rp.GetKey(eval,"get");
//set关键字
string setkey = rp.GetKey(eval,"set");
string align = rp.GetKey(eval,"align");
string size = rp.GetKey(eval,"size");
if(size == null || size == "")size = "50";
if(align == null || align == "")align = "center";
//判断是否需要输入
if(setkey == null || setkey == "")
{
//如果值为空用“ ”代替
if(data.Get(getkey) == null)
soure = soure.Replace(eval," ");
else
soure = soure.Replace(eval,data.Get(getkey).ToString());
}
else
{
//输入框
string sinput ="<input name='txt_{0}' type='text' style='background-color:#eeeeee;color:#003366;";
sinput += "border-top:1px none;border-right:1px none;border-left:1px none;border-bottom:1px solid;";
sinput += "TEXT-ALIGN:{1};width:{2}' value='{3}'>";
if(data.Get(getkey) == null)
{
//如果值为空用“”代替
sinput = string.Format(sinput,getkey,align,size,"");
soure = soure.Replace(eval,sinput);
}
else
{
//将值保持到输入框
sinput = string.Format(sinput,getkey,align,size,data.Get(getkey).ToString());
soure = soure.Replace(eval,sinput);
}
}
}
//返回被解析后的字符串
return soure;
}
#endregion
读取报表返回的值#region 读取报表返回的值
/**////<summary>
/// 读取报表返回的值(递归)
///</summary>
///<param name="c"></param>
private void GetReturnValue(Control c)
{
HtmlContainerControl cc = c as HtmlContainerControl;
if(cc!=null &&( cc.TagName.ToLower() == "td" || cc.TagName.ToLower() == "span"))
{
string s = cc.InnerHtml;//读取控件值
ReportParser rp = new ReportParser();
ArrayList list = rp.Parser(s);//获取匹配参数列表
for(int i = 0;i < list.Count;i ++)
{
string eval = (string)list[i];
string setkey = rp.GetKey(eval,"set");//set关键字
//判断是否需要输入
if(setkey == null || setkey == "")continue;
object v = HttpContext.Current.Request["txt_" + setkey];
data.Add(setkey,v);
}
}
foreach(Control fc in c.Controls)//遍历子控件
{
GetReturnValue(fc);
}
}
public void SaveReport()
{
//读取报表数据
XmlNode xRoot = ReportElement.GetChildNode(doc,"doc");
XmlNode xData = ReportElement.GetChildNode(xRoot,"data");
data = new ReportData();
InitCanvas();
GetReturnValue(Canvas);
ReportData.SetReportData(xData,data,"53738880");
}
#endregion
}
using System.Xml;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Collections;
using System.Web.UI.HtmlControls;
namespace XReport
{
/**////<summary>
/// 报表文档
///</summary>
public class ReportDocument
{
private XmlDocument doc ;
private HtmlControl _Canvas;
private string xmlPath;
ReportData data;
/**////<summary>
/// 画布
///</summary>
public HtmlControl Canvas
{
get{return _Canvas;}
set{_Canvas = value;}
}
/**////<summary>
/// 构造器
///</summary>
///<param name="path">xml定义文件路径</param>
public ReportDocument(string path)
{
xmlPath = path;
doc = new XmlDocument();
doc.Load(path);
}
初始化画布(用于容纳报表)#region 初始化画布(用于容纳报表)
/**////<summary>
/// 初始化画布(用于容纳报表)
///</summary>
private void InitCanvas()
{
XmlNode xRoot = ReportElement.GetChildNode(doc,"doc");
XmlNode xPageSetting = ReportElement.GetChildNode(xRoot,"pagesetting");
XmlNode xReport = ReportElement.GetChildNode(xRoot,"report");
XmlNode xReportHead = ReportElement.GetChildNode(xReport,"reporthead");
XmlNode xReportFoot = ReportElement.GetChildNode(xReport,"reportfoot");
XmlNode xReportTable = ReportElement.GetChildNode(xReport,"reporttable");
//设置报表格式
_Canvas = new System.Web.UI.HtmlControls.HtmlGenericControl("DIV");
_Canvas.Style.Add("width",ReportElement.GetChildNode(xPageSetting,"paperwidth").InnerText);
_Canvas.Style.Add("heiht",ReportElement.GetChildNode(xPageSetting,"paperheight").InnerText);
_Canvas.Style.Add("OVERFLOW","hidden");
//绘制页头
foreach(XmlNode xNode in xReportHead.ChildNodes)
{
ReportRow rw = new ReportRow(xNode);
rw.Draw(_Canvas);
}
//绘制表格
ReportTable rt = new ReportTable(xReportTable);
rt.Draw(_Canvas);
//绘制页脚
foreach(XmlNode xNode in xReportFoot.ChildNodes)
{
ReportRow rw = new ReportRow(xNode);
rw.Draw(_Canvas);
}
HtmlContainerControl c = new HtmlGenericControl("script");//添加客户端计算脚本
c.InnerText = ParseClientScript();
_Canvas.Controls.Add(c);
}
#endregion
输出报表对象及报表所包含的值#region 输出报表对象及报表所包含的值
/**////<summary>
/// 输出报表对象
///</summary>
///<returns></returns>
public System.Web.UI.Control WriteReport()
{
//读取报表数据
XmlNode xRoot = ReportElement.GetChildNode(doc,"doc");
XmlNode xData = ReportElement.GetChildNode(xRoot,"data");
data = ReportData.GetReportData(xData,"12345");
InitCanvas();
parserCanvas(_Canvas);
return _Canvas;
}
/**////<summary>
/// 解析客户端脚本(动态计算用)
///</summary>
private string ParseClientScript()
{
XmlNode xRoot = ReportElement.GetChildNode(doc,"doc");
XmlNode xReport = ReportElement.GetChildNode(xRoot,"report");
XmlNode xCalcus = ReportElement.GetChildNode(xReport,"calcus");//计算节点
//报表解析器
ReportParser rp = new ReportParser();
ArrayList list = rp.ParserClient(xCalcus.InnerXml);
StringBuilder sb = new StringBuilder();
sb.Append(" function calcus(){/n");
for(int i = 0 ;i< list.Count;i ++)
{
string eval = (string)list[i];
eval = eval.Replace("#","document.all['txt_");
eval = eval.Replace("$","'].value");
sb.Append(eval);
sb.Append(";/n");
}
sb.Append("}/n");
sb.Append(" window.onload = calcus;/n");
sb.Append(" document.onkeyup = calcus;/n");
sb.Append("function parseValue(v,def){/n");
sb.Append(" if(isNaN(parseFloat(v)))/n");
sb.Append(" return def;/n");
sb.Append(" else/n");
sb.Append(" return parseFloat(v);/n");
sb.Append("}/n");
return sb.ToString();
}
/**////<summary>
/// 解析画布中的参数
///</summary>
///<param name="c"></param>
private void parserCanvas(Control c)
{
HtmlContainerControl cc = c as HtmlContainerControl;
if(cc!=null &&( cc.TagName.ToLower() == "td" || cc.TagName.ToLower() == "span"))
cc.InnerHtml = Parser(cc.InnerHtml);
foreach(Control fc in c.Controls)
{
parserCanvas(fc);
}
}
/**////<summary>
/// 解析参数
///</summary>
///<param name="s"></param>
///<returns></returns>
private string Parser(string s)
{
string soure = s;
//取得参数
ReportParser rp = new ReportParser();
ArrayList evalList = rp.Parser(s);
for(int i = 0; i< evalList.Count;i ++)
{
string eval = (string)evalList[i];
//get关键字
string getkey = rp.GetKey(eval,"get");
//set关键字
string setkey = rp.GetKey(eval,"set");
string align = rp.GetKey(eval,"align");
string size = rp.GetKey(eval,"size");
if(size == null || size == "")size = "50";
if(align == null || align == "")align = "center";
//判断是否需要输入
if(setkey == null || setkey == "")
{
//如果值为空用“ ”代替
if(data.Get(getkey) == null)
soure = soure.Replace(eval," ");
else
soure = soure.Replace(eval,data.Get(getkey).ToString());
}
else
{
//输入框
string sinput ="<input name='txt_{0}' type='text' style='background-color:#eeeeee;color:#003366;";
sinput += "border-top:1px none;border-right:1px none;border-left:1px none;border-bottom:1px solid;";
sinput += "TEXT-ALIGN:{1};width:{2}' value='{3}'>";
if(data.Get(getkey) == null)
{
//如果值为空用“”代替
sinput = string.Format(sinput,getkey,align,size,"");
soure = soure.Replace(eval,sinput);
}
else
{
//将值保持到输入框
sinput = string.Format(sinput,getkey,align,size,data.Get(getkey).ToString());
soure = soure.Replace(eval,sinput);
}
}
}
//返回被解析后的字符串
return soure;
}
#endregion
读取报表返回的值#region 读取报表返回的值
/**////<summary>
/// 读取报表返回的值(递归)
///</summary>
///<param name="c"></param>
private void GetReturnValue(Control c)
{
HtmlContainerControl cc = c as HtmlContainerControl;
if(cc!=null &&( cc.TagName.ToLower() == "td" || cc.TagName.ToLower() == "span"))
{
string s = cc.InnerHtml;//读取控件值
ReportParser rp = new ReportParser();
ArrayList list = rp.Parser(s);//获取匹配参数列表
for(int i = 0;i < list.Count;i ++)
{
string eval = (string)list[i];
string setkey = rp.GetKey(eval,"set");//set关键字
//判断是否需要输入
if(setkey == null || setkey == "")continue;
object v = HttpContext.Current.Request["txt_" + setkey];
data.Add(setkey,v);
}
}
foreach(Control fc in c.Controls)//遍历子控件
{
GetReturnValue(fc);
}
}
public void SaveReport()
{
//读取报表数据
XmlNode xRoot = ReportElement.GetChildNode(doc,"doc");
XmlNode xData = ReportElement.GetChildNode(xRoot,"data");
data = new ReportData();
InitCanvas();
GetReturnValue(Canvas);
ReportData.SetReportData(xData,data,"53738880");
}
#endregion
}
新建立一个webform,读取报表的时候只要用
ReportDocument r
=
new
ReportDocument(Server.MapPath(
"
pp.xml
"
));
System.Web.UI.Control c = r.WriteReport();
Label1.Controls.Add(c);
System.Web.UI.Control c = r.WriteReport();
Label1.Controls.Add(c);
将数据保存到数据库则调用
ReportDocument r
=
new
ReportDocument(Server.MapPath(
"
pp.xml
"
));
r.SaveReport();
r.SaveReport();