2010-06-09 51 views
3

我一直在关闭xslt,因为我成为了SharePoint管理员,它使用xslt很多显示列表数据。我最近开始使用它来转换我使用扩展方法转换为xml的数据库结果。我正在尝试生成干净的html。XSLT为简单分组的XML数据使用模板而不是为每个

我的第一次尝试,工作正常。然而,我曾经在各地都用过,我从那以后就读过这是一件坏事。我读了一堆关于使用密钥的东西,但我无法理解或者无法使用它。所以我重写了这个样式表,下面是它下面的样式表。它使用没有for-each的模板。

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

    <xsl:template match="/"> 


<html> 
    <head> 
    <link rel="Stylesheet" type="text/css" href="../styles/BoxReportStyle.css" /> 
    </head> 
    <body> 


    <span class="BoxReport"> 
     <h2>Checked Out Boxes by Department with Transaction History</h2> 

     Count=<xsl:value-of select="count(/CheckedOutBoxes/row) "/> 

    <!-- Get the divisions, since we are groing to group by division--> 
    <xsl:variable name="DivisionList" select="/CheckedOutBoxes/row[ not(Division = preceding-sibling::row/Division) ]/Division" /> 

    <xsl:for-each select="$DivisionList"> 

     <xsl:variable name="DivisionName" select="." /> 

     <h3> 
     <xsl:value-of disable-output-escaping="yes" select="$DivisionName "/> 
     </h3> 

     <!-- Get the list of departments, so we can group by department --> 
     <xsl:variable name="DepartmentList" select="/CheckedOutBoxes/row[ Division = $DivisionName and not(Department = preceding-sibling::row/Department) ]/Department" /> 

     <xsl:for-each select="$DepartmentList"> 
     <xsl:variable name="DepartmentName" select="." /> 

     <h4> 
      <xsl:value-of disable-output-escaping="yes" select="$DepartmentName"/> 
     </h4> 

     <xsl:variable name="Rows" select="/CheckedOutBoxes/row[ Division = $DivisionName and Department = $DepartmentName ]" /> 

     <!-- Start displaying the checked out box information for this division and department --> 
     <table> 
      <th>Box Number</th> 
      <th>Status Name</th> 
      <th>Entry Date</th> 
      <th>Description</th> 

      <xsl:for-each select="$Rows"> 

      <tr> 
       <td> 
       <xsl:value-of select="BoxNumber"/> 
       </td> 
       <td> 
       <xsl:value-of select="StatusName"/> 
       </td> 
       <td> 
       <xsl:value-of select="EntryDate"/> 
       </td> 
       <td width="200px"> 
       <xsl:value-of disable-output-escaping="yes" select="Description"/> 
       </td> 

      </tr> 

      <!-- Now display the transaction history if there is any--> 
      <xsl:if test=" count(Transaction) > 0 "> 
       <tr> 
       <td></td> <!-- One blank row to shift things over--> 
       <td colspan="3"> 
        <!-- Display transaction table--> 
        <table class="SubTable"> 
        <th>Transaction Date</th> 
        <th>Requestor</th> 
        <th>Comments</th> 

        <xsl:for-each select="Transaction" > 
         <tr> 
         <td> 
          <xsl:value-of select="TransactionDate"/> 
         </td> 
         <td> 
          <xsl:value-of select="Requestor"/> 
         </td> 
         <td width="200px"> 
          <xsl:value-of disable-output-escaping="yes" select="Comments"/> 
         </td> 
         </tr> 
        </xsl:for-each> 
        </table> 
       </td> 
       </tr> 
      </xsl:if> 
      </xsl:for-each> 
     </table> 

     </xsl:for-each> 

    </xsl:for-each> 
    </span> 


    </body> 

</html> 


    </xsl:template> 



</xsl:stylesheet> 

我现在已经重写了,要这样:

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



<xsl:template match="/"> 
<html> 
    <head> 
    <link rel="Stylesheet" type="text/css" href="../styles/BoxReportStyle.css" /> 
    </head> 
    <body> 
    <span class="BoxReport"> 

     <h2>Checked Out Boxes by Department with Transaction History</h2> 

     Count=<xsl:value-of select="count(/CheckedOutBoxes/row) "/> 

     <xsl:apply-templates mode="Division" select="/CheckedOutBoxes/row[ not(Division = preceding-sibling::row/Division) ]"></xsl:apply-templates> 


    </span> 
    </body> 
</html> 
    </xsl:template> 

<xsl:template mode="Division" match="row"> 
<h3> 
    <xsl:value-of select="Division" disable-output-escaping="yes"/> 
</h3> 

<xsl:variable name="DivisionName" select="Division" /> 

<xsl:apply-templates mode="Department" select="/CheckedOutBoxes/row[ Division = $DivisionName and not(Department = preceding-sibling::row/Department) ]"></xsl:apply-templates> 

</xsl:template> 

<xsl:template mode="Department" match="row"> 
<h4> 
    <xsl:value-of select="Department" disable-output-escaping="yes"/> 
</h4> 

<xsl:variable name="DivisionName" select="Division" /> 
<xsl:variable name="DepartmentName" select="Department" /> 

