基於PHP與XML的PDF文檔產生技術

來源:互聯網
上載者:User
xml 摘要

本論文簡要介紹了PHP、XML、PDF等技術的原理以及它們的應用情況。力圖運用PHP物件導向的特性,構建出一套基於PHP和XML的線上PDF文檔產生系統。文中詳細探討了整個系統的組成部分以及各自的實現過程。並在最後給出一個運用這套系統實現的動態建立報表的執行個體。

Abstract
This article introduced the fundamentls of PHP,XML and PDF and their application situation at present,expecting to build a PHP&XML-based dynamic PDF documents creating system through the PHP’s OO features. Furthermore,we discussed in detail on the components of the whole system and their respective realizing methods. Finally,we represented an example of creating reports dynamically using this system.



關鍵詞

PHP  XML XSLT  DTD  PDF





1. 引言



在資訊技術飛速發展的時代,無論政府、企業還是個人,他們對如何通過資訊技術提高自身工作效率,節省開支具有濃厚的興趣。他們急切要找到一種優秀的技術,可以把傳統上以紙張為媒介的檔案、報表、票單據、手冊、申請書等等等等轉化為一種可以非常方便的在互連網以及內部網路自動產生、傳播、下載、瀏覽、列印的電子文檔。而如今最為熱門的“無紙化辦公”、“電子商務”等等都將以此為基礎。



這種文檔格式就Adobe公司的PDF(可移植文檔格式),它已是全世界電子版文檔分發的公開實用標準 。 任何瀏覽器只要安裝Acrobat reader 5.0 的外掛程式,便可以自由瀏覽、下載、列印PDF文檔。PDF無疑具有其它電子文檔格式不可比擬的優越性。



我們知道B/S系統作為當前以及將來最流行的一種軟體架構,可以很好的實現各種基於瀏覽器的Web應用程式,而PHP作為一種優秀的Web程式設計語言,特別適合開發用於處理使用者表單輸入,查詢資料庫等針對瀏覽器使用者的前端應用程式。由於PHP是開放源碼的,這使得它的使用比其它同類的Web指令碼語言更為廣泛,它的功能也在不斷的擴充和完善之中。現在最新的PHP版本已經可以很好的支援PDF,XML等。通過系統提供的API,我們能非常快捷的產生PDF文檔,而最具魅力的是,我們可以通過PHP,查詢資料庫或XML資料檔案並將結果插入所產生的PDF文檔之中,形成各種具有絕佳的瀏覽和列印效果的報表、單據、手冊等。



不難看出,結合PHP、XML、PDF三項技術,構造出一種可以線上動態產生PDF文檔的系統是極具現實意義的,其主要表現在:



?文檔可以在網路上產生,並通過網路分發。節省大量的人力物力。具有精確美觀的列印效果,真正實現了無紙化辦公。

?電子商務交易過程中的各種票據、 憑證都可以通過PHP指令碼程式線上產生,並轉為PDF格式發送給客戶。

 ?企業MIS系統中各種面向列印的報表的產生,並可直接通過瀏覽器獲得,無須安裝任用戶端,使用極為方便。

?以前檔案流轉是"先列印,後分發",每年花在印刷上的費用是政府、企業沉重的負擔。而PDF文檔"先散發,後列印",接件人可以在瀏覽後,再按需要列印。印刷的費用大大減少。而且,很有利於環保事業。



2. 課題簡介



在某些軟體項目的開發過程中,我們遇到一個很關鍵的問題就是大量面向列印的報表、單據的產生。我們知道,HTML適合瀏覽,但不適合格式規範的列印。因此必需找到一種可以由PHP動態產生,且具有良好的列印效果的文檔格式。而這正是我研究這個課題的最直接的需求。 明白了這一點,我們就很自然的想到了PDF以及PHP的PDF支援庫PDFLib。通過PDFLib提供的一套API,我們可以很容易在PHP指令碼動態建立PDF文檔。但是這隻是一套非常基本的函數,只能進行一些簡單的輸出,如線條、文本、矩形框等,而且每輸出一個對象之前,都要為其指定座標。如果直接使用來這套函數來做一些實際的應用,比如複雜的報表的產生,其困難程度是難以想象的。我們不可能為建立這樣一個報表,而事先算好各個元素的座標,並把儲存格用矩形框一個一個的畫出來。



所以,我們第一步要做的就是利用PHP物件導向的編程方法將這套基本的API進行封裝,以產生多個實用的具有獨立功能的對象模組(如page對象、table對象、text對象等)。應該說,這一塊是此項目最基本,也是最重要的部分。我參考並部分採用

了國外一些類似的開放源碼的程式,在此基礎上開發出了一套功能較為強大的類庫。大大簡化了PDF文檔的產生,特別是其中的table對象,可以象HTML中的TABLE標記一樣任意嵌套,輕鬆快捷的實現各種複雜的表格的繪製(這對動態產生報表是非常有用的)。



