最近研究了一下基於xml+Xslt的統計報表導出Excel功能,原有的設計是用JS實現,優點是實現起來比較簡單,缺點同樣很明顯,對導出復雜的表格無能為力,而且需要客戶端安裝Excel,另一種辦法是在服務器端實現,調用office的DLL直接操作Excel,可控范圍較廣,但是遇到大數據量的統計報表則響應較慢,這對於客戶來說是無法忍受的。於是,就有了基於xml+xslt的解決方案。由於Excel可另存為后綴名為.xml的數據格式,這就為這種解決方案提供了實現的可能性。
實現原理:由於統計報表是基於xml+xslt實現,從數據庫取出的數據已保存在xml中,我們只需要將這xml暫存下來,然后用導出Excel所用的xslt文件轉換即可。
實現過程:
用於導出Excel所用的DepositExcel.xslt

<?xml version="1.0" encoding="gb2312" ?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="zkSuperMap"> <?mso-application progid="Excel.Sheet"?> <Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" xmlns:html="http://www.w3.org/TR/REC-html40"> <Styles> <Style ss:ID="Default" ss:Name="Normal"> <Alignment ss:Vertical="Center"/> <Borders/> <Font ss:FontName="宋體" x:CharSet="134" ss:Size="11" ss:Color="#000000"/> <Interior/> <NumberFormat/> <Protection/> </Style> <Style ss:ID="s10"> <Alignment ss:Horizontal="Center" ss:Vertical="Center"/> </Style> <Style ss:ID="s11"> <Alignment ss:Horizontal="Center" ss:Vertical="Center"/> <Borders> <Border ss:Position="Bottom" ss:LineStyle="Continuous" ss:Weight="1"/> <Border ss:Position="Left" ss:LineStyle="Continuous" ss:Weight="1"/> <Border ss:Position="Right" ss:LineStyle="Continuous" ss:Weight="1"/> <Border ss:Position="Top" ss:LineStyle="Continuous" ss:Weight="1"/> </Borders> </Style> </Styles> <Worksheet ss:Name="Sheet1"> <Table ss:ExpandedColumnCount="9" x:FullColumns="1" x:FullRows="1" ss:DefaultColumnWidth="54" ss:DefaultRowHeight="13.5"> <Row ss:AutoFitHeight="0"> <Cell ss:MergeAcross="8" ss:StyleID="s10"> <Data ss:Type="String">商品房專項維修資金繳存、使用、變更周報表</Data> </Cell> </Row> <Row ss:AutoFitHeight="0"> <Cell ss:MergeAcross="8" ss:StyleID="s10"> <Data ss:Type="String"> <xsl:value-of select="BEGINTEIM" /> 至 <xsl:value-of select="ENDTIME" /> </Data> </Cell> </Row> <Row ss:AutoFitHeight="0"> <Cell ss:MergeDown="1" ss:StyleID="s11"> <Data ss:Type="String">序號</Data> </Cell> <Cell ss:MergeDown="1" ss:StyleID="s11"> <Data ss:Type="String">小區名稱</Data> </Cell> <Cell ss:MergeAcross="1" ss:StyleID="s11"> <Data ss:Type="String">繳 存</Data> </Cell> <Cell ss:MergeAcross="1" ss:StyleID="s11"> <Data ss:Type="String">使 用</Data> </Cell> <Cell ss:StyleID="s11"> <Data ss:Type="String">變 更</Data> </Cell> <Cell ss:MergeAcross="1" ss:MergeDown="1" ss:StyleID="s11"> <Data ss:Type="String">備 注</Data> </Cell> </Row> <Row ss:AutoFitHeight="0"> <Cell ss:StyleID="s11" ss:Index="3"> <Data ss:Type="String">戶 數</Data> </Cell> <Cell ss:StyleID="s11"> <Data ss:Type="String">金 額(元)</Data> </Cell> <Cell ss:StyleID="s11"> <Data ss:Type="String">戶 數</Data> </Cell> <Cell ss:StyleID="s11"> <Data ss:Type="String">金 額(元)</Data> </Cell> <Cell ss:StyleID="s11"> <Data ss:Type="String">戶 數</Data> </Cell> </Row> <xsl:for-each select="FUNDINFO"> <Row ss:AutoFitHeight="0"> <Cell ss:StyleID="s11"> <Data ss:Type="String"> <xsl:value-of select="position()" /> </Data> </Cell> <Cell ss:StyleID="s11"> <Data ss:Type="String"> <xsl:value-of select="DISTRICT_NAME" /> </Data> </Cell> <Cell ss:StyleID="s11"> <Data ss:Type="String"> <xsl:value-of select="HOUSEFUND_COUNT" /> </Data> </Cell> <Cell ss:StyleID="s11"> <Data ss:Type="String"> <xsl:value-of select="HOUSEFUND_MONEY" /> </Data> </Cell> <Cell ss:StyleID="s11"> <Data ss:Type="String"> <xsl:value-of select="FUNDUSE_COUNT" /> </Data> </Cell> <Cell ss:StyleID="s11"> <Data ss:Type="String"> <xsl:value-of select="FUNDUSE_MONEY" /> </Data> </Cell > <Cell ss:StyleID="s11"> <Data ss:Type="String"> <xsl:value-of select="FUNDMODIFY_COUNT" /> </Data> </Cell> <Cell ss:MergeAcross="1" ss:StyleID="s11"> <Data ss:Type="String"> </Data> </Cell> </Row> </xsl:for-each> <Row ss:AutoFitHeight="0"> <Cell ss:StyleID="s11"> <Data ss:Type="String"> 總計: </Data> </Cell> <Cell ss:StyleID="s11"> <Data ss:Type="String"> </Data> </Cell> <Cell ss:StyleID="s11"> <Data ss:Type="String"> <xsl:value-of select="SUM_HOUSEFUND_COUNT" /> </Data> </Cell> <Cell ss:StyleID="s11"> <Data ss:Type="String"> <xsl:value-of select="SUM_HOUSEFUND_MONEY" /> </Data> </Cell> <Cell ss:StyleID="s11"> <Data ss:Type="String"> <xsl:value-of select="SUM_FUNDUSE_COUNT" /> </Data> </Cell> <Cell ss:StyleID="s11"> <Data ss:Type="String"> <xsl:value-of select="SUM_FUNDUSE_MONEY" /> </Data> </Cell> <Cell ss:StyleID="s11"> <Data ss:Type="String"> <xsl:value-of select="SUM_FUNDMODIFY_COUNT" /> </Data> </Cell> <Cell ss:MergeAcross="1" ss:StyleID="s11"> <Data ss:Type="String"> </Data> </Cell> </Row> <Row ss:AutoFitHeight="0"> <Cell ss:MergeAcross="2" > <Data ss:Type="String">負責人:</Data> </Cell> <Cell ss:MergeAcross="2" > <Data ss:Type="String">復核人:</Data> </Cell> <Cell ss:MergeAcross="2" > <Data ss:Type="String">填表:</Data> </Cell> </Row> </Table> </Worksheet> </Workbook> </xsl:template> </xsl:stylesheet>
數據文件DepositStatistic.xml

