xsl,xml group by

时间:2012-02-26 18:48:45

标签: xml xslt group-by

嘿,我有愚蠢的xml文件:

<?xml version="1.0"?>
 <accidents>
 <accident>
   <org>1</org>
   <com>194</com>
   <dep>010</dep>
   <grav>0.64</grav>
 </accident>
 <accident>
   <org>1</org>
   <com>194</com>
   <dep>420</dep>
   <grav>0.54</grav>
 </accident>
 <accident>
   <org>1</org>
   <com>44</com>
   <dep>010</dep>
   <grav>0.4</grav>
</accident>
</accidents>

我想通过dep应用xslt 1.0来获取事故数量:输出应该像这样的html页面:

 <table> <thead> <tr> <th>420</th> <th>010</th> </tr> </thead> <tbody> <tr> 
   <th>accidents</th> <td>1</td> <td>2</td> </tr> </tbody> </table>

谢谢,请注意我使用php5

2 个答案:

答案 0 :(得分:1)

您可以使用与上一个问题几乎相同的答案

<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="kAccByDept" match="accident" use="dep"/>

     <xsl:template match="/*">
      <html>
       <table border="1">
         <thead>
           <tr>
            <th>deps:</th>
             <xsl:apply-templates/>
           </tr>
         </thead>
         <tbody>
            <tr>
             <th>accidents:</th>
             <xsl:apply-templates mode="count"/>
           </tr>
         </tbody>
       </table>
      </html>
     </xsl:template>

     <xsl:template match=
      "accident
        [generate-id()
        =
         generate-id(key('kAccByDept', dep)[1])
         ]">
         <td><xsl:value-of select="dep"/></td>
     </xsl:template>
     <xsl:template mode="count" match=
      "accident
        [generate-id()
        =
         generate-id(key('kAccByDept', dep)[1])
         ]">
         <td><xsl:value-of select="count(key('kAccByDept', dep))"/></td>
     </xsl:template>
     <xsl:template match="text()"/>
     <xsl:template match="text()" mode="count"/>
</xsl:stylesheet>

将此转换应用于提供的XML文档

<accidents>
    <accident>
        <org>1</org>
        <com>194</com>
        <dep>010</dep>
        <grav>0.64</grav>
    </accident>
    <accident>
        <org>1</org>
        <com>194</com>
        <dep>420</dep>
        <grav>0.54</grav>
    </accident>
    <accident>
        <org>1</org>
        <com>44</com>
        <dep>010</dep>
        <grav>0.4</grav>
    </accident>
</accidents>

生成了正确的结果(在标题中添加了“deps:”以实现正确对齐):

<html>
   <table border="1">
      <thead>
         <tr>
            <th>deps:</th>
            <td>010</td>
            <td>420</td>
         </tr>
      </thead>
      <tbody>
         <tr>
            <th>accidents:</th>
            <td>2</td>
            <td>1</td>
         </tr>
      </tbody>
   </table>
</html>

如果发生事故以外的其他事件和没有事故的部门,事情会变得更有趣。假设我们现在有这个XML文档

<events>
    <accidents>
        <accident>
            <org>1</org>
            <com>194</com>
            <dep>010</dep>
            <grav>0.64</grav>
        </accident>
        <accident>
            <org>1</org>
            <com>194</com>
            <dep>420</dep>
            <grav>0.54</grav>
        </accident>
        <accident>
            <org>1</org>
            <com>44</com>
            <dep>010</dep>
            <grav>0.4</grav>
        </accident>
    </accidents>
    <achievements>
        <achievement>
            <org>1</org>
            <com>194</com>
            <dep>002</dep>
            <grav>0.64</grav>
        </achievement>
        <achievement>
            <org>1</org>
            <com>194</com>
            <dep>420</dep>
            <grav>0.54</grav>
        </achievement>
        <achievement>
            <org>1</org>
            <com>44</com>
            <dep>011</dep>
            <grav>0.4</grav>
        </achievement>
    </achievements>
</events>

这又是一次正确产生所有不同部门及其事故数量的转变

