Как вы делаете оператор for-each, который меняет значение переменной каждый раз, когда оно повторяется? - PullRequest
0 голосов
/ 12 февраля 2012

Iv'e получил XML-файл, содержащий данные об играх, которые загружаются в формате .exe; название игры; расположение изображения и альтернативный текст для использования. Который сортируется по категориям. (См. Ниже)

<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="games.xsl"?>
<all>
 <general>
  <catagory_name>
   <catg_1>Action</catg_1>
   <catg_2>Other</catg_2>
  </catagory_name>
 </general>
 <games>
  <catagory name='Action'>
   <game>
    <name>1945<!--name--></name>
    <url><!--URL to game download--></url>
    <image><!--image location--></image>
    <alt>1945 Icon<!--alt text for image--></alt>
   </game>
  </catagory>
  <catagory name='Other'>
   <game>
    <name>Platform Game<!--name--></name>
    <url><!--URL to game download--></url>
    <image><!--image location--></image>
    <alt>Platform Game Icon<!--alt text for image--></alt>
   </game>
  </catagory>
 </games>
</all>

Затем я получил этот xslt-файл для преобразования xml в xhtml ...

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:template match="/all">
  <html>
   <body>
    <h1 style="text-align:center;">Games</h1>
    <center>
     <table>
      <xsl:if test="//general/catagory_name/catg_1">
       <xsl:variable name="catg">
        <xsl:value-of select="//general/catagory_name/catg_1"/>
       </xsl:variable>
       <xsl:if test="//games/catagory[@name=$catg]/game[position() = (1)]/url">
        <tr>
         <td colspan="4" rowspan="1">
          <h2>
           <xsl:copy-of select="$catg"/>
          </h2>
         </td>
        </tr>
        <xsl:for-each select="//games/catagory[@name=$catg]/game[position() mod 4 = 1]">
         <xsl:variable name="pos" select="position() * 4"/>
         <tr>
          <xsl:if test="//games/catagory[@name=$catg]/game[position() = ($pos - 3)]/url">
           <td>
            <a>
             <xsl:attribute name="href">
              <xsl:value-of select="normalize-space(//games/catagory[@name=$catg]/game[position() = ($pos - 3)]/url)"/>
             </xsl:attribute>
             <img>
              <xsl:attribute name="src">
               <xsl:value-of select="normalize-space(//games/catagory[@name=$catg]/game[position() = ($pos - 3)]/image)"/>
              </xsl:attribute>
              <xsl:attribute name="alt">
               <xsl:value-of select="normalize-space(//games/catagory[@name=$catg]/game[position() = ($pos - 3)]/alt)"/>
              </xsl:attribute>
             </img>
            </a>
           </td>
          </xsl:if>
          <xsl:if test="//games/catagory[@name=$catg]/game[position() = ($pos - 2)]/url">
           <td>
            <a>
             <xsl:attribute name="href">
              <xsl:value-of select="normalize-space(//games/catagory[@name=$catg]/game[position() = ($pos - 2)]/url)"/>
             </xsl:attribute>
             <img>
              <xsl:attribute name="src">
               <xsl:value-of select="normalize-space(//games/catagory[@name=$catg]/game[position() = ($pos - 2)]/image)"/>
              </xsl:attribute>
              <xsl:attribute name="alt">
               <xsl:value-of select="normalize-space(//games/catagory[@name=$catg]/game[position() = ($pos - 2)]/alt)"/>
              </xsl:attribute>
             </img>
            </a>
           </td>
          </xsl:if>
          <xsl:if test="//games/catagory[@name=$catg]/game[position() = ($pos - 1)]/url">
           <td>
            <a>
             <xsl:attribute name="href">
              <xsl:value-of select="normalize-space(//games/catagory[@name=$catg]/game[position() = ($pos - 1)]/url)"/>
             </xsl:attribute>
             <img>
              <xsl:attribute name="src">
               <xsl:value-of select="normalize-space(//games/catagory[@name=$catg]/game[position() = ($pos - 1)]/image)"/>
              </xsl:attribute>
              <xsl:attribute name="alt">
               <xsl:value-of select="normalize-space(//games/catagory[@name=$catg]/game[position() = ($pos - 1)]/alt)"/>
              </xsl:attribute>
             </img>
            </a>
           </td>
          </xsl:if>
          <xsl:if test="//games/catagory[@name=$catg]/game[position() = ($pos)]/url">
           <td>
            <a>
             <xsl:attribute name="href">
              <xsl:value-of select="normalize-space(//games/catagory[@name=$catg]/game[position() = ($pos)]/url)"/>
             </xsl:attribute>
             <img>
              <xsl:attribute name="src">
               <xsl:value-of select="normalize-space(//games/catagory[@name=$catg]/game[position() = ($pos)]/image)"/>
              </xsl:attribute>
              <xsl:attribute name="alt">
               <xsl:value-of select="normalize-space(//games/catagory[@name=$catg]/game[position() = ($pos)]/alt)"/>
              </xsl:attribute>
             </img>
            </a>
           </td>
          </xsl:if>
         </tr>
         <tr>
          <xsl:if test="//games/catagory[@name=$catg]/game[position() = ($pos - 3)]/url">
           <td>
            <a>
             <xsl:attribute name="href">
              <xsl:value-of select="normalize-space(//games/catagory[@name=$catg]/game[position() = ($pos - 3)]/url)"/>
             </xsl:attribute>
             <p>
              <xsl:value-of select="//games/catagory[@name=$catg]/game[position() = ($pos -3)]/name"/>
             </p>
            </a>
           </td>
          </xsl:if>
          <xsl:if test="//games/catagory[@name=$catg]/game[position() = ($pos - 2)]/url">
           <td>
            <a>
             <xsl:attribute name="href">
              <xsl:value-of select="normalize-space(//games/catagory[@name=$catg]/game[position() = ($pos - 2)]/url)"/>
             </xsl:attribute>
             <p>
              <xsl:value-of select="//games/catagory[@name=$catg]/game[position() = ($pos -2)]/name"/>
             </p>
            </a>
           </td>
          </xsl:if>
          <xsl:if test="//games/catagory[@name=$catg]/game[position() = ($pos - 1)]/url">
           <td>
            <a>
             <xsl:attribute name="href">
              <xsl:value-of select="normalize-space(//games/catagory[@name=$catg]/game[position() = ($pos - 1)]/url)"/>
             </xsl:attribute>
             <p>
              <xsl:value-of select="//games/catagory[@name=$catg]/game[position() = ($pos -1)]/name"/>
             </p>
            </a>
           </td>
          </xsl:if>
          <xsl:if test="//games/catagory[@name=$catg]/game[position() = ($pos)]/url">
           <td>
            <a>
             <xsl:attribute name="href">
              <xsl:value-of select="normalize-space(//games/catagory[@name=$catg]/game[position() = ($pos)]/url)"/>
             </xsl:attribute>
             <p>
              <xsl:value-of select="//games/catagory[@name=$catg]/game[position() = ($pos)]/name"/>
             </p>
            </a>
           </td>
          </xsl:if>
         </tr>
        </xsl:for-each>
       </xsl:if>
      </xsl:if>
      <xsl:if test="//general/catagory_name/catg_2">
       <xsl:variable name="catg2">
        <xsl:value-of select="//general/catagory_name/catg_2"/>
       </xsl:variable>
       <xsl:if test="//games/catagory[@name=$catg2]/game[position() = (1)]/url">
        <tr>
         <td colspan="4" rowspan="1">
          <h2>
           <xsl:copy-of select="$catg2"/>
          </h2>
         </td>
        </tr>
        <xsl:for-each select="//games/catagory[@name=$catg2]/game[position() mod 4 = 1]">
         <xsl:variable name="pos" select="position() * 4"/>
         <tr>
          <xsl:if test="//games/catagory[@name=$catg2]/game[position() = ($pos - 3)]/url">
           <td>
            <a>
             <xsl:attribute name="href">
              <xsl:value-of select="normalize-space(//games/catagory[@name=$catg2]/game[position() = ($pos - 3)]/url)"/>
             </xsl:attribute>
             <img>
              <xsl:attribute name="src">
               <xsl:value-of select="normalize-space(//games/catagory[@name=$catg2]/game[position() = ($pos - 3)]/image)"/>
              </xsl:attribute>
              <xsl:attribute name="alt">
               <xsl:value-of select="normalize-space(//games/catagory[@name=$catg2]/game[position() = ($pos - 3)]/alt)"/>
              </xsl:attribute>
             </img>
            </a>
           </td>
          </xsl:if>
          <xsl:if test="//games/catagory[@name=$catg2]/game[position() = ($pos - 2)]/url">
           <td>
            <a>
             <xsl:attribute name="href">
              <xsl:value-of select="normalize-space(//games/catagory[@name=$catg2]/game[position() = ($pos - 2)]/url)"/>
             </xsl:attribute>
             <img>
              <xsl:attribute name="src">
               <xsl:value-of select="normalize-space(//games/catagory[@name=$catg2]/game[position() = ($pos - 2)]/image)"/>
              </xsl:attribute>
              <xsl:attribute name="alt">
               <xsl:value-of select="normalize-space(//games/catagory[@name=$catg2]/game[position() = ($pos - 2)]/alt)"/>
              </xsl:attribute>
             </img>
            </a>
           </td>
          </xsl:if>
          <xsl:if test="//games/catagory[@name=$catg2]/game[position() = ($pos - 1)]/url">
           <td>
            <a>
             <xsl:attribute name="href">
              <xsl:value-of select="normalize-space(//games/catagory[@name=$catg2]/game[position() = ($pos - 1)]/url)"/>
             </xsl:attribute>
             <img>
              <xsl:attribute name="src">
               <xsl:value-of select="normalize-space(//games/catagory[@name=$catg2]/game[position() = ($pos - 1)]/image)"/>
              </xsl:attribute>
              <xsl:attribute name="alt">
               <xsl:value-of select="normalize-space(//games/catagory[@name=$catg2]/game[position() = ($pos - 1)]/alt)"/>
              </xsl:attribute>
             </img>
            </a>
           </td>
          </xsl:if>
          <xsl:if test="//games/catagory[@name=$catg2]/game[position() = ($pos)]/url">
           <td>
            <a>
             <xsl:attribute name="href">
              <xsl:value-of select="normalize-space(//games/catagory[@name=$catg2]/game[position() = ($pos)]/url)"/>
             </xsl:attribute>
             <img>
              <xsl:attribute name="src">
               <xsl:value-of select="normalize-space(//games/catagory[@name=$catg2]/game[position() = ($pos)]/image)"/>
              </xsl:attribute>
              <xsl:attribute name="alt">
               <xsl:value-of select="normalize-space(//games/catagory[@name=$catg2]/game[position() = ($pos)]/alt)"/>
              </xsl:attribute>
             </img>
            </a>
           </td>
          </xsl:if>
         </tr>
         <tr>
          <xsl:if test="//games/catagory[@name=$catg2]/game[position() = ($pos - 3)]/url">
           <td>
            <a>
             <xsl:attribute name="href">
              <xsl:value-of select="normalize-space(//games/catagory[@name=$catg2]/game[position() = ($pos - 3)]/url)"/>
             </xsl:attribute>
             <p>
              <xsl:value-of select="//games/catagory[@name=$catg2]/game[position() = ($pos -3)]/name"/>
             </p>
            </a>
           </td>
          </xsl:if>
          <xsl:if test="//games/catagory[@name=$catg2]/game[position() = ($pos - 2)]/url">
           <td>
            <a>
             <xsl:attribute name="href">
              <xsl:value-of select="normalize-space(//games/catagory[@name=$catg2]/game[position() = ($pos - 2)]/url)"/>
             </xsl:attribute>
             <p>
              <xsl:value-of select="//games/catagory[@name=$catg2]/game[position() = ($pos -2)]/name"/>
             </p>
            </a>
           </td>
          </xsl:if>
          <xsl:if test="//games/catagory[@name=$catg2]/game[position() = ($pos - 1)]/url">
           <td>
            <a>
             <xsl:attribute name="href">
              <xsl:value-of select="normalize-space(//games/catagory[@name=$catg2]/game[position() = ($pos - 1)]/url)"/>
             </xsl:attribute>
             <p>
              <xsl:value-of select="//games/catagory[@name=$catg2]/game[position() = ($pos -1)]/name"/>
             </p>
            </a>
           </td>
          </xsl:if>
          <xsl:if test="//games/catagory[@name=$catg2]/game[position() = ($pos)]/url">
           <td>
            <a>
             <xsl:attribute name="href">
              <xsl:value-of select="normalize-space(//games/catagory[@name=$catg2]/game[position() = ($pos)]/url)"/>
             </xsl:attribute>
             <p>
              <xsl:value-of select="//games/catagory[@name=$catg2]/game[position() = ($pos)]/name"/>
             </p>
            </a>
           </td>
          </xsl:if>
         </tr>
        </xsl:for-each>
       </xsl:if>
      </xsl:if>
     </table>
    </center>
   </body>
  </html>
 </xsl:template>
