2013-03-08 77 views
0

我很努力使用XSLT。我被困在程序性的土地上。 基本上我有一個會從看起來有點像這個數據庫中生成一些XML:嘗試使用XSLT從XML創建HTML表格

<?xml version="1.0" encoding="iso-8859-1"?> 
<report> 
    <generated_dtm>2013-03-08T18:57:26+00:00</generated_dtm> 

    <range> 
     <start_dtm>2013-02-21T17:52:00+00:00</start_dtm> 
     <end_dtm>2013-03-08T17:52:00+00:00</end_dtm> 
    </range> 

    <sensor site_code="A0001" unit_no="1" sensor_no="1"> 
     <name>Food</name> 
     <mu_symbol>°C</mu_symbol> 
    </sensor> 

    <sensor site_code="A0001" unit_no="1" sensor_no="2"> 
     <name>Air</name> 
     <mu_symbol>°C</mu_symbol> 
    </sensor> 

    <readings> 
     <slot slot_dtm="2013-02-21T17:50:00+00:00"> 
      <sensor sensor_no="1"> 
       <v>10</v> 
       <status_code>IR</status_code> 
       <status_desc>In Range</status_desc> 
      </sensor> 
      <sensor sensor_no="2"> 
       <v>20</v> 
       <status_code>Lo</status_code> 
       <status_desc>Low</status_desc> 
       </sensor> 
     </slot> 

     <slot slot_dtm="2013-02-21T18:00:00+00:00"> 
      <sensor sensor_no="2"> 
       <v>21</v> 
       <status_code>Lo</status_code> 
       <status_desc>Low</status_desc> 
      </sensor> 
      <sensor sensor_no="1"> 
       <v>11</v> 
       <status_code>IR</status_code> 
       <status_desc>In Range</status_desc> 
      </sensor> 
     </slot> 
    </readings> 
</report> 

我想在一個HTML表讀數結束了,每個傳感器是一列,每行與時間下來左手邊是這樣的:

Time      | Food | Air 
------------------------------------- 
2013-02-21T17:50:00+00:00 | 10 | 11 
2013-02-21T18:00:00+00:00 | 20 | 22 

雖然時隙的順序是保證上升,所以我並不需要對它們進行排序(有可能是1000年),問題在每個時隙內傳感器的順序不能得到保證,所以我想我會循環使用我用來創建表頭的傳感器,每個傳感器e,並且在迭代插槽時從每個插槽中選擇正確的傳感器。雖然這並不工作,你可能會得到什麼,我試圖做(我現在知道爲什麼它不工作..變量不規矩我沒有料到!): -

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:template match="report"> 
    <html> 
    <head> 
    <title>Report</title> 
    </head> 
    <body> 
     <table border="0" width="100%" bgcolor="#ffffff" cellspacing="0" cellpadding="2"> 
     <tr> 
      <td class="column_head_above" width="70">Time</td> 
      <xsl:for-each select="sensor"> 
      <td class="column_head_above"><xsl:value-of select="name"/><xsl:text> </xsl:text><xsl:value-of select="mu_symbol"/></td> 
      </xsl:for-each> 
     </tr> 

     <!-- go through each time slot --> 

     <xsl:for-each select="readings/slot"> 
      <tr> 
      <xsl:variable name="sdtm" select="@slot_dtm" /> 

      <td class="table_data"><xsl:value-of select="$sdtm"/></td> 

      <!-- go through each sensor header --> 

      <xsl:for-each select="../sensor"> 
       <xsl:variable name="sno" select="@sensor_no" /> 
       <td> 
       <xsl:value-of select="../readings/slot[@slot_dtm=$sdtm]/sensor[@sensor_no=$sno]/v"/> 
       <xsl:value-of select="../readings/slot[@slot_dtm=$sdtm]/sensor[@sensor_no=$sno]/status_desc"/> 
       </td> 
      </xsl:for-each> 

      </tr> 
     </xsl:for-each> 

     <!-- end: go through each time slot --> 

     </table> 
    </body> 
    </html> 
