我有以下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>
输入项已经排序。
我想为每个group
生成一个3列HTML表格,每个不同的fileunder
都有一个子标题(一个3列生成单元格),最佳显示在自上而下,然后-next-column(项目已经排序):
<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>
如果项目是从左到右,然后是下一行,我可以活着。
到目前为止我所拥有的是:
<?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项,fileunder
A
有一个B项。
所以,我的问题是:
如何生成所需的输出(逐列)?
如果我不能这样做,我怎么能让行方输出避免“流血”?
请注意我对XSLT的经验很少,所以如果我的代码显然效率低下/愚蠢/无论如何,请随时通过替换所有内容来教育我!
注意:XSLT版本1,显然没有index-of
功能可用。
答案 0 :(得分: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]"/>
答案 1 :(得分: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() <= $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 <
((count($items) mod $row-count) + 1))" />
<xsl:variable name="empties" select="3 - ($full-cols + $part-col)" />
<xsl:for-each select="(document('')/*/*)[position() <= $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> </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时,您将获得
或等效的文字空格。它依赖于XSLT处理器实现,但不应引起任何顾虑,因为它与模型等效。