---------------------------------------------------
<?xml version="1.0" ?>
<document>
<id>a</id>
<text>あああ</text>
<id>b</id>
<text>いいい</text>
<id>c</id>
<text>ううう</text>
<id>d</id>
<id>e</id>
<text>えええ</text>
<id>f</id>
<text>おおお</text>
</document>
---------------------------------------------------
このXMLから下記のようなidとtextを併記したHTMLを生成するXSLを作りたいと思います。
---------------------------------------------------
<HTML>
<BODY>
<TABLE border="1">
<TR>
<TD>a:あああ</TD>
<TD>b:いいい</TD>
</TR>
<TR>
<TD>c:ううう</TD>
<TD>e:えええ</TD>
</TR>
<TR>
<TD>f:おおお</TD>
<TD> </TD>
</TR>
</TABLE>
</BODY>
</HTML>
---------------------------------------------------
条件、
・idの総数は未知です。
・id"d"のように、<text>要素がない場合はセル自体をつめて表示します。もちろんidも表示しません。
・表示すべき要素が奇数個であった場合は、最後に空白セルを追加します。
皆さんのお知恵を貸していただければうれしいです。
力技で変換してみました。IE7で動作確認。
<?xml version="1.0" encoding="Shift_JIS"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="html" encoding="shift_jis" indent="yes"/> <!-- ID群変数 --> <xsl:variable name="ids" select="//id[name(./following-sibling::*[position()=1]) = 'text']"/> <!-- ルート --> <xsl:template match="/document"> <html> <body> <table border="1"> <xsl:if test="count($ids) > 0"> <xsl:call-template name="list"> <xsl:with-param name="no">1</xsl:with-param> <xsl:with-param name="count" select="count($ids)"/> </xsl:call-template> </xsl:if> </table> </body> </html> </xsl:template> <!-- リスト --> <xsl:template name="list"> <xsl:param name="no"/> <xsl:param name="count"/> <xsl:variable name="id1" select="$ids[position() = $no]"/> <xsl:variable name="id2" select="$ids[position() = $no + 1]"/> <tr> <xsl:call-template name="item"> <xsl:with-param name="id" select="$id1"/> <xsl:with-param name="text" select="$id1/following-sibling::*[position()=1]"/> </xsl:call-template> <xsl:choose> <xsl:when test="$no < $count"> <xsl:call-template name="item"> <xsl:with-param name="id" select="$id2"/> <xsl:with-param name="text" select="$id2/following-sibling::*[position()=1]"/> </xsl:call-template> </xsl:when> <xsl:otherwise> <!-- 対象IDなし --> <td> </td> </xsl:otherwise> </xsl:choose> </tr> <xsl:if test="$no + 1 < $count"> <xsl:call-template name="list"> <xsl:with-param name="no" select="$no + 2"/> <xsl:with-param name="count" select="$count"/> </xsl:call-template> </xsl:if> </xsl:template> <!-- TD内容 --> <xsl:template name="item"> <xsl:param name="id"/> <xsl:param name="text"/> <td> <xsl:value-of select="$id"/> <xsl:text>:</xsl:text> <xsl:value-of select="$text"/> </td> </xsl:template> </xsl:stylesheet>
tokuya_n さんのおっしゃる通り、XMLの構造がやりたいことにかなっていないと思われます。
XMLは、各タグの書かれている順番や位置、数などを気にせずに記述できる半構造データというツリー構造を持っています。
現在のデータ構造はイメージとしては
<document>
|
------------- ~ ----------------------- ~
| | | | | | |
<id> <id> <id> <text> <text> <text> <text>
| | | | | | |
a b c あああ いいい ううう えええ
ですね。(文字の幅の問題できれいに出来ませんでした…読みにくくてすみません)
この構造ではidがdであるときのテキスト要素があるかないかの判別が出来ません(つまり<document>内で<id>タグのn番目、<text>タグのm番目といった指定の仕方でアクセスをすることは出来ますが、イメージ的には上述したようなツリー構造になるので、<id>タグと<text>タグを交互に記述しても、XMLではそれは無視されてしまうからです)。
おっしゃることをしたいのであれば、tokuya_nさんの提案されている用に、組になるタグを、例えば<word></word>で囲ってやることによってaとあああが対であることをコンピュータが読むことが出来るようになります。
<document>
|
---------------------- ~
| |
<word> <word> ~
| |
---------- ---------
| | | |
<id> <text> <id> <text>
| | | |
a あああ i いいい
この場合処理としては
1 for-each によってそれぞれのword要素を順番に呼び出し、
2 count()を使ってtextタグの有無を判定して<text>か空白を書き込むように選択
3 for-eachを抜ける
4 count()でwordの個数を判定して奇数の場合に空白セルを挿入
というようにすれば、簡単に実装できると思います。
もし、それがフォーマットを変えるのが不可能であれば、XMLを使わずにJavaスクリプトなどでがりがり一行ずつの判定をしなければならない気がします…そうするとXMLで書いてある意味が全くありませんし、厳密に改行や、タグの順番が要求されてきますが。
丁寧なご説明ありがとうございます。
また、返事が遅くなりすみません。
(こんなに早く適切なご回答が得られると思っていませんでした!)
tokuya_n さんにもご指摘いただいたように、XMLは
<document>
<word>
<id>a</id>
<text>あああ</text>
</word>
<word>
<id>b</id>
<text>いいい</text>
</word>
</document>
のような形で結構です。
ただ、後半部分で教えていただいたような方法では、表の途中に空白の欄ができてしまうと思うのですが、
これは詰めて表示したいと思います。
ところで、はてな初心者で恐縮ですが、このような場合(質問の条件を変えてしまったので)新しく質問を立て直したほうがよいでしょうか
ありがとうございます!
動作確認したところ、確かに要求どおりに動いているようです。
これからじっくりソースを読んでみます。