產生PDF的問題解決以後,我們面臨了新的問題,舉個例子來說,資料庫查詢頁面如何將包含大量資訊的結果集以及其它資訊傳給PDF產生頁面? 最初我們想到的方法是通過文字檔傳遞,即在資料庫查詢頁面將資料寫到一個文字檔當中,並對其

中不同類別的資料定義一套區分的標記,PDF產生頁面讀取此檔案,將內容插入到PDF中。 但是這樣做,並不可靠。因為在這個文字檔中,我們採用特定的字元(或空格)來分離資料,如果恰好有用資料中也包含同樣的字元或空格呢?可見,以這種方式傳遞資料是有隱患的。其實上面我們提到在文字檔中用不同的標記區分不同類別的資料。而這正是XML技術的思想。何不一步到為採用XML來作為資料傳遞的手段呢? 況且PHP對XML和XSLT具有很好的支援,通過expat解析器,我們可以任意提取XML文檔中的資料,也可以通過PHP的XSLT引擎Sablotron對XML文檔進行任意轉換。



首先由“XML產生器”將資料(來自資料庫或使用者輸入等)放到一個符合事先定義好的DTD的XML文檔中,此文檔對其中的資料內容進行描述,不包含任何格式資訊。 然後由“XML轉換器”將這個XML文檔轉換成包含顯示樣式資訊的另一個XML文檔。 最後由“PDF產生器”讀取這個文檔,根據其中的內容和顯示樣式產生相應的PDF文檔。在這一個過程中,我要做的是再次運用 PHP的物件導向特性,構建出可重用的類:XMLWriter(產生XML檔案)、XMLParser(解析XML檔案)以及XMLTransformer(對XSLT函數的封裝)。



系統構建成功後,就是具體的應用了。主要是進銷存系統中各種報表、單據的動態產生。



3. 可行性分析



開發一個功能強大、適應性好的PDF文檔線上產生系統,必然需要彈性大、靈活性

高的開發模型。我們提出的基於PHP和XML的PDF文檔線上產生技術,為各種面向列印的應用,如報表、單票據、手冊等提供了新的思路。我們用PHP來查詢資料庫,處理使用者輸入,並在此基礎上產生原始的XML文檔;然後通過XSLT將該XML文檔加上顯示層資訊,產生另外一個新的XML文檔。最後利用“PDF產生器”將這個新的XML文檔轉化為相應格式的PDF文檔。對於最初產生的XML文檔,我可以做二度利用,因為該文檔包含了所有的有用資訊,可以非常容易的被其它應用程式處理。如果我們想改變資訊在PDF文檔顯示的樣式,可以非常容易的實現。只要專門人員修改相應的XSL樣式單檔案即可,不需要對其它環節做任何修改,具有非常好的靈活性。除此之外,PHP、XML、PDF三者都具有極好的可移植性,可以跨平台使用。 對該系統的研究並非憑空想象的,它建立在直接的需求之上的。到目前為止,這套技術已經投入實際應用,收到了極為滿意的效果。實踐證明,運用PHP和XML開發出的一套線上PDF文檔產生系統具有廣闊和非常實際的應用前景。



4 總體設計



本課題主要完成四個基礎模組的設計及編程實現。這四個類別模組分別為PDFCreator、XMLWriter、XMLTransfomer以及XMLParser。它們分佈於系統的各個環節之中,具有各自獨立的功能和作用,是系統的核心組成部分(見下圖)。



系統構成圖



從圖中可見,四者在本系統中又是緊密聯絡的有機整體。XMLWriter作為系統的輸

入介面,負責產生原始的XML資料檔案。該檔案的格式規範(DTD)由我們事先編寫好,而XMLWriter按照該DTD產生相應的XML文檔。這個XML文檔接著交由XMLTransfomer處理,XMLTransfomer其實是對PHP提供的XSLT函數的封裝,它一般接受兩個參數,其中之一是需要轉換的XML文檔,另一個是相應的XSL樣式單檔案。XMLTransfomer正是根據該樣式單檔案將原始的XML文檔轉化為符合這個樣式單樣式的另一個XML文檔(包含資訊在PDF文檔中放置的格式)。然後,這個新的XML檔案繼續交由“PDF產生器”進行處理。而這個過程有分為兩個部分:首先,必需對這個XML文檔進行解析,提取其中所需的資料,這一步有XMLParser來完成,XMLParser對此XML文檔進行解析,將其轉化為一棵對象樹,XML文檔中每一個節點都是一個對象,每個對象都有各自的屬性(即相應節點的所有資訊)。這樣一來,我們可以非常方便的訪問這個XML文檔的任意內容。之後,要做的就是將該XML文檔中讀出的資訊(包括格式資訊和內容資訊)用PDFCreator轉化為最終的PDF文檔的輸出。



5.應用樣本



在這裡,我們運用上面的這套系統建立一個面向列印的報表??“庫存曆史事