</xsl:stylesheet>

Этот код работает абсолютно нормально, однако он уже довольно сложен. Сначала он проверяет, существует ли конкретная категория, а затем есть ли в этой категории какие-либо игры. Затем он отображает это, но только если данные существуют. Так что вы будете рады, что все в порядке. Моя проблема в том, что каждый раз, когда я хочу добавить новую категорию, я должен зайти в файл xslt и добавить код ниже с переменной $ catg, называемой $ catg1, $ catg2 и так далее, для всех катагорий, которые мне нужны, потому что вы можете не изменять значение существующей переменной.

 <xsl:if test="//general/catagory_name/catg_2">
  <xsl:variable name="catg2">
   <xsl:value-of select="//general/catagory_name/catg_2"/>
  </xsl:variable>
  <xsl:if test="//games/catagory[@name=$catg2]/game[position() = (1)]/url">
   <tr>
    <td colspan="4" rowspan="1">
     <h2>
      <xsl:copy-of select="$catg2"/>
     </h2>
    </td>
   </tr>
   <xsl:for-each select="//games/catagory[@name=$catg2]/game[position() mod 4 = 1]">
    <xsl:variable name="pos" select="position() * 4"/>
    <tr>
     <xsl:if test="//games/catagory[@name=$catg2]/game[position() = ($pos - 3)]/url">
      <td>
       <a>
        <xsl:attribute name="href">
         <xsl:value-of select="normalize-space(//games/catagory[@name=$catg2]/game[position() = ($pos - 3)]/url)"/>
        </xsl:attribute>
        <img>
         <xsl:attribute name="src">
          <xsl:value-of select="normalize-space(//games/catagory[@name=$catg2]/game[position() = ($pos - 3)]/image)"/>
         </xsl:attribute>
         <xsl:attribute name="alt">
          <xsl:value-of select="normalize-space(//games/catagory[@name=$catg2]/game[position() = ($pos - 3)]/alt)"/>
         </xsl:attribute>
        </img>
       </a>
      </td>
     </xsl:if>
     <xsl:if test="//games/catagory[@name=$catg2]/game[position() = ($pos - 2)]/url">
      <td>
       <a>
        <xsl:attribute name="href">
         <xsl:value-of select="normalize-space(//games/catagory[@name=$catg2]/game[position() = ($pos - 2)]/url)"/>
        </xsl:attribute>
        <img>
         <xsl:attribute name="src">
          <xsl:value-of select="normalize-space(//games/catagory[@name=$catg2]/game[position() = ($pos - 2)]/image)"/>
         </xsl:attribute>
         <xsl:attribute name="alt">
          <xsl:value-of select="normalize-space(//games/catagory[@name=$catg2]/game[position() = ($pos - 2)]/alt)"/>
         </xsl:attribute>
        </img>
       </a>
      </td>
     </xsl:if>
     <xsl:if test="//games/catagory[@name=$catg2]/game[position() = ($pos - 1)]/url">
      <td>
       <a>
        <xsl:attribute name="href">
         <xsl:value-of select="normalize-space(//games/catagory[@name=$catg2]/game[position() = ($pos - 1)]/url)"/>
        </xsl:attribute>
        <img>
         <xsl:attribute name="src">
          <xsl:value-of select="normalize-space(//games/catagory[@name=$catg2]/game[position() = ($pos - 1)]/image)"/>
         </xsl:attribute>
         <xsl:attribute name="alt">
          <xsl:value-of select="normalize-space(//games/catagory[@name=$catg2]/game[position() = ($pos - 1)]/alt)"/>
         </xsl:attribute>
        </img>
       </a>
      </td>
     </xsl:if>
     <xsl:if test="//games/catagory[@name=$catg2]/game[position() = ($pos)]/url">
      <td>
       <a>
        <xsl:attribute name="href">
         <xsl:value-of select="normalize-space(//games/catagory[@name=$catg2]/game[position() = ($pos)]/url)"/>
        </xsl:attribute>
        <img>
         <xsl:attribute name="src">
          <xsl:value-of select="normalize-space(//games/catagory[@name=$catg2]/game[position() = ($pos)]/image)"/>
         </xsl:attribute>
         <xsl:attribute name="alt">
          <xsl:value-of select="normalize-space(//games/catagory[@name=$catg2]/game[position() = ($pos)]/alt)"/>
         </xsl:attribute>
        </img>
       </a>
      </td>
     </xsl:if>
    </tr>
    <tr>
     <xsl:if test="//games/catagory[@name=$catg2]/game[position() = ($pos - 3)]/url">
      <td>
       <a>
        <xsl:attribute name="href">
         <xsl:value-of select="normalize-space(//games/catagory[@name=$catg2]/game[position() = ($pos - 3)]/url)"/>
        </xsl:attribute>
        <p>
         <xsl:value-of select="//games/catagory[@name=$catg2]/game[position() = ($pos -3)]/name"/>
        </p>
       </a>
      </td>
     </xsl:if>
     <xsl:if test="//games/catagory[@name=$catg2]/game[position() = ($pos - 2)]/url">
      <td>
       <a>
        <xsl:attribute name="href">
         <xsl:value-of select="normalize-space(//games/catagory[@name=$catg2]/game[position() = ($pos - 2)]/url)"/>
        </xsl:attribute>
        <p>
         <xsl:value-of select="//games/catagory[@name=$catg2]/game[position() = ($pos -2)]/name"/>
        </p>
       </a>
      </td>
     </xsl:if>
     <xsl:if test="//games/catagory[@name=$catg2]/game[position() = ($pos - 1)]/url">
      <td>
       <a>
        <xsl:attribute name="href">
         <xsl:value-of select="normalize-space(//games/catagory[@name=$catg2]/game[position() = ($pos - 1)]/url)"/>
        </xsl:attribute>
        <p>
         <xsl:value-of select="//games/catagory[@name=$catg2]/game[position() = ($pos -1)]/name"/>
        </p>
       </a>
      </td>
     </xsl:if>
     <xsl:if test="//games/catagory[@name=$catg2]/game[position() = ($pos)]/url">
      <td>
       <a>
        <xsl:attribute name="href">
         <xsl:value-of select="normalize-space(//games/catagory[@name=$catg2]/game[position() = ($pos)]/url)"/>
        </xsl:attribute>
        <p>
         <xsl:value-of select="//games/catagory[@name=$catg2]/game[position() = ($pos)]/name"/>
        </p>
       </a>
      </td>
     </xsl:if>
    </tr>
   </xsl:for-each>
  </xsl:if>
 </xsl:if>

