如何使用XSLT将XML文件中的兄弟节点子节点合并到XHTML表中

时间:2012-04-23 19:46:14

标签: xml xslt xhtml

第一次来这里。我在这个网站上搜索了很多,并没有找到与我的问题类似的例子,所以我有机会发布我的问题。

我有以下XML文档,我想使用XSLT转换转换为XHTML。

XML输入:

<Procedure Analyse="MyAnalysis1">
  <Identification Name="MetaTestA">
    <Blah Name="TestA" Result="1" /> 
    <Blah Name="TestB" Result="2" /> 
  </Identification>
  <Identification Name="MetaTestB">
    <Blah Name="TestB" Result="3" /> 
    <Blah Name="TestC" Result="4" /> 
 </Identification>
</Procedure>

预期的XHTML输出:

<table>
  <thead>
    <tr>MyAnalysis1</tr>
    <tr>
      <td></td>
      <td>MetaTestA</td>
      <td>MetaTestB</td>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>TestA</td>
      <td>1</td>
      <td></td>
    </tr>
    <tr>
      <td>TestB</td>
      <td>2</td>
      <td>3</td>
    </tr>
    <tr>
      <td>TestC</td>
      <td></td>
      <td>4</td>
    </tr>
  </tbody>
</table>

所以基本上我想让每一列成为MetaTest名称,将行作为MetaTestA和MetaTestB的Blah.Name和Blah.Result(可能有任意数量的列)

我很难弄清楚如何将两个表中的数据合并在一起(参见两个测试结果的TestB),这样它们就可以显示在同一行上。对于只应在第二列上的TestC也存在同样的问题。

感谢您的帮助,

此致

安德烈克劳德

1 个答案:

答案 0 :(得分:3)

这是一个分组问题。您需要按名称对测试结果进行分组。如何执行此操作取决于您使用的是XSLT1.0还是XSLT2.0。我将向您展示XSLT1.0解决方案,它使用一种称为 Muenchian 分组的技术。

您首先要定义一个keep来查找您的测试元素

<xsl:key name="Tests" match="Blah" use="@Name"/>

然后,要在每个组中找到第一个测试结果(对应于输出表中的行),您可以这样做

<xsl:apply-templates 
   select="Identification/Blah[generate-id() = generate-id(key('Tests', @Name)[1])]"/>

即找到 Blah 元素,该元素恰好是该名称的键中的第一个元素。

然后,对于每个 Blah 元素,输出与标识元素对应的结果。

这是完整的XSLT:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" indent="yes"/>
   <xsl:key name="Tests" match="Blah" use="@Name"/>
   <xsl:template match="Procedure">
      <table>
         <thead>
            <tr>
               <td rowspan="{count(Identification) + 1}">
                  <xsl:value-of select="@Analyse"/>
               </td>
            </tr>
            <tr>
               <td/>
               <xsl:apply-templates select="Identification" mode="header"/>
            </tr>
         </thead>
         <tbody>
            <xsl:apply-templates select="Identification/Blah[generate-id() = generate-id(key('Tests', @Name)[1])]"/>
         </tbody>
      </table>
   </xsl:template>

   <xsl:template match="Identification" mode="header">
      <td>
         <xsl:value-of select="@Name"/>
      </td>
   </xsl:template>

   <xsl:template match="Identification" mode="test">
      <xsl:param name="Name"/>
      <td>
         <xsl:value-of select="Blah[@Name=$Name]/@Result"/>
      </td>
   </xsl:template>

   <xsl:template match="Blah">
      <tr>
         <td>
            <xsl:value-of select="@Name"/>
         </td>
         <xsl:apply-templates select="//Identification" mode="test">
            <xsl:with-param name="Name" select="@Name"/>
         </xsl:apply-templates>
      </tr>
   </xsl:template>
</xsl:stylesheet>

当应用于您的示例XML时,输出以下内容

<table>
   <thead>
      <tr>
         <td rowspan="3">MyAnalysis1</td>
      </tr>
      <tr>
         <td/>
         <td>MetaTestA</td>
         <td>MetaTestB</td>
      </tr>
   </thead>
   <tbody>
      <tr>
         <td>TestA</td>
         <td>1</td>
         <td/>
      </tr>
      <tr>
         <td>TestB</td>
         <td>2</td>
         <td>3</td>
      </tr>
      <tr>
         <td>TestC</td>
         <td/>
         <td>4</td>
      </tr>
   </tbody>
</table>

(在XSLT2.0中,您可以使用 xsl:for-each-group 来简化分组)