表”。這個報表包含的資訊有:報表名稱(協和庫存曆史事務表)、單位、建表日期等,另外就是從資料庫中提取的資料了,品名(LLPROD)、批號(LLOC)、等級(LCLS)、倉庫(LWHS)、庫位(LLOCT)、數量(LNUM)、日期(LDATE)等。假設我們已經用XMLWriter產生了下面的原始XML文檔(report.xml):

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

<report>

<report_param>

<title>庫存曆史事務表</title>

<unit>平方米</unit>

<date>20020611</date>

</report_param>

<report_records>

<record>

<llprod>W2308</llprod>

<lloc>1234</lloc>

<lcls>a</lcls>

<lwhs>01</lwhs>

<lloct>0001</lloct>

<lnum>200</lnum>

<ldate>20020609</ldate>

</record>

<record>

<llprod>W2307</llprod>

<lloc>4321</lloc>

<lcls>a</lcls>

<lwhs>01</lwhs>

<lloct>0001</lloct>

<lnum>100</lnum>

<ldate>20020609</ldate>

</record>

</report_records>

</report>



該文檔包含了這張報表的所有有用資訊,我們需要用特定的XSL樣式單為其加上格式資訊。XMLTransformer執行轉換的代碼如下:

<?php

$xslt = new XMLTransformer ("report.xsl", "report.xml");

$xslt->apply("pdfreport.xml");

?>



轉換後產生的新的XML文檔如下:



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

<pdfreport pagetype="a4" pagesize="25" top="20" bottom="20" left="20" right="20">

<head>

<line top="5" bottom="5" size="50%" linetype="single" show="false"/>

<text fontsize="30" fontlaguage="cn" align="center">庫存曆史事務表</text>

<line top="5" bottom="30" size="80%" linetype="double" show="true"/>

<text fontsize="12" fontlaguage="cn" align="left">單位:平方米</text>

</head>



<body>

<table>

<tr><th>品名</th><th>批號</th><th>等級</th><th>倉庫</th><th>庫位</th><th>數量</th><th>日期</th></tr>

<tr><td>W2308</td><td>1234</td><td>a</td><td>01</td><td>0001</td><td>200</td><td>20020609</td></tr>

<tr><td>W2307</td><td>4321</td><td>a</td><td>01</td><td>0001</td><td>100</td><td>20020609</td></tr>

</table>

</body>

<foot>

<line top="5" bottom="5" size="50%" linetype="single" show="false"/>

<text fontsize="12" fontlaguage="cn" align="center">建表日期:20020611</text>

</foot>

</pdfreport>

用XMLParser對該XML文檔解析後,得到一個包含所有資訊的對象樹,我們可以非常方便的訪問其中的內容。產生的PDF報表如下圖:





程式片斷如下:



<? include( "../include/pc_init.inc" );?>

<? include( "xmlparser.inc" );

<?

$xmlobject=getRootNode("report.xml");

// get the attrs of root element

$pageSet=$xmlobject->attrs;

// get the report-head

$head=$xmlobject->nodes[0];

// code ignored...

?>

<?



function draw_line(&$parent,$line){

$line = &pc_create_object( $parent, "line" );

$line->pc_set_linestyle( $line->attrs["LINETYPE"]);

$line->pc_set_width( $line->attrs["SIZE"] );

$line->pc_set_alignment( "center" );

if($line->attrs["SHOW"]==false){

$line->pc_set_linecolor( "white" );

}

$line->pc_set_margin( array( "top" => $line->attrs["TOP"], "bottom" => $line->attrs["BOTTOM"], "left" => 0, "right" => 0 ) );

}



function draw_text(&$parent,$text){

// code ignored...

}

function draw_table(&$parent,$table){

// code ignored...

}



function addhead(&$parent,$head){

for($i=0;$i< $head->n;$i++){

switch ($head->nodes[$i]->name){

case "LINE":draw_line($parent,$head->nodes[$i]);break;

case "TEXT":draw_text($parent,$head->nodes[$i]);break;

}

}

}

//..

?>

<?

// Create a PDF Document

$PDF = &pc_create_pdf( array( "Author" => "cyman", "Title" => "a report example" ) );

// Create an A4-format page

$Page1 = &pc_create_page( $PDF, $pageSet["PAGETYPE"]);

addhead($Page1,$head);

$PDF->pc_draw();

?>





6.總結

在幾個月來的畢業設計過程中,雖然忙碌,卻非常充實。通過對一個實際的課題的分析,研究,論證,實現。感覺收穫頗多。目前,這套系統已投入使用,收到了非常滿意的效果,可以很容易的做出美觀實用的報表、單據等。但是,由於時間上的倉促以及自己水平的有限,這套系統仍有許多不足之處。其中最遺憾就是,沒有能定義出一套對各種文檔(包括報表、單據、手冊等等)都通用的XML標記,並編製通用的程式將這個XML文檔轉化為PDF,就如同瀏覽器解析HTML一樣。這樣就不必為每一種文檔都定義各自的XML標記並編寫相對應的轉換程式,可以大大提高工作效率。

雖然畢業設計已經結束,但是我將會今後的日子裡繼續這個課題的研究。


相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.