http://bbs.wankuma.com/index.cgi?mode=al2&namber=575ネタ元は上記のわんくま BBS です。
DataTable の行と列を入れ替えるのをわざわざ XSLT を利用してやってやろうという試み。
DataTable::WriteXml で出力した XML に XSLT をかませて変換し、変換後の XML を食わせて DataTable を作ってやる。
ちなみに、DataTable に名前が設定してなければ WriteXml ができないのでご注意。
なので、DataTable ではなく DataSet (Tables[0] に 対象の DataTable を持つ)を対象とする。
DataSet::WriteXml と DataTable::WriteXml で出力される XML に大きな違いはない。
(Tables.Count == 1 であれば)ルート要素の要素名が DataSet の名前になるか、DocumentElement 固定になるかの違いだけである。
DataTable より DataSet を使ったほうがいい理由は、XmlDataDocument が利用しやすいからである。
XmlDataDocument は作成時に DataSet を引数に取れる。
また XmlDataDocument は XmlDocument を継承しており、IXPathNavigatable を実装しているので XSLT 変換が容易にできる。
前置きはここまでにして、使用する XSLT は以下のものである。
<?xml version="1.0" encoding="utf-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:apply-templates mode="root"/>
</xsl:template>
<xsl:template match="*" mode="root">
<NewDataSet>
<xsl:apply-templates mode="controlRowRender"/>
</NewDataSet>
</xsl:template>
<xsl:template match="*" mode="controlRowRender">
<xsl:if test="position() = 1">
<xsl:apply-templates mode="renderRow"/>
</xsl:if>
</xsl:template>
<xsl:template match="*" mode="renderRow">
<xsl:variable name="name" select="name(.)"/>
<NewDataTable>
<xsl:for-each select="../..//*[name(.) = $name]">
<xsl:element name="{concat('col', position())}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:for-each>
</NewDataTable>
</xsl:template>
</xsl:stylesheet>
列名もテーブル名も全くもってわからないので、このように汎用的にする必要がある。
逆に言えば、どんな DataTable もこの XSLT 一つで行と列を入れ替えることができる。
ポイントは、match を * にしておいて、mode 指定によって切り替えるということ。
要素名はわからないけれども、構成・階層が固定になるから使えるテクニックだ。
で、この XSLT で変換した結果の XML を DataSet に食わせて、Tables[0] を取得すれば、行と列が入れ替わった DataTable が取得できる。
はっきり言ってこんなものを使ってまで、行と列を入れ替える必要がない。
簡単な二重ループで事足りる。
しかしこれは、少し変えれば限定状況ながらも有効に利用できる。
もともとの用途では、GridView にバインドすることが想定されていた。
ここで、バインド後に GridView 固有の機能(イベントやら何やら)を使用しないという状況を考える。
そんな場合、Xml コントロールを使用し、先述した XmlDataDocument を使用し、下記のような XSLT を使用する。
要素名をテーブルに対応させただけのものである。
<?xml version="1.0" encoding="utf-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:apply-templates mode="root"/>
</xsl:template>
<xsl:template match="*" mode="root">
<table border="0" cellpadding="0" cellspacing="1">
<xsl:apply-templates mode="controlRowRender"/>
</table>
</xsl:template>
<xsl:template match="*" mode="controlRowRender">
<xsl:if test="position() = 1">
<xsl:apply-templates mode="renderRow"/>
</xsl:if>
</xsl:template>
<xsl:template match="*" mode="renderRow">
<xsl:variable name="name" select="name(.)"/>
<tr>
<xsl:for-each select="../..//*[name(.) = $name]">
<td>
<xsl:value-of select="."/>
</td>
</xsl:for-each>
</tr>
</xsl:template>
</xsl:stylesheet>
すると、DataTable には何の操作も行わずに、行と列を入れ替えたテーブルを表示することができる。
「表示だけ」という限定された状況なれど、利用する価値はあるのではなかろうか。