Хитрое XSLT-преобразование - PullRequest
       5

Хитрое XSLT-преобразование

0 голосов
/ 23 сентября 2011

У меня есть слабо структурированные данные XHTML, и мне нужно преобразовать их в более структурированный XML.

Вот пример:

<tbody>
<tr>
    <td class="header"><img src="http://www.abc.com/images/icon_apples.gif"/><img src="http://www.abc.com/images/flag/portugal.gif" alt="Portugal"/> First Grade</td>
</tr>
<tr>
    <td>Green</td>
    <td>Round shaped</td>
    <td>Tasty</td>
</tr>
<tr>
    <td>Red</td>
    <td>Round shaped</td>
    <td>Bitter</td>
</tr>
<tr>
    <td>Pink</td>
    <td>Round shaped</td>
    <td>Tasty</td>
</tr>
<tr>
    <td class="header"><img src="http://www.abc.com/images/icon_strawberries.gif"/><img src="http://www.abc.com/images/flag/usa.gif" alt="USA"/> Fifth Grade</td>
</tr>
<tr>
    <td>Red</td>
    <td>Heart shaped</td>
    <td>Super tasty</td>
</tr>
<tr>
    <td class="header"><img src="http://www.abc.com/images/icon_bananas.gif"/><img src="http://www.abc.com/images/flag/congo.gif" alt="Congo"/> Third Grade</td>
</tr>
<tr>
    <td>Yellow</td>
    <td>Smile shaped</td>
    <td>Fairly tasty</td>
</tr>
<tr>
    <td>Brown</td>
    <td>Smile shaped</td>
    <td>Too sweet</td>
</tr>

Я пытаюсьдобиться следующей структуры:

    <data>
    <entry>
        <type>Apples</type>
        <country>Portugal</country>
        <rank>First Grade</rank>
        <color>Green</color>
        <shape>Round shaped</shape>
        <taste>Tasty</taste>
    </entry>
    <entry>
        <type>Apples</type>
        <country>Portugal</country>
        <rank>First Grade</rank>
        <color>Red</color>
        <shape>Round shaped</shape>
        <taste>Bitter</taste>
    </entry>
    <entry>
        <type>Apples</type>
        <country>Portugal</country>
        <rank>First Grade</rank>
        <color>Pink</color>
        <shape>Round shaped</shape>
        <taste>Tasty</taste>
    </entry>
    <entry>
        <type>Strawberries</type>
        <country>USA</country>
        <rank>Fifth Grade</rank>
        <color>Red</color>
        <shape>Heart shaped</shape>
        <taste>Super</taste>
    </entry>
    <entry>
        <type>Bananas</type>
        <country>Congo</country>
        <rank>Third Grade</rank>
        <color>Yellow</color>
        <shape>Smile shaped</shape>
        <taste>Fairly tasty</taste>
    </entry>
    <entry>
        <type>Bananas</type>
        <country>Congo</country>
        <rank>Third Grade</rank>
        <color>Brown</color>
        <shape>Smile shaped</shape>
        <taste>Too sweet</taste>
    </entry>
</data>

Во-первых, мне нужно извлечь тип фрукта из tbody / tr / td / img [1] / @ src , во-вторых, страну из Атрибут tbody / tr / td / img [2] / @ alt и, наконец, оценка самого tbody / tr / td .

Далее мне нужно заполнить все записи вкаждая категория, включая эти значения (как показано выше).

Но ... Как вы видите, данные, которые мне дали, очень слабо структурированы.Категория - это просто td , и после этого идут все предметы в этой категории.Что еще хуже, в моих наборах данных количество элементов в каждой категории варьируется от 1 до 100 ...

Я пробовал несколько подходов, но, похоже, не могу его получить.Любая помощь очень ценится.Я знаю, что XSLT 2.0 вводит xsl: for-each-group, но я ограничен XSLT 1.0.

1 Ответ

