2009-04-20 7 views
3

Wie würde ich dieses XML nehmen und eine Tabelle mit einer Spalte für jedes Element "section" erstellen und dann alle Elemente "document" in dieser Spalte mit xslt anzeigen?xslt: Wie kann ich mit xslt eine Tabelle mit mehreren Spalten und Zeilen erstellen?

<Documents> 
    <Section> 
    <SectionName>Green</SectionName> 
    <Document> 
     <FileName>Tier 1 Schedules</FileName>  
    </Document> 
    <Document> 
     <FileName>Tier 3 Schedules</FileName>  
    </Document> 
    <Document> 
     <FileName>Setback Schedule</FileName>  
    </Document> 
    <Document> 
     <FileName>Tier 2 Governance</FileName>  
    </Document> 
</Section> 
<Section> 
<SectionName>MRO/Refurb</SectionName> 
    <Document> 
    <FileName>Tier 2 Governance</FileName>  
    </Document> 
</Section> 

Danke, Al

+0

Tabelle? Säule? Sie sind keine Standard-XML-Wörter. Du übersetzst was? XHTML? – bortzmeyer

+0

@bortzmeyer: Ich denke, eine (X) HTML-Tabelle ist, was das OP ist. – Tomalak

+0

Ich denke, du solltest meine Antwort noch nicht akzeptieren. Ich bin sicher, wenn Sie die Frage offen lassen, werden bessere Alternativen auftauchen. – Tomalak

Antwort

1

Dies ist eine mögliche Lösung:

<xsl:variable name="vCountRows"> 
    <xsl:apply-templates select="Documents/Section[1]" mode="findmax" /> 
</xsl:variable> 

<xsl:variable name="vCountCols" select="count(Documents/Section)" /> 

<xsl:template match="/Documents"> 
    <table r="{$vCountRows}" s="{$vCountCols}"> 
    <thead> 
     <xsl:call-template name="create-thead" /> 
    </thead> 
    <tbody> 
     <xsl:call-template name="create-tr" /> 
    </tbody> 
    </table> 
</xsl:template> 

<xsl:template name="create-thead"> 
    <tr> 
    <xsl:apply-templates select="Section" /> 
    </tr>  
</xsl:template> 

<xsl:template match="Section"> 
    <th><xsl:value-of select="SectionName" /></th> 
</xsl:template> 

<xsl:template name="create-tr"> 
    <xsl:param name="row" select="1" /> 

    <tr> 
    <xsl:call-template name="create-td"> 
     <xsl:with-param name="row" select="$row" /> 
    </xsl:call-template> 
    </tr> 

    <xsl:if test="$row &lt; $vCountRows"> 
    <xsl:call-template name="create-tr"> 
     <xsl:with-param name="row" select="$row + 1" /> 
    </xsl:call-template> 
    </xsl:if> 

</xsl:template> 

<xsl:template name="create-td"> 
    <xsl:param name="col" select="1" /> 
    <xsl:param name="row" select="1" /> 

    <td> 
    <xsl:value-of select="Section[$col]/Document[$row]/FileName" /> 
    </td> 

    <xsl:if test="$col &lt; $vCountCols"> 
    <xsl:call-template name="create-td"> 
     <xsl:with-param name="col" select="$col + 1" /> 
     <xsl:with-param name="row" select="$row" /> 
    </xsl:call-template> 
    </xsl:if> 
</xsl:template> 

<xsl:template match="Section" mode="findmax"> 
    <xsl:variable name="c" select="count(Document)" /> 
    <xsl:variable name="next" select="following-sibling::Section[count(Document) &gt; $c][1]" /> 

    <xsl:choose>  
    <xsl:when test="$next"> 
     <xsl:apply-templates select="$next" mode="findmax" /> 
    </xsl:when> 
    <xsl:otherwise> 
     <xsl:value-of select="$c" /> 
    </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 

Mit Ihrer Eingabe es produziert:

<table> 
    <thead> 
    <tr> 
     <td>Green</td> 
     <td>MRO/Refurb</td> 
    </tr> 
    </thead> 
    <tbody> 
    <tr> 
     <td>Tier 1 Schedules</td> 
     <td>Tier 2 Governance</td> 
    </tr> 
    <tr> 
     <td>Tier 3 Schedules</td> 
     <td></td> 
    </tr> 
    <tr> 
     <td>Setback Schedule</td> 
     <td></td> 
    </tr> 
    <tr> 
     <td>Tier 2 Governance</td> 
     <td></td> 
    </tr> 
    </tbody> 
</table> 

