C#发现之旅第二讲 C#-XSLT开发
袁永福 2008-5-15
系列課程說明 ????為了讓大家更深入的了解和使用C#,我們開始這一系列的主題為“C#發現之旅”的技術講座。考慮到各位大多是進行WEB數據庫開發的,而所謂發現就是發現我們所不熟悉的領域,因此本系列講座內容將是C#在WEB數據庫開發以外的應用。目前規劃的主要內容是圖形開發和XML開發,并計劃編排了多個課程。在未來的C#發現之旅中,我們按照由淺入深,循序漸進的步驟,一起探索和發現C#的其他未知的領域,更深入的理解和掌握使用C#進行軟件開發,拓寬我們的視野,增強我們的軟件開發綜合能力。
本系列課程配套的演示代碼下載地址為 http://files.cnblogs.com/xdesigner/cs_discovery.zip 。
本系列課程已發布的文章有
C#發現之旅第一講 C#-XML開發
C#發現之旅第二講 C#-XSLT開發
C#發現之旅第三講 使用C#開發基于XSLT的代碼生成器
C#發現之旅第四講 Windows圖形開發入門
C#發現之旅第五講 圖形開發基礎篇
C#發現之旅第六講 C#圖形開發中級篇
C#發現之旅第七講 C#圖形開發高級篇
C#發現之旅第八講 ASP.NET圖形開發帶超鏈接的餅圖
C#發現之旅第九講 ASP.NET驗證碼技術
C#發現之旅第十講 文檔對象模型
本課程說明
本課程介紹XPath和XSLT的基本概念,并介紹了如何在C#中使用這些技術。
XPath介紹??? XPath是從XML基礎規范上派生的技術,專門用于快速檢索和查詢XML文檔,使用方便,功能強大,XPath也是XSLT技術的基礎。
??? XPath是W3C國際標準組織定義的用于在單個XML文檔中快速檢索和定位XML文檔節點的規范,它也是跨平臺的,若一些軟件支持XPath,則必然是支持標準的XPath語法。因此無論是JAVA還是C#都是支持相同語法的XPath。
??? 我們理解XPath時可以參考文件目錄結構FilePath,在Windows資源管理器左邊的文件目錄樹狀列表中,可以看到各種文件對象,包括磁盤根目錄,各級文件目錄等等,它們共同構成了一個樹狀結構,我們選擇對象時既可以在這個樹狀結構中一個個查找,也可以指定路徑名來進行快速定位,文件系統的路徑名采用斜杠號來分隔各個目錄層次的目錄名。比如在這個示意圖中,我們選中的目錄,可以使用路徑名”c:\documents and settings\袁永福”來快速定位。
??? 而XML文檔中也是這種樹狀層次結構,因此我們也可以套用這種文件路徑名的概念到XML文檔中,于是形成了XPath路徑。我們處理XML文檔時可以一層層查找所需的XML節點,也可以指定XPath路徑字符串來快速定位XML節點。在XPath路徑中,我們使用反斜杠符號來分隔各個層次的XML元素的名稱。
??? 在文件目錄系統中,我們可以可以使用絕對路徑名,也可以使用相對路徑名,我們可以使用一個點號表示當前目錄,使用兩個點表示父目錄。在XPath中我們也套用了類似的概念,我們從XML文檔根節點出發而指定的XPath路徑為絕對路徑,從某個XML節點開始轉到其它節點所經過的路徑為相對路徑,我們也使用一個點表示當前節點,也使用兩個點來表示父節點。其實我們可以將絕對路徑看成從根節點出發的相對路徑。
??? 在這個示意圖中,第一個選中的節點可以使用XPath路徑“Table/Record/Country”來快速定位。
??? 在文件目錄系統中,同一個目錄下面不能有相同名稱的對象,因此相對路徑名和絕對路徑名都能準確的定位到一個目錄上,而在XML文檔中,同一個XML節點下可以存在多個具有相同名稱的子節點,因此XPath路徑可能無法唯一的確定一個XML節點。此時XPath采用了內嵌條件判斷語句的方法來解決這個問題。XPath路徑字符串中可以使用一對方括號來包含一個邏輯表達式,在這個表達式中可以使用字符串判斷,數學四則運算,邏輯判斷和一些預定義函數,而且XPath路徑中每個層次都能包含表格式,因此XPath的邏輯判斷的功能是非常強大的。
??? 在示意圖中,我們使用XPath路徑”Table/Record[CustomerID=’ANATR’]/Phone”來快速定位第二個節點,此處使用了一段方括弧包含了一個邏輯表達式。表示查找某個節點,該節點下的CustoemrID子節點的文本值等于 “ANATR”。
??? XPath是一種國際標準,但在微軟的.NET框架當然支持這個國際標準。我們可以使用.NET類庫中的System.Xml.Xsl.XslTransform類型來執行XSLT轉換。這個類型除了支持標準的XPath外,還進行一些擴展,主要是能擴展使用開發者自己定義的函數。
??? 使用XPath,我們可以很方便的搜索XML文檔中的任何部分,因此具有很好的數據檢索分析功能,近期業界興起的半結構化文檔技術大多就是以XPath為基礎的。
??? 由于XPath技術是相當強的,而且是國際標準,跨平臺的,因此大家有時間好好學習使用它。對于XPath的詳細語法可訪問網站 http://www.w3.org/TR/xpath ,若大家安裝了MSDN2003版,也可參考 MSDN Library/XML Web Services/XML核心/SDK 文檔/MSXML4.0 SDK/XPath Reference。這些電子文檔全是英文,大家也可以購買一些專門講述XML技術的中文書籍看看。
?XSLT介紹
??? XSLT是一種將XML文檔轉換為其他文本文檔的語言,是建立在XML和XPath之上的國際標準,內容比較多,功能強大。
??? 對于編程人員來說,XSLT可以看作以前序遍歷的方式專門處理XML樹狀結構的標記語言。以前編程根據XML文檔輸出純文本數據時需要寫代碼以前序遍歷方式的方式遍歷XML文檔對象組成的樹狀結構,對于每一個特定名稱或特定層次的XML節點而輸出不同的內容,這個過程比較復雜,代碼量大,需用進行很多的狀態判斷。而XSLT則使用一種簡潔明了的標記語言實現了相同的邏輯。因此XSLT從程序邏輯的角度看類似支持遞歸的編程語言,而且是專門處理XML文檔的。
??? XSLT轉換過程會涉及到三個文本文檔,一個是要處理的原始XML文檔,第二個就是XSLT樣式表文檔,該文檔包含了XSLT代碼,XSLT代碼本身就是XML格式,但使用了XML的名稱空間。第三個就是XSLT處理輸出的文本文檔,注意,此處輸出的是純文本文檔,這個文檔具體是什么格式完全靠XSLT代碼來決定,可以是另外一個XML文檔,HTML文檔,SQL語句字符串或者其他任意格式的字符串數據等等,XSLT轉換只能輸出純文本文檔,此外就沒有限制輸出文檔的具體格式。
XSLT范例
??? 下面使用一個XSLT范例來說明XSLT處理過程。
??? 在這個示意圖中有三個圖片,第一個是原始的包含數據的XML文檔,第二個是XSLT樣式表文檔的內容,第三個就是轉換結果。XSLT代碼如下
| <xsl:stylesheet version='1.0' xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> ??? <xsl:output method='xml' /> ??? <xsl:template match='/'> ??????? <html> ??????????? <body> ??????????????? <table border='1'> ??????????????????? <xsl:for-each select="Table/Record"> ??????????????????????? <tr> ??????????????????????????? <xsl:for-each select="*"> ??????????????????????????????? <td> ??????????????????????????????????? <xsl:value-of select="." /> ??????????????????????????????? </td> ??????????????????????????? </xsl:for-each> ??????????????????????? </tr> ??????????????????? </xsl:for-each> ??????????????? </table> ??????????? </body> ??????? </html> ??? </xsl:template> </xsl:stylesheet> |
??? 數據XML文檔是一個很簡單的XML文檔,此處不加說明了。重點說說XSLT樣式表文檔,可以看到XSLT樣式表文檔本身一個XML文檔。它采用XML的樹狀結構來描述遞歸處理過程,也比較好理解。
??? 在樣式表文檔中,根元素為 xsl:stylesheet ,里面定義了一個名為xsl的名稱空間,這個根節點及其屬性值都是固定的。
xsl:output 元素是可選的,它的method屬性用于指定輸出文檔的格式,可以設置為xml,html或text值。此處使用xml輸出樣式,說明輸出的文檔是XML格式的,XSLT轉換會盡量生成XML文檔,但不作保證,因此仍然有可能生成不合格的XML文檔。
??? xsl:template 用于定義一個XSLT模板,模板類似編程語言中的函數,可實現XSLT代碼的重用。模板可以使用name屬性定義名稱,也可以使用match屬性定義匹配的XPath路徑,這個模板使用了match屬性來匹配XML文檔本身。
??? 然后是 html 元素,由于html元素沒有使用xsl的前綴,因此不屬于xslt代碼,因此將原樣輸出,跟著后面的body,table元素也是一樣的。
??? xsl:for-each 元素類似C#中的foreach 語法結果,表示循環遍歷元素,它使用select屬性指定一個XPath相對路徑,XSLT使用這個相對路徑查詢所有要遍歷的XML節點,此時當前節點就是XML文檔本身,因此XSLT處理器會調用XmlDocument的SelectNodes 函數來獲得要遍歷的XML節點,函數的參數就是Table/Record。于是我們開始循環遍歷所有的Record元素了。
??? 在循環遍歷Record元素時,對每一個Record元素都要輸出xsl:for-each的子節點,首先是 tr 元素,這不是XSLT元素,因此原樣輸出。這里還套嵌定義了另外一個for-each元素,于是我們又開始了一個新的循環遍歷了,新的循環指定的相對XPath路徑是一個星號,表示匹配所有名稱的子元素,這類似DOS命令Dir中使用星號匹配所有文件。此處表示循環遍歷Record元素下面所有的字段元素。
??? 對每一個字段元素,首先輸出td 元素,然后處理xsl:value-of 元素,xsl:value-of 表示輸出指定相對路徑的節點的值,這里指定的XPath是一個點號,表示當前節點本身,由于當前節點是XML元素,因此也就輸出元素的文本內容,相當于輸出XmlElement的InnerText 屬性值。
??? 為了讓大家更清楚的了解XSLT執行過程,我寫了一段C#代碼來模擬實現這個XSLT轉換過程,代碼在演示程序的 codexslt.aspx 中。代碼如下
| // 此處代碼動態構造 xml 文檔對象結構來輸出XML文檔 System.Xml.XmlDocument XmlDoc = new System.Xml.XmlDocument(); -------------- 查詢數據庫,填充XmlDoc -------------------------- // 保存輸出結果的緩沖區 System.IO.StringWriter myResult = new System.IO.StringWriter(); myResult.WriteLine("<html>"); myResult.WriteLine("??? <body>"); myResult.WriteLine("??????? <table border='1'>"); // 模擬 <xsl:for-each select="Table/Record"> foreach( System.Xml.XmlNode node in XmlDoc.SelectNodes("Table/Record")) { ??? myResult.WriteLine("??????? <tr>"); ??? // 模擬 <xsl:for-each select="*"> ??? foreach( System.Xml.XmlNode node2 in node.SelectNodes("*")) ??? { ??????? myResult.Write("??????????? <td>"); ??????? // 模擬 <xsl:value-of select="." /> ??? ??? myResult.Write( node2.InnerText ); ??????? myResult.WriteLine("</td>"); ??? } ??? myResult.WriteLine("??????? </tr>"); } myResult.WriteLine("??????? </table>"); myResult.WriteLine("??? </body>"); myResult.WriteLine("</html>"); myResult.Close(); |
??? 代碼很簡單,這里我就不詳細說明了。
??? 這里只是展示了一個非常簡單的XSLT轉換過程,XSLT和XPath語法不少,但花點時間是可以記下來的,編寫XSLT模板是很有技巧性的。一般的我們要設計XSLT模板,首先獲得要轉換的XML文檔樣本以及所需轉換結果的樣本,這兩個樣本可能相差非常大,所有的差別都需要依靠XSLT轉換模板來彌補,此時XSLT模板的編寫不只是XSLT元素和函數的堆砌,而是需要同時兼顧輸入和輸出,還需要使用面向過程的編程思想。有時還需要編程對XSLT轉換器進行擴展。
XML/XSLT在WEB開發中的應用??? XML/XSLT技術在WEB開發中可以發揮很大的應用,可以為WEB開發提供一種新的HTML頁面生成方式。
??? 一般的在WEB開發中使用XML/XSLT技術主要有兩種模式,一個是在服務器端執行XSLT轉換,另一個是在客戶端執行XSLT轉換。
??? 在服務器端執行XSLT轉換時,應用系統的業務模塊生成包含要顯示的數據的XML文檔,然后調用事先寫好的XSLT模板文檔,執行XSLT轉換,轉換結果一般是HTML文檔,當然也可以是其他類型的文本文檔,此時客戶端就可以將生成的HTML文檔直接作為頁面響發送到客戶端瀏覽器中。客戶端瀏覽器接受HTML文檔并顯示出來。在這個過程中,服務器端生成的XML文檔,XSLT轉換生成的HTML文檔都是臨時生成的文檔,都可以存留在內存中,用完即可清除掉,不需要寫到磁盤文件中。
??? 在客戶端執行XSLT轉換時,應用系統的業務模塊生成包含要顯示的數據的XML文檔,加上XSLT轉換信息標記,直接發送到客戶端瀏覽器,客戶端瀏覽器獲得這個XML文檔,根據其中的XSLT轉換信息標記,從服務器上下載指定名稱的XSLT文檔。然后調用自己的XSLT轉換器進行轉換,在內存中生成了HTML文檔并顯示出來。此時顯示的HTML頁面不會出現在瀏覽器的緩沖文件夾中,也看不到HTML源代碼,只能看到XML的源代碼。
??? 由于XSLT轉換是國際標準,在服務器端的轉換結果和在客戶端的轉換結果是一樣的。因此兩種模式下瀏覽器中顯示的頁面內容是一樣的。
??? 在傳統的WEB開發中,我們都是直接使用業務系統拼湊出HTML字符串來生成要顯示的HTML頁面。雖然在ASP.NET中大量使用Web控件來簡化開發,但web控件內部還是拼湊HTML字符串的。使用程序代碼來拼湊HTML字符串會影響程序代碼的可讀性,很容易使得程序代碼雜亂無章,而且生成的HTML可讀性差。
??? 若使用XML/XSLT技術則可以有效的改善這種情況,由于XML文檔格式檢查非常嚴格,因此這就使得程序代碼生成XML文檔過程準確,不得出現錯誤,在這個環境下迫使程序員注意保持程序代碼質量。而且生成的XML文檔不只用于生成HTML頁面,還能方便的向其他程序模塊提供數據,并可充當WebService。
??? 考察WEB應用中生成的HTML代碼,可以發現,大量的HTML頁面中用于實現頁面各種動態效果和頁面格式的HTML代碼多于直接顯示數據的HTML代碼,而且HTML代碼普遍重復。這使得HTML頁面代碼臃腫,文件大,這會使得客戶端瀏覽器下載頁面緩慢。當采用XML/XSLT技術并在客戶端執行XSLT轉換時,由于服務器端發送的XML文檔非常簡潔,只包含純粹的數據,并沒有其他冗余的代碼,因此文檔小,下載快。與之配套的XSLT模板也是經過分析處理的,代碼重復少,因此XSLT文件也小,這樣客戶端瀏覽器以前要下載一個很大的HTML文檔,而現在只要下載兩個較小的文檔,這縮短了瀏覽器下載數據的時間。
??? 除了改善數據傳輸過程,瀏覽器自己執行XSLT轉換,這樣能將一部分的工作量從服務器端轉移到客戶端,此時服務器端只要快速生成包含數據的XML文檔即完成工作。由于XSLT是廣泛采用的國際標準,此時WEB系統能可靠的使用客戶端的運算能力,從而減少服務器端運算壓力,而利用客戶端長期閑置的運算能力。
??? 雖然XML/XSLT技術具有很大的優勢,但在實際開發中仍然存在不小的問題,其中最大的問題就是編制XSLT模板文件成本高。我們在開發WEB系統中使用了很多開發工具,包括VS.NET的WEB窗體設計器,美工人員使用的FrontPage,Dreamwave等等,都是用于生成HTML文檔的,而HTML文檔要求不嚴格,很多內容還不符合XML規范,因此需要使用各種方法將這些HTML文檔轉換為標準的XML文檔,然后還需要分析頁面結構,將這些XML文檔加工成XSLT文檔。在目前的技術條件下,這個過程成本比較大,使得XML/XSLT技術難于推廣和普及。在此建議大家多多思考,如何低成本的將HTML文檔轉換為XSLT文檔。
??? 而且XML/XSLT技術調試比較困難,對開發者要求很高,這也加大了這個技術的應用成本。而且目前的web系統中大量使用的WEB控件沒有考慮到XML/XSLT技術,這也阻礙了這種新技術的應用。
使用C#執行XSLT轉換??? 在演示程序中,其中有些代碼就是使用C#來執行XSLT轉換的。
record.aspx??? 演示程序中record.aspx演示了在服務器端執行XSLT轉換,打開這個頁面的C#代碼中,在Page_Load函數中,首先是查詢數據庫并生成一個包含數據的XML文檔。然后我們使用了一個名為xsl的頁面參數,這個參數就指定了使用XSLT模板文件。若用戶指定了該參數,我們開始執行XSLT轉換。
??? 首先是創建一個XslTransform對象,調用它的Load函數來加載用戶指定的XSLT模板文件,然后調用它的Transform函數,這個函數有四個參數,第一個就是包含數據的XML文檔對象,第二個是XSLT轉換參數的列表,此處未用,第三個就使輸出轉換結果的流對象,我們就使用頁面輸出流,最后一個是XML文檔解析對象,此處未用。
| string strXSLRef = this.Request.QueryString["xsl"] ; if( strXSLRef != null && strXSLRef.Length > 0 ) { ??? // 根據頁面參數指定的XSLT樣式表名稱執行XSLT轉換 ??? strXSLRef = this.Server.MapPath( strXSLRef ); ??? System.Xml.Xsl.XslTransform transform = new System.Xml.Xsl.XslTransform(); ??? transform.Load( strXSLRef ); ??? transform.Transform( XmlDoc , null , this.Response.Output , null ); } |
??? 可以看到在C#中執行XSLT轉換是非常簡單的,只要創建一個XslTransform對象,使用Load函數加載XSLT模板,使用Transform函數來執行XSLT轉換即可。
recordxml.aspx??? 演示程序中的recordxml.aspx演示了在客戶端執行XSLT轉換,打開這個頁面的C#代碼,在Page_Load函數中,可以看到是查詢數據庫并使用XmlTextWriter輸出包含數據的XML文檔。其中有這么一段代碼,首先判斷一個名為xsl的頁面參數是否存在,若存在則調用xmlwriter的WriteProcessingInstruction方法輸出一段名為 xml-stylesheet的XML指令,這個指令的 href 屬性值就使頁面參數指定的XSLT模板文件名。
| // 輸出XSLT樣式表信息頭 string strXSLRef = this.Request.QueryString["xsl"] ; if( strXSLRef != null && strXSLRef.Length > 0 ) { ??? xmlwriter.WriteProcessingInstruction( ??????? "xml-stylesheet" , ??????? "type='text/xsl' href='" + strXSLRef + "'"); } |
??? 客戶端瀏覽器解析下載的XML文檔,若遇到這個這段XML指令根據其中的href屬性下載XSLT模板文件,然后執行XSLT轉換,將生成的轉化結果再作為HTML文檔顯示出來。
??? 在這個頁面中,服務器端只負責輸出數據XML文檔,并提供XSLT模板文件下載,而XSLT轉換就給客戶端瀏覽器處理,這樣就能減少服務器端的工作量并利用客戶端的運算能力。
??? 注意這里的xml-stylesheet指令只對瀏覽器有效,一般其他的程序處理XML文檔時會忽略掉這個XML指令。即使我們在服務器端使用XslTransform對象執行XSLT轉換,這個XML指令也是毫無作用的,就像不存在一樣。
使用C#執行XPath查詢??? 演示程序中的recordxpath.aspx就演示了使用C#執行XPath查詢。打開這個頁面的界面設計,可以看到其界面是比較簡單地,其中一個單行文本框用于輸入XPath字符串,一個大的多行文本框用于顯示查詢結果,還有一個按鈕用于點擊執行操作。頁面代碼主要在這個按鈕的點擊事件處理中。
??? 雙擊這個按鈕,可以看到該按鈕的點擊事件處理代碼。在該處理中,首先調用CreateRecordXMLDocument函數來獲得包含數據的XML文檔對象,生成XML文檔的過程可以參考record.aspx的說明。
??? 程序生成包含數據的XML文檔后,在從單行的文本輸入框獲得用戶輸入的XPath字符串,若用戶輸入的內容,則對XML文檔的根節點調用SelectNodes方法,執行XPath查詢,SelectNodes函數返回一個XmlNodeList列表,該列表中的元素類型是XmlNode。我們遍歷這個列表,對其中每一個XML節點對象獲得它的XML字符串,然后進行輸出。
??? 若用戶沒有輸入XPath字符串,則直接輸出XML文檔根節點的內容。
??? 在這里我們定義了GetXMLString 函數,這個函數主要是返回指定的XML節點對象的帶縮進的XML字符串。用于取代Xml節點的OuterXml屬性。
小結??? 在本課程中,我們了解了XPath,XML/XSLT的基礎知識。并演示使用C#使用XPath和XML/XSLT技術。
??? XML及其派生的技術都是很重要的國際標準技術,對現代WEB開發具有很大的影響力,XML技術是一種優質的軟件開發技術,因此大家要花點時間好好學習,熟練掌握XML及其派生技術將大大提高大家的軟件開發能力。
轉載于:https://www.cnblogs.com/xdesigner/archive/2008/05/19/1202313.html
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的C#发现之旅第二讲 C#-XSLT开发的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CSS文本对齐text-align详解
- 下一篇: Lucene使用案例(包括索引的维护)