计算XML文档中特定节点的频率

时间:2011-02-21 11:02:01

标签: xml xslt xpath

之前可能已经介绍过,但经过大量谷歌搜索后,我似乎找不到任何例子。基本上我正在试图获得一本书借出的时间的频率计数。下面给出了我的XML树,以及XSL和结果输出。

    <?xml-stylesheet type="text/xsl" href="LoanStyler.xsl"?>
<loans>
  <loan id="0001">
    <summary>
      <user>AAA</user>
      <dateOut>2011-01-01</dateOut>
      <dateDue>2011-01-14</dateDue>
    </summary>
    <details>
      <books>
        <name>Book7</name>
        <name>Book4</name>
      </books>
    </details>
  </loan>
  <loan id="0002">
    <summary>
      <user>BBB</user>
      <dateOut>2011-01-10</dateOut>
      <dateDue>2011-01-24</dateDue>
    </summary>
    <details>
      <books>
        <name>Book1</name>
        <name>Book2</name>
        <name>Book4</name>
        <name>Book6</name>
      </books>
    </details>
  </loan>
  <loan id="0003">
    <summary>
      <user>CCC</user>
      <dateOut>2011-01-14</dateOut>
      <dateDue>2011-01-28</dateDue>
    </summary>
    <details>
      <books>
        <name>Book1</name>
        <name>Book3</name>
        <name>Book4</name>
        <name>Book7</name>
        <name>Book8</name>
      </books>
    </details>
  </loan>
  <loan id="0004">
    <summary>
      <user>DDD</user>
      <dateOut>2011-02-01</dateOut>
      <dateDue>2011-02-14</dateDue>
    </summary>
    <details>
      <books>
        <name>Book1</name>
        <name>Book2</name>
        <name>Book4</name>
      </books>
    </details>
  </loan>
</loans>

    <?xml version="1.0" encoding="ISO-8859-1"?>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:key 
    name="books-by-name" 
    match="//loans/loan/details/books" 
    use="name" 
  />


<xsl:template match="/">
  <html>
  <body>
    <h1>Loan Records Log</h1>
    <table Border="1">
        <tr>
            <th>Loan ID</th>
            <th>User</th>
            <th>Date Out</th>
            <th>Date Due</th>
        </tr>
        <xsl:for-each select="//loans/loan">
            <tr>
                <td><xsl:value-of select="@id"/></td>
                <td><xsl:value-of select="summary/user"/></td>
                <td><xsl:value-of select="summary/dateOut"/></td>
                <td><xsl:value-of select="summary/dateDue"/></td>
            </tr>
        </xsl:for-each>
    </table>

    <table Border="1">
        <tr>
            <th>Book name</th>
            <th>Count</th>
        </tr>

        <xsl:for-each select="books[count(. | key('books-by-name', name)[1]) = 1]">
            <tr>
                <td><xsl:value-of select="name" /></td>
                <td><xsl:value-of select="count(key('books-by-name', name))" /></td>
            </tr>
        </xsl:for-each>
    </table>
  </body>
  </html>
</xsl:template>

</xsl:stylesheet>

Loan Records Log
Loan ID User    Date Out    Date Due
0001    AAA 2011-01-01  2011-01-14
0002    BBB 2011-01-10  2011-01-24
0003    CCC 2011-01-14  2011-01-28
0004    DDD 2011-02-01  2011-02-14
Book name   Count

正如您所看到的,对Muenchian Grouping的尝试似乎并不起作用。有人可以解释一下我做错了什么,因为我能找到的唯一例子似乎没有帮助。

1 个答案:

答案 0 :(得分:3)

问题在于

   <xsl:for-each select="books
                 [count(. | key('books-by-name', name)[1]) = 1]"> 

必须

   <xsl:for-each select="loans/loan/details/books
                 [count(. | key('books-by-name', name)[1]) = 1]"> 

在指定上述指令的位置,当前节点为//没有子元素books

此外,还存在逻辑错误。关键必须是不同的。

