2014-12-17 2 views
1

У меня есть XSLT, который я создал для группировки данных для каталога обуви. Обувь должна быть сгруппирована по «линии» и «бренду». Заголовки Line и Brand должны появляться в начале каждого раздела. Каждая строка имеет более одного бренда. У каждого бренда обычно есть несколько ботинок.Группировка данных с использованием XSLT не работает полностью

Ниже приведен пример XML-данных:

<?xml version="1.0" encoding="UTF-8"?> 
<catalog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
<shoe> 
    <line>LINE 43: WOMENS BRANDED ATHLETIC</line> 
    <brand>WALKING</brand> 
    <style-name>NEW BALANCE-NB 475V2 (WIDE)</style-name> 
    <color>Black</color> 
    <price>67.99</price> 
</shoe> 
<shoe> 
    <line>LINE 43: WOMENS BRANDED ATHLETIC</line> 
    <brand>WALKING</brand> 
    <style-name>NEW BALANCE-496 (WIDE)</style-name> 
    <color>Grey/Pink</color> 
    <price>64.99</price> 
</shoe> 
<shoe> 
    <line>LINE 43: WOMENS BRANDED ATHLETIC</line> 
    <brand>CROSS TRANING</brand> 
    <style-name>FILA-MEMORY PANACHE</style-name> 
    <color>Black/Pink</color> 
    <price>69.99</price> 
</shoe> 
<shoe> 
    <line>LINE 43: WOMENS BRANDED ATHLETIC</line> 
    <brand>RUNNING</brand> 
    <style-name>FILA-VITALITY 2 TRAIL</style-name> 
    <color>Grey/Prpl/Turq</color> 
    <price>59.99</price> 
</shoe> 
<shoe> 
    <line>LINE 87: MENS BRANDED ATHLETIC</line> 
    <brand>CASUAL</brand> 
    <style-name>LEVI'S-HAMILTON BUCK HI</style-name> 
    <color>Black/Black</color> 
    <price>34.99</price> 
</shoe> 
<shoe> 
    <line>LINE 87: MENS BRANDED ATHLETIC</line> 
    <brand>CASUAL</brand> 
    <style-name>EVERLAST-EVAN SKATE</style-name> 
    <color>Black</color> 
    <price>29.99</price> 
</shoe> 
<shoe> 
    <line>LINE 87: MENS BRANDED ATHLETIC</line> 
    <brand>RUNNING</brand> 
    <style-name>SKECHERS-POWER SWITCH (WIDE)</style-name> 
    <color>Black/White</color> 
    <price>69.99</price> 
</shoe> 
<shoe> 
    <line>LINE 87: MENS BRANDED ATHLETIC</line> 
    <brand>RUNNING</brand> 
    <style-name>SKECHERS-EQUALIZER GEL TOP </style-name> 
    <color>Black</color> 
    <price>69.99</price> 
</shoe> 
</catalog> 

Вот мой XSLT:

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE xsl:stylesheet> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="xml" encoding="UTF-8"/> 

    <xsl:key name="shoes-by-line" match="shoe" use="line" /> 
    <xsl:key name="shoes-by-brand" match="shoe" use="concat(line,'#',brand)" /> 

    <xsl:template match="catalog"> 
     <catalog> 
      <shoes> 
       <xsl:for-each select="shoe[count(. | key('shoes-by-line', line)[1]) = 1]"> 
        <line> 
         <xsl:value-of select="line"/> 
        </line> 
        <brands> 
         <brand> 
          <xsl:value-of select="brand"/> 
         </brand> 
         <xsl:for-each select="key('shoes-by-brand', concat(line,'#',brand))"> 
          <shoe> 
           <style-name> 
            <xsl:value-of select="style-name"/> 
           </style-name> 
           <color> 
            <xsl:value-of select="color"/> 
           </color> 
           <price> 
            <xsl:value-of select="price"/> 
           </price> 
          </shoe> 
         </xsl:for-each> 
        </brands> 
       </xsl:for-each> 
      </shoes> 
     </catalog> 
    </xsl:template> 

</xsl:stylesheet> 

Я получаю 1 "линия" и "бренд" 1, но я не получаю дополнительный брендов в каждой строке. В каждой строке должно быть не менее двух-трех брендов. В этом XML есть 2 строки.

