Поворот XML с использованием XSLT - PullRequest
4 голосов
/ 07 января 2010

Использование XML в этом формате:

<?xml version="1.0"?>
<GetResult version="1.0">
<Fetch>
    <StartTime>2004-08-01 00:00:00</StartTime>
    <EndTime>2004-08-01 00:00:00</EndTime>
</Fetch>
<Items>
    <Item>
        <Name>Item Name Number 1</Name>
        <Data>
            <Datum>
                <Timestamp>2004-07-31 16:00:00+00:00</Timestamp>
                <Value><![CDATA[25]]></Value>
            </Datum>
            <Datum>
                <Timestamp>2004-07-31 18:00:00+00:00</Timestamp>
                <Value><![CDATA[35]]></Value>
            </Datum>
        </Data>
    </Item> 
    <Item>
        <Name>Item Number 2</Name>
        <Data>
            <Datum>
                <Timestamp>2004-07-31 16:00:00+00:00</Timestamp>
                <Value><![CDATA[45]]></Value>
            </Datum>
            <Datum>
                <Timestamp>2004-07-31 17:00:00+00:00</Timestamp>
                <Value><![CDATA[55]]></Value>
            </Datum>
            <Datum>
                <Timestamp>2004-07-31 18:00:00+00:00</Timestamp>
                <Value><![CDATA[65]]></Value>
            </Datum>
        </Data>
    </Item> 
</Items>
</GetResult>

Я бы хотел создать такую ​​таблицу, используя XSLT:

<table>
  <tr>
    <th>Timestamp</th>
    <th>Item Name Number 1</th>
    <th>Item Number 2</th>
  </tr>
  <tr>
    <td>2004-07-31 16:00:00+00:00</td>
    <td>25</td>
    <td>45</td>
  </tr>
  <tr>
    <td>2004-07-31 17:00:00+00:00</td>
    <td></td>
    <td>55</td>
  </tr>
  <tr>
    <td>2004-07-31 18:00:00+00:00</td>
    <td>35</td>
    <td>65</td>
  </tr>
</table>

Это должно работать независимо от того, сколько элементов возвращено и сколько датумов для каждого элемента. Я прочитал несколько других ответов, которые похожи без удачи. Я довольно новичок в XSLT, и это сводит меня с ума. Решение для этого будет высоко ценится.

Ответы [ 2 ]

3 голосов
/ 07 января 2010

Вот метод, который использует довольно пугающий метод Muenchian Grouping, о котором вы, вероятно, упомянули, если вы посмотрите на другие проблемы XSLT в StackOverflow, поэтому его стоит знать. В этом случае Muenchian Grouping будет использоваться для циклического обхода элементов Timestamp района.

Сначала вы определяете ключ для поиска элементов отметки времени

<xsl:key name="Timestamps" match="Timestamp" use="."/>

Таким образом, если вы используете это для поиска ключа '2004-07-31 16: 00: 00 + 00: 00', он будет содержать две метки времени, но '2004-07-31 17:00 : 00 + 00: 00 'будет содержать только один.

Чтобы циклически проходить по разным элементам Timestamp, вы сначала должны пройти по всем элементам Timestamp, например

<xsl:for-each select="//Timestamp">

Но тогда вам потребуется условие XSL: IF, чтобы проверить, что элемент Timestamp является первым подобным случаем этого значения. Это делается с помощью ключа. Если элемент окажется первым в списке ключей, он может быть обработан.

<xsl:if test="generate-id(.) = generate-id(key('Timestamps',.)[1])">

generate-id - это метод, который нужно использовать, когда вы хотите проверить два одинаковых элемента. В целом это дает:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:key name="Timestamps" match="Timestamp" use="."/>
   <xsl:template match="/">
      <table>
         <tr>
            <th>Timestamp</th>
            <!-- Output the Item headers -->
            <xsl:for-each select="//Item">
               <th>
                  <xsl:value-of select="Name"/>
               </th>
            </xsl:for-each>
         </tr>
         <!-- Loop through all Timestamps -->
         <xsl:for-each select="//Timestamp">
            <xsl:sort select="."/>
            <!-- Only process the element if it is the first occurence of this value -->
            <xsl:if test="generate-id(.) = generate-id(key('Timestamps',.)[1])">
               <xsl:variable name="Timestamp" select="."/>
               <tr>
                  <td>
                     <xsl:value-of select="."/>
                  </td>
                  <xsl:for-each select="//Item">
                     <td>
                        <!-- Output the relevant Value for the Item -->
                        <xsl:value-of select="Data/Datum[Timestamp=$Timestamp][1]/Value"/>
                     </td>
                  </xsl:for-each>
               </tr>
            </xsl:if>
         </xsl:for-each>
      </table>
   </xsl:template>
</xsl:stylesheet>
1 голос
/ 07 января 2010

Есть несколько шагов, которые вы должны сделать.

  1. получить список предметов
  2. получить список временных меток
  3. для каждой временной отметки вы должны печатать значение для каждого элемента

Это может звучать сложно, но это действительно просто, если вы знаете основы XSLT

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:variable name="items" select="//Item" />
  <xsl:variable name="timestamps" select="distinct-values(//Timestamp)" />

  <xsl:template match="/" >
     <table>
       <tr>
         <th>Timestamp</th>
         <xsl:for-each select="$items">
           <th><xsl:value-of select="Name" /></th>
         </xsl:for-each>
       </tr>

       <xsl:for-each select="$timestamps">
         <xsl:variable name="stamp" select="."/>
         <tr>
           <td><xsl:value-of select="$stamp" /></td>
           <xsl:for-each select="$items">
             <td><xsl:value-of select=".//Datum[ Timestamp = $stamp ]/Value" /></td>
           </xsl:for-each>
         </tr>
       </xsl:for-each>

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

Я надеюсь, что ошибок нет. Если им потом их жаль, но я думаю, что основная идея ясна и правильна.

Если у вас есть вопросы, не стесняйтесь спрашивать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...