<?xml version="1.0" encoding="gb2312"?> <?xml-stylesheet type='text/xsl' href=''?> <zkSuperMap> <BEGINTEIM>2012/7/1</BEGINTEIM> <ENDTIME>2012/8/3</ENDTIME> <FUNDINFO> <DISTRICT_NAME>安順家園</DISTRICT_NAME> <HOUSEFUND_COUNT>22</HOUSEFUND_COUNT> <HOUSEFUND_MONEY>541519</HOUSEFUND_MONEY> <FUNDUSE_COUNT>0</FUNDUSE_COUNT> <FUNDUSE_MONEY>0</FUNDUSE_MONEY> <FUNDMODIFY_COUNT>0</FUNDMODIFY_COUNT> </FUNDINFO> <SUM_HOUSEFUND_COUNT>22</SUM_HOUSEFUND_COUNT> <SUM_HOUSEFUND_MONEY>541519</SUM_HOUSEFUND_MONEY> <SUM_FUNDUSE_COUNT>0</SUM_FUNDUSE_COUNT> <SUM_FUNDUSE_MONEY>0</SUM_FUNDUSE_MONEY> <SUM_FUNDMODIFY_COUNT>0</SUM_FUNDMODIFY_COUNT> </zkSuperMap>
呈現統計報表的DepositStatistic.xslt

