2016-03-19 7 views
1

Für ein bestimmtes Ausgabeformat (nicht HTML-like), muss ich HTML-Tabellen ‚Quadrat‘ Tabellen konvertieren, wobei jede colspan und rowspan ist nicht nur in der angegebenen Elternzelle, aber auch von der richtigen Anzahl leerer Zellen gefolgt.Convert HTML colspan und rowspan zu „leeren“ Zellen

Zum Beispiel die einfache HTML-Tabelle

<table> 
    <tr> 
     <th>test</th> 
     <th colspan="2">span 1/2</th> 
     <th colspan="3">span 2/2</th> 
    </tr> 
    <tr> 
     <td>col 1</td> 
     <td>col 2</td> 
     <td>col 3</td> 
     <td>col 4</td> 
     <td>col 5</td> 
     <td>col 6</td> 
    </tr> 
</table> 

sollte

<table> 
    <tr> 
     <th>test</th> 
     <th colspan="2">span 1/2</th> 
     <th /> <!-- < empty cell added --> 
     <th colspan="3">span 2/2</th> 
     <th /> <!-- < empty cell added --> 
    </tr> 
    .. 

übersetzt werden (Anmerkung: das Ausgabeformat verwendet eine ganz andere Syntax, dies aus Gründen der Übersichtlichkeit ist nur!)

und in ähnlicher Weise sollten Zeilenspans zum nächsten <tr> Zeilen weitergeleitet werden:

<table><tr><td rowspan="3" /><td rowspan="2" /><td /></tr> 
    <tr><td>data</td></tr> 
    <tr><td>data</td><td>data</td></tr> 
</table> 

was kommen sollte als

<table> 
    <tr><td /><td /><td /></tr> 
    <tr><td /><td /><td>data</td></tr> <!-- 2 empty cells added --> 
    <tr><td /><td>data</td><td>data</td></tr> <!-- 1 empty cell added --> 
<table> 

colspan Handhabung ist einfach:

<xsl:template name="add-empty"> 
    <xsl:param name="repeat" /> 

    <xsl:if test="$repeat &gt; 1"> 
     <td class="empty" /> 
     <xsl:call-template name="add-empty"> 
      <xsl:with-param name="repeat" select="$repeat - 1" /> 
     </xsl:call-template> 
    </xsl:if> 
</xsl:template> 

<xsl:template match="th|td"> 
    <td> 
     <xsl:apply-templates /> 
    </td> 
    <xsl:if test="@colspan"> 
     <xsl:call-template name="add-empty"> 
      <xsl:with-param name="repeat" select="@colspan" /> 
     </xsl:call-template> 
    </xsl:if> 
</xsl:template> 

Dies wird einzelne hinzufügen th oder td, überprüfen jedes der colspan, und so viele leere Zellen einfügen je nach Bedarf mit ein rekursiver Aufruf der Vorlage add-empty. Das Klassenattribut empty dient nur zum Debuggen.

Das Problem ist in der rowspan s. Damit dies ordnungsgemäß funktioniert, müssen Sie über alle vorherige tr scannen und eine Zählung der Spalten beibehalten, die leer sein müssen. Die Iteration wäre so etwas wie

<xsl:if test="position() &gt; 1"> 
    <xsl:variable name="currentRow" select="position()" /> 
    <xsl:for-each select="../tr[position() &lt; $currentRow]"> 
     <xsl:message>testing <xsl:value-of select="." /></xsl:message> 
    </xsl:for-each> 
</xsl:if> 

sein - es ist nicht in der ersten Reihe, da für, dass nur colspan Bedürfnis Hinzufügen genannt werden muss. Die Frage ist also zweifach: Wie würde ich die Zellensatzliste erstellen, um einen korrekten Satz für die aktuelle Zeile zu ergeben? Und mit so einer Liste, wie kann ich über beide diese Liste (die so lange wie die Gesamtzahl der Spalten in der Tabelle ist) und jeder Zeile th|td Elemente?

Letzteres ist ein Problem, weil ich über beiden die Zelle etwas mit wie

<xsl:for-each select="1 to string-length(cell-set)"> 
    <xsl:if test="substring($cell-set, ., 1) = 'E'> 
    .. empty .. 
    ... 
</xsl:for-each> 

gesetzt laufen kann (wenn cell-set ist ein String), oder über den ‚aktuellen‘ tr Inhalt

mit
<xsl:for-each select="th|td"> 
    .. 

In diesem Fall gibt es keine direkte Beziehung zum Inhalt von cell-set. Mit dem ersten weiß ich nicht, welchen Index td|th einzufügen ist, mit dem zweiten weiß ich nicht, wann ein Leerzeichen einzufügen ist.

+1

Wie Sie zu haben scheinen schaltet 2,0 bis XSLT möchten Sie vielleicht http://andrewjwelch.com/code/xslt/ überprüfen table/table-normalization.html als idee kopiert es die vorhandene zelle, anstatt eine leere hinzuzufügen, aber anders als der algorithmus sollte es tun, wenn ich mich nicht mit ihren anforderungen täusche. –

+0