以下是更正后的解决方案

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:key      name="books-by-name"
    match="books/name"      use="."    />
    <xsl:template match="/">
        <html>
            <body>
                <h1>Loan Records Log</h1>
                <table Border="1">
                    <tr>
                        <th>Loan ID</th>
                        <th>User</th>
                        <th>Date Out</th>
                        <th>Date Due</th>
                    </tr>
                    <xsl:for-each select="//loans/loan">
                        <tr>
                            <td>
                                <xsl:value-of select="@id"/>
                            </td>
                            <td>
                                <xsl:value-of select="summary/user"/>
                            </td>
                            <td>
                                <xsl:value-of select="summary/dateOut"/>
                            </td>
                            <td>
                                <xsl:value-of select="summary/dateDue"/>
                            </td>
                        </tr>
                    </xsl:for-each>
                </table>
                <table Border="1">
                    <tr>
                        <th>Book name</th>
                        <th>Count</th>
                    </tr>
                    <xsl:for-each select="loans/loan/details/books/name
                            [count(. | key('books-by-name', name)[1]) = 1]">
                        <tr>
                            <td>
                                <xsl:value-of select="." />
                            </td>
                            <td>
                                <xsl:value-of select="count(key('books-by-name',.))" />
                            </td>
                        </tr>
                    </xsl:for-each>
                </table>
            </body>
        </html>
    </xsl:template>
</xsl:stylesheet>

在提供的XML文档上应用此转换时:

<loans>
    <loan id="0001">
        <summary>
            <user>AAA</user>
            <dateOut>2011-01-01</dateOut>
            <dateDue>2011-01-14</dateDue>
        </summary>
        <details>
            <books>
                <name>Book7</name>
                <name>Book4</name>
            </books>
        </details>
    </loan>
    <loan id="0002">
        <summary>
            <user>BBB</user>
            <dateOut>2011-01-10</dateOut>
            <dateDue>2011-01-24</dateDue>
        </summary>
        <details>
            <books>
                <name>Book1</name>
                <name>Book2</name>
                <name>Book4</name>
                <name>Book6</name>
            </books>
        </details>
    </loan>
    <loan id="0003">
        <summary>
            <user>CCC</user>
            <dateOut>2011-01-14</dateOut>
            <dateDue>2011-01-28</dateDue>
        </summary>
        <details>
            <books>
                <name>Book1</name>
                <name>Book3</name>
                <name>Book4</name>
                <name>Book7</name>
                <name>Book8</name>
            </books>
        </details>
    </loan>
    <loan id="0004">
        <summary>
            <user>DDD</user>
            <dateOut>2011-02-01</dateOut>
            <dateDue>2011-02-14</dateDue>
        </summary>
        <details>
            <books>
                <name>Book1</name>
                <name>Book2</name>
                <name>Book4</name>
            </books>
        </details>
    </loan>
</loans>

产生了想要的正确结果:

<html>
   <body>
      <h1>Loan Records Log</h1>
      <table Border="1">
         <tr>
            <th>Loan ID</th>
            <th>User</th>
            <th>Date Out</th>
            <th>Date Due</th>
         </tr>
         <tr>
            <td>0001</td>
            <td>AAA</td>
            <td>2011-01-01</td>
            <td>2011-01-14</td>
         </tr>
         <tr>
            <td>0002</td>
            <td>BBB</td>
            <td>2011-01-10</td>
            <td>2011-01-24</td>
         </tr>
         <tr>
            <td>0003</td>
            <td>CCC</td>
            <td>2011-01-14</td>
            <td>2011-01-28</td>
         </tr>
         <tr>
            <td>0004</td>
            <td>DDD</td>
            <td>2011-02-01</td>
            <td>2011-02-14</td>
         </tr>
      </table>
      <table Border="1">
         <tr>
            <th>Book name</th>
            <th>Count</th>
         </tr>
         <tr>
            <td>Book7</td>
            <td>2</td>
         </tr>
         <tr>
            <td>Book4</td>
            <td>4</td>
         </tr>
         <tr>
            <td>Book1</td>
            <td>3</td>
         </tr>
         <tr>
            <td>Book2</td>
            <td>2</td>
         </tr>
         <tr>
            <td>Book4</td>
            <td>4</td>
         </tr>
         <tr>
            <td>Book6</td>
            <td>1</td>
         </tr>
         <tr>
            <td>Book1</td>
            <td>3</td>
         </tr>
         <tr>
            <td>Book3</td>
            <td>1</td>
         </tr>
         <tr>
            <td>Book4</td>
            <td>4</td>
         </tr>
         <tr>
            <td>Book7</td>
            <td>2</td>
         </tr>
         <tr>
            <td>Book8</td>
            <td>1</td>
         </tr>
         <tr>
            <td>Book1</td>
            <td>3</td>
         </tr>
         <tr>
            <td>Book2</td>
            <td>2</td>
         </tr>
         <tr>
            <td>Book4</td>
            <td>4</td>
         </tr>
      </table>
   </body>
</html>