3 голосов
/ 23 сентября 2011

В этом случае вы на самом деле не группируете элементы.Это больше похоже на разгруппировку.

Один из способов сделать это - использовать xsl: key для поиска строки «заголовка» для каждой из строк сведений.

<xsl:key name="fruity" 
   match="tr[not(td[@class='header'])]" 
   use="generate-id(preceding-sibling::tr[td[@class='header']][1])"/>

т.е. для каждой строки сведений получите самую предыдущую строку заголовка.

Затем вы можете сопоставить все строки заголовка следующим образом:

<xsl:apply-templates select="tr/td[@class='header']"/>

Внутри соответствующего шаблона,Вы можете извлечь тип, страну и звание.Затем, чтобы получить связанные строки подробностей, это простой случай просмотра ключа родительской строки:

<xsl:apply-templates select="key('fruity', generate-id(..))">

Вот общий XSLT

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

   <xsl:key name="fruity" 
      match="tr[not(td[@class='header'])]" 
      use="generate-id(preceding-sibling::tr[td[@class='header']][1])"/>

   <xsl:template match="/tbody">
      <data>
         <!-- Match header rows -->
         <xsl:apply-templates select="tr/td[@class='header']"/>
      </data>
   </xsl:template>

   <xsl:template match="td">
      <!-- Match associated detail rows -->
      <xsl:apply-templates select="key('fruity', generate-id(..))">
         <!-- Extract relevant parameters from the td cell -->
         <xsl:with-param name="type" select="substring-before(substring-after(img[1]/@src, 'images/icon_'), '.gif')"/>
         <xsl:with-param name="country" select="img[2]/@alt"/>
         <xsl:with-param name="rank" select="normalize-space(text())"/>
      </xsl:apply-templates>
   </xsl:template>

   <xsl:template match="tr">
      <xsl:param name="type"/>
      <xsl:param name="country"/>
      <xsl:param name="rank"/>
      <entry>
         <type>
            <xsl:value-of select="$type"/>
         </type>
         <country>
            <xsl:value-of select="$country"/>
         </country>
         <rank>
            <xsl:value-of select="$rank"/>
         </rank>
         <color>
            <xsl:value-of select="td[1]"/>
         </color>
         <shape>
            <xsl:value-of select="td[2]"/>
         </shape>
         <taste>
            <xsl:value-of select="td[3]"/>
         </taste>
      </entry>
   </xsl:template>
</xsl:stylesheet>

Применительно к вашемувходной документ, генерируется следующий вывод:

<data>
   <entry>
      <type>apples</type>
      <country>Portugal</country>
      <rank>First Grade</rank>
      <color>Green</color>
      <shape>Round shaped</shape>
      <taste>Tasty</taste>
   </entry>
   <entry>
      <type>apples</type>
      <country>Portugal</country>
      <rank>First Grade</rank>
      <color>Red</color>
      <shape>Round shaped</shape>
      <taste>Bitter</taste>
   </entry>
   <entry>
      <type>apples</type>
      <country>Portugal</country>
      <rank>First Grade</rank>
      <color>Pink</color>
      <shape>Round shaped</shape>
      <taste>Tasty</taste>
   </entry>
   <entry>
      <type>strawberries</type>
      <country>USA</country>
      <rank>Fifth Grade</rank>
      <color>Red</color>
      <shape>Heart shaped</shape>
      <taste>Super tasty</taste>
   </entry>
   <entry>
      <type>bananas</type>
      <country>Congo</country>
      <rank>Third Grade</rank>
      <color>Yellow</color>
      <shape>Smile shaped</shape>
      <taste>Fairly tasty</taste>
   </entry>
   <entry>
      <type>bananas</type>
      <country>Congo</country>
      <rank>Third Grade</rank>
      <color>Brown</color>
      <shape>Smile shaped</shape>
      <taste>Too sweet</taste>
   </entry>
</data>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...