Что я хочу сделать, так это уметь использовать для каждого из них, поэтому нужно иметь только один код (см. Выше), настолько сложный, который никогда не нуждается в изменении для новой категории. Итак, мой вопрос, как бы я это сделал? Я пробовал с переменными ect, но вам все равно придется редактировать код каждый раз, когда вы хотите новую категорию, потому что вы не можете изменить значение существующей переменной.

Единственное решение, которое я могу придумать, это заменить $ catg значением узла, которое он представляет, то есть general / catagory_name / catg, и зацикливать его каждый раз, но я не добился успеха.

Ответы [ 2 ]

2 голосов
/ 12 февраля 2012

Простой ответ на вопрос в заголовке: «Вы не можете». Переменные XSLT имеют несколько неправильное имя, так как они не могут быть изменены после их создания.

Существует два стиля XSLT. Вы пытаетесь использовать XSLT процедурным образом, когда таблица стилей находится под контролем, и вы «извлекаете» необходимые данные из входного документа. Это обычно идет вразрез с предполагаемым использованием XSLT, который по своей природе гораздо более декларативен. Стиль «push» опирается на процесс XSLT для естественного чтения входного XML и передачи вам интересующих вас событий, которые вы определили с помощью соответствующих шаблонов. Простой поиск в Google по запросу "xslt push vs pull" предоставит вам много информации.

