1

我是 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。

问题是“列”节点包含一个“显示类型”,它确定该列是否应该显示。使用 'xsl:if' 我确保不会显示任何具有该类型的列。但是,我无法弄清楚如何执行此操作并确保没有关联的记录也被输出。如果将这两个一起运行,您将看到表格的第四列没有标题。但是无论如何都会输出带有“付费”节点的两行的内容。

任何想法如何同步两者?(也欢迎任何证明我所拥有的建议,因为这是我的第一次尝试)

克里斯

4

3 回答 3

2

首先,我建议你养成使用模板规则而不是 for-each 的习惯。所以这段代码:

    <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>
于 2012-05-28T17:35:20.543 回答
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>
于 2012-05-28T17:29:02.917 回答
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()]部分不是必需的。

于 2012-05-28T17:40:02.130 回答