<?xml version="1.0" encoding="gb2312" ?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="zkSuperMap"> <xsl:call-template name="DepositStatistic"></xsl:call-template> </xsl:template> <xsl:template name="DepositStatistic"> <xsl:element name="style"> <![CDATA[ .AcceptTable { border-collapse:collapse; table-layout:fixed; } .AcceptTable td { border: solid black 1px; font-family: 宋體; padding: 5px; vertical-align: middle; font-size: 10pt; font-weight: 600; } .AcceptTable td.AcceptTitle { text-align:center; font-weight: 900; font-size: 18pt; border: none; } .AcceptTable td.AcceptHeader { font-weight: 900; font-size:10pt; padding: 2px; border: none; } .AcceptTable tr { height:35px; } .AcceptTable td.AcceptFooter { border:none; vertical-align:middle; } .AcceptTable td p { margin-top:5px; margin-bottom:10px; } .AcceptTable td p.AcceptMater { margin-left:20px; margin-right:20px; margin-top:5px; margin-bottom:3px; border-bottom:1px dashed #dcdcdc; word-break: break-all; } .pageSplit{PAGE-BREAK-AFTER:always;} ]]> </xsl:element> <table cellSpacing="0" cellPadding="0" border="0" class="AcceptTable" align="center"> <tr style="height:0;"> <td style="width:80px;border:none;"></td> <td style="width:130px;border:none;"></td> <td style="width:80px;border:none;"></td> <td style="width:100px;border:none;"></td> <td style="width:80px;border:none;"></td> <td style="width:90px;border:none;"></td> <td style="width:80px;border:none;"></td> <td style="width:120px;border:none;"></td> <td style="width:80px;border:none;"></td> </tr> <tr> <td colspan="9" class="AcceptTitle">商品房專項維修資金繳存、使用、變更周報表</td> </tr> <tr> <td colspan="9" style="text-align:center;border:none;"> <xsl:value-of select="BEGINTEIM" /> 至 <xsl:value-of select="ENDTIME" /> </td> </tr> <tr> <td rowspan="2" style="text-align:center;">序號</td> <td rowspan="2" style="text-align:center;">小區名稱</td> <td colspan="2" style="text-align:center;">繳 存</td> <td colspan="2" style="text-align:center;">使 用</td> <td style="text-align:center;">變 更</td> <td rowspan="2" colspan="2" style="text-align:center;">備 注</td> </tr> <tr> <td style="text-align:center;">戶 數</td> <td style="text-align:center;">金 額(元)</td> <td style="text-align:center;">戶 數</td> <td style="text-align:center;">金 額(元)</td> <td style="text-align:center;">戶 數</td> </tr> <xsl:for-each select="FUNDINFO"> <xsl:if test="position() mod 16=0"> <tr style="height:0;"> <td colspan="8" style="border:0px;"> <div class="pageSplit"></div> </td> </tr> </xsl:if> <tr> <td style="text-align:center;"> <xsl:value-of select="position()" /> </td> <td style="text-align:center;" > <xsl:value-of select="DISTRICT_NAME" /> </td> <td style="text-align:center;" > <xsl:value-of select="HOUSEFUND_COUNT" /> </td> <td style="text-align:center;" > <xsl:value-of select="HOUSEFUND_MONEY" /> </td> <td style="text-align:center;" > <xsl:value-of select="FUNDUSE_COUNT" /> </td> <td style="text-align:center;" > <xsl:value-of select="FUNDUSE_MONEY" /> </td> <td style="text-align:center;" > <xsl:value-of select="FUNDMODIFY_COUNT" /> </td> <td style="text-align:center;" colspan="2"> </td> </tr> </xsl:for-each> <tr> <td style="text-align:center;">總 計:</td> <td></td> <td style="text-align:center;"> <xsl:value-of select="SUM_HOUSEFUND_COUNT" /> </td> <td style="text-align:center;"> <xsl:value-of select="SUM_HOUSEFUND_MONEY" /> </td> <td style="text-align:center;"> <xsl:value-of select="SUM_FUNDUSE_COUNT" /> </td> <td style="text-align:center;"> <xsl:value-of select="SUM_FUNDUSE_MONEY" /> </td> <td style="text-align:center;"> <xsl:value-of select="SUM_FUNDMODIFY_COUNT" /> </td> <td style="text-align:center;" colspan="2"></td> </tr> <tr > <td colspan="3" style="text-align:left;border:none;"> 負責人: </td> <td colspan="3" style="text-align:left;border:none;"> 復核人: </td> <td colspan="3" style="text-align:left;border:none;"> 填表: </td> </tr> </table> </xsl:template> </xsl:stylesheet>
這里有個小竅門,一般我們設計統計報表,都是先制作完成DepositStatistic.xslt,與xml結合后的報表呈現無誤后,即可在頁面上復制報表,粘貼到Excel,再在Excel里另存為xml 電子表格格式,再打開這個文件,去掉冗余的代碼,即可得到DepositExcel.xslt.

#region ButtonExportExcel_Click protected void ButtonExportExcel_Click(object sender, EventArgs e) { XmlDocument _XmlDocument = new XmlDocument(); System.Xml.Xsl.XslCompiledTransform xslt = new System.Xml.Xsl.XslCompiledTransform(); string _BuildPath = zkSuperMap.Web.Configuration.PathSetting.TemporaryPath + "WeekStatisticXML\\"; if (!Directory.Exists(_BuildPath)) Directory.CreateDirectory(_BuildPath); _BuildPath += "WeekStatistic_" + BeginTime.Text + ".xml"; if (File.Exists(_BuildPath)) { StringWriter stringWrite = new System.IO.StringWriter(); xslt.Load(Server.MapPath("Xsl/DepositExcel.xslt")); xslt.Transform(_BuildPath, null, stringWrite); //清除客戶端當前顯示 HttpContext.Current.Response.Clear(); HttpContext.Current.Response.Buffer = true; HttpContext.Current.Response.Charset = "gb2312"; HttpContext.Current.Response.AddHeader("content-disposition", string.Format("attachment; filename={0}.xls", HttpUtility.UrlEncode(BeginTime.Date.ToShortDateString(), System.Text.Encoding.UTF8))); HttpContext.Current.Response.ContentEncoding = System.Text.Encoding.UTF8; HttpContext.Current.Response.ContentType = "application/ms-excel";//設置輸出文件類型為excel文件。 HttpContext.Current.Response.Write(stringWrite.ToString()); HttpContext.Current.Response.End(); HttpContext.Current.Response.Close(); stringWrite.Close(); } } #endregion
最后呈現出來的報表:
基於xml+xslt的導出Excel解決方案,整合了JS跟office組件等解決方案的優點,實乃一大殺器,哈哈^_^