Для очень простых таблиц стилей pull-style часто приводит к сокращению кода, но с ростом сложности (как в вашем случае) push-стиль может быть значительно проще для чтения и понимания, при условии, что вы понимаете, как работает поток обработки XSLT. Лучшее объяснение того, как XSLT обрабатывает ваш ввод, можно найти в «Справочнике по карману XSLT 1.0» Эвана Ленца (я не связан ни с О'Рейли, ни с мистером Ленцем). Кроме того, статья Википедии о XSLT довольно хорошо описывает основы.

Переход от процедурного мышления к XSLT требует значительной корректировки, но как только вы почувствуете это "ага!" Если научиться мыслить декларативно, все становится намного проще.

1 голос
/ 13 февраля 2012

Используйте OL для нумерации их от 1.

Выберите каждую категорию, независимо от дублированных значений.

Узнайте, является ли это первым появлением категории, по идентификатору первой игры,и идентификатор первой игры в той же категории.

Если это первое вхождение категории, просто примените шаблоны для каждой игры с предком в качестве данной категории.Используйте li для каждой категории и используйте классы и CSS для достижения табличного упорядочения.

Сортировки добавляются для получения отсортированного вывода ...

<xsl:template name="categoryList">
    <ol>
    <xsl:for-each select="//game/ancestor::category">
        <xsl:sort select="@name" />
        <xsl:variable name="name" select="@name"/>
        <xsl:variable name="gameid1" select="generate-id(game[1])"/>
        <xsl:variable name="gameidFirst" select="generate-id(//game[ancestor::category[@name=$name]][1])"/>
        <xsl:if test="$gameid1=$gameidFirst">
            <li><xsl:value-of select="@name"/>
                <xsl:apply-templates select="//game[ancestor::category[@name=$name]]">
                    <xsl:sort select="name/text()"/>
                </xsl:apply-templates>
            </li>
        </xsl:if>
    </xsl:for-each>
    </ol>
</xsl:template>

<xsl:template match="game">
                <div>
                    Name:<span class="name"><xsl:value-of select="name"/></span>,
                    URL:<span class="url"><xsl:value-of select="url"/></span>,
                    Image:<span class="image"><xsl:value-of select="image"/></span>,
                </div>
</xsl:template>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...