</xsl:template> 
</xsl:stylesheet> 

可以有100的甚至1000個時隙,這只是一個小例子。 如果有幫助,我可以調整XML的層次結構,但是我不能在每個時隙內按順序放置傳​​感器,而不會對數據庫查詢進行一些嚴重的返工。我希望這不是必要的。

我原本XML在插槽中分離出來是這樣的:

<readings> 
    <slot slot_dtm="2013-02-21T17:50:00+00:00"> 
     <sensor sensor_no="1"> 
      <v>10</v> 
      <status_code>IR</status_code> 
      <status_desc>In Range</status_desc> 
     </sensor> 
    </slot> 

    <slot slot_dtm="2013-02-21T17:50:00+00:00"> 
     <sensor sensor_no="2"> 
      <v>20</v> 
      <status_code>Lo</status_code> 
      <status_desc>Low</status_desc> 
      </sensor> 
    </slot> 

    <slot slot_dtm="2013-02-21T18:00:00+00:00"> 
     <sensor sensor_no="1"> 
      <v>11</v> 
      <status_code>IR</status_code> 
      <status_desc>In Range</status_desc> 
     </sensor> 
    </slot> 

    <slot slot_dtm="2013-02-21T18:00:00+00:00"> 
     <sensor sensor_no="2"> 
      <v>21</v> 
      <status_code>Lo</status_code> 
      <status_desc>Low</status_desc> 
     </sensor> 
    </slot> 
</readings> 

其中涉及一個更簡單的數據庫查詢!在這裏我可以保證順序,但是我使用的QQuery處理器(Qt的QXmlQuery)不支持for-each-group,所以我找不到一種基於時間進行分組的方法。

對不起,這是如此漫長,我希望有人能夠幫助至少把我指向正確的方向。

謝謝。

回答

1

這應做到:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:variable name="allSensors" select="/report/sensor" /> 

    <xsl:template match="report"> 
    <html> 
     <head> 
     <title>Report</title> 
     </head> 
     <body> 
     <table border="0" width="100%" bgcolor="#ffffff" 
       cellspacing="0" cellpadding="2"> 
      <tr> 
      <td class="column_head_above" width="70">Time</td> 
      <xsl:apply-templates select="sensor" /> 
      </tr> 
      <xsl:apply-templates select="readings/slot" /> 
     </table> 
     </body> 
    </html> 
    </xsl:template> 

    <xsl:template match="report/sensor"> 
    <td class="column_head_above"> 
     <xsl:value-of select="concat(name, ' ', mu_symbol)"/> 
    </td> 
    </xsl:template> 

    <xsl:template match="slot"> 
    <xsl:variable name="currentSensors" select="sensor" /> 
    <tr> 
     <td class="table_data"> 
     <xsl:value-of select="@slot_dtm"/> 
     </td> 

     <xsl:apply-templates select="$allSensors/@sensor_no"> 
     <xsl:with-param name="currentSlot" select="current()/@slot_dtm" /> 
     </xsl:apply-templates> 
    </tr> 
    </xsl:template> 

    <xsl:template match="@sensor_no"> 
    <xsl:param name="currentSlot" /> 

    <td> 
     <xsl:variable name="matchingSensor" 
        select="/report/readings/slot[@slot_dtm = $currentSlot] 
          /sensor[@sensor_no = current()]" /> 
     <xsl:value-of select="concat($matchingSensor/v, ' - ', 
             $matchingSensor/status_desc)" /> 
    </td> 
    </xsl:template> 
</xsl:stylesheet> 

我在這裏做了一些清理,但要點是:

  • 保持爲方便
  • 創建變量參考傳感器定義一個可變參考當前插槽的傳感器,可在for-each內引用。

當你的樣品輸入運行,這將產生:

<html> 
    <head> 
    <META http-equiv="Content-Type" content="text/html; charset=utf-8"> 
    <title>Report</title> 
    </head> 
    <body> 
    <table border="0" width="100%" bgcolor="#ffffff" cellspacing="0" cellpadding="2"> 
     <tr> 
     <td class="column_head_above" width="70">Time</td> 
     <td class="column_head_above">Food °C</td> 
     <td class="column_head_above">Air °C</td> 
     </tr> 
     <tr> 
     <td class="table_data">2013-02-21T17:50:00+00:00</td> 
     <td>10 - In Range</td> 
     <td>20 - Low</td> 
     </tr> 
     <tr> 
     <td class="table_data">2013-02-21T18:00:00+00:00</td> 
     <td>11 - In Range</td> 
     <td>21 - Low</td> 
     </tr> 
    </table> 
    </body> 
</html> 
+0

謝謝!自寫這個問題以來,我開始在這個地方找到它,並且與上面的內容相距甚遠。我認爲在仔細檢查後,它會被點擊。我會把我迄今爲止得到的答案放在一個單獨的答案中,但我會將你的答案標記爲正確答案。再次感謝:-) – Mark 2013-03-08 20:58:24

+0

問題:我已根據您的代碼更新了我的版本,但實際上它不工作。這可能與我使用的XSLT處理器有關(它是Qt 4.8.4中的一個,我認爲它使用libxml2),但基本上只要進入for-each循環,$ currentSensors就會變成空的,就像它一樣不存在。這基本上是我不得不從頭開始的問題,只要我進入for-each循環,以前的範圍內的任何東西似乎都不存在。有什麼想法嗎? – Mark 2013-03-09 09:15:01

+0

嗯,這很奇怪。你可以嘗試上述修改嗎?我爲'td'創建了一個單獨的模板,並傳遞'$ currentSensors'作爲參數。我想知道在這種情況下變量是否仍然會被忽略。 – JLRishe 2013-03-09 09:50:30

0

這裏是花一些時間想出來後的最新情況。感謝JLRishe的回答。在這之間以及我制定的計劃開始變得清晰(直到下一個問題!)。

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:template match="report"> 
    <html> 
    <head> 
    <title>Report</title> 
    </head> 
    <body> 
     <table border="0" width="100%" bgcolor="#ffffff" cellspacing="0" cellpadding="2"> 
     <tr> 
      <td class="column_head_above" width="70">Time</td> 
      <xsl:apply-templates select="sensors/sensor"> 
      <xsl:sort select="@sensor_no" /> 
      </xsl:apply-templates> 
     </tr> 

     <!-- go through each time slot --> 

     <xsl:for-each select="readings/slot"> 
      <tr> 
      <td class="table_data"><xsl:value-of select="@slot_dtm"/></td> 

      <!-- go through each sensor header --> 

      <xsl:apply-templates select="sensor"> 
       <xsl:sort select="@sensor_no" /> 
      </xsl:apply-templates> 

      </tr> 
     </xsl:for-each> 

     <!-- end: go through each time slot --> 

     </table> 
    </body> 
    </html> 
</xsl:template> 

<xsl:template match="slot/sensor"> 
    <td> 
     <xsl:value-of select="@sensor_no"/> - 
     <xsl:value-of select="v"/> - 
     <xsl:value-of select="status_desc"/> 
    </td> 
</xsl:template> 

<xsl:template match="sensors/sensor"> 
    <td class="column_head_above"> 
     <xsl:value-of select="name"/><xsl:text> </xsl:text><xsl:value-of select="mu_symbol"/> 
    </td> 
</xsl:template> 

</xsl:stylesheet> 
+0

這種方法的一個限制是,如果任何''元素丟失了''(我不知道你的情況是否會發生這種情況),你可能會缺少'​​'。如果ID始終爲數字,我會建議將'data-type =「numeric」'添加到'xsl:sort's。 – JLRishe 2013-03-09 09:54:32