採用XML+XSL樣式表製作報表

採用XML+XSL樣式表製作報表

 

一、問題的產生:

在項目中,需要對一些交易和業務查詢結果製作報表,最初的方法是製作了專門的打印報表類來專門製作報表,但問題是報表的設計需要使用畫圖技術來製作表格,而畫圖的方法很難解決數據的多樣性帶來的可擴展性的挑戰,比如數據長度增加不能很好的自動換行,彙總結果需要人工來控制,報表的打印顯示也不夠美觀,還有,需要對把報表結果存儲爲EXCEL文件。所以這些問題給我們帶來了很大的挑戰。

二、解決思路:

    考慮到報表的可視化設計、可擴展性、美觀以及存儲,採用XML存儲數據,XSL樣式表來設計報表樣式的技術解決我們的困難。

三、解決步驟:

    1、首先根據需求的報表樣式設計報表的樣式表;

    2、把報表所需的數據存儲爲XML文件;

    3、通過XSL樣式表來把XML文件顯示出來既是我們所要的報表;

    4、使用IE自帶的打印功能把這個具有樣式表的XML文件打印出來;

    5、可以把XMLXSL進行轉換,可以轉換爲我們所要的EXCEL文件。

四、詳細設計:

    1、報表樣式需求如圖1

   

    2、樣式表XSL設計如圖:

   

    代碼如下:

    <?xml version="1.0" encoding="GB2312"?>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:key name="LogItem-TotalAmount" match="LogItem" use="totalAmount" />

<xsl:template match="InvoiceReport">

<html>

<head>

<title>Receipt/TAX Invoice Report</title>

