XSLT:按类型分组XML元素,并将输出分组为HTML表

时间:2013-10-10 00:47:58

标签: xslt xslt-2.0

我有XML包含描述对象类型和名称的元素。对象按类型分为Animated = [Dog,Person]和Inanimate = [Plant,Automobile]类别。下面显示了一个示例XML和所需的HTML。

我还希望有一个全能的XSL模板,告诉我哪些类型,例如猫,无法映射到Animate / Inanimate组。

我正在使用Saxon 9.4。

XML:

<items>
<item>
    <type>Dog</type>
    <name>Fido</name>
</item>
<item>
    <type>Person</type>
    <name>Bob</name>
</item>
<item>
    <type>Plant</type>
    <name>Tomato</name>
</item>
<item>
    <type>Automobile</type>
    <name>Honda</name>
</item>
<item>
    <type>Automobile</type>
    <name>Ford</name>
</item>

HTML:

<table>
<th>There are 2 Animated objects</th>
<tr>
    <td>Dog Fido</td>
    <td>Person Bob</td>
</tr>
</table>

<table>
<th>There are 3 Inanimate objects</th>
<tr>
    <td>Plant Tomato</td>
    <td>Automobile Honda</td>
    <td>Automobile Ford</td>
</tr>
</table>

*添加以下内容以回应评论*

某些对象类型与Animate / Inanimate组之间的映射是经验已知的,但映射不完整。因此,在这个表面的例子中,如果遇到Cat类型,则需要在catch-all模板中打印出来。

我遇到的最大问题是打印单个并打印多个<tr>。我尝试在<th>的模板中打印match="items[item/type='Dog'] | items[item/type='Person']",然后递归<xsl:apply-template select="items"/>,但后来我不知道如何为我所做的类型的项目执行全部检查t占,例如Cat。

我还尝试使用match="item[type='Dog' or type='Person']"制作模板,但为了打印<th>,我必须<xsl:if test="position() = 1">打印<table><th>..</th>。但这不起作用,因为在我处理组中的最后一项之前,XSLT中没有关闭</table>

我希望这能澄清我的困境。

谢谢,

艾力

1 个答案:

答案 0 :(得分:1)

假设您使用XSLT 2.0,您可以使用所需的映射定义参数:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="2.0">

    <xsl:param name="map">
      <map>
        <key name="Dog">Animated</key>
        <key name="Person">Animated</key>
        <key name="Plant">Inanimate</key>
        <key name="Automobile">Inanimate</key>
      </map>
    </xsl:param>

    <xsl:strip-space elements="*"/>
    <xsl:output method="html" indent="yes" version="5.0"/>

    <xsl:key name="k1" match="map/key" use="@name"/>

    <xsl:template match="items">
      <xsl:for-each-group select="item" group-by="(key('k1', type, $map), 'unmapped')[1]">
        <table>
          <thead>
            <tr>
              <th>There are <xsl:value-of select="count(current-group()), 
               current-grouping-key()"/>
              objects.</th>
            </tr>
          </thead>
          <tbody>
            <xsl:apply-templates select="current-group()"/>
          </tbody>
        </table>
      </xsl:for-each-group>

    </xsl:template>

    <xsl:template match="item">
      <tr>
        <xsl:value-of select="*"/>
      </tr>
    </xsl:template>

</xsl:stylesheet>

那样输入样本

<items>
<item>
    <type>Dog</type>
    <name>Fido</name>
</item>
<item>
    <type>Person</type>
    <name>Bob</name>
</item>
<item>
    <type>Plant</type>
    <name>Tomato</name>
</item>
<item>
    <type>Automobile</type>
    <name>Honda</name>
</item>
<item>
    <type>Automobile</type>
    <name>Ford</name>
</item>
<item>
    <type>Cat</type>
    <name>Garfield</name>
</item>
</items>

转换为

<table>
   <thead>
      <tr>
         <th>There are 2 Animated
            objects.
         </th>
      </tr>
   </thead>
   <tbody>
      <tr>Dog Fido</tr>
      <tr>Person Bob</tr>
   </tbody>
</table>
<table>
   <thead>
      <tr>
         <th>There are 3 Inanimate
            objects.
         </th>
      </tr>
   </thead>
   <tbody>
      <tr>Plant Tomato</tr>
      <tr>Automobile Honda</tr>
      <tr>Automobile Ford</tr>
   </tbody>
</table>
<table>
   <thead>
      <tr>
         <th>There are 1 unmapped
            objects.
         </th>
      </tr>
   </thead>
   <tbody>
      <tr>Cat Garfield</tr>
   </tbody>
</table>