tags:

views:

326

answers:

3

I have to create one table using XSLT and CSS. The table should look like:

ID    FNAME
1    AA
2    BB

My XML is:

<students>
  <studentDetails>
    <id>1</id>
    <fname>AA</fname>
  </studentDetails>
  <studentDetails>
    <id>2</id>
    <fname>BB</fname>
  </studentDetails>
<students>

And here my XSLT so far:

<xsl:template match="students">
  <div>
    <div class="idcol">
      <div class="header">
        <xsl:text>ID</xsl:text>
      </div>
      <div class="row">
        <xsl:value-of select="studentDetails[1]/id"/>
      </div>
      <div class="row">
        <xsl:value-of select="studentDetails[2]/id"/>
      </div>
    </div>
    <div class="fnamecol">
      <div class="header">
        <xsl:text>FNAME</xsl:text>
      </div>
      <div class="row">
        <xsl:value-of select="studentDetails[1]/fname"/>
      </div>
      <div class="row">
        <xsl:value-of select="studentDetails[2]/fname"/>
      </div>
    </div>
  </div>
</xsl:template>

The output looks right after applying CSS, but the problem is that I have used [1] and [2] directly. So if there is 3rd row then I have to change my code again. How to do this dynamically using some index - can somebody help?

+2  A: 

You could use <xsl:for-each>, but I think this is more concise, and extensible to arbitrarily many columns (so long as they're all the same):

<xsl:stylesheet version="1.0" xmlns:xs="...">

  <xsl:template match="students">
    <div>
      <div class="idcol">
        <div class="header">
          <xsl:text>ID</xsl:text>
        </div>
        <xsl:apply-templates>
          <xsl:with-param name="child-name" select="'id'"/>
        </xsl:apply-templates>
      </div>
      <div class="fnamecol">
        <div class="header">
          <xsl:text>FNAME</xsl:text>
        </div>
        <xsl:apply-templates>
          <xsl:with-param name="child-name" select="'fname'"/>
        </xsl:apply-templates>
      </div>
    </div>
  </xsl:template>

  <xsl:template match="studentDetails">
    <xsl:param name="child-name"/>
    <div class="row">
      <xsl:value-of select="*[name() = $child-name]"/>
    </div>
  </xsl:template>

</xsl:stylesheet>
Pavel Minaev
Thanks, it worked for me.
Wondering
can u pls explain <xsl:value-of select="*[name() = $child-name]"/>this line of code?
Wondering
+1 for the solution. And to get you over 10k. ;-)
Tomalak
I've posted an alternative solution.
Tomalak
@Wondering: it selects all child elements with name of element (i.e. name of its tag) equal to `$child-name`.
Pavel Minaev
A: 

First you should reorganize your HTML code to represent each row in one piece. If you organize the table in columns then it's not easy to create that code from your source XML data.

After you reorganized your HTML you can write a new template for the node "studentDetails". Move the code for each row into that template. In the template that matches the node "student" insert

<xsl:apply-templates match="studentDetails" />

to insert the information for each Student.

migu
+2  A: 

An even more dynamic solution (dynamic rows and columns):

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

  <xsl:variable name="l" select="'abcdefghijklmnopqrstuvwxyz'" />
  <xsl:variable name="u" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" />
  <xsl:key name="kSd" match="studentDetails/*" use="name()" />

  <xsl:template match="students">
    <div>
      <xsl:for-each select="studentDetails[1]/*">
        <div class="{name()}col">
          <div class="header">
            <xsl:value-of select="translate(name(), $l, $u)" />
          </div>
          <xsl:apply-templates select="key('kSd', name())" />
        </div>           
      </xsl:for-each>
    </div>
  </xsl:template>

  <xsl:template match="studentDetails/*">
    <div class="row">
      <xsl:value-of select="." />
    </div>
  </xsl:template>

</xsl:stylesheet>

produces:

<div>
  <div class="idcol">
    <div class="header">ID</div>
    <div class="row">1</div>
    <div class="row">2</div>
  </div>
  <div class="fnamecol">
    <div class="header">FNAME</div>
    <div class="row">AA</div>
    <div class="row">BB</div>
  </div>
</div>
Tomalak
Thanks Tomalak for ur help.This is really cool. :-)
Wondering