我是XSLT的新手,今天早上大部分时间都在玩这个以达到这一点,但不确定如何继续。
这是一些测试XML来表示我正在尝试做的事情
<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="style.xslt"?>
<ResultCollection>
<ColumnSet>
<Column>
<Caption>Site</Caption>
<DisplayType>String</DisplayType>
</Column>
<Column>
<Caption>Date</Caption>
<DisplayType>String</DisplayType>
</Column>
<Column>
<Caption>Attendee</Caption>
<DisplayType>String</DisplayType>
</Column>
<Column>
<Caption>Paid</Caption>
<DisplayType>Hidden</DisplayType>
</Column>
</ColumnSet>
<RowSet>
<Row>
<Site>London</Site>
<Date>15/06/2012</Date>
<Attendee>James</Attendee>
<Paid>Yes</Paid>
</Row>
<Row>
<Site>London</Site>
<Date>15/06/2012</Date>
<Attendee>John</Attendee>
<Paid>Yes</Paid>
</Row>
</RowSet>
</ResultCollection>
这是我用来转换它的相关XSLT:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<head>
<style type="text/css">
table.resultsCollection
{
border-collapse:collapse;
text-align:center;
margin:5px;
padding:2px;
}
table.resultsCollection tr th,
table.resultsCollection tr td
{
padding:2px 8px 2px 8px;
}
</style>
</head>
<body>
<table border="1" class="resultsCollection">
<tr bgcolor="#eeeeff">
<xsl:for-each select="ResultCollection/ColumnSet/Column">
<xsl:if test="not(self::*/DisplayType[text()]='Hidden')">
<th><xsl:value-of select="Caption"/></th>
</xsl:if>
</xsl:for-each>
</tr>
<xsl:for-each select="ResultCollection/RowSet/Row">
<tr>
<td><xsl:value-of select="Site"/></td>
<td><xsl:value-of select="Date"/></td>
<td><xsl:value-of select="Attendee"/></td>
<td><xsl:value-of select="Paid"/></td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
我无法改变我正在使用的XML结构,因为我认为这会让我的生活更轻松。尽管如此,我的目标是使其看起来可读,因此XSLT。
问题是'Column'节点包含'DisplayType',用于确定该列是否应该显示。使用'xsl:if'我确保不会显示任何具有该类型的列。但是,我无法弄清楚如何遵循这一点,并确保没有输出相关的记录。如果将这两个一起运行,您将看到表的第四列没有标题。但无论如何都会输出带有'付费'节点的两行内容。
任何想法如何同步这两个? (任何证明我所得到的建议也欢迎,因为这是我第一次尝试)
克里斯
答案 0 :(得分:2)
首先,我建议您养成使用模板规则而不是每个模板规则的习惯。所以这段代码:
<xsl:for-each select="ResultCollection/RowSet/Row">
<tr>
<td><xsl:value-of select="Site"/></td>
<td><xsl:value-of select="Date"/></td>
<td><xsl:value-of select="Attendee"/></td>
<td><xsl:value-of select="Paid"/></td>
</tr>
</xsl:for-each>
变为
<xsl:apply-templates select="ResultCollection/RowSet/Row" />
加
<xsl:template match="Row">
<tr><xsl:apply-templates/></tr>
</xsl:template>
<xsl:template match="Row/*">
<td><xsl:value-of select="."/></td>
</xsl:template>
现在,您需要进行的更改会影响Row的子项,即最后一个模板规则。它改为:
<xsl:template match="Row/*">
<xsl:variable name="position" select="position()"/>
<xsl:if test="not(ancestor::ResultCollection/ColumnSet/Column[$position]/DisplayType='Hidden')">
<td><xsl:value-of select="."/></td>
</xsl:if>
</xsl:template>
答案 1 :(得分:1)
您可能想要制作一个键
<xsl:key name="VisibleCols" match="ResultCollection/ColumnSet/Column[DisplayType!='Hidden']" use="Caption"/>
并像
一样使用它<xsl:for-each select="ResultCollection/ColumnSet/Column[DisplayType!='Hidden']">
<th><xsl:value-of select="Caption"/></th>
</xsl:for-each>
</tr>
<xsl:for-each select="ResultCollection/RowSet/Row">
<tr>
<xsl:for-each select="*[key('VisibleCols', name())]">
<td><xsl:value-of select="."/></td>
</xsl:for-each>
</tr>
</xsl:for-each>
请注意,它不使用预定义的元素集,而是使用源xml中的任何元素,这可能不是您想要的。它还按列名称将单元格与其标题链接,而不是通过它们在xml文件中的位置(与其他答案相对)链接。
补充:此外,您可以使用变量来保留列:
<xsl:variable name="VisibleCols" select="ResultCollection/ColumnSet/Column[DisplayType!='Hidden']"/>
<xsl:for-each select="$VisibleCols">
<th><xsl:value-of select="Caption"/></th>
</xsl:for-each>
</tr>
<xsl:for-each select="ResultCollection/RowSet/Row">
<tr>
<xsl:for-each select="*">
<xsl:if test="$VisibleCols[Caption=name(current())]">
<td><xsl:value-of select="."/></td>
</xsl:if>
</xsl:for-each>
</tr>
</xsl:for-each>
答案 2 :(得分:1)
此样式表应生成正确的结果:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<head>
<style type="text/css">
table.resultsCollection
{
border-collapse:collapse;
text-align:center;
margin:5px;
padding:2px;
}
table.resultsCollection tr th,
table.resultsCollection tr td
{
padding:2px 8px 2px 8px;
}
</style>
</head>
<body>
<table border="1" class="resultsCollection">
<xsl:variable name="columns" select="ResultCollection/ColumnSet/Column"/>
<tr bgcolor="#eeeeff">
<xsl:for-each select="$columns">
<xsl:if test="DisplayType!='Hidden'">
<th>
<xsl:value-of select="Caption"/>
</th>
</xsl:if>
</xsl:for-each>
</tr>
<xsl:for-each select="ResultCollection/RowSet/Row">
<tr>
<xsl:for-each select="*">
<xsl:variable name="pos" select="position()"/>
<xsl:if test="$columns[$pos]/DisplayType!='Hidden'">
<td>
<xsl:value-of select="."/>
</td>
</xsl:if>
</xsl:for-each>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
它保存变量中的列列表,然后在处理行时检查这些列以检查是否应显示该列。
简化DisplayType
上的测试 - 不需要[text()]
部分。