2009-06-04 15 views
3

にXMLの階層をフラット化する:XSLTは、私はこのようないくつかの階層的なXMLを持っているHTMLテーブル

<node text="a" value="1"> 
    <node text="gga" value="5"> 
    <node text="dh" value="9"> 
     <node text="tyfg" value="4"> 
     </node> 
    </node> 
    </node> 
    <node text="dfhgf" value="7"> 
    <node text="fdsg" value="2"> 
    </node> 
    </node> 
</node> 

要素の名前が同じすべての方法ダウン(「ノード」)、および深さです階層はあらかじめわかっていません - 上記のサンプルでは、​​最も深い葉は4つ下がっていますが、どの深さでも構いません。

私が行う必要があるのは、このXMLをHTMLテーブルにまとめることです。表の列の数は、最も深い要素の深さと、各要素のvalue属性の列に等しくなければなりません。 "値"はテーブルの右端の列に表示されるはずです。そのため、出力行は不揃いなエッジを持つことはできません。どのレベルにあるかにかかわらず、各ノードの行が存在するはずです。上記の例は、次のように変換する必要があります。

<table> 
    <tr> 
    <td>a</td> 
    <td></td> 
    <td></td> 
    <td></td> 
    <td>1</td> 
    </tr> 
    <tr> 
    <td>a</td> 
    <td>gga</td> 
    <td></td> 
    <td></td> 
    <td>5</td> 
    </tr> 
    <tr> 
    <td>a</td> 
    <td>gga</td> 
    <td>dh</td> 
    <td></td> 
    <td>9</td> 
    </tr> 
    <tr> 
    <td>a</td> 
    <td>gga</td> 
    <td>dh</td> 
    <td>tyfg</td> 
    <td>4</td> 
    </tr> 
    <tr> 
    <td>a</td> 
    <td>dfhgf</td> 
    <td></td> 
    <td></td> 
    <td>7</td> 
    </tr> 
    <tr> 
    <td>a</td> 
    <td>dfhgf</td> 
    <td>fdsg</td> 
    <td></td> 
    <td>2</td> 
    </tr> 
</table> 

これを達成できる賢いXSLTを手に入れた人はいますか?

+0

あなたがしようとしているように見えます構造を可視化し、親の鎖を繰り返す各列のements。あなたは本当にそれをテーブルにする必要がありますか?結果は私にとっては実際の表形式のデータのようには見えません。 – Rytmis

+0

はい、目的は構造を視覚化することです。テーブルは私にとっては最高の選択のように思えましたが、私の心は別の提案に向かっています。あなたが言うように、私が本当に必要とするのは、各行の要素の連鎖です。 – Matt

答えて

3

それはあなたが必要とするかなりのものではないのです(それはギザギザのテーブルを離れたので)それはまだHTMLに

<xsl:template match="/"> 
    <html> 
     <head> 
     </head> 
     <body> 
      <table> 
       <xsl:apply-templates select="//node" mode="row" /> 
      </table> 
     </body> 
    </html> 
</xsl:template> 

<xsl:template match="node" mode="row"> 
    <tr> 
     <xsl:apply-templates select="ancestor-or-self::node" mode="popcell"/> 
     <xsl:apply-templates select="node[1]" mode="emptycell"/> 
    </tr> 
</xsl:template> 

<xsl:template match="node" mode="popcell"> 
    <td><xsl:value-of select="@text"/></td> 
</xsl:template> 

<xsl:template match="node" mode="emptycell"> 
    <td></td> 
    <xsl:apply-templates select="node[1]" mode="emptycell"/> 
</xsl:template> 

をうまくいくバージョン2:まあ、私はそれで自己満足してかなり少ないですよ:P、ただし、次のようにギザギザは削除されます:

<xsl:variable name="depth"> 
    <xsl:for-each select="//node"> 
     <xsl:sort select="count(ancestor::node)" data-type="number" order="descending"/> 
     <xsl:if test="position()=1"> 
      <xsl:value-of select="count(ancestor::node)+1"/> 
     </xsl:if> 
    </xsl:for-each> 
</xsl:variable> 

<xsl:template match="/"> 
    <html> 
     <head> 
     </head> 
     <body> 
      <table> 
       <xsl:apply-templates select="//node" mode="row" /> 
      </table> 
     </body> 
    </html> 
</xsl:template> 

<xsl:template match="node" mode="row"> 
    <tr> 
     <xsl:apply-templates select="ancestor-or-self::node" mode="popcell"/> 
     <xsl:call-template name="emptycells"> 
      <xsl:with-param name="n" select="($depth)-count(ancestor-or-self::node)"/> 
     </xsl:call-template> 
     <td><xsl:value-of select="@value"/></td> 
    </tr> 
