XSLT中for-each内部使用apply-templates

5
我有一个以下的XSLT,想在xsl:for-each元素内使用apply-templates,这样我就不必重复带有"cliente" XML元素信息的<tr>元素。
我尝试着创建一个xsl:template并将xsl:apply-templates放在xsl:for-each内部,但没有成功。
我知道我可以使用xsl:call-template,但是否有任何方法可以在for-each内外使用xsl:apply-templates
你有任何想法吗?
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:template match="/">
      <html>
         <head><title>Informações</title></head>
         <body>
            <h1>Relação de Clientes</h1>
            <table border="2">
               <tr bgcolor="LightBlue">
                  <th>Nome</th>
                  <th>Telefone</th>
                  <th>Cidade</th>
                  <th>Estado</th>
                  <th>Crédito</th>
               </tr>
               <tr>
                  <th colspan="6" bgcolor="LightPink">Critério usado abaixo: exibir todos os elementos ordenado por nome</th>
               </tr>
               <xsl:for-each select="informacoes/cliente">
               <xsl:sort select="nome" order="ascending" />
                  <tr>
                     <td bgcolor="LightGreen"><xsl:value-of  select="nome"/></td>
                     <td><xsl:value-of  select="telefone"/></td>
                     <td><xsl:value-of select="cidade"/></td>
                     <td><xsl:value-of select="estado"/></td>
                     <td><xsl:value-of select="credito"/></td>
                  </tr>
               </xsl:for-each>
               <tr>
                  <th colspan="6" bgcolor="LightCyan"> Critério usado abaixo: exibir os clientes da cidade do Rio de Janeiro</th>
               </tr>
               <xsl:for-each select="informacoes/cliente">
                   <xsl:if test="cidade='Rio de Janeiro'">
                      <tr>
                         <td bgcolor="LightGreen"><xsl:value-of  select="nome"/></td>
                         <td><xsl:value-of  select="telefone"/></td>
                         <td><xsl:value-of select="cidade"/></td>
                         <td><xsl:value-of select="estado"/></td>
                         <td><xsl:value-of select="credito"/></td>
                      </tr>
                    </xsl:if>
                </xsl:for-each>
               <tr>
                  <th colspan="6" bgcolor="LightYellow"> Critério usado abaixo:  exibir os clientes do estado do RJ com ordenado pelo nome; </th>
               </tr>
               <xsl:for-each select="informacoes/cliente">
               <xsl:sort select="nome" order="ascending" />
               <xsl:if test="estado='RJ'">
                  <tr>
                     <td bgcolor="LightGreen"><xsl:value-of  select="nome"/></td>
                     <td><xsl:value-of  select="telefone"/></td>
                     <td><xsl:value-of select="cidade"/></td>
                     <td><xsl:value-of select="estado"/></td>
                     <td><xsl:value-of select="credito"/></td>
                  </tr>
                </xsl:if>
                  </xsl:for-each>
               <tr>
                  <th colspan="6" bgcolor="LightYellow"> Critério usado abaixo:  exibir os clientes com crédito entre 250 e 400, em ordem descendente de crédito) </th>
               </tr>
               <xsl:for-each select="informacoes/cliente">
               <xsl:sort select="credito" order="descending" />
               <xsl:if test="credito&gt;250 and credito&lt;400">
                  <tr>
                     <td bgcolor="LightGreen"><xsl:value-of  select="nome"/></td>
                     <td><xsl:value-of  select="telefone"/></td>
                     <td><xsl:value-of select="cidade"/></td>
                     <td><xsl:value-of select="estado"/></td>
                     <td><xsl:value-of select="credito"/></td>
                  </tr>
                </xsl:if>
                  </xsl:for-each>
               </table>
            </body>
         </html>
      </xsl:template>
</xsl:stylesheet>
2个回答

7
在你的 xsl:for-each 中遍历 informacoes/cliente,上下文节点将是当前的 cliente 元素。
为了对上下文节点应用模板,您可以在选择语句中使用 .。例如:
<xsl:for-each select="informacoes/cliente">
  <xsl:sort select="nome" order="ascending" />
  <xsl:apply-templates select="."/>
</xsl:for-each>

接下来,创建模板以匹配cliente元素:

<xsl:template match="informacoes/cliente">
    <tr>
        <td bgcolor="LightGreen"><xsl:value-of  select="nome"/></td>
        <td><xsl:value-of  select="telefone"/></td>
        <td><xsl:value-of select="cidade"/></td>
        <td><xsl:value-of select="estado"/></td>
        <td><xsl:value-of select="credito"/></td>
    </tr>
</xsl:template>

您还可以通过使用self::轴引用当前上下文节点,然后在上下文节点的谓词过滤器中应用测试条件来消除某些项目周围的<xsl:if>测试:

  <xsl:for-each select="informacoes/cliente">
     <xsl:sort select="nome" order="ascending" />
     <xsl:apply-templates select="self::*[estado='RJ']"/>
  </xsl:for-each>

