質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
XSLT

XSLTは、組み立てられた文書を(XML、HTML、そしてプレーンテキストのような)別のフォーマットに変化する為にデザインされたXMLの為の変換用言語です。

Q&A

2回答

3875閲覧

XSLによるrowspanの変換処理について

syes

総合スコア10

XSLT

XSLTは、組み立てられた文書を(XML、HTML、そしてプレーンテキストのような)別のフォーマットに変化する為にデザインされたXMLの為の変換用言語です。

0グッド

0クリップ

投稿2016/06/15 02:53

編集2022/01/12 10:55

###発生している問題
XSLを作成し、XMLファイルをブラウザ表示する中で、
tableの「rowspan」に正しく対応したXSLを作成できず、困っております。

課題となっているポイントとしては、
インプットとなるXMLは、既定のフォーマットとして、
「rowspan」が指定された行の、次の行(以降)に本来不要となる列データ(<td>)が
常時空データの列として入っているため、単純に変換した場合、
テーブルがズレて表示されてしまいます。

そのため、XSLの中で「rowspan」に関連する不要な列を「colspan」の指定状況も踏まえ判断し、
削除する(出力しない)制御を記載することが必要と考えているのですが、
その記載方法がわからない状況です。
※なお、空要素列を全て削除する(出力対象外とする)処理は、
実データ上、出力が必要な列も存在するためできないです。

ご教示の程、何卒よろしくお願いいたします。

###該当のXSLおよびXML
以下に現状のXSLファイル内容(table制御関連部分)と、
インプットとなるXMLのサンプルを記載させていただきます。

■XSL <xsl:template match="tbl"> <table border="1" width="100%" cellpadding="0" style="font:10pt"> <xsl:apply-templates /> </table> </xsl:template> <xsl:template match="row"> <tr> <xsl:apply-templates /> </tr> </xsl:template> <xsl:template match="cell"> <td> <xsl:apply-templates select="@rowspan" /> <xsl:apply-templates select="@width" /> <xsl:apply-templates select="@colspan" /> <xsl:apply-templates /> </td> </xsl:template> <xsl:template match="@width"> <xsl:variable name="tblwidth"> <xsl:value-of select="." />*100<xsl:text>%</xsl:text> </xsl:variable> <xsl:attribute name="width"><xsl:value-of select="$tblwidth"/></xsl:attribute> </xsl:template> <xsl:template match="@rowspan"> <xsl:attribute name="rowspan"><xsl:value-of select="."/></xsl:attribute> </xsl:template> <xsl:template match="@colspan"> <xsl:attribute name="colspan"><xsl:value-of select="."/></xsl:attribute> </xsl:template> <xsl:template match="br"> <br /> </xsl:template> <xsl:template match="text()"> <xsl:value-of select="."/> </xsl:template>
■XML <tbl> <row> <cell colspan="3" width=".447">AAA</cell> <cell width=".138">1mg</cell> <cell width=".138">2mg</cell> <cell width=".138">4mg</cell> <cell width=".139">6mg</cell> </row> <row> <cell colspan="3" width=".447">BBB</cell> <cell width=".138">0.3mg/日</cell> <cell width=".138">0.6mg/日</cell> <cell width=".138">1.2mg/日</cell> <cell width=".139">1.8mg/日</cell> </row> <row> <cell rowspan="5" width=".149">CCC</cell> <cell rowspan="3" width=".149">DDD</cell> <cell width=".149">EEE</cell> <cell width=".138">≦29</cell> <cell width=".138">30~89</cell> <cell width=".138">90~149</cell> <cell width=".139">150~209</cell> </row> <row> <cell width=".149"></cell> <cell width=".149"></cell> <cell width=".149"></cell> <cell width=".138">≦10</cell> <cell width=".138">20~40</cell> <cell width=".138">50~70</cell> <cell width=".139">80~100</cell> </row> <row> <cell width=".149"></cell> <cell width=".149"></cell> <cell width=".149">GGG</cell> <cell width=".138">≦9</cell> <cell width=".138">10~29</cell> <cell width=".138">30~49</cell> <cell width=".139">50~69</cell> </row> <row> <cell width=".149"></cell> <cell colspan="2" width=".298">HHH</cell> <cell width=".138">≦19</cell> <cell width=".138">20~59</cell> <cell width=".138">60~99</cell> <cell width=".139">100~139</cell> </row> <row> <cell width=".149"></cell> <cell colspan="2" width=".298">III</cell> <cell width=".138">2.1</cell> <cell width=".138">4.2</cell> <cell width=".138">8.4</cell> <cell width=".139">12.6</cell> </row> </tbl>

