1

私は次のxmlを持っています:

入力

<page>
 <group category="cat1">
  <item fileunder="#">.45 colt</item>
  <item fileunder="#">8 queens</item>
  <item fileunder="#">9 lives</item>
  <item fileunder="#">99 bottles of beer</item>
  <item fileunder="A">An innocent man</item>
  <item fileunder="A">Academy awards</item>
  <item fileunder="B">Before the dawn</item>
 </group>
 <group category="cat2">
  <item fileunder="R">Rows of houses</item>
 </group>
</page>

入力項目はすでにソートされています。

希望の出力

すべての ごとに 3 列の HTML テーブルを作成し、group個別の ごとにサブヘッダー (3 列にまたがるセル) を作成fileunderし、トップダウンで次の列に最適に表示します (アイテムは既に並べ替えられています)。

<table>
 <tr><td colspan="3">#</td></tr>
 <tr><td>.45 colt</td><td>9 lives</td><td>99 bottles of beer</td></tr>
 <tr><td>8 queens</td></tr>
 <tr><td colspan="3">A</td></tr>
 <tr><td>An innocent man</td><td>Academy awards</td></tr>
 <tr><td colspan="3">B</td></tr>
 <tr><td>Before the dawn</td></tr>
</table>
<table>
 <tr><td colspan="3">R</td></tr>
 <tr><td>Rows of houses</td></tr>
</table>

アイテムが左から右、次に次の行として提示されれば、私は生きていける。

私がこれまでに持っているものは次のとおりです。

現在の xslt

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="itm_grp" match="/page/group/item" use="concat(../@category,':',@fileunder)"/>
<xsl:template match="page/group">
  <table>
  <xsl:for-each select="item[.=key('itm_grp',concat(../@category,':',@fileunder))[1]]">
    <tr><td colspan="3"><xsl:value-of select="@fileunder"/></td></tr>
    <xsl:variable name="nodeset" select="key('itm_grp',concat(../@category,':',@fileunder))"/>
    <xsl:for-each select="$nodeset[position() mod 3=1]">
      <tr>
      <td><xsl:value-of select="."/></td>
      <td><xsl:value-of select="following-sibling::item[1]"/></td>
      <td><xsl:value-of select="following-sibling::item[2]"/></td>
      </tr>
    </xsl:for-each>
  </xsl:for-each>
  </table>
</xsl:template>
</xsl:stylesheet>

左から右、次に次の行の出力を生成します (最適ではありません)。ただし、following-sibling選択すると「にじみ」効果が生じます。

#
.45 colt            8 queens         9 lives
99 bottles of beer  An innocent man  Academy awards
A
An innocent man     Academy awards   Before the dawn
B
Before the dawn     
R
Rows of houses      

ご覧のとおり、 にfileunder #は A 項目が 2 つ、fileunder AB 項目が 1 つあります。

だから、私の質問は:

目的の出力 (列単位) を生成するにはどうすればよいですか?
それができない場合、行単位の出力で「出血」を回避するにはどうすればよいですか?

私は XSLT の経験がほとんどないことに注意してください。そのため、私のコードが明らかに非効率的/ばかげている/その他の場合は、すべてを置き換えて自由に教えてください!

注意: XSLT バージョン 1 であるため、明らかにindex-of機能はありません。

4

2 に答える 2

1

あなたの物語とリストされた予想される結果との間にわずかな矛盾があります。上から下、次に左から右の列の塗りつぶし順序を要求しましたが、空でない値のリストにはありますが、空の値にはありません。この空間的な順序は、次の列を開始する前に列全体を埋める必要があることを意味します。あなたのリストは間違いであり、出力で本当に欲しいものは...

<table>
  <tr>
    <td colspan="3">#</td>
  </tr>
  <tr>
    <td>.45 colt</td>
    <td>9 lives</td>
    <td>&npsp;</td>
  </tr>
  <tr>
    <td>8 queens</td>
    <td>99 bottles of beer</td>
    <td>&npsp;</td>
  </tr>
  <tr>
    <td colspan="3">A</td>
  </tr>
  <tr>
    <td>An innocent man</td>
    <td>Academy awards</td>
    <td>&npsp;</td>
  </tr>
  <tr>
    <td colspan="3">B</td>
  </tr>
  <tr>
    <td>Before the dawn</td>
    <td>&npsp;</td>
    <td>&npsp;</td>
  </tr>
</table>
<table>
  <tr>
    <td colspan="3">R</td>
  </tr>
  <tr>
    <td>Rows of houses</td>
    <td>&npsp;</td>
    <td>&npsp;</td>
  </tr>
</table>

...これは一貫したトップダウン、次に左から右の列の塗りつぶし順序です。

