【问题标题】:XSLT if two values of an element match then merge cells?XSLT 如果一个元素的两个值匹配然后合并单元格?
【发布时间】:2016-07-25 04:44:36
【问题描述】:

我正在尝试使用 XML 和 XSLT 文件创建一段 XHTML。

我想测试两个或多个 XML 元素的值是否与表中的其他元素一致,在这种情况下,我希望将这些单元格合并到结果 XHTML 文件中。

为了简单起见,我将使用一个简单的 w3schools 示例。 (更多人应该在 stackoverflow 上这样做)。

这是 XML:

<?xml version="1.0" encoding="UTF-8"?>
<catalog>
<cd>
    <title>Empire Burlesque</title>
    <artist>Bob Dylan</artist>
</cd>
<cd>
    <title>Empire Burlesque</title>
    <artist>Bonnie Tyler</artist>
</cd>
<cd>
    <title>Empire Burlesque</title>
    <artist>Mr G</artist>
</cd>
<cd>
    <title>Greatest Hits</title>
    <artist>Dolly Parton</artist>
</cd>
</catalog>

这是 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>
<body>
<h2>My CD Collection</h2>
<table border="1">
<tr bgcolor="#9acd32">
  <th>Title</th>
  <th>Artist</th>
</tr>
<xsl:for-each select="catalog/cd">
<tr>
  <xsl:choose>
  <xsl:when test="count(title) %gr 2">
     <td rowspan="2"><xsl:value-of select="title"/></td>
  </xsl:when>
  <xsl:otherwise>
     <td><xsl:value-of select="title"/></td>
  </xsl:otherwise>
  </xsl:choose>
  <td><xsl:value-of select="artist"/></td>
  </tr>
  </xsl:for-each>
  </table>
  </body>
  </html>
  </xsl:template>
  </xsl:stylesheet>

XSLT 中有两个错误的元素是:TEST 和 ROWSPAN。

  1. 如何测试一个标题是否有多个实例? (在这种情况下是帝国滑稽剧)

  2. 在这种情况下,我如何告诉程序将这两个单元格(因此输出是一个显示 Empire Burlesque 的单元格)与行跨度 3 合并。

注意:请不要告诉我 test='Empire Burlesque'。如果我在哪里添加它们,我希望它适用于其他重复实例。谢谢。

【问题讨论】:

  • 像这样分组问题的解决方案在很大程度上取决于您使用的是 XSLT 1.0 还是 2.0(在 2.0 中要容易得多!)。所以你需要告诉我们你的目标是哪个版本。

标签: xml xslt xhtml


【解决方案1】:

我不会告诉你 test='Empire Burlesque' 但我会告诉你阅读 XSLT 1.0 中称为Muenchian Grouping 的技术,它允许你将cd 元素按不同的@ 分组987654323@

在您的情况下,您首先定义一个按标题查找 cd 的键

<xsl:key name="cds" match="cd" use="title" />

然后,要获得不同的标题(或者更确切地说,要获得每个不同标题第一次出现的 cd 元素),您可以使用这个表达式

<xsl:for-each select="catalog/cd[generate-id() = generate-id(key('cds', title)[1])]">

在这个循环中,您将分组,然后使用密钥获得所有具有匹配标题的 cd。例如,要查看是否需要行跨度,您可以这样做

<xsl:if test="count(key('cds', title)) > 1">

试试这个 XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" doctype-public="XSLT-compat" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />

<xsl:key name="cds" match="cd" use="title" />

<xsl:template match="/">
<html>
<body>
<h2>My CD Collection</h2>
<table border="1">
<tr bgcolor="#9acd32">
  <th>Title</th>
  <th>Artist</th>
</tr>
<xsl:for-each select="catalog/cd[generate-id() = generate-id(key('cds', title)[1])]">
<tr>
  <td>
      <xsl:if test="key('cds', title)[2]">
          <xsl:attribute name="rowspan">
              <xsl:value-of select="count(key('cds', title))" />
          </xsl:attribute>
      </xsl:if>
      <xsl:value-of select="title"/>
  </td>
  <td><xsl:value-of select="artist"/></td>
</tr>
<xsl:for-each select="key('cds', title)[position() > 1]">
<tr>
    <td>
      <xsl:value-of select="artist"/>
    </td>
</tr>    
</xsl:for-each>
  </xsl:for-each>
  </table>
  </body>
  </html>
</xsl:template>
</xsl:stylesheet>

【讨论】:

  • 有效,感谢您的快速回复。但是,如果我要添加另一张也称为帝国滑稽剧的 cd,它就会停止工作。有没有什么简单的方法可以让它不仅仅适用于两个重复元素?
  • 这可能有点棘手,但您可以编辑您的问题以显示一个包含三张“帝国滑稽剧”cd 的示例,以及您期望的输出吗?谢谢!
  • 完成,我添加了另一张名为 Empire burlesque 的 CD。现在我想要一个类似的结果:这一次,Empire Burlesque 应该有 3 行跨度并包含艺术家 Bob Dylan、Bonnie Tyler 和 Mr G
  • 其实一点都不难。我的 XSLT 中出现了一个错误,因为我没有输出我应该输出的 tr 元素。我已经更正了我的答案。
  • 太棒了。非常感谢,真的!
猜你喜欢
  • 2016-08-25
  • 1970-01-01
  • 2014-06-16
  • 1970-01-01
  • 1970-01-01
  • 2015-05-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多