<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="kAccByDept" match="accident" use="dep"/>
     <xsl:key name="kDepByCode" match="dep" use="."/>

     <xsl:variable name="vDeps" select=
     "/*/*/*/dep
             [generate-id()
             =
              generate-id(key('kDepByCode', .)[1])
             ]
     "/>

     <xsl:template match="/*">
      <html>
       <table border="1">
         <thead>
           <tr>
            <th>deps:</th>
             <xsl:apply-templates select="$vDeps"/>
           </tr>
         </thead>
         <tbody>
            <tr>
             <th>accidents:</th>
             <xsl:apply-templates select="$vDeps" mode="acc"/>
           </tr>
         </tbody>
       </table>
      </html>
     </xsl:template>

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

     <xsl:template match="dep" mode="acc">
         <td><xsl:value-of select="count(key('kAccByDept', .))"/></td>
     </xsl:template>
</xsl:stylesheet>

当对上述XML文档应用此转换时,它会生成正确的,想要的结果

<html>
   <table border="1">
      <thead>
         <tr>
            <th>deps:</th>
            <td>010</td>
            <td>420</td>
            <td>002</td>
            <td>011</td>
         </tr>
      </thead>
      <tbody>
         <tr>
            <th>accidents:</th>
            <td>2</td>
            <td>1</td>
            <td>0</td>
            <td>0</td>
         </tr>
      </tbody>
   </table>
</html>

更新:在评论中,OP还要求每个部门都有“com”的总和。

转化需要稍微改变

<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="kAccByDept" match="accident" use="dep"/>
         <xsl:key name="kDepByCode" match="dep" use="."/>

         <xsl:variable name="vDeps" select=
         "/*/*/*/dep
                 [generate-id()
                 =
                  generate-id(key('kDepByCode', .)[1])
                 ]
         "/>

         <xsl:template match="/*">
          <html>
           <table border="1">
             <thead>
               <tr>
                <th>deps:</th>
                 <xsl:apply-templates select="$vDeps"/>
               </tr>
             </thead>
             <tbody>
                <tr>
                 <th>accidents:</th>
                 <xsl:apply-templates select="$vDeps" mode="acc"/>
               </tr>
                <tr>
                 <th>coms:</th>
                 <xsl:apply-templates select="$vDeps" mode="com"/>
               </tr>
             </tbody>
           </table>
          </html>
         </xsl:template>

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

         <xsl:template match="dep" mode="acc">
             <td><xsl:value-of select="count(key('kAccByDept', .))"/></td>
         </xsl:template>
         <xsl:template match="dep" mode="com">
             <td><xsl:value-of select="sum(key('kAccByDept', .)/com)"/></td>
         </xsl:template>
</xsl:stylesheet>

现在,当应用于同一个XML文档(上图)时,再次生成想要的答案

<html>
   <table border="1">
      <thead>
         <tr>
            <th>deps:</th>
            <td>010</td>
            <td>420</td>
            <td>002</td>
            <td>011</td>
         </tr>
      </thead>
      <tbody>
         <tr>
            <th>accidents:</th>
            <td>2</td>
            <td>1</td>
            <td>0</td>
            <td>0</td>
         </tr>
         <tr>
            <th>coms:</th>
            <td>238</td>
            <td>194</td>
            <td>0</td>
            <td>0</td>
         </tr>
      </tbody>
   </table>
</html>

答案 1 :(得分:0)

使用:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>

  <xsl:key name="k" match="accident" use="dep"/>

  <xsl:template match="/accidents">
    <xsl:variable name="accidents" select="accident[generate-id() 
                  = generate-id(key('k', dep))]"/>

    <table>
      <thead>
        <tr>
          <xsl:for-each select="$accidents">
            <th>
              <xsl:value-of select="dep"/>
            </th>
          </xsl:for-each>
        </tr>
      </thead>
      <tbody>
        <tr>
          <xsl:for-each select="$accidents">
            <td>
              <xsl:value-of select="count(key('k', dep))"/>
            </td>
          </xsl:for-each>
        </tr>
      </tbody>
    </table>
  </xsl:template>

</xsl:stylesheet>