tags:

views:

140

answers:

3

Hi,

Say I have the following XML:

<a>
  <b>1</b>
  <b>2</b>
  <b>3</b>
</a>

... and require:

Header
1
2
3

... but an xslt like:

<xsl:template match = "/" >  
  <xsl:variable name="headed" select="false()"/>
  <xsl:for-each select = "a/*" >
    <xsl:if test="not($headed)">
      <xsl:text>Header</xsl:text>
      <!-- 
        this next line causes a problem due to 
        the attempted reassignment of $headed
      -->
      <xsl:variable name="headed" select="true()"/>
    </xsl:if>
    <xsl:value-of select="." />
    <xsl:value-of select="'&#x0a;'"/>
  </xsl:for-each>
</xsl:template>

is invalid, can anybody recommend a brief and readable solution? and perhaps a good book to learn a functional mindset from :)

Cheers

Simon

------------------------------ addendum --------------------------

After pondering the answers I've been presented with I realised I've lost some of the key components of the problem I was trying to tackle.

my data is more like:

<address>
  <line1>street</line1>
  <line2>town</line2>
  <line3>city</line3>
  <country>uk</country>
</address>

and my desired output is more like:

<table>
  <tr><td rowspan="6" valign="top">Address</td><td>street</td></tr>
  <tr><td>town</td></tr>
  <tr><td>city</td></tr>
  <tr><td>uk</td></tr>
</table>

any further help would be greatly appreciated.

+1  A: 

Just take <xsl:text>Header</xsl:text> out of for-each...

Michał Chaniewski
Yeah, that would work for this example.This question was a simplification of a real problem, I was creating an html table. In that problem the solution you gave falls down due to the table row tags not lining up within the xsl tags.Thanks though, sorry I wqasn't more explict.
Simon Nunn
+4  A: 
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;

<xsl:template match="a">Header
   <xsl:apply-templates/>
</xsl:template>

<xsl:template match="a/b">
  <xsl:apply-templates/>
</xsl:template>

</xsl:stylesheet>

Is practically what you want, and simpler than what you have now.

Alex Brown
You need to do some work on whitespace formatting, though.
Alex Brown
Cheers, I think you've shown me the right direction. As you said I'll need to jiggle the formating. The real world problem is going to output an html table, so there's quite a way to go. Cheers Simon
Simon Nunn
The use of <xsl:text> is recommendable over the use of literal strings in the XSL. Output white-space is a lot more easily controlled while code format can be kept independent of output format. Also, a template that does nothing else but call <xsl:apply-templates/> is superfluous. This is happening anyway through the pre-defined default templates.
Tomalak
+1  A: 

The end result was more like:

        <?xml version="1.0" encoding="ISO-8859-1"?>
        <xsl:stylesheet  version = "1.0"
        xmlns:xsl = "http://www.w3.org/1999/XSL/Transform" >

          <xsl:template match="/a">
            <html><body><table>
             <xsl:apply-templates select="*"/>
            </table></body></html>
          </xsl:template>


          <xsl:template match="a/*">
            <xsl:if test="not(.='')">
              <TR>
                <xsl:if test="position()=1">
    <!--
                  <TD rowspan="6" valign="top">Address</TD>
                 improved based on Tomalak's suggestion
    -->
              <xsl:element name="TD">
                <xsl:attribute name="rowspan" >
    <!--
                  <cough />
                  <xsl:value-of select="count(*)"/>
    -->
                  <xsl:value-of select="count(*[not(.='')]"/>
                </xsl:attribute>
                <xsl:attribute name="valign" >
                  <xsl:text>top</xsl:text>
                </xsl:attribute>
                <xsl:text>Address</xsl:text>
              </xsl:element>

                </xsl:if>
                <TD>
                  <xsl:value-of select="."/>
                </TD>
              </TR>
            </xsl:if>
          </xsl:template>
        </xsl:stylesheet>
Simon Nunn
Actually, that's a good solution. +1 -- The only check I'd remove is the "if not(.='')" - the rowspan will break if you do that.
Tomalak
amend, cheers for bug spotting.
Simon Nunn