2010-06-30 5 views
1

je les données XML suivantes:tableau HTML dynamique Génération avec XSL

<Activity> 
<ObjectGroup type="default"> 
<Object id="1874" name="PR1010Date" type="reference label" index="10" columnNo="0" dynamic="true"> 
     <Description>Date</Description>  
     <Value instance="0">30/06/2010</Value> 
    </Object> 
    <Object id="1875" name="PR1020LoggedBy" type="reference label" index="20" columnNo="1" dynamic="true"> 
     <Description>Request Logged By</Description>  
     <Value>Site Administrator</Value> 
    </Object> 
    <Object id="1876" name="PR1030Comments" type="large text box" index="30" columnNo="0" dataType="Text"> 
     <Description>Comments</Description>  
     <Value instance="0">Test</Value> 
    </Object> 
<ObjectGroup> 
</Activity> 

Je dois créer un XSL qui produira la sortie suivante:

<html> 
<table> 
<tr> 
<td width="50%">30/06/2010</td> 
<td width="50%">Site Admin</td> 
</tr> 
<tr> 
<td width="100%">Test</td> 
</tr> 
</table> 

Dans le XML ci-dessus l'attribut index avec la colonneNo détermine le nombre de lignes et de colonnes générées. Le résultat final est déterminé sur ColumnNo, donc si le ObjectGroup a des objets avec columnNo incrémental, ils sont tous rendus en une seule ligne avec la largeur appropriée pour chaque colonne.

+0

Et qu'est-ce que vous avez eu jusqu'à maintenant? Où avez-vous des difficultés? Les gens ici ne feront pas votre travail pour vous. – Oded

+0

Petit côté, mais votre HTML ne va pas afficher correctement; Si vous définissez la largeur sur 100%, cela ne fera pas passer les deux colonnes, vous devrez spécifier 'colspan =" 2 "'. – Flynn1179

+0

Bonne question (+1). Voir ma réponse pour une solution complète et efficace. –

Répondre

1

Cette transformation:

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

<xsl:key name="kObjByCol" match="Object" 
    use="@columnNo"/> 

<xsl:key name="kRow" match="Object[@columnNo != 0]" 
    use="generate-id(preceding-sibling::Object 
           [@columnNo = 0][1] 
        )"/> 

<xsl:template match="/*"> 
    <html> 
    <table border="1"> 
     <xsl:apply-templates select= 
     "key('kObjByCol', 0)"/> 
    </table> 
    </html> 
</xsl:template> 

<xsl:template match="Object"> 
    <xsl:variable name="vcellNodes" 
    select=".|key('kRow',generate-id())"/> 
    <tr> 
    <xsl:apply-templates mode="row" select= 
     "$vcellNodes"> 
     <xsl:with-param name="pCount" 
      select="count($vcellNodes)"/> 
    </xsl:apply-templates> 
    </tr> 
</xsl:template> 

<xsl:template match="Object" mode="row"> 
    <xsl:param name="pCount"/> 
    <td width="{100 div $pCount}%"> 
    <xsl:value-of select="Value"/> 
    </td> 
</xsl:template> 
</xsl:stylesheet> 

lorsqu'il est appliqué au document XML fourni (corrigé pour être bien formé):

<Activity> 
    <ObjectGroup type="default"> 
     <Object id="1874" name="PR1010Date" 
     type="reference label" index="10" 
     columnNo="0" dynamic="true"> 
      <Description>Date</Description> 
      <Value instance="0">30/06/2010</Value> 
     </Object> 
     <Object id="1875" name="PR1020LoggedBy" 
     type="reference label" index="20" 
     columnNo="1" dynamic="true"> 
      <Description>Request Logged By</Description> 
      <Value>Site Administrator</Value> 
     </Object> 
     <Object id="1876" name="PR1030Comments" 
     type="large text box" index="30" 
     columnNo="0" dataType="Text"> 
      <Description>Comments</Description> 
      <Value instance="0">Test</Value> 
     </Object> 
    </ObjectGroup> 
</Activity> 

produit le résultat souhaité, corriger:

<html> 
    <table border="1"> 
     <tr> 
      <td width="50%">30/06/2010</td> 
      <td width="50%">Site Administrator</td> 
     </tr> 
     <tr> 
      <td width="100%">Test</td> 
     </tr> 
    </table> 
</html> 
1