Вот структуру XML, что я хочу:

<?xml version="1.0" encoding="UTF-8"?> 
<catalog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
<lines> 
    <line>LINE 43: WOMENS BRANDED ATHLETIC</line> 
<brands> 
    <brand>WALKING</brand> 
<shoes> 
<shoe> 
    <style-name>NEW BALANCE-NB 475V2 (WIDE)</style-name> 
    <color>Black</color> 
    <price>67.99</price> 
</shoe> 
<shoe> 
    <style-name>NEW BALANCE-496 (WIDE)</style-name> 
    <color>Grey/Pink</color> 
    <price>64.99</price> 
</shoe> 
</shoes> 
</brands> 
</lines> 
<lines> 
    <line>LINE 43: WOMENS BRANDED ATHLETIC</line> 
<brands> 
    <brand>CROSS TRANING</brand> 
<shoes> 
<shoe> 
    <style-name>FILA-MEMORY PANACHE</style-name> 
    <color>Black/Pink</color> 
    <price>69.99</price> 
</shoe> 
<shoe> 
    <line>LINE 43: WOMENS BRANDED ATHLETIC</line> 
    <brand>RUNNING</brand> 
    <style-name>FILA-VITALITY 2 TRAIL</style-name> 
    <color>Grey/Prpl/Turq</color> 
    <price>59.99</price> 
</shoe> 
</shoes> 
</brands> 
</lines> 
<lines> 
    <line>LINE 87: MENS BRANDED ATHLETIC</line> 
<brands> 
    <brand>CASUAL</brand> 
<shoes> 
<shoe> 
    <style-name>LEVI'S-HAMILTON BUCK HI</style-name> 
    <color>Black/Black</color> 
    <price>34.99</price> 
</shoe> 
<shoe> 
    <style-name>EVERLAST-EVAN SKATE</style-name> 
    <color>Black</color> 
    <price>29.99</price> 
</shoe> 
</shoes> 
</brands> 
</lines> 
<lines> 
    <line>LINE 87: MENS BRANDED ATHLETIC</line> 
<brands> 
    <brand>RUNNING</brand> 
<shoes> 
<shoe> 
    <line>LINE 87: MENS BRANDED ATHLETIC</line> 
<brands> 
    <brand>RUNNING</brand> 
<shoes> 
<shoe> 
    <style-name>SKECHERS-POWER SWITCH (WIDE)</style-name> 
    <color>Black/White</color> 
    <price>69.99</price> 
</shoe> 
<shoe> 
    <style-name>SKECHERS-EQUALIZER GEL TOP </style-name> 
    <color>Black</color> 
    <price>69.99</price> 
</shoe> 
</shoes> 
</brands> 
</lines> 
</catalog> 

ответ

0

Я пересмотрел XSLT Я считаю, что нашел решение с помощью XSLT 1.0

<?xml version="1.0" encoding="UTF-8"?><!-- DWXMLSource="D76-shoebook.xml" --> 
<!DOCTYPE xsl:stylesheet> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output method="xml" encoding="UTF-8"/> 

<xsl:key name="shoes-by-line" match="shoe" use="line"/> 
<xsl:key name="shoes-by-brand" match="shoe" use="concat(line, '|', brand)"/> 
<xsl:template match="catalog"> 

<catalog> 
<xsl:for-each select="shoe[generate-id() = generate-id(key('shoes-by-line', line)[1])]"> 
<lines> 
<xsl:for-each select="key('shoes-by-line', line)[generate-id() = generate-id(key('shoes-by-brand', concat(line, '|', brand))[1])]"> 
<line><xsl:value-of select="line"/></line><xsl:text> 
</xsl:text><brand><xsl:value-of select="brand"/></brand><xsl:text> 
</xsl:text><shoes> 
<xsl:for-each select="key('shoes-by-brand', concat(line, '|', brand))"> 
<shoe> 
<style-name><xsl:value-of select="style-name" /></style-name> 
<color><xsl:value-of select="color" /></color><xsl:text> 
<price><xsl:value-of select="price" /></price><xsl:text> 
</xsl:text>     
</shoe>   
      </xsl:for-each> 
     </shoes> 
     </xsl:for-each> 