将这些更改应用到您的示例样式表中:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
        <html>
            <head><title>Informações</title></head>
            <body>
                <h1>Relação de Clientes</h1>
                <table border="2">
                    <tr bgcolor="LightBlue">
                        <th>Nome</th>
                        <th>Telefone</th>
                        <th>Cidade</th>
                        <th>Estado</th>
                        <th>Crédito</th>
                    </tr>
                    <tr>
                        <th colspan="6" bgcolor="LightPink">Critério usado abaixo: exibir todos os elementos ordenado por nome</th>
                    </tr>
                    <xsl:for-each select="informacoes/cliente">
                        <xsl:sort select="nome" order="ascending" />
                        <xsl:apply-templates select="."/>
                    </xsl:for-each>
                    <tr>
                        <th colspan="6" bgcolor="LightCyan"> Critério usado abaixo: exibir os clientes da cidade do Rio de Janeiro</th>
                    </tr>
                    <xsl:for-each select="informacoes/cliente">
                        <xsl:apply-templates select="self::*[cidade='Rio de Janeiro']"/>
                    </xsl:for-each>
                    <tr>
                        <th colspan="6" bgcolor="LightYellow"> Critério usado abaixo:  exibir os clientes do estado do RJ com ordenado pelo nome; </th>
                    </tr>
                    <xsl:for-each select="informacoes/cliente">
                        <xsl:sort select="nome" order="ascending" />
                        <xsl:apply-templates select="self::*[estado='RJ']"/>
                    </xsl:for-each>
                    <tr>
                        <th colspan="6" bgcolor="LightYellow"> Critério usado abaixo:  exibir os clientes com crédito entre 250 e 400, em ordem descendente de crédito) </th>
                    </tr>
                    <xsl:for-each select="informacoes/cliente">
                        <xsl:sort select="credito" order="descending" />
                        <xsl:apply-templates select="self::*[credito&gt;250 and credito&lt;400]"/>
                    </xsl:for-each>
                </table>
            </body>
        </html>
    </xsl:template>

    <xsl:template match="informacoes/cliente">
        <tr>
            <td bgcolor="LightGreen"><xsl:value-of  select="nome"/></td>
            <td><xsl:value-of  select="telefone"/></td>
            <td><xsl:value-of select="cidade"/></td>
            <td><xsl:value-of select="estado"/></td>
            <td><xsl:value-of select="credito"/></td>
        </tr>
    </xsl:template>
</xsl:stylesheet>   

正如Dimitre Novatchev的回答所示,您可以通过消除xsl:for-each语句并调整xsl:apply-templates选择语句来进一步简化样式表; 在必要时在应用模板内部应用xsl:sort以确保所选的cliente元素按照期望的顺序进行处理。

<xsl:apply-templates select="informacoes/cliente[estado='RJ']">
  <xsl:sort select="nome" order="ascending" />
</xsl:apply-templates>

太棒了,Mads!!我完全明白了。self::的提示也非常好!再次感谢! - delta
对此答案进行了downvote,因为虽然它可以正常工作并回答了问题,但使用<for-each select=x><apply-templates select="."/></for-each>是非常不必要的,因为它等效于<apply-templates select=x/> - Michael Kay
@Michael Kay - 理解了。同意消除 xsl:for-each 会更简单易行。本来是想回答如何实现的问题,但忘记提供更好、更简单的方法了。 - Mads Hansen

3
只需更换:
           <xsl:for-each select="informacoes/cliente"> 
           <xsl:sort select="nome" order="ascending" /> 
              <tr> 
                 <td bgcolor="LightGreen"><xsl:value-of  select="nome"/></td> 
                 <td><xsl:value-of  select="telefone"/></td> 
                 <td><xsl:value-of select="cidade"/></td> 
                 <td><xsl:value-of select="estado"/></td> 
                 <td><xsl:value-of select="credito"/></td> 
              </tr> 
           </xsl:for-each> 

随着:

<xsl:apply-templates select="informacoes/cliente">
  <xsl:sort select="nome" order="ascending" />
</xsl:apply-templates>

同样地,替换:

           <xsl:for-each select="informacoes/cliente">       
               <xsl:if test="cidade='Rio de Janeiro'">       
                  <tr>       
                     <td bgcolor="LightGreen"><xsl:value-of  select="nome"/></td>       
                     <td><xsl:value-of  select="telefone"/></td>       
                     <td><xsl:value-of select="cidade"/></td>       
                     <td><xsl:value-of select="estado"/></td>       
                     <td><xsl:value-of select="credito"/></td>       
                  </tr>       
                </xsl:if>       
            </xsl:for-each>   

with:

<xsl:apply-templates select="informacoes/cliente[cidade='Rio de Janeiro']"/>

