2

My XML is

<row>
  <entry>1.</entry>
  <entry>foo</entry>
  <entry>morefoo</entry>
</row>
<row>
  <entry>2.</entry>
  <entry>2foo</entry>
  <entry>2morefoo</entry>
</row>

using XSLT, i'm trying to represent this information in a html table, and i want to have a Serial no. column.

How do i go about selecting the value of only the first 'entry' tag?

2
  • 1
    Can you post a sample of the table that should be produced? Commented Jul 19, 2010 at 20:24
  • Good question (+1). See my answer for a number of XPath expressions that provide the wanted functionality and more... Commented Jul 19, 2010 at 20:27

4 Answers 4

2

My XML is

<row> 
<entry>1.</entry> 
<entry>foo</entry> 
<entry>morefoo</entry> 
</row> 
<row> 
<entry>2.</entry> 
<entry>2foo</entry> 
<entry>2morefoo</entry> 
</row>

This is not wellformed XML document. A well-formed XML document must have exactly one top-level element. I will use the following (corrected to be well-formed) XML document:

<rows>
    <row>
        <entry>1.</entry>
        <entry>foo</entry>
        <entry>morefoo</entry>
    </row>
    <row>
        <entry>2.</entry>
        <entry>2foo</entry>
        <entry>2morefoo</entry>
    </row>
</rows>

How do i go about selecting the value of only the first 'entry' tag?

/*/row/entry[1]

The above selects the first entry element-child of every row element.

/*/row[1]/entry[1]

The above selects the first entry element-child of the first row element in the document.

/*/row[2]/entry[1]

The above selects the first entry element-child of the second row element in the document.

(//entry)[1]

The above selects the first entry element in the whole document.

//entry[1]

Note that this is different from the previous expression: this selects every entry element in the document, which is the first entry-child of its parent.

Sign up to request clarification or add additional context in comments.

5 Comments

+1 for the explanation of different XPath flavors. The W3C XPath Recommendation contains every detail on XPath expressions, in case @charudatta is interested.
+1 from me too, but a question that might raise: why would (//entry)[1] be used instead of just //entry[1]?
@Abel: (//entry)[1] isn't equivalent to //entry[1] and they both have their uses.
I know, I was just trying to make a point, sorry if it added to the confusion ;)
@Abel: No problem, I added this last expression in my answer, without lengthy explanations.
1

In your XSLT you should have something like this:

<!-- matches the root (not specified in your post) -->
<xsl:template match="/">
   <!-- at root level, make your table -->
   <table>
     <thead>.... </thead>
     <tbody>
       <!-- push the rows through, make sure the path is correct -->
       <xsl:apply-templates select="path/to/row" />
     </tbody>
   </table>
</xsl:template>

<xsl:template match="row">
   <!-- create the rows -->
   <tr>
     <!-- process first entry only, as you requested (why?) -->
     <xsl:apply-templates select="entry[1]" mode="first"/>
     <!-- process other entries -->
     <xsl:apply-templates select="entry[position() > 1]" mode="other"/>
   </tr>
</xsl:template>

<xsl:template match="entry" mode="first">
   <!-- maybe you want the first cell to be treated specially, i.e. as row header -->
   <th><xsl:value-of select="."/></th>
</xsl:template>

<xsl:template match="entry" mode="other">
   <!-- the other cells -->
   <td><xsl:value-of select="."/></td>
</xsl:template>

Note: the code above is not tested, use it as a template for your own real code and data.

Output would be something like the following:

<table>
  <thead>....</thead>
  <tbody>
    <tr>
      <th>1.</th>
      <td>foo</td>
      <td>morefoo</td>
    </tr>
    <tr>
      <th>2.</th>
      <td>2foo</td>
      <td>2morefoo</td>
    </tr>
    <tr>....
  </tbody>
</table>

1 Comment

good answer! But, I think it would be even better example with more "pattern matching" as match="entry[1]" and without apply-templates/@select... It would reflect better that it is just transforming Row to TR and entry to TD.
1
//row/entry[1]

This will select all the entry tags that are the first child of the parent node.

Comments

1

The XSLT below will produce this table:

Serial No  Name   Description
1.         foo    morefoo 
2.         2foo   2morefoo 

Sample document:

<?xml version="1.0" encoding="utf-8"?>
<document>
  <row>
    <entry>1.</entry>
    <entry>foo</entry>
    <entry>morefoo</entry>
  </row>
  <row>
    <entry>2.</entry>
    <entry>2foo</entry>
    <entry>2morefoo</entry>
  </row>
</document>

XSLT:

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

  <xsl:template match="/">
    <html>
      <head>
        <title>Sample</title>
      </head>
      <body>
        <table border="1">
          <tr>
            <th>Serial No</th>
            <th>Name</th>
            <th>Description</th>
          </tr>
          <xsl:apply-templates />
        </table>
      </body>
    </html>
  </xsl:template>

  <xsl:template match="row">
    <tr>
      <xsl:for-each select="entry">
        <td>
          <xsl:value-of select="."/>
        </td>
      </xsl:for-each>
    </tr>
  </xsl:template>

</xsl:stylesheet>

1 Comment

+1 for a good working example (and you were quicker than me ;-). I wouldn't opt for the for-each though, which in this case makes it (slightly) harder to distinguish between first cell and the rest.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.