Quantcast
Channel: 黑暗執行緒
Viewing all articles
Browse latest Browse all 2447

CODE-利用T4依XML產生多個資料物件

$
0
0

遇到的需求是有現成的XML資料定義檔如下

<?xmlversion="1.0"encoding="utf-8" ?>
<datatable>
<tableid="Running"version="1.0">
<colname="RunDateTime"datatype="System.DateTime"pkey="Y"/>
<colname="RunnerId"datatype="System.String"pkey="Y"/>
<colname="Record"datatype="System.String"/>
</table>
<tableid="Runner"version="1.0">
<colname="RunnerId"datatype="System.String"pkey="Y"/>
<colname="Name"datatype="System.String"/>
<colname="Birthday"datatype="System.DateTime"/>
</table>
</datatable>

希望為其中每個Table各產生一個C#類別轡下:

using System.ComponentModel.DataAnnotations;
 
publicclass Runner
{
    [Key]
public System.String RunnerId { get; set; }
public System.String Name { get; set; }
public System.DateTime Birthday { get; set; }
}

在過去,我會自己寫Code,解析XML文件再用StringBuilder組裝C#類別的內容。但既然已經學會T4範本程式產生器這等好物,自然沒有再走回頭路的道理。

由XML產生C#類別的邏輯很簡單,唯一的小挑戰是一般T4範例多是一個.tt檔產生一個.cs檔,而這個需求得依照XML定義一次產生多個.cs檔案。爬文找到範例,單一.tt要輸出多個檔案的原理,是在執行過程由GenerationEnvironment.ToString()取得當時累積的輸出結果,以File.WriteAllText()寫入檔案後,執行GenerationEnvironment.Clear()清掉已寫到檔案的內容,再執行下個類別的程式碼產生邏輯。

T4程式碼如下:

<#@ template  debug="true" hostSpecific="true" #>
<#@ output extension=".log" #>
<#@ Assembly Name="System.Core.dll" #>
<#@ Assembly Name="System.Windows.Forms.dll" #>
<#@ Assembly Name="System.Xml.dll" #>
<#@ Assembly Name="System.Xml.Linq.dll" #>
<#@ import namespace="System" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Diagnostics" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Xml" #>
<#@ import namespace="System.Xml.Linq" #>
<#@ import namespace="System.Collections" #>
<#@ import namespace="System.Collections.Generic" #> 
<#
string currPath = Path.GetDirectoryName(Host.TemplateFile);
    XDocument xd = XDocument.Load(Path.Combine(currPath, "marathon.xml"));
foreach (var t in xd.Root.Elements()) {
string tableName = t.Attribute("id").Value;
#>
using System.ComponentModel.DataAnnotations;
 
publicclass<#= tableName #>
{
<#
foreach (var c in t.Elements()) {
string name = c.Attribute("name").Value;
string type = c.Attribute("datatype").Value;
bool isPK = c.Attribute("pkey") != null;
if (isPK) {
#>
    [Key]
<#
            }
#>
public<#= type #> <#= name #> { get; set; }
<#
        }
#>
}
<#
string relativeOutputFilePath = "Code\\" + tableName + ".cs";
string outputFilePath = Path.Combine(currPath, relativeOutputFilePath);
        TemplateHelper.WriteTemplateOutputToFile(outputFilePath, GenerationEnvironment);
    }
#>
<#+
//REF: http://bit.ly/X9wTu0
publicclass TemplateHelper
{
publicstaticvoid WriteTemplateOutputToFile(
string outputFilePath,
        System.Text.StringBuilder genEnvironment)
    {
        System.IO.File.WriteAllText(outputFilePath, genEnvironment.ToString());
        genEnvironment.Clear();
 
    }
}
#>

補充幾點:

  1. 預設T4並未參照System.Xml.dll及System.Xml.Linq.dll,記得要在最前方透過<#@ Assembly #>及<#@ import #>加入參照。
  2. 透過Host.TemplateFile可取得T4檔案所在實體路徑,可用來決定輸出檔案路徑。
  3. T4檔末端透過<#+ #>宣告了共用函數TemplateHelper.WriteTemplateOutputToFile(),透過其將產生結果寫入檔案。

Viewing all articles
Browse latest Browse all 2447

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>