</xsl:template> 

<xsl:template match="node" mode="popcell"> 
    <td><xsl:value-of select="@text"/></td> 
</xsl:template> 

<xsl:template name="emptycells"> 
    <xsl:param name="n" /> 
    <xsl:if test="$n &gt; 0"> 
     <td></td> 
     <xsl:call-template name="emptycells"> 
      <xsl:with-param name="n" select="($n)-1"/> 
     </xsl:call-template> 
    </xsl:if> 
</xsl:template> 
+0

+1これはすばらしいxsltです:) –

+0

ありがとう。時々、XSLTの優雅さは本当に驚くべきものです。 – annakata

+0

こんにちはannakata、ありがとう!残念ながら、ギザギザのテーブルは問題です。質問の私の最初の草案で、私は自分の問題を単純化しました。私は今修正したので、エッジがギザギザにならない理由は明らかです。 – Matt

0

このXSLT 1.0の解決方法があります。

  • 何の再帰が

XSLTコードを使用しない整形式HTMLテーブルを生成します。出力

<xsl:stylesheet 
    version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
> 

    <xsl:output method="xml" indent="yes" omit-xml-declaration="yes" /> 

    <!-- some preparation --> 
    <xsl:variable name="vAllNodes" select="//node" /> 

    <!-- find out the deepest nested node --> 
    <xsl:variable name="vMaxDepth"> 
    <xsl:for-each select="$vAllNodes"> 
     <xsl:sort 
     select="count(ancestor::node)" 
     data-type="number" 
     order="descending" 
     /> 
     <xsl:if test="position() = 1"> 
     <xsl:value-of select="count(ancestor-or-self::node)" /> 
     </xsl:if> 
    </xsl:for-each> 
    </xsl:variable> 

    <!-- select a list of nodes, merely to iterate over them --> 
    <xsl:variable name="vIteratorList" select=" 
    $vAllNodes[position() &lt;= $vMaxDepth] 
    " /> 

    <!-- build the table --> 
    <xsl:template match="/"> 
    <table> 
     <!-- the rows will be in document order --> 
     <xsl:apply-templates select="$vAllNodes" /> 
    </table> 
    </xsl:template> 

    <!-- build the rows --> 
    <xsl:template match="node"> 
    <xsl:variable name="self" select="." /> 
    <tr> 
     <!-- iteration instead of recursion --> 
     <xsl:for-each select="$vIteratorList"> 
     <xsl:variable name="vPos" select="position()" /> 
     <td> 
      <!-- the ancestor axis is indexed the other way around --> 
      <xsl:value-of select=" 
      $self/ancestor-or-self::node[last() - $vPos + 1]/@text 
      " /> 
     </td> 
     </xsl:for-each> 
     <td> 
     <xsl:value-of select="@value" /> 
     </td> 
    </tr> 
    </xsl:template> 

</xsl:stylesheet> 

を:

<table> 
    <tr> 
    <td>a</td> 
    <td></td> 
    <td></td> 
    <td></td> 
    <td>1</td> 
    </tr> 
    <tr> 
    <td>a</td> 
    <td>gga</td> 
    <td></td> 
    <td></td> 
    <td>5</td> 
    </tr> 
    <tr> 
    <td>a</td> 
    <td>gga</td> 
    <td>dh</td> 
    <td></td> 
    <td>9</td> 
    </tr> 
    <tr> 
    <td>a</td> 
    <td>gga</td> 
    <td>dh</td> 
    <td>tyfg</td> 
    <td>4</td> 
    </tr> 
    <tr> 
    <td>a</td> 
    <td>dfhgf</td> 
    <td></td> 
    <td></td> 
    <td>7</td> 
    </tr> 
    <tr> 
    <td>a</td> 
    <td>dfhgf</td> 
    <td>fdsg</td> 
    <td></td> 
    <td>2</td> 
    </tr> 
</table> 
+0

このTomalakのおかげで、とてもうまく動作します。私は私が欲しかった出力を得るために1つの小さな変更を加えた - ます。に変更 : ます。 それ以外の場合、行のテキストセルは逆順になります(つまり、リーフノードのテキストが一番左の列にあります)。 – Matt

+0

実際には、起こっている。$ vNodesは先祖の軸から作成されます。つまり、$ vNodes [1]はリーフでなければなりません。どのXSLTプロセッサを使用していますか? – Tomalak

+0

Visual Studio 2008 – Matt

関連する問題