zoukankan      html  css  js  c++  java
  • 利用XML实现通用WEB报表输入和输出

    利用XML实现通用WEB报表输入和输出
          开发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>

       注意事项:
      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派生出三个子类,分别是ReportTable和ReportText,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值,这个值的作用是用来指示标签是否在页内打印完毕。
      然后再添一个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;
    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;
    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);
             }

     
             
    初始化画布(用于容纳报表)
     
             
    输出报表对象及报表所包含的值
     
             
    读取报表返回的值
    }
    新建立一个webform,读取报表的时候只要用
                
      ReportDocument r = new ReportDocument(Server.MapPath("pp.xml"));
                  System.Web.UI.Control c 
    = r.WriteReport();
                  Label1.Controls.Add(c);
    将数据保存到数据库则调用            
      ReportDocument r = new ReportDocument(Server.MapPath("pp.xml"));
                  r.SaveReport();
  • 相关阅读:
    MySQL 高可用架构在业务层面的分析研究
    HDU 4983 Goffi and GCD(数论)
    Request中的方法调用
    servlet中不能没有无参构造函数
    ServletConfig、ServletContext属性遍历
    Eclipse格式化代码换行、删除空行
    Spring EL中的类操作符
    Spring集合配置
    spring EL表达式,null-safe表达式
    spring的value,null标签
  • 原文地址:https://www.cnblogs.com/sukyboor/p/372233.html
Copyright © 2011-2022 走看看