2013-03-08 4 views
0

Я борюсь с XSLT. Я застрял в процедурной земле. В принципе у меня есть некоторые XML, который получает сгенерированный из базы данных, которая выглядит немного как это:Попытка использовать XSLT для создания таблицы HTML из XML

<?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> 

который включал гораздо более простой запрос к базе данных! Здесь я мог бы гарантировать порядок, но процессор XQuery, который я использую (Qt QXmlQuery), не поддерживает для каждой группы, поэтому я не мог найти способ группировки в зависимости от времени.

Извините, что так долго, надеюсь, кто-то может помочь хотя бы указать мне в правильном направлении.

Спасибо.

ответ

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

+0

Проблема: я обновил свою версию на основе вашего кода и на самом деле не работает.Вероятно, это связано с используемым мной процессором XSLT (это тот, который я использую в Qt 4.8.4, который, как мне кажется, использует libxml2), но в основном, как только я вхожу в цикл for-each, currentSensors становится пустым, например не существует. Это в основном проблема, с которой мне пришлось начинать, что, как только я вхожу в цикл для каждого, ничего из предыдущей области, похоже, не существует. Есть предположения? – Mark

+0

Хм, это очень странно. Не могли бы вы попробовать вышеупомянутую модификацию? Я создал отдельный шаблон для 'td' s и пропускаю '$ currentSensors' в качестве параметра. Интересно, будет ли переменная по-прежнему игнорироваться в этом случае. – JLRishe

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

Одним из ограничений этого подхода является то, что у вас может отсутствовать '' s, если какой-либо элемент '' отсутствует '' (я не знаю, может ли это произойти в вашем случае). Я бы предложил добавить 'data-type =" numeric "' в 'xsl: sort', если идентификаторы всегда будут числовыми. – JLRishe

 Смежные вопросы

  • Нет связанных вопросов^_^