Die allgemeine a pporach geht so:

  1. Finden Sie heraus, wie viele Zeilen bekommen wir wollen (dies geschieht in <xsl:template match="Section" mode="findmax">, die rekursiv den Abschnitt mit der maximalen Anzahl von <Document> Knoten findet
  2. Finden Sie heraus, wie viele Spalten wir gehen zu erhalten (durch die Anzahl der <Section> s Zählung)
  3. eine Vorlagen aufrufen, die eine <tr> schafft und hält sich ruft, bis alle notwendigen Reihen haben
  4. in dieser Vorlage erstellt wurde, wird eine zweite Vorlage aufgerufen wird, erzeugt dies eine der <td> s. Es hält die sich selbst, bis er die maximale Anzahl der Spalten erreicht (aus Schritt 2)

Der Algorithmus:

  • verwendet Spalten- und Zeilennummern als Indizes Inkrementieren
  • verwendet Rekursion ein zu erreichen -Durch-Inkrementen ein Index (da tatsächlich eine variable Inkrementieren in XSLT unmöglich ist)
  • schafft die richtige Anzahl von leeren Zellen für die Abschnitte, die weniger Dokumente

Eine effizientere Version (wahrscheinlich unter Verwendung von <xsl:key> s) existiert, werde ich in die Optimierung meiner ein wenig mehr suchen.

+0

hat perfekt funktioniert dank – user69971

+1

Trotzdem sollten Sie mit der Annahme der Lösung warten. Lassen Sie die Frage über Nacht offen, um weitere Antworten zu erhalten. – Tomalak

3

Diese Lösung verwendet keine Rekursion und Hi-Lights ein paar nützliche XSLT-Techniken wie Muenchian Gruppierung, Schlüssel, Suche nach Maximum und Iteration ohne Rekursion.

Diese Transformation:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output omit-xml-declaration="yes" indent="yes"/> 

    <xsl:strip-space elements="*"/> 

    <xsl:key name="kSectsByValue" match="SectionName" 
     use="."/> 

    <xsl:key name="kDocBySect" match="Document" 
     use="../SectionName"/> 

    <xsl:variable name="vCols" select= 
     "/*/*/SectionName 
       [generate-id() 
       =   
       generate-id(key('kSectsByValue',.)[1]) 
       ]"/> 

    <xsl:variable name="vMaxRows"> 
      <xsl:for-each select="$vCols"> 
       <xsl:sort data-type="number" order="descending" 
        select="count(key('kDocBySect', .))"  /> 
       <xsl:if test="position() = 1"> 
       <xsl:value-of select="count(key('kDocBySect', .))"/> 
       </xsl:if> 
      </xsl:for-each> 
    </xsl:variable> 

    <xsl:template match="/"> 
      <table> 
       <tr> 
       <xsl:apply-templates select="$vCols"/> 
       </tr> 

       <xsl:for-each select= 
       "(/*/*/Document)[not(position() > $vMaxRows)]">     
       <tr> 

        <xsl:variable name="vPos" select="position()"/> 

        <xsl:for-each select="$vCols"> 
        <td> 
         <xsl:value-of select= 
          "../Document[$vPos]/FileName"/> 
        </td> 
        </xsl:for-each> 

       </tr> 
       </xsl:for-each> 
      </table> 

    </xsl:template> 

    <xsl:template match="SectionName"> 
      <td> 
       <xsl:value-of select="." /> 
      </td> 
    </xsl:template> 
</xsl:stylesheet> 

, wenn sie auf dem ursprünglichen XML Dokument angewendet (korrigierter wohlgeformt werden):

<Documents> 
    <Section> 
     <SectionName>Green</SectionName> 
     <Document> 
      <FileName>Tier 1 Schedules</FileName> 
     </Document> 
     <Document> 
      <FileName>Tier 3 Schedules</FileName> 
     </Document> 
     <Document> 
      <FileName>Setback Schedule</FileName> 
     </Document> 
     <Document> 
      <FileName>Tier 2 Governance</FileName> 
     </Document> 
    </Section> 
    <Section> 
     <SectionName>MRO/Refurb</SectionName> 
     <Document> 
      <FileName>Tier 2 Governance</FileName> 
     </Document> 
    </Section> 
</Documents> 

erzeugt das gewünschte Ergebnis:

<table> 
    <tr> 
     <td>Green</td> 
     <td>MRO/Refurb</td> 
    </tr> 
    <tr> 
     <td>Tier 1 Schedules</td> 
     <td>Tier 2 Governance</td> 
    </tr> 
    <tr> 
     <td>Tier 3 Schedules</td> 
     <td/> 
    </tr> 
    <tr> 
     <td>Setback Schedule</td> 
     <td/> 
    </tr> 
    <tr> 
     <td>Tier 2 Governance</td> 
     <td/> 
    </tr> 
</table> 

Sie beachten Sie:

  1. Wir verwenden die Muenchian method for grouping, um alle verschiedenen Spaltennamen zu finden, nicht, dass sie einzigartig werden im XML-Dokument zu verlassen.

  2. Keys werden sowohl für die Münchische Gruppierung als auch für das Finden aller zu einer Spalte gehörenden Elemente verwendet.

  3. Die maximale Anzahl der Zeilen ist und gehalten in der Variablen $vMaxRows

  4. Wir iterieren N-mal fand die N Zeilen der Tabelle zu erzeugen - nicht Rekursion!

  5. Die N -ten Zeile ausgegeben von Vorlagen auf alle Spaltenelemente Anwendung dieser Position N in ihrer Spalte.

+1

Ihre Lösung erzeugt derzeit keine leeren Tabellenzellen, da sie für die Erstellung einer gültigen HTML-Tabelle benötigt werden. :) – Tomalak

+0

@Tomalak Danke für diese Beobachtung. Jetzt korrigiert! –

+0

Es ist immer noch ein kleiner Fehler. Jetzt produziert Ihre Lösung überschüssige und falsch verschachtelte "" s. – Tomalak