###現状の変換結果および不要列の注記

■現状の変換結果および不要列の注記 <table border="1" width="100%" cellpadding="0" style="font:10pt"> <tr> <td width=".447*100%" colspan="3" >AAA</td> <td width=".138*100%">1mg</td> <td width=".138*100%">2mg</td> <td width=".138*100%">4mg</td> <td width=".139*100%">6mg</td> </tr> <tr> <td width=".447*100%" colspan="3" >BBB</td> <td width=".138*100%">0.3mg/日</td> <td width=".138*100%">0.6mg/日</td> <td width=".138*100%">1.2mg/日</td> <td width=".139*100%">1.8mg/日</td> </tr> <tr> <td rowspan="5" width=".149*100%">CCC</td> <td rowspan="3" width=".149*100%">DDD</td> <td width=".149*100%">EEE</td> <td width=".138*100%">≦29</td> <td width=".138*100%">30~89</td> <td width=".138*100%">90~149</td> <td width=".139*100%">150~209</td> </tr> <tr> <td width=".149*100%"></td> ←不要 <td width=".149*100%"></td> ←不要 <td width=".149*100%"></td> <td width=".138*100%">≦10</td> <td width=".138*100%">20~40</td> <td width=".138*100%">50~70</td> <td width=".139*100%">80~100</td> </tr> <tr> <td width=".149*100%"></td> ←不要 <td width=".149*100%"></td> ←不要 <td width=".149*100%">GGG</td> <td width=".138*100%">≦9</td> <td width=".138*100%">10~29</td> <td width=".138*100%">30~49</td> <td width=".139*100%">50~69</td> </tr> <tr> <td width=".149*100%"></td> ←不要 <td width=".298*100%" colspan="2" >HHH</td> <td width=".138*100%">≦19</td> <td width=".138*100%">20~59</td> <td width=".138*100%">60~99</td> <td width=".139*100%">100~139</td> </tr> <tr> <td width=".149*100%"></td> ←不要 <td width=".298*100%" colspan="2" >III</td> <td width=".138*100%">2.1</td> <td width=".138*100%">4.2</td> <td width=".138*100%">8.4</td> <td width=".139*100%">12.6</td> </tr> /table>

###補足情報(言語/FW/ツール等のバージョンなど)
対象ブラウザはIEのみ

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tmakita

2016/09/23 08:54

XSLTプロセッサは何をお使いでしょうか?(MSXML,Saxon?など) XSLT 1.0なら大変ですが、XSLT 2.0が使えればまだ方策はあるように思えます.(それともこの問題自身がすでに解決済みでしょうか?)
guest

回答2

0

4年前の質問ですが閲覧数が多いので…

あえてfor-eachを使わずに書いてみました。

ロジック

以下のようにしています。
0. 自分と同じ列で、自分より前の行に@rowspanがあれば
0. 自分と1の行(複数ある場合は近い方)との間隔を取得
0. 2の間隔と1の@rowspanとの値を比較。@rowspanよりも間隔が大きければtdを出力

実行環境

xsltは2.0です。
ブラウザでの確認はしていませが、サンプルをsaxonHE9.9.1.5で変換し、期待する結果になることを確認しています。

コード

cellにマッチするテンプレート内での変数がかなめです。
変数では型宣言をしています。
いくつか記述を簡素化した箇所があります。

xslt

