XSLT HTML avec simple regroupement de données XML à l'aide des modèles au lieu de for-each

StackOverflow https://stackoverflow.com/questions/3006818

Question

Je suis de jouer avec xslt par intermittence depuis que je suis devenu administrateur sharepoint, il utilise beaucoup xslt pour afficher des données de la liste. J'ai récemment commencé à l'utiliser pour transformer les résultats de la base de données que j'ai converti en XML en utilisant une méthode d'extension. Je suis en train de produire html propre.

Ma première tentative, a bien fonctionné. Cependant, j'utilisé pour chaque-partout, j'ai lu depuis qui est une mauvaise chose à faire. Je lis un tas de choses sur l'utilisation de clés, mais je ne pouvais pas comprendre que ou le faire fonctionner. Donc, je réécris cette feuille de style, ci-dessous pour celui qui est en dessous. Il utilise des modèles sans pour-chacun.

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

Je l'ai maintenant récrit que ceci:

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

Je ne mentionnaient pas l'entrée de l'échantillon et la sortie, car cela est tout généré automatiquement. S'il est nécessaire que je peux prendre beaucoup de temps, et d'essayer de produire quelque chose.

Ma question est, est-ce une meilleure façon de le faire? De plus, si la façon dont la clé est mieux que quelqu'un pourrait l'expliquer ou fournir un lien vers une bonne explication?

Était-ce utile?

La solution

Au fond la question de l'utilisation for-each par rapport à des modèles se résume à la création réutilisables, des transformations plus génériques.

En utilisant des modèles, tous les nœuds correspondant à - pas seulement ceux utilisés explicitement dans le for-each - peuvent bénéficier du modèle, ce qui permet d'éviter la duplication de code et en même temps casse la feuille en unités plus petites qui sont plus faciles à gérer. Il est en fait à peu près la même chose que d'avoir une énorme procédure ou de procédures plus petites appelant l'autre dans la programmation impérative.

Alors que certaines personnes suggèrent que l'utilisation de modèles peuvent être performants mieux dans certains moteurs, je crois que cela ne va pas vraiment faire une différence.

Cela dit, vous pouvez en apprendre davantage sur la méthode muenchian ( qui utilise des clés) pour regrouper les données réellement où vous avez des clés répétées. L'utilisation de l'axe preceding-sibling est très lent sur certains moteurs, afin qu'il le mieux pour l'éviter lorsqu'ils ne sont pas tout à fait nécessaire.

Quelque chose comme cela devrait faire l'affaire pour les divisions (non testé):

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

...

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

Autres conseils

Le modèle "for-each" est une bonne caractéristique de XSLT.

Les conseils à utiliser « modèles » au lieu de « for-each » est la plupart du temps sur l'utilisation abusive du modèle de traitement XSLT.

Dans votre exemple est clair: un seul « modèle » naïf et beaucoup « pour-chaque » qui guident le processus

.

Utilisation de la clé dans XSLT est lui-même sur la performance. Son utilité réside dans le remplacement des expressions XPath qui impliquent des voyages répétitifs de nombreux noeuds de l'arbre d'entrée. méthode Muenchian de regroupement est une utilisation spéciale pour les clés. simple regroupement peut être optimale sans l'utilisation de clés.

D'autre part, la population est un cas particulier de la transformation. Je pense qu'il vaut mieux pour maintenir de séparer le XHTML sémantique de la transformation XSLT. Consultez www.aranedabienesraices.com.ar comme exemple.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top