自分用メモ – 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 - 繰り返し構文
123456public class Hello{<# foreach(int idx in Enumerable.Range(0, 3)) { #>ああああ<# } #>}
出力
123456public 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
1 2 3 4 5 6 |
<?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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<#@ 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
1 2 3 4 5 6 |
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 はどうやって取得するか?
-
1<span class="typ">XDocument</span><span class="pln"> xDoc </span><span class="pun">=</span> <span class="typ">XDocument</span><span class="pun">.</span><span class="typ">Load</span><span class="pun">(</span><span class="kwd">new</span> <span class="typ">XmlNodeReader</span><span class="pun">(</span><span class="pln">xmlDoc</span><span class="pun">));</span>
- XElement は XDocument からの要素アクセスに使われる。
-
取り敢えずこれ使え
XDocument を使う
参考:
html
1 2 3 4 5 6 7 8 9 10 11 12 |
<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> |
ソース
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
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"); } } } } |
コメントを残す