你如何创建for-each语句,每次循环时都会更改变量值?

时间:2012-02-12 18:10:48

标签: xml xslt variables

我有一个包含游戏数据的xml文件,这是一个.exe下载;游戏名称;图像位置和要使用的备用文本。哪个被分类到catagorys。 (见下文)

<?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等所有我需要的catagorys因为你可以不要改变现有变量的值。

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

我想要做的是能够为每个人使用一个,所以只需要有一个代码(上面),但是复杂,从来不需要改变一个新的类别。所以我的问题是我该怎么做?我尝试过变量等,但是每次你想要一个新的类别时你仍然需要编辑代码,因为你无法改变现有变量的值。

我能想到的唯一解决方案是将$ catg替换为它所代表的节点值,即general / catagory_name / catg并每次循环它但我没有取得任何成功。

2 个答案:

答案 0 :(得分:2)

标题中问题的简单答案是“你不能”。 XSLT变量有点错误命名,因为它们在创建后无法更改。

有两种样式的XSLT,您试图以过程方式使用XSLT,样式表处于控制状态,您可以从输入文档中“提取”所需的数据。这通常与XSLT的预期用法背道而驰,XSLT本质上更具说明性。 “push”样式依赖于XSLT进程自然地读取输入XML并将您感兴趣的事件交给您,这些事件是由匹配模板定义的。一个简单的Google search on "xslt push vs pull"将为您提供大量信息。

对于非常简单的样式表,pull-style通常会产生更短的代码,但是随着复杂性的增加(如在您的情况下),推送样式可以更容易阅读和理解,假设您了解XSLT处理流程的工作原理。我已经看到过XSLT如何处理输入的最佳解释可以在Evan Lenz的“XSLT 1.0 Pocket Reference”中找到(我与O'Reilly或Lenz先生没有联系)。 Wikipedia article on XSLT也很好地涵盖了基础知识。

从程序思维到XSLT需要进行重大调整,但一旦你体验到“啊哈!”时刻并学会以声明的方式思考,一切都变得简单得多。

答案 1 :(得分:1)

使用OL从1开始编号。

选择每个类别,无论重复的值如何。

确定这是第一次出现的类别,第一个游戏的ID,以及同一类别中首个游戏的ID。

如果这是第一次出现的类别,只需为每个游戏应用模板,并将祖先作为给定类别。对每个类别使用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>