XSLT:将未分组数据拆分为块

时间:2011-10-18 21:40:23

标签: xslt xslt-2.0

我需要转

   <question>
      <static><![CDATA[Static Data]]></static>

      <debit-row />
      <debit-row />
      <credit-row />

      <header><![CDATA[Header HTML 1]]></header>
      <debit-row />
      <debit-row />
      <credit-row />
   </question>

<p>Static Data</p>
<ul>
   <li>
      <table>
         <tr><td> debit row </td></tr>
         <tr><td> credit row </td></tr>
         <tr><td> credit row </td></tr>
      </table>
   </li>
   <li> Header HTML 1
      <table>
         <tr><td> debit row </td></tr>
         <tr><td> debit row </td></tr>
         <tr><td> credit row </td></tr>
      </table>
   </li>
</ul>

基本上,标题或借记行表示新块的开始。每个块都是一个列表项。每个一个或多个行都是一个表(通常,信用行总是最后一个,因此很容易判断何时启动表)。

XSLT和XPATH似乎非常困难,而且我很难找到任何我想要做的事情,所以如果有人有一个很好的参考,我也会很感激。

我开始使用这个xsl:

<xsl:template match="question">
   <xsl:apply-templates select="static|header|debit-row[preceding-sibling::*[1] != header]" />
</xsl:template>

这不是一个好的开始,因为模板根本不应用于任何借记行,但它们应该应用于第一个借记行(它之前没有标题元素)。这个表达是错的吗?

即使我开始工作,我也需要找到一种方法来说“如果这是第一个标题或借记行,请打开<ul>”,我不知道如何做到这一点应用标题/借记行模板时。 debit-row每个都有自己的xml也需要应用(它需要一个表行和td)。我还必须在第一个借记行之前和最后一个信用额之后适当地打开和关闭表。

我会非常感谢任何帮助,因为我甚至无法使上面的简单xpath表达式正常工作。

1 个答案:

答案 0 :(得分:3)

<强>予。 XSLT 1.0解决方案:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>
 <xsl:key name="kFollowing"
  match="*[not(self::static or self::header)]"
  use="generate-id(preceding-sibling::*
                              [self::static
                              or
                               self::header
                              ][1]
                  )"/>

 <xsl:template match="/*[static]">
  <p><xsl:value-of select="static"/></p>
  <ul>
    <xsl:apply-templates select="static|header"/>
  </ul>
 </xsl:template>

 <xsl:template match="static|header">
  <li>
    <xsl:value-of select=
     "concat(self::header, '&#xA;')"/>
    <table>
     <xsl:apply-templates
       select="key('kFollowing', generate-id())"/>
    </table>
  </li>
 </xsl:template>

 <xsl:template match=
  "*/*[not(self::static or self::header)]">
  <tr>
    <td>
     <xsl:value-of select=
      "translate(name(),'-', ' ')"/>
    </td>
  </tr>
 </xsl:template>
</xsl:stylesheet>

应用于提供的XML文档

<question>
    <static><![CDATA[Static Data]]></static>
    <debit-row />
    <debit-row />
    <credit-row />
    <header><![CDATA[Header HTML 1]]></header>
    <debit-row />
    <debit-row />
    <credit-row />
</question>

生成想要的正确结果

<p>Static Data</p>
<ul>
   <li>

      <table>
         <tr>
            <td>debit row</td>
         </tr>
         <tr>
            <td>debit row</td>
         </tr>
         <tr>
            <td>credit row</td>
         </tr>
      </table>
   </li>
   <li>Header HTML 1
<table>
         <tr>
            <td>debit row</td>
         </tr>
         <tr>
            <td>debit row</td>
         </tr>
         <tr>
            <td>credit row</td>
         </tr>
      </table>
   </li>
</ul>

解释:使用键定位所有属于组的元素的位置分组。


<强> II。 XSLT 2.0解决方案:

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="/*[static]">
  <p><xsl:value-of select="static"/></p>
  <ul>
    <xsl:for-each-group select="*"
         group-starting-with="static|header">
      <li>
        <xsl:value-of separator="&#xA;" select=
         "current-group()[1][self::header], ''"/>
        <table>
         <xsl:apply-templates
           select="current-group()[position() gt 1]"/>
        </table>
      </li>
    </xsl:for-each-group>
  </ul>
 </xsl:template>

 <xsl:template match=
  "*/*[not(self::static or self::header)]">
  <tr>
    <td>
     <xsl:value-of select=
      "translate(name(),'-', ' ')"/>
    </td>
  </tr>
 </xsl:template>
</xsl:stylesheet>

将此XSLT 2.0转换应用于同一XML文档(上图)时,再次生成相同的正确结果

<p>Static Data</p>
<ul>
   <li>
      <table>
         <tr>
            <td>debit row</td>
         </tr>
         <tr>
            <td>debit row</td>
         </tr>
         <tr>
            <td>credit row</td>
         </tr>
      </table>
   </li>
   <li>Header HTML 1
<table>
         <tr>
            <td>debit row</td>
         </tr>
         <tr>
            <td>debit row</td>
         </tr>
         <tr>
            <td>credit row</td>
         </tr>
      </table>
   </li>
</ul>

解释:使用带有<xsl:for-each-group>属性的XSLT 2.0 group-starting-with指令。还使用标准的XSLT 2.0函数current-group()