通过xslt创建带有rowspan的语义表

时间:2015-01-22 19:08:41

标签: html xml xslt

我有以下xml文档:

...

<x>
<symptom><descr></descr></symptom>
<cause></cause>
<solution></solution>
<cause></cause>
<solution></solution>
</x>

...

在我的文档中,我有几个<x>

在每个<x>中,我只有一个<symptom> n <cause><solution>,其中<cause>和{<solution> {1}}总是一样的。

我希望得到以下自动生成的结构:

<table>
<tr>
<td rowspan=count(cause)><xsl:value-of select="symptom/descr"></td>
<td><xsl:value-of select="cause"></td>
<td><xsl:value-of select="symptom"></td>
<tr>
<tr>
<td><xsl:value-of select="cause"></td>
<td><xsl:value-of select="symptom"></td>
<tr>
...
</table>

我尝试了以下代码,我知道这是完全错误的。但是几个小时后我就陷入困境,在互联网上找不到任何好的解决方案。

    <xsl:for-each select="cause">
             <tr>
               <td rowspan="count(.)">
                 <xsl:value-of select="../descr[1]"/>
               </td>
               <td>
                 <xsl:value-of select="."/>
               </td>
               <xsl:for-each select="../solution">
                <td>
                 <xsl:value-of select="."/>
               </td>
</xsl:for-each>
 </tr>
             </xsl:for-each>
      </table>

2 个答案:

答案 0 :(得分:0)

这是基于您希望结果具有以下结构的表的假设:给出一个示例输入XML

<x>
  <symptom>
    <descr>
      Description
    </descr>
  </symptom>
  <cause>
    Cause 1
  </cause>
  <solution>
    Solution 1
  </solution>
  <cause>
    Cause 2
  </cause>
  <solution>
    Solution 2
  </solution>
</x>

我假设你想要下表:

<table>
   <tr>
     <td rowspan="2">Description</td>
     <td>Cause 1</td>
     <td>Solution 1</td>
   </tr>
   <tr>
     <td>Cause 2</td>
     <td>Solution 2</td>
   </tr>
</table>

这可以通过以下XSLT完成:

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html"  omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
  <xsl:strip-space elements="*"/>
    <xsl:template match="x">
      <table>
        <xsl:for-each select="cause">
          <xsl:apply-templates select="." mode="row">
            <xsl:with-param name="amount" select="count(../cause)"/>
            <xsl:with-param name="position" select="position()"/>
          </xsl:apply-templates>
        </xsl:for-each>
      </table>
    </xsl:template>
    <xsl:template match="cause" mode="row">
    <xsl:param name="amount"/>
    <xsl:param name="position"/>
      <tr>
        <xsl:if test="$position = 1">
          <td rowspan="{$amount}">
              <xsl:value-of select="//symptom/descr"/>
          </td>
        </xsl:if>
        <td>
          <xsl:value-of select="."/>
        </td>
        <td>
          <xsl:value-of select="following-sibling::solution"/>
        </td>
    </tr>
  </xsl:template>
</xsl:transform>

对于每个原因,通过应用模板

创建一行
<xsl:template match="cause" mode="row">

以行数和当前cause的位置作为参数。如果该排名为1,description将被写为td中的值,cause的值为rowspan的值。
每行包含当前cause的值:

<td>
  <xsl:value-of select="."/>
</td>

以及solution在同一位置的值(solution是当前following-sibling的{​​{1}}:

cause

答案 1 :(得分:0)

你的每行tr只有cause一行,这是怎么回事:

<xsl:template match="x">
  <table>
    <xsl:for-each select="cause">
      <!-- the index of this cause within the list of causes in the current x -->
      <xsl:variable name="pos" select="position()" />
      <tr>
        <!-- first cause - create the spanning symptom cell -->
        <xsl:if test="$pos = 1">
          <td rowspan="{last()}"><xsl:value-of select="../symptom/descr"/></td>
        </xsl:if>
        <!-- this cause -->
        <td><xsl:value-of select="." /></td>
        <!-- the matching solution -->
        <td><xsl:value-of select="../solution[$pos]" /></td>
      </tr>
    </xsl:for-each>
  </table>
</xsl:template>

这里的一个技巧是last()函数,它返回当前for-each(或apply-templates)正在处理的节点总数,在这种情况下恰好是你想要跨越的行。