@MartinHonnen: Ich habe nicht so viel "umgestellt", als etwas spät, merkte ich, dass ich besser angeben soll :) - die Aufgabe scheint entmutigend genug, sogar * mit * 2.0 Funktionen. Schaut nach dem Link und Ihrer Antwort a.s.a.p. (Ah - zum Beispiel, for-jedes select = "1 bis @colspan" 'statt meiner eigenen rekursiven Vorlage in 1.0 ... ordentlich!) – usr2564301

+0

@RadLexus Sehen Sie, ob dies hilft: http://StackOverflow.com/a/27217608/3016153 –

Antwort

3

Basierend auf http://andrewjwelch.com/code/xslt/table/table-normalization.html, die ich bereits in einem Link erwähnt könnten Sie verwenden:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" version="2.0" exclude-result-prefixes="xs"> 

    <xsl:output indent="yes" omit-xml-declaration="yes" /> 

    <xsl:variable name="table_with_no_colspans"> 
     <xsl:apply-templates mode="colspan" /> 
    </xsl:variable> 

    <xsl:variable name="table_with_no_rowspans"> 
     <xsl:for-each select="$table_with_no_colspans"> 
      <xsl:apply-templates mode="rowspan" /> 
     </xsl:for-each> 
    </xsl:variable> 

    <xsl:template match="/"> 
     <xsl:apply-templates select="$table_with_no_rowspans" mode="final" /> 
    </xsl:template> 

    <xsl:template match="@*|*" mode="#all"> 
     <xsl:copy> 
      <xsl:apply-templates select="@*|*" mode="#current" /> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="td | th" mode="colspan"> 
     <xsl:choose> 
      <xsl:when test="@colspan"> 
       <xsl:copy> 
        <xsl:copy-of select="@* except @colspan"/> 
        <xsl:apply-templates/> 
       </xsl:copy> 
       <xsl:for-each select="2 to @colspan"> 
        <td/> 
       </xsl:for-each> 
      </xsl:when> 
      <xsl:otherwise> 
       <xsl:copy-of select="." /> 
      </xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 

    <!-- make sure it works for both table/tr and table/tbody/tr --> 
    <xsl:template match="tbody|table[not(tbody)]" mode="rowspan"> 
     <xsl:copy> 
      <xsl:copy-of select="tr[1]" /> 
      <xsl:apply-templates select="tr[2]" mode="rowspan"> 
       <xsl:with-param name="previousRow" select="tr[1]" /> 
      </xsl:apply-templates> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="tr" mode="rowspan"> 
     <xsl:param name="previousRow" as="element()" /> 

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

     <xsl:variable name="normalizedTDs"> 
      <xsl:for-each select="$previousRow/*"> 
       <xsl:choose> 
        <xsl:when test="@rowspan &gt; 1"> 
         <xsl:copy> 
          <xsl:attribute name="rowspan"> 
           <xsl:value-of select="@rowspan - 1" /> 
          </xsl:attribute><!-- 
          <xsl:copy-of select="@*[not(name() = 'rowspan')]" /> 
          <xsl:copy-of select="node()" /> 
         --></xsl:copy> 
        </xsl:when> 
        <xsl:otherwise> 
         <xsl:copy-of select="$currentRow/*[1 + count(current()/preceding-sibling::*[not(@rowspan) or (@rowspan = 1)])]" /> 
        </xsl:otherwise> 
       </xsl:choose> 
      </xsl:for-each> 
     </xsl:variable> 

     <xsl:variable name="newRow" as="element(tr)"> 
      <xsl:copy> 
       <xsl:copy-of select="$currentRow/@*" /> 
       <xsl:copy-of select="$normalizedTDs" /> 
      </xsl:copy> 
     </xsl:variable> 

     <xsl:copy-of select="$newRow" /> 

     <xsl:apply-templates select="following-sibling::tr[1]" mode="rowspan"> 
      <xsl:with-param name="previousRow" select="$newRow" /> 
     </xsl:apply-templates> 
    </xsl:template> 

    <xsl:template match="td | th" mode="final"> 
     <xsl:choose> 
      <xsl:when test="@rowspan"> 
       <xsl:copy> 
        <xsl:copy-of select="@* except @rowspan" /> 
        <xsl:copy-of select="node()" /> 
       </xsl:copy> 
      </xsl:when> 
      <xsl:otherwise> 
       <xsl:copy-of select="." /> 
      </xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 

</xsl:stylesheet> 
+0

Funktioniert ein Vergnügen. Ich muss immer noch herausfinden, wie und wo 'tr's erzeugt werden (ich muss sie in getaggten Text übersetzen), aber keine Sorge, ich komme dorthin. Ich habe bemerkt, dass der Wert von 'colspan' stillschweigend verworfen wird, was logisch ist - aber ich brauche diesen Wert immer noch. Hinzufügen eines '' nach dem '' hat das behoben. (Für interessierte Lurker: die meisten 'xsl: copy' können sicher in' xsl: apply-templates' übersetzt werden, mit einem zusätzlichen 'mode', um nur den Inhalt zu kopieren.) – usr2564301

+1

Wenn Sie den' colspan' dann kopieren wollen doing '' anstelle von '' reicht aus, da letzterer alle Attribute mit Ausnahme des 'colspan' kopiert Attribut, während ersteres alle Attribute kopieren würde. Wie für die "tr" -Elemente werden sie im Modus "colspan" und im Modus "final" einfach durch die Identitätstransformationsvorlage ' kopiert 'eingerichtet für alle Modi. Im Modus 'rowspan' gibt es' '. Du brauchst wahrscheinlich eine Vorlage 'match =" tr "mode =" final "'. –

Verwandte Themen