Suite à l'excellente réponse de Dimitre, une autre feuille de style sans clés.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output indent="yes"/> 
    <xsl:template match="ObjectGroup"> 
     <html> 
      <table border="1"> 
       <xsl:apply-templates select="Object[@columnNo=0]"/> 
      </table> 
     </html> 
    </xsl:template> 
    <xsl:template match="Object"> 
     <xsl:variable name="td" 
         select=".|following-sibling::*[@columnNo!=0][ 
             count(current()| 
              preceding-sibling::*[@columnNo=0][1] 
            )=1]"/> 
     <tr> 
      <xsl:apply-templates select="$td/Value"> 
       <xsl:with-param name="td-count" select="count($td)"/> 
      </xsl:apply-templates> 
     </tr> 
    </xsl:template> 
    <xsl:template match="Value"> 
     <xsl:param name="td-count"/> 
     <td width="{100 div $td-count}%"> 
      <xsl:value-of select="."/> 
     </td> 
    </xsl:template> 
</xsl:stylesheet> 

Cependant, la plupart des processeurs XSLT permettent l'utilisation de clés.

Maintenant, pour colspan:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output indent="yes"/> 
    <xsl:variable name="td-max"> 
     <xsl:call-template name="max"> 
      <xsl:with-param name="nodes" select="/*/*/Object[@columnNo=0]"/> 
     </xsl:call-template> 
    </xsl:variable> 
    <xsl:template name="max"> 
     <xsl:param name="nodes"/> 
     <xsl:if test="$nodes"> 
      <xsl:variable name="head" 
           select="count($nodes[1]/following-sibling::*[@columnNo!=0][ 
              count($nodes[1]| 
               preceding-sibling::*[@columnNo=0][1] 
             )=1])+1"/> 
      <xsl:variable name="tail"> 
       <xsl:call-template name="max"> 
        <xsl:with-param name="nodes" select="$nodes[position() > 1]"/> 
       </xsl:call-template> 
      </xsl:variable> 
      <xsl:choose> 
       <xsl:when test="$head > $tail or $tail=''"> 
        <xsl:value-of select="$head"/> 
       </xsl:when> 
       <xsl:otherwise> 
        <xsl:value-of select="$tail"/> 
       </xsl:otherwise> 
      </xsl:choose> 
     </xsl:if> 
    </xsl:template> 
    <xsl:template match="ObjectGroup"> 
     <html> 
      <table border="1"> 
       <xsl:apply-templates select="Object[@columnNo=0]"/> 
      </table> 
     </html> 
    </xsl:template> 
    <xsl:template match="Object"> 
     <xsl:variable name="td" 
          select=".|following-sibling::*[@columnNo!=0][ 
              count(current()| 
               preceding-sibling::*[@columnNo=0][1] 
             )=1]"/> 
     <tr> 
      <xsl:apply-templates select="$td/Value"> 
       <xsl:with-param name="td-count" select="count($td)"/> 
      </xsl:apply-templates> 
     </tr> 
    </xsl:template> 
    <xsl:template match="Value"> 
     <xsl:param name="td-count"/> 
     <td width="{100 div $td-count}%"> 
      <xsl:if test="position()=last() and $td-max > $td-count"> 
       <xsl:attribute name="colspan"> 
        <xsl:value-of select="$td-max - $td-count + 1"/> 
       </xsl:attribute> 
      </xsl:if> 
      <xsl:value-of select="."/> 
     </td> 
    </xsl:template> 
</xsl:stylesheet> 

Modifier: colspan dynamique Ajouté. Il pourrait être moins verbeux si vous ne vous souciez pas de plusieurs colspan="1".

Édition 2: Meilleur motif max.

+0

Merci pour les réponses. La feuille de style fournie par Dimitre m'a aidé et m'a indiqué dans la bonne direction. – Manthan

+0

@Manthan: Vous êtes bienvenu! Aussi, je dois dire que vous devriez marquer Dimitre poste comme la bonne réponse afin d'aider les autres. –

+0

@Dimitre: Y a-t-il un moyen de calculer aussi le colspan pour les lignes dont la largeur va être de 100% pour que le HTML s'affiche correctement comme actuellement quand j'utilise 100% comme largeur pour les lignes avec une seule colonne le HTML tout détraqué. Est-il possible dans la feuille de style que je puisse traverser la sortie de la xslt à un stade ultérieur afin que je puisse ajuster le colspan des lignes avec une seule colonne. – Manthan

Questions connexes