同样,替换:

           <xsl:for-each select="informacoes/cliente">           
           <xsl:sort select="nome" order="ascending" />           
           <xsl:if test="estado='RJ'">           
              <tr>           
                 <td bgcolor="LightGreen"><xsl:value-of  select="nome"/></td>           
                 <td><xsl:value-of  select="telefone"/></td>           
                 <td><xsl:value-of select="cidade"/></td>           
                 <td><xsl:value-of select="estado"/></td>           
                 <td><xsl:value-of select="credito"/></td>           
              </tr>           
            </xsl:if>           
              </xsl:for-each> 

with:

<xsl:apply-templates select="informacoes/cliente[estado='RJ']">
  <xsl:sort select="nome" order="ascending" />
</xsl:apply-templates>

最后替换:

           <xsl:for-each select="informacoes/cliente">               
           <xsl:sort select="credito" order="descending" />               
           <xsl:if test="credito&gt;250 and credito&lt;400">               
              <tr>               
                 <td bgcolor="LightGreen"><xsl:value-of  select="nome"/></td>               
                 <td><xsl:value-of  select="telefone"/></td>               
                 <td><xsl:value-of select="cidade"/></td>               
                 <td><xsl:value-of select="estado"/></td>               
                 <td><xsl:value-of select="credito"/></td>               
              </tr>               
            </xsl:if>               
              </xsl:for-each>  

with:

<xsl:apply-templates select="informacoes/cliente[credito >250 and 400 > credito]">
  <xsl:sort select="credito" order="descending" />
</xsl:apply-templates>

接着添加这个简单的模板:

<xsl:template match="informacoes/cliente">
 <tr>               
  <td bgcolor="LightGreen"><xsl:value-of  select="nome"/></td>               
  <td><xsl:value-of  select="telefone"/></td>               
  <td><xsl:value-of select="cidade"/></td>               
  <td><xsl:value-of select="estado"/></td>               
  <td><xsl:value-of select="credito"/></td>               
 </tr>               
</xsl:template> 

您完整的XSLT代码现在变成了这样:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:template match="/">
      <html>
         <head><title>Informações</title></head>
         <body>
            <h1>Relação de Clientes</h1>
            <table border="2">
               <tr bgcolor="LightBlue">
                  <th>Nome</th>
                  <th>Telefone</th>
                  <th>Cidade</th>
                  <th>Estado</th>
                  <th>Crédito</th>
               </tr>
               <tr>
                  <th colspan="6" bgcolor="LightPink">Critério usado abaixo: exibir todos os elementos ordenado por nome</th>
               </tr>
                             <xsl:apply-templates select="informacoes/cliente">
                              <xsl:sort select="nome" order="ascending" />
                             </xsl:apply-templates>
                             <tr>
                  <th colspan="6" bgcolor="LightCyan"> Critério usado abaixo: exibir os clientes da cidade do Rio de Janeiro</th>
               </tr>
                 <xsl:apply-templates select="informacoes/cliente[cidade='Rio de Janeiro']"/>
                 <tr>
                  <th colspan="6" bgcolor="LightYellow"> Critério usado abaixo:  exibir os clientes do estado do RJ com ordenado pelo nome; </th>
               </tr>
                             <xsl:apply-templates select="informacoes/cliente[estado='RJ']">
                              <xsl:sort select="nome" order="ascending" />
                             </xsl:apply-templates>
               <tr>
                  <th colspan="6" bgcolor="LightYellow"> Critério usado abaixo:  exibir os clientes com crédito entre 250 e 400, em ordem descendente de crédito) </th>
               </tr>
                             <xsl:apply-templates select="informacoes/cliente[credito >250 and 400 > credito]">
                              <xsl:sort select="credito" order="descending" />
                             </xsl:apply-templates>
              </table>
            </body>
         </html>
      </xsl:template>

            <xsl:template match="informacoes/cliente">
             <tr>
              <td bgcolor="LightGreen"><xsl:value-of  select="nome"/></td>
              <td><xsl:value-of  select="telefone"/></td>
              <td><xsl:value-of select="cidade"/></td>
              <td><xsl:value-of select="estado"/></td>
              <td><xsl:value-of select="credito"/></td>
             </tr>
            </xsl:template>
</xsl:stylesheet>

太棒了!我不知道可以省略xsl:for-each标签。谢谢Dimitre! - delta
2
@user1676355,欢迎。建议避免使用xsl:for-each(改用xsl:apply-templates),在99.999%的情况下都是可行的。我只知道一个使用场景需要真正使用xsl:for-each - Dimitre Novatchev
@DimitreNovatchev - 我非常好奇:你在想什么一个用例? - ABach
@ABach,一个案例是当为了得到key()函数的结果时,必须更改当前文档。在XSLT 1.0中,可以使用<xsl:for-each select="document(newUrl)">来完成这个操作。 - Dimitre Novatchev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接