- PR -

XSLTで書き出した属性を使ってHTMLのテーブルを整形する方法?

1
投稿者投稿内容
てんてん
会議室デビュー日: 2007/03/25
投稿数: 2
投稿日時: 2007-03-25 19:28
はじめまして。
こちらで、再帰処理と変数処理の書き込みを見かけましたので、相談させてください

■元データ(table.xml)

<?xml version="1.0" encoding="UTF-8"?>
<Table trows="3" tcols="3">
<Cell crows="1" ccols="1">A1</Cell>
<Cell crows="1" ccols="1">A2</Cell>
<Cell crows="1" ccols="1">A3</Cell>
<Cell crows="1" ccols="2">B1</Cell>
<Cell crows="1" ccols="1">B3</Cell>
<Cell crows="1" ccols="1">C1</Cell>
<Cell crows="1" ccols="2">C2</Cell>
</Table>

■書き出したデータのイメージ(table.html)

<table border="1">
<tr>
<td colspan="1" rowspan="1">A1</td>
<td colspan="1" rowspan="1">A2</td>
<td colspan="1" rowspan="1">A3</td>
</tr>
<tr>
<td colspan="2" rowspan="1">B1</td>
<td colspan="1" rowspan="1">B3</td>
</tr>
<tr>
<td colspan="1" rowspan="1">C1</td>
<td colspan="2" rowspan="1">C2</td>
</tr>
</table>

上のような形にしたくて、いろいろと調べて下記のようなコードを試してみたのですが、colspan属性を考慮していないため、colspan属性が1で無い限り<tr>の位置が不適切な部分に入ってしまいます(当たり前の話なのですが)。

<xsl:template match="Table">
  <xsl:variable name="tyoko" select="@tcols"/>
  <table border="1">
   <xsl:for-each select="Cell[position() mod $tyoko = 1]">
    <tr>
     <xsl:for-each select=". | following-sibling::Cell[position() < $tyoko]">
      <td colspan="{@ccols}" rowspan="{@crows}">
       <xsl:value-of select="normalize-space(.)"/>
      </td>
     </xsl:for-each>
    </tr>
   </xsl:for-each>
  </table>
</xsl:template>

おそらく、<xsl:for-each select="Cell[position() mod $tyoko = 1]">あたりを
colspan属性を加算して、なんとかすればよいのではないか?と考えているのですが。

よい方法があれば、よろしくお願いいたします。

#初歩ゆえ勉強不足な質問ですみません。

[ メッセージ編集済み 編集者: てんてん 編集日時 2007-03-25 19:53 ]

[ メッセージ編集済み 編集者: てんてん 編集日時 2007-03-25 19:55 ]

[ メッセージ編集済み 編集者: てんてん 編集日時 2007-03-25 19:57 ]
ひだちのいろ
会議室デビュー日: 2007/02/14
投稿数: 9
投稿日時: 2007-03-26 00:44
てんてんさんはじめまして。

表現の中身を全部足す「sum()」という関数があるので、それを使うと以下のようにかけます。

=== sample.xsl (全角スペースを半角スペースに置き換えてください) ===
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
 
 <xsl:template match="Table">
  <table>
   <xsl:variable name="max" select="@tcols"/>
   <xsl:for-each select="Cell">
    <xsl:variable name="sum" select="sum(preceding-sibling::Cell/@ccols)"/>
    <xsl:if test="$sum mod $max = 0">
     <tr>
      <xsl:apply-templates select="."/>
      <xsl:for-each select="following-sibling::Cell[sum(preceding-sibling::Cell/@ccols) &lt; $sum+$max]">
       <xsl:apply-templates select="."/>
      </xsl:for-each>
     </tr>
    </xsl:if>
   </xsl:for-each>
  </table>
 </xsl:template>

 <xsl:template match="Cell">
  <td colspan="{@ccols}" rowspan="{@crows}"><xsl:value-of select="."/></td>
 </xsl:template>
 
</xsl:stylesheet>

========================================================

考え方としては、
1、『あるCell要素の前にあるCell要素のccolsの中身』を全部足してみて
2、それがtcolsの倍数になっていればそれは行の先頭に来るCell要素なので
3、同じ行に含まれるCell要素を探して一緒に<tr>の中に入れて出力
となります。
よってccolsの値がずれていたりすると上手く動作しません。

再帰を使うともう少し高速かつccolsの値がずれていてもある程度OKなスクリプトを書けますが、
その分スクリプトが複雑になってしまうので、内容が少なければこんな感じでもいいかと思います。
てんてん
会議室デビュー日: 2007/03/25
投稿数: 2
投稿日時: 2007-03-26 06:54
ひだちのいろさん>

ありがとうございます!
早速、試させていただきます。

--追記です--

ばっちり動きました。大感謝です。
ありがとうございました。

これは、余談になりますが、XMLのソースをみたところccolsが連結されているパターンのほかに、crowsで縦に連結されているものがありました。
教えていただいたコードを応用して解決できないか考えてみます。
(またご相談するかもしれませんが、その時はよろしくお願いします)

[ メッセージ編集済み 編集者: てんてん 編集日時 2007-03-26 18:14 ]
1

スキルアップ/キャリアアップ(JOB@IT)