<style>

 .abc {border-width:1px;border-style:solid;border-color:#000000}

 .reportno{font-size:10px}

 .title{border-width:1px;border-style:solid;border-color:#000000;font-size:20px}

 td{font-family:Arial;font-size:15px}

</style>

</head>

<body topmargin="20" leftmargin="20" rightmargin="20" bottommargin="20">

<table width="100%" cellspacing="0" cellpadding="3" align="center">  

 <tr>   

    <td bgcolor="#ffffff" >

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

        <tr>

          <td colspan="12"></td>

          <td align="right" class="reportno">Report No:BI-R1<xsl:text disable-output-escaping="yes">&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;</xsl:text></td>         

        </tr>

      </table>     

        <table width="100%" cellpadding="3" cellspacing="0">       

        <tr>

          <td align="center" height="30" colspan="13" class="title"><b>Receipt/TAX Invoice Report</b></td>

        </tr>

        </table>

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

        <tr>

          <td height="50" colspan="3" >PEA Area: <xsl:value-of select="PeaArea" /></td>

          <td colspan="3">TAX ID: <xsl:value-of select="TaxID" /></td>

          <td colspan="5">Selected Period</td>         

          <td colspan="2">Issue Date: <xsl:value-of select="IssueDate" /></td>

        </tr>

        <tr>

          <td height="50" colspan="6" >PEA Sub Area Code: <xsl:value-of select="AreaCode" /></td>         

          <td colspan="2">Start Date: <xsl:value-of select="StartDate" /></td>

          <td colspan="5">End Date: <xsl:value-of select="EndDate" /></td>         

        </tr>       

      </table>

      <table cellpadding="3" cellspacing="0">    

        <tr align="center">

          <td class="abc">Printer Serial No.</td>

          <td class="abc">Receipt No./Tax</td>

          <td class="abc">Purchase Date</td>         

          <td class="abc">Consumer ID</td>

          <td class="abc">Renew Smart Card (Baht)</td>

          <td class="abc">FT Cal. Back +/- (Baht)</td>

          <td class="abc">Estimated Energy Unit (KWh)</td>

          <td class="abc">Purchase Amount (Baht)</td>

          <td class="abc">VAT 7% (Baht)</td>

          <td class="abc">Total Amount (Baht)</td>

          <td class="abc">Cash Receiver</td>

        </tr>      

        <xsl:for-each select="InvoiceItem[count(. | key('LogItem-TotalAmount', totalAmount)[last()]) = 1]">

            <xsl:sort select="totalAmount" />                         

        </xsl:for-each>    

        <xsl:for-each select="InvoiceItem">

             <tr>

               <td align="left" class="abc"><xsl:value-of select="PrintSn" /><xsl:text disable-output-escaping="yes">&amp;nbsp;</xsl:text></td>       

               <td align="left" class="abc"><xsl:value-of select="ReceiptNo" /><xsl:text disable-output-escaping="yes">&amp;nbsp;</xsl:text></td>

               <td align="left" class="abc"><xsl:value-of select="PurchaseDate" /><xsl:text disable-output-escaping="yes">&amp;nbsp;</xsl:text></td>                                                                                                   

               <td align="left" class="abc"><xsl:value-of select="ConsumerID" /><xsl:text disable-output-escaping="yes">&amp;nbsp;</xsl:text></td>

               <td align="right" class="abc"><xsl:text disable-output-escaping="yes">&amp;nbsp;</xsl:text><xsl:value-of select="format-number(CardAmount, '###,##0.00')" /></td>

               <td align="right" class="abc"><xsl:text disable-output-escaping="yes">&amp;nbsp;</xsl:text><xsl:value-of select="format-number(BackAmount, '###,##0.00')" /></td>

               <td align="right" class="abc"><xsl:text disable-output-escaping="yes">&amp;nbsp;</xsl:text><xsl:value-of select="format-number(EnergyUnit, '###,##0.00')" /></td>

               <td align="right" class="abc"><xsl:text disable-output-escaping="yes">&amp;nbsp;</xsl:text><xsl:value-of select="format-number(PurchaseAmount, '###,##0.00')" /></td>

               <td align="right" class="abc"><xsl:text disable-output-escaping="yes">&amp;nbsp;</xsl:text><xsl:value-of select="format-number(VatAmount, '###,##0.00')" /></td>

               <td align="right" class="abc"><xsl:text disable-output-escaping="yes">&amp;nbsp;</xsl:text><xsl:value-of select="format-number(TotalAmount, '###,##0.00')" /></td>

               <td align="left" class="abc"><xsl:value-of select="Reveiver" /><xsl:text disable-output-escaping="yes">&amp;nbsp;</xsl:text></td>      

            </tr>     

        </xsl:for-each>

        <tr align="center">

          <td colspan="4"  class="abc">Total</td>

          <td class="abc"><b><xsl:value-of select="format-number(sum(InvoiceItem/CardAmount), '###,##0.00')" /><xsl:text disable-output-escaping="yes">&amp;nbsp;</xsl:text></b></td>

          <td class="abc"><b><xsl:value-of select="format-number(sum(InvoiceItem/BackAmount), '###,##0.00')" /><xsl:text disable-output-escaping="yes">&amp;nbsp;</xsl:text></b></td>         

          <td class="abc"><b><xsl:value-of select="format-number(sum(InvoiceItem/EnergyUnit), '###,##0.00')" /><xsl:text disable-output-escaping="yes">&amp;nbsp;</xsl:text></b></td>

          <td class="abc"><b><xsl:value-of select="format-number(sum(InvoiceItem/PurchaseAmount), '###,##0.00')" /><xsl:text disable-output-escaping="yes">&amp;nbsp;</xsl:text></b></td>

          <td class="abc"><b><xsl:value-of select="format-number(sum(InvoiceItem/VatAmount), '###,##0.00')" /><xsl:text disable-output-escaping="yes">&amp;nbsp;</xsl:text></b></td>

          <td class="abc"><b><xsl:value-of select="format-number(sum(InvoiceItem/TotalAmount), '###,##0.00')" /><xsl:text disable-output-escaping="yes">&amp;nbsp;</xsl:text></b></td>

          <td class="abc"><xsl:text disable-output-escaping="yes">&amp;nbsp;</xsl:text></td>         

        </tr>  

      </table>

    </td>

</tr>

</table>

</body>

</html>

</xsl:template>

</xsl:stylesheet>

3、使用tinyXML來解析XML,把查詢數據存儲到XML文件。

內容如下:

    <?xml version="1.0" encoding="GB2312" ?>

<?xml-stylesheet href="Receipt.xsl" type="text/xsl" ?>

<InvoiceReport>

    <PeaArea>bj</PeaArea>

    <AreaCode>0000</AreaCode>

    <TaxID>5469465890</TaxID>

    <StartDate>23/07/07</StartDate>

    <EndDate>23/08/07</EndDate>

    <IssueDate>23/08/50</IssueDate>

    <InvoiceItem>

        <PrintSn>print1</PrintSn>

        <ReceiptNo>50000000100</ReceiptNo>

        <PurchaseDate>2007-08-13</PurchaseDate>

        <PurchaseTime>16:08</PurchaseTime>

        <ConsumerID>0505185712000001</ConsumerID>

        <CardAmount>0.00</CardAmount>

        <BackAmount>0.00</BackAmount>

        <ExtraAmount>0.00</ExtraAmount>

        <EnergyUnit>0.00</EnergyUnit>

        <PurchaseAmount>1000.00</PurchaseAmount>

        <VatAmount>70.00</VatAmount>

        <TotalAmount>1070.00</TotalAmount>

        <Reveiver>Administrator</Reveiver>

    </InvoiceItem>

    <InvoiceItem>

        <PrintSn>print1</PrintSn>

        <ReceiptNo>50000000101</ReceiptNo>

        <PurchaseDate>2007-08-13</PurchaseDate>

        <PurchaseTime>17:08</PurchaseTime>

        <ConsumerID>0505185712000001</ConsumerID>

        <CardAmount>0.00</CardAmount>

        <BackAmount>0.00</BackAmount>

        <ExtraAmount>0.00</ExtraAmount>

        <EnergyUnit>0.00</EnergyUnit>

        <PurchaseAmount>1.00</PurchaseAmount>

        <VatAmount>0.07</VatAmount>

        <TotalAmount>1.07</TotalAmount>

        <Reveiver>Administrator</Reveiver>

    </InvoiceItem>

    <InvoiceItem>

        <PrintSn>print1</PrintSn>

        <ReceiptNo>50000000102</ReceiptNo>

        <PurchaseDate>2007-08-13</PurchaseDate>

        <PurchaseTime>17:08</PurchaseTime>

        <ConsumerID>0505185712000001</ConsumerID>

        <CardAmount>0.00</CardAmount>

        <BackAmount>0.00</BackAmount>

        <ExtraAmount>0.00</ExtraAmount>

        <EnergyUnit>0.00</EnergyUnit>

        <PurchaseAmount>100.00</PurchaseAmount>

        <VatAmount>7.00</VatAmount>

        <TotalAmount>107.00</TotalAmount>

        <Reveiver>Administrator</Reveiver>

    </InvoiceItem>     

</InvoiceReport>

4、報表結果:

在應用程序中使用了CHtmlCtrl控件類來加載XML瀏覽報表結果如圖:

   

    顯示很好,可以自動擴展,彙總等。

    主要代碼:

    static CHtmlCtrl m_page;   

    VERIFY(m_page.CreateFromStatic(IDC_HTMLVIEW, this));

    m_page.Navigate2(m_url,NULL,NULL);

    5、打印報表預覽如圖:

   

    代碼:

    ExecWB(OLECMDID_PRINTPREVIEW, OLECMDEXECOPT_PROMPTUSER, NULL, NULL);

6、存儲爲EXCEL如圖:

代碼:

VARIANT_BOOL    status;

    IXMLDOMDocument *pXMLDoc, *pXSLDoc;

    CoCreateInstance(CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER,

        IID_IXMLDOMDocument, (void**)&pXMLDoc);

    CoCreateInstance(CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER,

        IID_IXMLDOMDocument, (void**)&pXSLDoc);

    CString xmlFile = g_apppath + "report//Receipt.xml";

    CString xslFile = g_apppath + "report//Receipt.xsl";

    HRESULT hr = pXMLDoc->load(COleVariant((LPCSTR)xmlFile), &status);

    if (S_OK != hr) {

        AfxMessageBox("load error");

        return ;

    }

    hr = pXSLDoc->load(COleVariant((LPCSTR)xslFile), &status);

    if (S_OK != hr) {

        AfxMessageBox("load error");

        return ;

    }

    BSTR sHTML;  //存儲轉換後的數據

    hr = pXMLDoc->transformNode(pXSLDoc, &sHTML);

    if (S_OK != hr) {

        AfxMessageBox("transformNode error");

        return ;

    }

    //另存爲EXCEL文件

TCHAR szSaveFileNames[MAX_PATH] = {0};

    OPENFILENAME ofn;

    ZeroMemory( &ofn, sizeof(ofn));

    ofn.lStructSize = sizeof(OPENFILENAME);

    ofn.hwndOwner = this->m_hWnd;

    ofn.lpstrFilter = TEXT("Microsoft Office Excel Files (*.xls)|*.xls");

    ofn.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR;

    ofn.lpstrFile = szSaveFileNames;

    ofn.nMaxFile = sizeof(szSaveFileNames);

    ofn.nFilterIndex = 1;

    ofn.lpstrFileTitle = NULL;

    ofn.nMaxFileTitle = 0;

    ofn.lpstrDefExt = TEXT("xls");

    CString strPath = g_apppath + "report";

    ofn.lpstrInitialDir = strPath;

 

    if ( !GetSaveFileName( &ofn ) )

        return;

           

    FILE *stream;

    if( (stream = fopen( szSaveFileNames, "w" )) == NULL ) {

        AfxMessageBox( "The file 'data' can not be written/n" );

        return ;

    }

    else {

        fprintf( stream, "%s", (CString)sHTML);

        fflush(stream);

        fclose(stream);

        AfxMessageBox("Save Successful!");         

    }

五、結論:

    很好的解決了問題。效果很好!

六、參考資料:

    tinyXMLXMLXSLCHtmlCtrlExecWBOPENFILENAME;

 
發佈了6 篇原創文章 · 獲贊 1 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章