tags:

views:

64

answers:

2

Hi, i Have the following data in XML

<data> 
 <record> 
  <id>1</id> 
  <name>David</name> 
  <age>40</age>  
 </record> 
 <record> 
  <id>2</id> 
  <name>Tully</name> 
  <age>38</age> 
 </record> 
 <record> 
  <id>3</id>  
  <name>Solai</name> 
  <age>32</age> 
 </record> 
 <record> 
  <id>4</id>  
  <name>Michael</name> 
  <age>49</age> 
 </record> 
 <record> 
  <id>5</id>  
  <name>Tony</name> 
  <age>19</age> 
 </record> 
 <record> 
  <id>6</id>  
  <name>Ray</name> 
  <age>26</age> 
 </record> 
 <record> 
  <id>7</id>  
  <name>Leeha</name> 
  <age>13</age> 
 </record> 
</data> 

And would like to display the data like this:

ID    1     2   
Name  David Tully
Age   40    38

How can I do that in XSLT? Thanks in advanced

A: 

Assuming you're outputting to HTML, you can loop over records to line them up under each other:

<xsl:template match="data">
   <table>
      <tr>
         <td>ID</td>
         <xsl:apply-templates select="record" mode="id" />
      </tr>
      <tr>
         <td>Name</td>
         <xsl:apply-templates select="record" mode="name" />
      </tr>
      <tr>
          <td>Age</td>
           <xsl:apply-templates select="record" mode="age" />
      </tr>
   </table>
</xsl:template>

<xsl:template match="record" mode="id">
   <td><xsl:value-of select="id" /></td>
</xsl:template>

<xsl:template match="record" mode="name">
   <td><xsl:value-of select="name" /></td>
</xsl:template>

<xsl:template match="record" mode="age">
   <td><xsl:value-of select="age" /></td>
</xsl:template>
LorenVS
Thanks, I need to quick answer on these. I google it and not seeing any example on it. Is that a good book that you can reference.
I found XSLT easier to learn by just doing it for a while. Eventually you learn the caveats and how to approach various problems
LorenVS
I am sorry, Faheemitian. For any offensive approach for this web site. I am not exactly a programmer and I am just bussiness analyst. I spent my whole weekend to find a solution of this but I am unable to. Thanks for LorenVS with motivation.
I only mean to help you, userxxx. What if you have another encounter with XSLT? Better approach is to get started from wikipedia article on XSLT... trust me you will save time that way - no harsh feelings
Faheem
@user479504: Faheemitian is a troll. Ignore him.
FrustratedWithFormsDesigner
+4  A: 

This stylesheet:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
    <xsl:template match="data">
        <table>
            <xsl:apply-templates select="*[1]"/>
        </table>
    </xsl:template>
    <xsl:template match="record[1]/*" priority="1">
        <tr>
            <th>
                <xsl:value-of select="name()"/>
            </th>
            <xsl:call-template name="td"/>
        </tr>
    </xsl:template>
    <xsl:template match="record/*" name="td">
        <td>
            <xsl:value-of select="."/>
        </td>
        <xsl:apply-templates select="following::*[count(../*)+1]"/>
    </xsl:template>
</xsl:stylesheet>

Output:

<table>
    <tr>
        <th>id</th>
        <td>1</td>
        <td>2</td>
        <td>3</td>
        <td>4</td>
        <td>5</td>
        <td>6</td>
        <td>7</td>
    </tr>
    <tr>
        <th>name</th>
        <td>David</td>
        <td>Tully</td>
        <td>Solai</td>
        <td>Michael</td>
        <td>Tony</td>
        <td>Ray</td>
        <td>Leeha</td>
    </tr>
    <tr>
        <th>age</th>
        <td>40</td>
        <td>38</td>
        <td>32</td>
        <td>49</td>
        <td>19</td>
        <td>26</td>
        <td>13</td>
    </tr>
</table>

EDIT: Just to show that this could be a not so trivial question, what about an XML tree with a more relaxed schema (missing some fields in records)?

This stylesheet:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
    <xsl:key name="kElementByName" match="record/*" use="name()"/>
    <xsl:template match="text()"/>
    <xsl:template match="data">
        <table>
            <xsl:apply-templates/>
        </table>
    </xsl:template>
    <xsl:template match="record/*[count(.|key('kElementByName',name())[1])=1]">
        <tr>
            <th>
                <xsl:value-of select="name()"/>
            </th>
            <xsl:apply-templates select="../../record" mode="td">
                <xsl:with-param name="pName" select="name()"/>
            </xsl:apply-templates>
        </tr>
    </xsl:template>
    <xsl:template match="record" mode="td">
        <xsl:param name="pName"/>
        <td>
            <xsl:value-of select="*[name()=$pName]"/>
        </td>
    </xsl:template>
</xsl:stylesheet>

With this input:

<data>
    <record>
        <id>1</id>
        <name>David</name>
    </record>
    <record>
        <name>Tully</name>
        <age>38</age>
    </record>
    <record>
        <id>3</id>
        <age>32</age>
    </record>
</data>

Output:

<table>
    <tr>
        <th>id</th>
        <td>1</td>
        <td></td>
        <td>3</td>
    </tr>
    <tr>
        <th>name</th>
        <td>David</td>
        <td>Tully</td>
        <td></td>
    </tr>
    <tr>
        <th>age</th>
        <td></td>
        <td>38</td>
        <td>32</td>
    </tr>
</table>
Alejandro
+1 for a good, generic solution.
Dimitre Novatchev
@Faheemitian: Please, follow FAQs guidelines. Bring your humor and desire to learn. As you can see, the two answers given here are diferent. In order to understand mine, you have to know about: named templates, template confict resolution, and `following` axis.
Alejandro
Your answer is better, I have not doubt about that.
Faheem
Great stylesheet. I have a tendency to focus on the ability to override specific templates due to a focus at a previous job. Your stylesheet makes better use of XSLT features to accomplish the specific purpose generically though.
LorenVS
@LorenVS: Not problem. I also think there are no general solutions. But, when I see a repeated pattern I try hard to express this generally enough to match all cases. That's because my functional paradigm background.
Alejandro