</lines> 
</xsl:for-each> 
</catalog> 
</xsl:template> 
</xsl:stylesheet> 

Это создает правильную группировку и гнездится из исходного XML манипуляции в автономном режиме, а затем на BRAND.

1

С некоторыми изменениями в вашем XSLT генерируется разыскиваемый результат:

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE xsl:stylesheet> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output method="xml" encoding="UTF-8"/> 
    <xsl:key name="shoes-by-line" match="shoe" use="line" /> 
    <xsl:key name="shoes-by-brand" match="shoe" use="concat(line,'#',brand)" /> 
    <xsl:template match="catalog"> 
    <catalog> 
     <xsl:for-each select="shoe[count(. | key('shoes-by-line', line)[1]) = 1]"> 
      <lines> 
       <line> 
        <xsl:value-of select="line"/> 
       </line> 
       <brands> 
        <brand> 
         <xsl:value-of select="brand"/> 
        </brand> 
        <shoes> 
         <xsl:for-each select="key('shoes-by-brand', concat(line,'#',brand))"> 
          <shoe> 
           <style-name> 
            <xsl:value-of select="style-name"/> 
           </style-name> 
           <color> 
            <xsl:value-of select="color"/> 
           </color> 
           <price> 
            <xsl:value-of select="price"/> 
           </price> 
          </shoe> 
         </xsl:for-each> 
        </shoes> 
       </brands> 
      </lines> 
     </xsl:for-each> 
    </catalog> 
    </xsl:template> 
</xsl:stylesheet> 

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

До:

<catalog> 
    <shoes> 
     <xsl:for-each select="shoe[count(. | key('shoes-by-line', line)[1]) = 1]"> 
      <line> 
      <xsl:value-of select="line"/> 
      </line> 
      <brands> 
      <brand> 
       <xsl:value-of select="brand"/> 
      </brand> 
       <xsl:for-each select="key('shoes-by-brand', 
             concat(line,'#',brand))"> 
        <shoe> 
         ... 

Скорректированная:

<catalog> 
    <xsl:for-each select="shoe[count(. | key('shoes-by-line', line)[1]) = 1]"> 
     <lines> 
      <line> 
       <xsl:value-of select="line"/> 
      </line> 
      <brands> 
       <brand> 
        <xsl:value-of select="brand"/> 
       </brand> 
       <shoes> 
        <xsl:for-each select="key('shoes-by-brand', 
              concat(line,'#',brand))"> 
         <shoe> 
          ... 

Update: Как заметил в комментарии выше XSLT не обеспечивает правильный вывод. Так же, как другой подход: после XSLT с использованием xsl:for-each-group вместо ключей:

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE xsl:stylesheet> 
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output method="xml" encoding="UTF-8"/> 
    <xsl:template match="catalog"> 
    <catalog> 
     <xsl:for-each-group select="shoe" group-by="line"> 
      <xsl:for-each-group select="current-group()" group-by="brand"> 
       <lines> 
        <line> 
         <xsl:value-of select="line"></xsl:value-of> 
        </line> 
        <brands> 
         <xsl:for-each-group select="current-group()" group-by="brand"> 
          <brand> 
           <xsl:value-of select="current-grouping-key()"></xsl:value-of> 
          </brand> 
          <shoes> 
           <xsl:for-each select="current-group()"> 
            <shoe> 
             <style-name> 
              <xsl:value-of select="style-name"/> 
             </style-name> 
             <color> 
              <xsl:value-of select="color"/> 
             </color> 
             <price> 
              <xsl:value-of select="price"/> 
             </price> 
            </shoe> 
           </xsl:for-each> 
          </shoes> 
         </xsl:for-each-group> 
        </brands> 
       </lines> 
      </xsl:for-each-group> 
     </xsl:for-each-group> 
    </catalog> 
    </xsl:template> 
</xsl:stylesheet> 

применительно к вашей входной XML производит следующий вывод:

<?xml version="1.0" encoding="UTF-8"?> 
<catalog> 
    <lines> 
    <line>LINE 43: WOMENS BRANDED ATHLETIC</line> 
    <brands> 
     <brand>WALKING</brand> 
     <shoes> 
      <shoe> 
       <style-name>NEW BALANCE-NB 475V2 (WIDE)</style-name> 
       <color>Black</color> 
       <price>67.99</price> 
      </shoe> 
      <shoe> 
       <style-name>NEW BALANCE-496 (WIDE)</style-name> 
       <color>Grey/Pink</color> 
       <price>64.99</price> 
      </shoe> 
     </shoes> 
    </brands> 
    </lines> 
    <lines> 
    <line>LINE 43: WOMENS BRANDED ATHLETIC</line> 
    <brands> 
     <brand>CROSS TRANING</brand> 
     <shoes> 
      <shoe> 
       <style-name>FILA-MEMORY PANACHE</style-name> 
       <color>Black/Pink</color> 
       <price>69.99</price> 
      </shoe> 
     </shoes> 
    </brands> 
    </lines> 
    <lines> 
    <line>LINE 43: WOMENS BRANDED ATHLETIC</line> 
    <brands> 
     <brand>RUNNING</brand> 
     <shoes> 
      <shoe> 
       <style-name>FILA-VITALITY 2 TRAIL</style-name> 
       <color>Grey/Prpl/Turq</color> 
       <price>59.99</price> 
      </shoe> 
     </shoes> 
    </brands> 
    </lines> 
    <lines> 
    <line>LINE 87: MENS BRANDED ATHLETIC</line> 
    <brands> 
     <brand>CASUAL</brand> 
     <shoes> 
      <shoe> 
       <style-name>LEVI'S-HAMILTON BUCK HI</style-name> 
       <color>Black/Black</color> 
       <price>34.99</price> 
      </shoe> 
      <shoe> 
       <style-name>EVERLAST-EVAN SKATE</style-name> 
       <color>Black</color> 
       <price>29.99</price> 
      </shoe> 
     </shoes> 
    </brands> 
    </lines> 
    <lines> 
    <line>LINE 87: MENS BRANDED ATHLETIC</line> 
    <brands> 
     <brand>RUNNING</brand> 
     <shoes> 
      <shoe> 
       <style-name>SKECHERS-POWER SWITCH (WIDE)</style-name> 
       <color>Black/White</color> 
       <price>69.99</price> 
      </shoe> 
      <shoe> 
       <style-name>SKECHERS-EQUALIZER GEL TOP </style-name> 
       <color>Black</color> 
       <price>69.99</price> 
      </shoe> 
     </shoes> 
    </brands> 
    </lines> 
</catalog> 

Заметьте, что есть одна разница от требуемой мощности, как указано в OP - марка RUNNING для линии LINE 43: WOMENS BRANDED ATHLETIC - это отдельный бренд, а не бренд CROSS TRAINING, но, возможно, это небольшая ошибка в желаемом выходе. В противном случае необходимо будет найти решение для получения RUNNING и CROSS TRAINING, перечисленных в той же марки.

Поскольку обувь должна быть указана для каждой марки каждой линии, <xsl:for-each-group select="shoe" group-by="line"> выбирает сначала все туфли, сгруппированные по строкам. Затем все бренды этой группы выбираются брендом с использованием <xsl:for-each-group select="current-group()" group-by="brand"> и всех туфель марки, обработанной в петле <xsl:for-each select="current-group()">.

Обновление: Как упоминалось в комментариях, это таблица стилей XSLT 2.0. Я только что исправил версию в вышеуказанном шаблоне. Хотя я протестировал шаблон с помощью онлайн-теста XSLT, который был объявлен как версия 1.0, он не выдавал никакой ошибки (хотя он должен был иметь).

+2

На мой взгляд, ваш ответ может быть значительно улучшен, если вы добавили объяснение выполненных вами корректировок. –

+0

@ MathiasMüller Спасибо за ваши проблемы, я в настоящее время добавляю это, поскольку я разделяю ваше мнение, а также не предпочитаю давать только ответы на код (хотя настройки здесь были незначительными). –

+0

Это решение еще не дает правильного вывода. Когда я запускаю этот отрегулированный XSLT, он показывает только две LINES (43 и 87) с одним BRAND (WALKING & CASUAL) каждый. Если вы посмотрите на образец XML, в «LINE» 43 и 2 «BRANDS» в «LINE» 87 есть 3 BRANDS. –

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