1<?xml version="1.0" encoding="UTF-8"?> 2<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 3 xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="2.0"> 4 <xsl:output method="xhtml" indent="yes"/> 5 <xsl:strip-space elements="*"/> 6 <xsl:template match="tbl"> 7 <table border="1" width="100%" cellpadding="0" style="font:10pt"> 8 <xsl:apply-templates/> 9 </table> 10 </xsl:template> 11 <xsl:template match="row"> 12 <tr> 13 <xsl:apply-templates/> 14 </tr> 15 </xsl:template> 16 <xsl:template match="cell"> 17 <!--表内での自行の位置。整数--> 18 <xsl:variable name="varParentRowPos" select="count(parent::row/preceding-sibling::row) + 1" 19 as="xs:integer"/> 20 <!--自行内での自列の位置。整数--> 21 <xsl:variable name="varMyColumnPos" select="count(preceding-sibling::cell) + 1" 22 as="xs:integer"/> 23 <!--表内での、自列に@rowspanを持つ直前の行の位置。整数だが該当するものがなければ値なし--> 24 <xsl:variable name="varRowspanRowPos" as="xs:integer?" 25 select="parent::row/preceding-sibling::row[cell[$varMyColumnPos][@rowspan]][1]/count(preceding-sibling::row) + 1"/> 26 <!--表内での、直前の行で自列にある@rowspanの値。整数だが該当するものがなければ値なし--> 27 <xsl:variable name="varRowspanValue" as="xs:integer?" 28 select="ancestor::tbl/row[$varRowspanRowPos]/cell[$varMyColumnPos]/@rowspan"/> 29 <!--自列に@rowspanをもつ行と次行との距離。整数だが$varRowspanRowPosの値がなければこれも値なし--> 30 <xsl:variable name="varDistance" select="$varParentRowPos - $varRowspanRowPos" 31 as="xs:integer?"/> 32 <!--上記@rowspanの値よりも、@rowspanをもつ行と次行との距離が大きければtdを出力--> 33 <xsl:message select="$varRowspanRowPos &lt;= $varDistance"/> 34 <xsl:if test="not($varRowspanValue &gt; $varDistance)"> 35 <td> 36 <xsl:apply-templates select="@* | child::node()"/> 37 </td> 38 </xsl:if> 39 </xsl:template> 40 <xsl:template match="@width"> 41 <xsl:variable name="tblwidth"> 42 <xsl:value-of select="."/>*100<xsl:text>%</xsl:text> 43 </xsl:variable> 44 <xsl:attribute name="width"> 45 <xsl:value-of select="$tblwidth"/> 46 </xsl:attribute> 47 </xsl:template> 48 <xsl:template match="@rowspan | @colspan"> 49 <xsl:sequence select="."/> 50 </xsl:template> 51</xsl:stylesheet>

なお、tdを出力する箇所で、以下上段のような記述をしています。
素直に下段のように記述しない理由は、$varDistanceが値を持たない場合に、演算がなりたたずfalse()を返すためです。

xslt

1not($varRowspanValue &gt; $varDistance) 2 3$varRowspanValue &lt;= $varDistance

投稿2020/08/16 03:54

quwano

総合スコア6

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

とりあえずIE11で動作確認済みです。

XSLT

1<xsl:template match="cell"> 2 <xsl:if test=".!=''"> 3 <td> 4 <xsl:apply-templates select="@rowspan" /> 5 <xsl:apply-templates select="@width" /> 6 <xsl:apply-templates select="@colspan" /> 7 <xsl:apply-templates /> 8 </td> 9 </xsl:if> 10</xsl:template>

【[XSLT] 空要素の判定 : してログ - LANDHERE】
http://landhere.jp/blog/a37.html

投稿2016/06/15 05:03

kei344

総合スコア69364

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

syes

2016/06/15 07:12 編集

早速のご回答まことにありがとうございます。 ただ、前提条件やサンプルデータに明確に記載しておらず大変恐縮ですが、空要素でも出力が必要な列(cell)も規定フォーマット上存在しているため、空要素全てを除外する処理では対処できないフォーマットになっております。 除外条件としては、「rowspanがこれまでの行(上位行)で指定されているため不要」、かつ、「空要素」となる必要があり、それをロジック化したいと考えております。 お手数をおかけして恐縮ですが、 上記条件での処理内容をご教示いただけませんでしょうか? 何卒よろしくお願い申し上げます。
syes

2016/06/15 05:45

早速のご回答ありがとうございます。 やはり複雑ですよね、ご助言ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問