<table> 
    <th>Box Number</th> 
    <th>Status Name</th> 
    <th>Entry Date</th> 
    <th>Description</th> 

    <xsl:apply-templates mode="row" select="/CheckedOutBoxes/row[ Division = $DivisionName and Department = $DepartmentName ]" ></xsl:apply-templates> 

    </table> 



</xsl:template> 

<xsl:template mode="row" match="row"> 

<tr> 
    <td> 
    <xsl:value-of select="BoxNumber"/> 
    </td> 
    <td> 
    <xsl:value-of select="StatusName"/> 
    </td> 
    <td> 
    <xsl:value-of select="EntryDate"/> 
    </td> 
    <td width="200px"> 
    <xsl:value-of disable-output-escaping="yes" select="Description"/> 
    </td> 

</tr> 

<!-- Display Transaction stuff as another row if we have any --> 
<xsl:if test=" count(Transaction) > 0 "> 
    <tr> 
    <td></td><!-- Shift the transaction over--> 
    <td colspan="3"> 
     <!-- Start Transaction Table --> 
     <table class="SubTable"> 
     <th>Transaction Date</th> 
     <th>Requestor</th> 
     <th>Comments</th> 

     <xsl:apply-templates select="Transaction"> 
      <xsl:sort order="descending" select="TransactionDate"/> 
     </xsl:apply-templates> 
     </table> 
    </td> 
    </tr> 
</xsl:if> 

</xsl:template> 


<xsl:template match="Transaction"> 
<tr> 
    <td> 
    <xsl:value-of select="TransactionDate"/> 
    </td> 
    <td> 
    <xsl:value-of select="Requestor"/> 
    </td> 
    <td width="200px"> 
    <xsl:value-of disable-output-escaping="yes" select="Comments"/> 
    </td> 
</tr> 
    </xsl:template> 

</xsl:stylesheet> 

我不包括样品的输入和输出,因为这是生成的所有汽车。如果需要,我可以花费很多时间,并尝试制作一些东西。

我的问题是,这是一个更好的方法吗?另外,如果关键方式更好,有人可以解释它,或提供一个良好解释的链接?

回答

1

基本上使用for-each与模板的问题归结为创建可重用,更通用的转换。

通过使用模板,所有匹配的节点 - 不仅仅是for-each中明确使用的节点 - 可以从模板中受益,这有助于避免重复的代码,同时将工作表分成更小的单元,从而更易于管理。实际上,它与在命令式编程中调用彼此巨大的过程或更小的过程几乎相同。

虽然有些人认为使用模板可能会在某些引擎中表现更好,但我相信这并不会真正有所作为。

也就是说,你可能想要了解muenchian method(它使用键)实际上分组数据,你有重复的键。在某些发动机上使用preceding-sibling轴的速度非常缓慢,因此在不是绝对需要时最好避免使用轴。

像这样的东西应该为师(未测试)做的伎俩:

<xsl:key name="divisions" match="/CheckedOutBoxes/row/Division" use="." /> 

...

<xsl:apply-templates mode="Division" select="/CheckedOutBoxes/Division[generate-id(.)=generate-id(key('divisions', .))]" /> 
+0

关键获得所有非重复的部门?也许我可以更好地理解它,如果这是它正在做的事情。然后,我可以为部门基本上与部门相同的另一个关键。然后,应用模板的select语句将确保我正在为当前部门而不是所有部门执行这些部门。 – 249076 2010-06-09 15:39:42

+1

在这种情况下,'key()'函数基本上返回一个包含所有匹配的“Divisions”的节点集。这里的“魔术”是'generate-id()'函数,该函数返回传递给它的节点集中第一个节点的唯一标识ID。因此,将每个'Division'节点ID与具有相同内容的第一个节点的ID进行比较(这就是为什么我们使用'key()'函数),因此每个不同的内容仅匹配一次。 – Lucero 2010-06-09 16:05:57

+0

嗯,我认为在对模板做了一点工作之后,就可以将部门和部门模板与部门和部门相匹配,而不是排成一行,并且实现了我得到的工作,而不是前面的兄弟姐妹。我现在明白了一切,但希望在学习之后我会开始更好地理解它。 – 249076 2010-06-09 16:52:47

1

了 “每个” 模板是XSLT的一个很好的功能。

使用“模板”而不是“for-each”的建议主要是关于可能滥用XSLT处理模型的建议。

在你的例子中很清楚:一个朴素的“模板”和许多“for-each”指导过程。

XSLT本身的关键用途是关于性能。它的用处在于替换涉及重复传输输入树中许多节点的XPath表达式。 Muenchian分组方法是键的特殊用法。简单的分组可以在不使用密钥的情况下达到最佳效果。

另一方面,人口是转型的特例。我认为维护将XHTML语义与XSLT转换分开会更好。以www.aranedabienesraices.com.ar为例。

+0

我想我看到模板的位置,把事情分解了。这几乎就像函数调用一样。因此,通过匹配“/”我可以看到整体布局,然后我可以按照应用模板来逐步完成转换。我可能会保留两个样式表。 – 249076 2010-06-09 15:50:15

相关问题