現在我們根據前因後果來說明其中的過程。在XSLT文件中,唯一的一個 xsl:template模板定義塊命中XML文檔的根節點,然後使用name函數來測試當前節點的名稱是 否為Table,若不是則輸出“本模板只能用於單表”的提示信息。XSLT沒有return 語句,只能按順序執行下去,因此不管XML文檔是否正確還是繼續輸出。
接著輸出 textarea標簽,由於使用Html格式顯示代碼,而這裡使用textarea元素,我們就不用做尖括 號字符轉義了。
這裡有xsl:variable 元素,說明開始定義一個變量,該變量的名稱 是classname,也就是這個C#類的名稱。XSLT變量不是真的變量,應當算是常量,其值是不能 改變的。這裡還用到了concat函數,這是XSLT中字符串連接函數,用於將多個字符串拼湊起 來,這個函數的參數個數不固定,但必須等於或超過2個。函數裡面可以使用XPath路徑來引 用某個XML節點,用單引號來定義固定的字符串。
然後XSLT輸出代碼開頭的一些說明 性的注釋文本,這裡是用了count函數來累計所有的字段個數。接著開始輸出C#代碼了,在輸 出類型定義中使用了xsl:value-of標記來輸出類型名稱,它是用$classname來引用剛才定義 的名為classname的XSLT變量。然後我們輸出靜態屬性TableName返回數據表的名稱。
在輸出FIEldNames屬性時,我們遍歷輸出了字段名稱,這裡有個判斷,若position函數的值 大於1則在字段名稱前輸出一個逗號,position函數用於返回當前處理的節點在整個要處理的 節點列表中的從1開始的序號。若position值大於1,則表示不是輸出第一個字段名稱,由於 這裡是定義一個字符串數組的,因此需要添加逗號。
在這裡我們使用xsl:text來輸出 純文本數據,這裡輸出逗號時可以不需要使用xsl:text元素,可以直接輸出,但使用 xsl:text元素可以改善XSLT代碼的可讀性。而且xsl:text元素可以輸出連續的空白字符。
接著我們輸出myValues 變量和Values屬性,然後又開始遍歷字段輸出各個字段的屬 性代碼了。
首先我們定義了一個名為remark的變量,用於保存字段說明文本。然後輸 出字段屬性的說明性注釋,並判斷PrimaryKey元素值,若該元素值為true則輸出文本“ 關鍵字段”。然後輸出public 屬性數據類型 屬性名稱,這裡是用concat函數來連接屬 性數據類型和字段名稱,中間加了一個空格。
這裡我們使用了xsl:choose結構, xsl:choose類似C#中的swith語句,下面的xsl:when 類似C#的case 語句,而xsl:otherwise 類似C#的default語句。Xsl:choose 可以包含若干個xsl:when,而且最多包含一個 xsl:oterwise元素。每一個xsl:when都可以進行各自的判斷,這點和switch不同,更像連續 的if else ifelse 語句。
在這裡,第一個xsl:when判斷字段類型名稱是否是 System.Byte[],也就是字節數組,若是字節數組則輸出字節數組強制轉化的C#代碼。剩余的 情況使用xsl:otherwise來輸出使用Convert.To函數進行類型轉換的C#代碼。
經過上 述的XSLT轉換處理,我們就能根據描述數據表和字段設計信息的XML文檔來自動生成C#代碼了 。把這個C#代碼復制到C#工程中就可以編譯了。這段代碼內部使用一個哈西表來保存字段的 值,並使用一個個屬性來影射數據庫表的字段。
在程序目錄下存在一些類似的模板, 比如_cshapr.xslt就是生成另外一種的C#代碼的模板,在生成的代碼中不是用哈西列表保存 數據,而是是用一個個變量來保存字段數據。_java.xslt是生成Java代碼的,_VB6.xslt是生 成VB6代碼的。
_Html.xslt
程序目錄下還有其他的代碼生成器模板,例如 _HTML.xslt能生成Html代碼,能是用表格的樣式來展示多個表結構信息。該 模板有個特點就 是既能生成單個表的信息,也能生成整個數據庫中所有表的信息。該模板的XSLT代碼為
<xsl:stylesheet XMLns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output indent='yes' />
<xsl:template match="/*">
<xsl:for-each select="//Table">
<xsl:call-template name="table" />
</xsl:for-each>
</xsl:template>
<xsl:template name="table">
<div>
<span>
<span>數據表 </span>
<b>
<xsl:value-of select="Name" />
</b>
<span> 結構,共 </span>
<xsl:value-of select="count( Fields/FIEld )" />
<span> 個字段 </span>
<xsl:value -of select="concat(' ', Remark)" />
<xsl:if test="count( Fields/FIEld[PrimaryKey='true']) > 0 ">
<span>關鍵字段:</span>
<b>
<xsl:for-each select="Fields/FIEld[PrimaryKey='true']">
<xsl:if test="position()> 1 ">,</xsl:if>
<xsl:value-of select="Name" />
</xsl:for- each>
</b>
</xsl:if>
</span>
<table style="border: black 1 solid"
border="0" width="100%"
rules='all' cellspacing="0"
cellpadding="0" bordercolor="#000000">
<tr bgcolor="#eeee99">
<td width="150">字段名</td>
<td width="80">字段類型</td>
<td width="50">長度</td>
<td width="80">可否為空</td>
<td width="80">是否索引</td>
<td>說 明</td>
</tr>
<xsl:for- each select="Fields/FIEld">
<xsl:sort select="Name" />
<tr valign="top">
<xsl:attribute name="bgcolor">
<xsl:iftest="position() mod 2 = 0">#eeeeee</xsl:if>
</xsl:attribute>
<td>
<font>
<xsl:if test="PrimaryKey='true'">
<xsl:attribute name="color">red</xsl:attribute>
</xsl:if>
<xsl:value-of select="concat(' ' , Name)" />
</font>
</td>
<td>
<xsl:value-of select="FIEldType" />
</td>
<td>
<xsl:value-of select="FIEldWidth" />
</td>
<td>
<xsl:if test="Nullable='true'">是</xsl:if>
</td>
<td>
<xsl:if test="Indexed='true'">是</xsl:if>
</td>
<td>
<xsl:value-of select="Remark" />
<xsl:if test="Description !=''">
<br />
<xsl:value-of select="Description" />
</xsl:if>
</td>
</tr>
</xsl:for-each>
</table>
</div>
<p />
</xsl:template>
< /xsl:stylesheet>