この XSLT 1.0 スタイルシート...

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" doctype-system="about:legacy-compat" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*" />  

<xsl:key name="kItemByFile" match="item" use="concat(../@category,':',@fileunder)"/>

<xsl:template match="/">
 <html lang="en">
   <head><title>Songs</title></head>
   <body>  
     <xsl:apply-templates select="*/group" />
   </body>  
 </html>
</xsl:template>

<xsl:template match="group">
  <xsl:variable name="cat" select="concat(@category,':')" />
  <table> 
    <xsl:apply-templates select="item[
      generate-id() = generate-id(key('kItemByFile',concat($cat,@fileunder))[1])]" 
      mode="group-head" />
  </table> 
</xsl:template>

<xsl:template match="item" mode="group-head">
  <xsl:variable name="items"
     select="key('kItemByFile',concat(../@category,':',@fileunder))" />
  <xsl:variable name="row-count" select="ceiling( count($items) div 3)" />
  <tr><td colspan="3"><xsl:value-of select="@fileunder" /></td></tr>
  <xsl:for-each select="$items[position() &lt;= $row-count]">
    <xsl:variable name="pos" select="position()" />
    <xsl:apply-templates select="." mode="row">  
      <xsl:with-param name="items" select="$items" />
      <xsl:with-param name="row" select="$pos" />
      <xsl:with-param name="row-count" select="$row-count" />
    </xsl:apply-templates>  
  </xsl:for-each>
</xsl:template>

<xsl:template match="item" mode="row">
  <xsl:param name="items" select="/.." />
  <xsl:param name="row" select="1" />
  <xsl:param name="row-count" select="1" />
  <tr>
    <xsl:apply-templates select="
       $items[(position() mod $row-count) = ($row mod $row-count)]" mode="td" />
    <xsl:variable name="full-cols" select="floor((count($items) div $row-count))" />
    <xsl:variable name="part-col" select="number($row &lt;
                 ((count($items) mod $row-count) + 1))" />
    <xsl:variable name="empties" select="3 - ($full-cols + $part-col)" />
    <xsl:for-each select="(document('')/*/*)[position() &lt;= $empties]">
      <xsl:call-template name="empty-cell" />
    </xsl:for-each> 
  </tr>  
</xsl:template>

<xsl:template match="item" mode="td">
  <td><xsl:value-of select="." /></td>  
</xsl:template>

<xsl:template name="empty-cell">
  <td>&#160;</td>
</xsl:template>

</xsl:stylesheet>

...この入力に適用すると...

<page>
 <group category="cat1">
  <item fileunder="#">.45 colt</item>
  <item fileunder="#">8 queens</item>
  <item fileunder="#">9 lives</item>
  <item fileunder="#">99 bottles of beer</item>
  <item fileunder="A">An innocent man</item>
  <item fileunder="A">Academy awards</item>
  <item fileunder="B">Before the dawn</item>
 </group>
 <group category="cat2">
  <item fileunder="R">Rows of houses</item>
 </group>
</page>

...収量...

<!DOCTYPE html SYSTEM "about:legacy-compat">
<html lang="en">
  <head>
    <META http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Songs</title>
  </head>
  <body>
    <table>
      <tr>
        <td colspan="3">#</td>
      </tr>
      <tr>
        <td>.45 colt</td>
        <td>9 lives</td>
        <td> </td>
      </tr>
      <tr>
        <td>8 queens</td>
        <td>99 bottles of beer</td>
        <td> </td>
      </tr>
      <tr>
        <td colspan="3">A</td>
      </tr>
      <tr>
        <td>An innocent man</td>
        <td>Academy awards</td>
        <td> </td>
      </tr>
      <tr>
        <td colspan="3">B</td>
      </tr>
      <tr>
        <td>Before the dawn</td>
        <td> </td>
        <td> </td>
      </tr>
    </table>
    <table>
      <tr>
        <td colspan="3">R</td>
      </tr>
      <tr>
        <td>Rows of houses</td>
        <td> </td>
        <td> </td>
      </tr>
    </table>
  </body>
</html>

出力内の空のセルについては、レキシカル HTML を表示すると、&nbsp;または リテラルの空白に相当するものが得られます。XSLT プロセッサの実装に依存しますが、モデルが同等であるため、心配する必要はありません。

于 2012-11-13T13:12:00.027 に答える
1

それを修正する最も簡単な方法:

<xsl:variable name="header" select="@fileunder"/>
...
<xsl:value-of select="following-sibling::item[@fileunder=$header][1]"/>
<xsl:value-of select="following-sibling::item[@fileunder=$header][2]"/>
于 2012-11-13T09:59:35.903 に答える