自分用メモ – C# T4 Text Template Transformation Toolkit
- keyword
- T4
- reflection
- サンプルコード
T4嵌り
- else を使う時は <#} else { #> と記述しないといけない
- <#+ #>で関数やクラスを定義する場合は独立したファイルに記述し、それを使用する時は <#@ include file=”Common.tt” #> でインクルードしないといけない。
- <#@ include file=”Common.tt” #> を記述する度に改行が追加される。
下記の様に空のコントロールブロックを追加すると何故か回避される。
<#@ include file=”Common.tt” #><##>
CRLFになっていない場合も発生する場合もあるらしい。
参考:stackoverflow - コメントを入れる <# // コメント #>
基本
- テンプレートのメタ定義
- 使用する言語の定義
- 出力ファイル拡張子
- 参照アセンブリ
- インポート宣言
- 文中への直接コード埋め込み
<#= “Hello” #> - インデントを入れる
PushIndent, PopIndent, ClearIndent - 繰り返し構文
public class Hello { <# foreach(int idx in Enumerable.Range(0, 3)) { #> ああああ <# } #> }
出力
public class Hello { ああああ ああああ ああああ }
- C++ コード生成サンプル
- Visual Studio のプロジェクト
- C# プロジェクトを作る。C++ プロジェクトでは .tt は扱えない
何を自動生成するべきか
- 欲しい物
- デスクリプタ
- DDONE 構造体定義
- 構造体名
- デスクリプタ名
- メンバ変数名
- パラメータ名を変数名
- ビット幅をビットセットで表す
- reserved で reserved を挿入
- 構造体名
- セッター・ゲッター・ダンパー
- メンバ変数名
- 引数の型をどう定義するか?
- スクレープ時に _count で int にするとか?
- struct の xml だけ手で書く
この時 enum 名を自分で書く - enum 生成だけ html テーブルを指定して列挙子を xml 化する
- html になっている時点で xml 化する必要が無い気はする。
- 同じ DOM 構造に落とし込めるのでその後の T4 テンプレートが作りやすくなる。
- DONE セッター・ゲッターのアサート
- ポインタならヌルチェックを挟むだけ
- その他の不正な値を取得する必要がある
- ⇒ もうこれはやらなくてもいいのでは?
- DDONE 構造体定義
- enum
- どうやってスクレイピングするか?
- デスクリプタの変数名から判定できるか?
多分難しい。
- デスクリプタの変数名から判定できるか?
- どうやってスクレイピングするか?
- デスクリプタ
- 自動生成して活用できる事
- C#向けにもコード生成ができる
- この位かな…。
- C# のデータ型
http://www.kumei.ne.jp/c_lang/cs/cs_05.htm
xml から enum を自動生成する
Enum.xml
<?xml version="1.0" encoding="utf-8" ?> <EnumType Name="Mode" UnderlyingType="Int16"> <Enumerator Name="ModeA" Value="0"/> <Enumerator Name="ModeB" Value="1"/> <Enumerator Name="ModeC" Value="2"/> </EnumType>
Enum.tt
<#@ template debug="false" hostspecific="false" language="C#" #> <#@ assembly name="System.Core" #> <#@ assembly name="System.Xml.dll" #> <#@ import namespace="System.IO" #> <#@ import namespace="System.Xml" #> <#@ import namespace="System.Linq" #> <#@ import namespace="System.Text" #> <#@ import namespace="System.Collections.Generic" #> <#@ output extension=".h" #> <# XmlDocument doc = new XmlDocument(); string absolutePath = @"D:\prj\zikken\t4\c++_class_simple\TextTemplate\TextTemplateModel\Enum.xml"; doc.Load(absolutePath); var rootNodes = doc.SelectNodes("/EnumType"); #> enum class <#=rootNodes[0].Attributes["Name"].InnerText #> { <# foreach (XmlNode node in doc.SelectNodes("/EnumType/Enumerator")){ #> <#=node.Attributes["Name"].InnerText #> = <#=node.Attributes["Value"].InnerText #> <# } #> };
Enum.h
enum class Mode { ModeA = 0 ModeB = 1 ModeC = 2 };
html のテーブルから enum を生成する
html の任意箇所の xpath を取得する。FireFox の場合
要素の検証 -> 取得したいタグを右クリック -> コピー -> xpath
/html/body/p[11]/table
/html/body/p[11]/table/tbody/tr[2]/td[4]
/html/body/p[11]/table/tbody/tr[3]/td[1]
※html のテーブルの要素のインデックスは 1 から始まる点に注意。
メモ
- html を xml として読み込まそうとするとタグの開始・終了が合わない等のエラーが出る事がある
- sjis の場合は XmlDocument で読み込めない。読み込み時にエラーが発生する。
- xhtml が元からあれば直接読み込める
- xml があればラッキー
XmlDocument によるアクセス
TODO: 全然まとまっていない。
- 要素下記で hoge が要素名、foo が値
<hoge>foo</hoge>
XElement::Element(hoge).Value で “foo” が取得される。 - XElement はどうやって取得するか?
-
XDocument xDoc = XDocument.Load(new XmlNodeReader(xmlDoc));
- XElement は XDocument からの要素アクセスに使われる。
-
取り敢えずこれ使え
XDocument を使う
参考:
html
<html> <body> <h3>Answer</h3> <div class="right"> <table> <tbody><tr class="headings"><th colspan="4">Types</th></tr> <tr><td><b>Type</b></td><td><b>Size</b></td><td><b>Range</b></td><td><b>Accuracy</b></td></tr> <tr><td>float</td><td>32 bits</td><td>3:0</td><td>comment1</td></tr> <tr><td>double</td><td>64 bits</td><td>7:4</td><td>comment2</td></tr> </tbody></table> </div> </body></html>
ソース
class ParseHtml { public void Parse() { var path = @"D:\prj\zikken\t4\c++_class_simple\TextTemplate\TextTemplateModel\Size_of_Floats.html"; var query = "/html/body/div/table/tbody"; //" / html/body/h3"; #if false // TODO: XElement だと読めない var xelm = XElement.Load(path); var dbElement = xelm.XPathSelectElement(query); #else var doc = XDocument.Load(path); // 要素指定アクセス var dbElement = doc.XPathSelectElement(query); #endif Console.WriteLine(dbElement.Value + "\n"); // テーブルダンプ IEnumerable<XElement> trs = dbElement.Elements("tr"); foreach (XElement tr in trs) { IEnumerable<XElement> tds = tr.Elements("td"); foreach (XElement td in tds) { if (td == null) continue; Console.WriteLine(td.Value + "\t"); } } } }
コメントを残す