Transforming XML into HTML with couple representations - xslt

My XML contains description of some resource. I want to build HTML with JSON, XML, etc. representation of this resource.
Here is XML:
<?xml version="1.0" encoding="UTF-8"?>
<resources>
<resource name="item">
<parameters>
<parameter name="id">
<example-value>1234</example-value>
<type>integer</type>
</parameter>
<parameter name="name">
<example-value>parameter</example-value>
<type>string</type>
</parameter>
<parameter name="timestamp">
<example-value>1466589751</example-value>
<type>integer</type>
</parameter>
<parameter name="status">
<example-value>1</example-value>
<type>integer</type>
</parameter>
</parameters>
</resource>
</resources>
And here is how I do it:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<html>
<xsl:apply-templates/>
</html>
</xsl:template>
<xsl:template match="resources">
<body>
<xsl:apply-templates/>
</body>
</xsl:template>
<xsl:template match="resource">
<div>
<h2>
<xsl:value-of select="#name"/>
</h2>
<xsl:apply-templates/>
</div>
</xsl:template>
<xsl:template match="parameters">
<h3>
<xsl:text>Examples</xsl:text>
</h3>
<div>
<xsl:call-template name="CSVExample"/>
<xsl:call-template name="TableExample"/>
<xsl:call-template name="JSONExample"/>
<xsl:call-template name="XMLExample"/>
</div>
</xsl:template>
<xsl:template name="CSVExample">
<div>
<pre>
<xsl:for-each select="parameter">
<xsl:value-of select="concat('"',#name,'"')"/>
<xsl:if test="position() < last()">
<xsl:text>,</xsl:text>
</xsl:if>
</xsl:for-each>
<xsl:text>
</xsl:text>
<xsl:for-each select="parameter">
<xsl:value-of select="concat('"',example-value,'"')"/>
<xsl:if test="position() < last()">
<xsl:text>,</xsl:text>
</xsl:if>
</xsl:for-each>
</pre>
</div>
</xsl:template>
<xsl:template name="TableExample">
<div>
<pre>
<table>
<tr>
<xsl:for-each select="parameter">
<th>
<xsl:value-of select="#name"/>
</th>
</xsl:for-each>
</tr>
<tr>
<xsl:for-each select="parameter">
<td>
<xsl:value-of select="example-value"/>
</td>
</xsl:for-each>
</tr>
</table>
</pre>
</div>
</xsl:template>
<xsl:template name="JSONExample">
<div>
<pre>
<xsl:text>{</xsl:text>
<xsl:for-each select="parameter">
<xsl:value-of select="concat('"',#name,'":')"/>
<xsl:if test="type = 'string'">
<xsl:text>"</xsl:text>
</xsl:if>
<xsl:value-of select="example-value"/>
<xsl:if test="type = 'string'">
<xsl:text>"</xsl:text>
</xsl:if>
<xsl:if test="position() < last()">
<xsl:text>,</xsl:text>
</xsl:if>
</xsl:for-each>
<xsl:text>}</xsl:text>
</pre>
</div>
</xsl:template>
<xsl:template name="XMLExample">
<div>
<pre>
<parameters>
<xsl:for-each select="parameter">
<xsl:element name="{#name}">
<xsl:value-of select="example-value"/>
</xsl:element>
</xsl:for-each>
</parameters>
</pre>
</div>
</xsl:template>
</xsl:stylesheet>
Do You think this is right way to do such a case? I mean templates structure, calls, applys, etc.
Should I mayby replace for-each with some apply-templates? I read somewhere that is better to avoid for-each in favour of apply-templates. But is that true in this case?

I'm sure we could discuss many alternative ways to rework your xsl but to be honest this is not the correct forum for such things -- You really ought to be using that code review forum on Stack Exchange.
That said, I think your xsl structure is generally good - better than most we see on this site!
However, as it stands if <parameters> exits without any child <<parameter> nodes the call-templates wil still generate unwanted(?) content.
You would be better to use apply-templates with a mode attribute.
<xsl:template match="properties" mode="CSVExample">
....
</xsl:template>
and replace the call-templates with
<xsl:apply-templates select="." mode="CSVExample"/>
As for deciding betwee the for-each or apply-templates : When using a select="", I dont think it generally matters which way you go. Personally, I opt for apply-templates every time, it's more flexible and only use for-each whenever the code looks neater or is easier to understand that way.

Related

Xpath - How to get all existing attributes name of siblings

The goal is simple. I'm trying to build a table with attributes in columns.
My problem : Some siblings don't have the same attributes as the first one.
When I build the table head I retrieve the attributes name of the first node and then hope that attributes of the following siblings will be the same in the same order. That is not the case.
I get only columns id, key, value, myattr1 and the myattr2 attribute is placed in the myattr1 column.
For building the table, I want to get columns : id, key, value, myattr1, myattr2
How can I retrieve the whole list of existing attributes for the node I am working on and loop over it?
I am still working the same js and form (see link at the bottom). It now requires bootstrap (css and js).
I slightly changed the xml. Here it is :
<?xml version="1.0" encoding="UTF-8"?>
<Domain>
<Properties id="myid">
<Property id="DOM00000" key="mykey1" value="value1" myattr2="Mail"/>
<Property id="DOM00001" key="mykey2" value="value2" myattr1="EveryDay"/>
</Properties>
<Tokens>
<Token name="token1" comment="" ><![CDATA[mydata1---blah-blah-blah]]></Token>
<Token name="token2" comment="" ><![CDATA[mydata2---blah-blah-blah]]></Token>
</Tokens>
<Resources>
<Resource name="res1" type="W" current="0">
<Value><![CDATA[10]]></Value>
</Resource>
<Resource name="res2" type="W" current="0">
<Value><![CDATA[10]]></Value>
</Resource>
</Resources>
</Domain>
The current state of the xsl :
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/*">
<xsl:element name="div">
<xsl:attribute name="class">container</xsl:attribute>
<ul class="nav nav-tabs">
<xsl:for-each select="./*">
<xsl:call-template name="tabs" />
</xsl:for-each>
</ul>
</xsl:element>
<xsl:element name="div">
<xsl:attribute name="class">tab-content</xsl:attribute>
<xsl:for-each select="./*">
<xsl:call-template name="tabcontent" />
</xsl:for-each>
</xsl:element>
</xsl:template>
<xsl:template name="tabs">
<xsl:variable name="active">
<xsl:choose>
<xsl:when test="preceding-sibling::*"></xsl:when>
<xsl:otherwise>active</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:element name="li">
<xsl:attribute name="class">nav-item <xsl:value-of select="$active" /></xsl:attribute>
<xsl:element name="a">
<xsl:attribute name="href">#<xsl:value-of select="name(.)" /></xsl:attribute>
<xsl:attribute name="class">nav-link</xsl:attribute>
<xsl:attribute name="data-toggle">tab</xsl:attribute>
<xsl:value-of select="name(.)" />
</xsl:element>
</xsl:element>
</xsl:template>
<xsl:template name="tabcontent">
<xsl:variable name="activetab">
<xsl:choose>
<xsl:when test="preceding-sibling::*"></xsl:when>
<xsl:otherwise>active in</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:element name="div">
<xsl:attribute name="id"><xsl:value-of select="name(.)" /></xsl:attribute>
<xsl:attribute name="class">container tab-pane fade <xsl:value-of select="$activetab" /></xsl:attribute>
<h3><xsl:value-of select="name(.)" /></h3>
<table class="table table-striped table-hover">
<thead>
<tr><xsl:for-each select="./*[1]/#*"><th><xsl:value-of select="name(.)" /></th></xsl:for-each></tr>
</thead>
<tbody>
<xsl:for-each select="./*"><tr>
<xsl:for-each select="./#*"><td><xsl:value-of select="." /></td></xsl:for-each></tr>
</tr></xsl:for-each>
</tbody>
</table>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
XSLT - How to manage CDATA as common content?
Edit :
Thanks to Tim-C answer
Here is the full xsl working for my use case :
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="attrs" match="/*/*/*/#*" use="concat(name(../..), '|', name())" />
<xsl:template match="/*">
<xsl:element name="div">
<xsl:attribute name="class">container</xsl:attribute>
<ul class="nav nav-tabs">
<xsl:for-each select="./*">
<xsl:call-template name="tabs" />
</xsl:for-each>
</ul>
</xsl:element>
<xsl:element name="div">
<xsl:attribute name="class">tab-content</xsl:attribute>
<xsl:for-each select="./*">
<xsl:call-template name="tabcontent" />
</xsl:for-each>
</xsl:element>
</xsl:template>
<xsl:template name="tabs">
<xsl:variable name="active">
<xsl:choose>
<xsl:when test="preceding-sibling::*"></xsl:when>
<xsl:otherwise>active</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:element name="li">
<xsl:attribute name="class">nav-item <xsl:value-of select="$active" /></xsl:attribute>
<xsl:element name="a">
<xsl:attribute name="href">#<xsl:value-of select="name(.)" /></xsl:attribute>
<xsl:attribute name="class">nav-link</xsl:attribute>
<xsl:attribute name="data-toggle">tab</xsl:attribute>
<xsl:value-of select="name(.)" />
</xsl:element>
</xsl:element>
</xsl:template>
<xsl:template name="tabcontent">
<xsl:variable name="activetab">
<xsl:choose>
<xsl:when test="preceding-sibling::*"></xsl:when>
<xsl:otherwise>active in</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="attrs" select="*/#*[generate-id() = generate-id(key('attrs', concat(name(../..), '|', name()))[1])]" />
<xsl:element name="div">
<xsl:attribute name="id"><xsl:value-of select="name(.)" /></xsl:attribute>
<xsl:attribute name="class">container tab-pane fade <xsl:value-of select="$activetab" /></xsl:attribute>
<h3><xsl:value-of select="name(.)" /></h3>
<table class="table table-striped table-hover">
<thead>
<tr>
<xsl:for-each select="$attrs">
<th>
<xsl:value-of select="name()" />
</th>
</xsl:for-each>
</tr>
</thead>
<tbody>
<xsl:for-each select="*">
<tr>
<xsl:variable name="current" select="." />
<xsl:for-each select="$attrs">
<td>
<xsl:value-of select="$current/#*[name() = name(current())]" />
</td>
</xsl:for-each>
</tr>
</xsl:for-each>
</tbody>
</table>
</xsl:element>
</xsl:template>
<xsl:template name="toto"></xsl:template>
</xsl:stylesheet>
What you make use of here is a technique called Muenchian Grouping to get a list of distinct attributes, based on their name.
However, although the question just mentions about id, key, value, myattr1, myattr2, which are the Property attributes, it looks like you want to repeat it for the Token and Resource nodes too (i.e. you are trying to be generic). In this case, you define a key like so, which takes into account the main element name
<xsl:key name="attrs" match="/*/*/*/#*" use="concat(name(../..), '|', name())" />
Then, for a given element (such as Properties) you can get distinct attributes like so:
<xsl:variable name="attrs" select="*/#*[generate-id() = generate-id(key('attrs', concat(name(../..), '|', name()))[1])]" />
This can then be used to get the headers, and access the relevant attributes for each row.
Try this (abridged) XSLT:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" />
<xsl:key name="attrs" match="/*/*/*/#*" use="concat(name(../..), '|', name())" />
<xsl:template match="/*">
<xsl:for-each select="*">
<xsl:call-template name="tabcontent" />
</xsl:for-each>
</xsl:template>
<xsl:template name="tabcontent">
<xsl:variable name="attrs" select="*/#*[generate-id() = generate-id(key('attrs', concat(name(../..), '|', name()))[1])]" />
<table class="table table-striped table-hover">
<thead>
<tr>
<xsl:for-each select="$attrs">
<th>
<xsl:value-of select="name()" />
</th>
</xsl:for-each>
</tr>
</thead>
<tbody>
<xsl:for-each select="*">
<tr>
<xsl:variable name="current" select="." />
<xsl:for-each select="$attrs">
<td>
<xsl:value-of select="$current/#*[name() = name(current())]" />
</td>
</xsl:for-each>
</tr>
</xsl:for-each>
</tbody>
</table>
</xsl:template>
</xsl:stylesheet>
See it in action at http://xsltfiddle.liberty-development.net/jyRYYi7

How to build a string with XSLT?

I have this XML snippet
<MediaTypes>
<DVD>true</DVD>
<HDDVD>false</HDDVD>
<BluRay>true</BluRay>
</MediaTypes>
And I want to create an output that looks like this
DVD / Blu-ray
or like this
DVD
or like this
DVD / HD-DVD / Blu-ray
depending on the true/false states
But I'm a total beginner in the XSLT game. :-/
Here's a snippet of the full XML
<?xml version="1.0" encoding="Windows-1252"?>
<Collection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<DVD>
<ProfileTimestamp>2012-06-07T05:20:51Z</ProfileTimestamp>
<ID>0044005507027.5</ID>
<MediaTypes>
<DVD>true</DVD>
<HDDVD>false</HDDVD>
<BluRay>false</BluRay>
</MediaTypes>
<UPC>0-044005-507027</UPC>
<CollectionNumber>448</CollectionNumber>
<CollectionType IsPartOfOwnedCollection="true">Owned</CollectionType>
<Title>The Big Lebowski</Title>
<DistTrait />
<OriginalTitle />
<CountryOfOrigin>United States</CountryOfOrigin>
...
</DVD>
<DVD>
...
</DVD>
</Collection>
I tried to follow the advices given below (regarding the loop), but it doesn't seem to work.
This is the XSL I have so far (complete):
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template name="MediaTypes" match="MediaTypes">
Test
<xsl:for-each select="*[.='true']">
<xsl:value-of select="name()"/>
<xsl:if test="position()!=last()">
<xsl:text>/</xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:template>
<xsl:template match="/">
<html>
<head>
<title>DVD Profiler Double Dips</title>
</head>
<body>
<div>
<h1>DVD Profiler Double Dips</h1>
</div>
<table border="1" cellpadding="3" cellspacing="0">
<tr>
<th>Title</th>
<th>Edition</th>
<th>Production Year</th>
<th>DVD /</th>
<th>Purchase Date</th>
<th>Collection Type</th>
<th>Original Title</th>
<th>Sort Title</th>
</tr>
<xsl:for-each select="/Collection/DVD">
<tr>
<td>
<xsl:value-of select="Title"/>
</td>
<td>
<xsl:if test="DistTrait != ''">
<xsl:value-of select="DistTrait"/>
</xsl:if>
<xsl:if test="DistTrait = ''">
 
</xsl:if>
</td>
<td>
<xsl:if test="ProductionYear != ''">
<xsl:value-of select="ProductionYear"/>
</xsl:if>
<xsl:if test="ProductionYear = ''">
 
</xsl:if>
</td>
<td>
<xsl:call-template name="MediaTypes" />
</td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
But where
<xsl:call-template name="MediaTypes" />
is standing, only "Test" comes out
Yay!
You guys are awesome. Yes
<xsl:apply-templates select="MediaTypes"/>
Was my weapon of choice.
My final template looks like this:
<xsl:template name="MediaTypes" match="MediaTypes">
<xsl:for-each select="*[.='true']">
<xsl:value-of select="name()"/>
<xsl:if test="position()!=last()">
<xsl:text> / </xsl:text>
</xsl:if>
</xsl:for-each>
<xsl:if test="CustomMediaType != ''">
<xsl:if test="*[.='true']">
<xsl:text> / </xsl:text>
</xsl:if>
<xsl:value-of select="CustomMediaType"/>
</xsl:if>
</xsl:template>
begins to understand how stuff works
Thanks for all your help!
The question is rather trivial - the real problem is that you only show a snippet of the XML document. XSLT is very much context-dependent.
Here is a template to match any <MediaTypes> element and output the required string; hopefully you'll know how to incorporate it into your own stylesheet:
<xsl:template match="MediaTypes">
<xsl:for-each select="*[.='true']">
<xsl:value-of select="name()"/>
<xsl:if test="position()!=last()">
<xsl:text>/</xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:template>
I'd advice you to change the xml a bit
Here is an example
<?xml version="1.0" ?>
<?xml-stylesheet type="text/xsl" ?>
<MediaTypes>
<Media name="DVD">true</Media>
<Media name="HDDVD">false</Media>
<Media name="BluRay">true</Media>
</MediaTypes>
This way you may write XPATH expressions like //MediaTypes/Media
However did #michael.hor257k write a nice solution, jacking this xml pattern into that would look like this
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="//MediaTypes">
<xsl:for-each select="*[.='true']">
<xsl:value-of select="#name"/>
<xsl:if test="position()!=last()">
<xsl:text>/</xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
This will render DVD/BluRay
Test here http://xslttest.appspot.com/

xslt sorting not working

basically i want to sort data by level and i'm getting an error. I'm a newbie to xslt. i tried the below code but not working.
here is my xml file.
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="XSLTEx1WT.xsl"?>
<Modules>
<module code="CSE2041">
<name>Web Technologies II</name>
<credit>3</credit>
<level>2</level>
</module>
<module code="CSE2031Y">
<name>Object Oriented Software Development</name>
<credit>6</credit>
<level>2</level>
</module>
<module code="CSE1041">
<name>Web Technologies I</name>
<credit>3</credit>
<level>1</level>
</module>
</Modules>
here is my xsl file
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:variable name="deptCredit" select="99"/>
<xsl:variable name="myBorder" select="1"/>
<xsl:template match="/">
<html>
<head>
<title>XSLT Exercise 1</title></head>
<body>
<table border="{$myBorder}">
<thead><tr><th>Module Name</th><th>No. of Credits</th><th>Level</th></tr></thead>
<tbody>
<xsl:apply-templates>
**<xsl:sort select="level" data-type="number"/>**
</xsl:apply-templates>
<tr><td colspan="3">Departmental credits needed: <xsl:value-of select="$deptCredit"/></td></tr>
<tr><td colspan="3">Percentage cleared: <strong> <xsl:value-of select="format-number(sum(//credit/text()) div $deptCredit,'##.##%')"/></strong>
</td></tr>
</tbody>
</table>
</body>
</html>
</xsl:template>
<xsl:template match="module">
<xsl:apply-templates select="#code"/>
<tr><xsl:apply-templates select="*"/></tr>
</xsl:template>
<xsl:template match="name">
<xsl:call-template name="sjName"/>
</xsl:template>
<xsl:template match="#code">
<tr style="background-color:silver;">
<td colspan="3" style="text-align:center;">
<xsl:value-of select="."/>
</td>
</tr>
</xsl:template>
<xsl:template match="credit">
<td style="color:blue;"><strong><xsl:value-of select="text()"/></strong></td>
</xsl:template>
<xsl:template match="level">
<td style="color:blue;"><strong><xsl:value-of select="text()"/></strong></td>
</xsl:template>
<xsl:template name="sjName">
<xsl:choose>
<xsl:when test="contains(../#code,'Y')">
<td style="color:orange;font-weight:bold;"><xsl:value-of select="."/></td>
</xsl:when>
<xsl:otherwise>
<td style="color:lime;font-weight:bold;"><xsl:value-of select="."/></td>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
i have tried the above but its not working
You simply need to change this:
<xsl:apply-templates>
<xsl:sort select="level" data-type="number"/>
</xsl:apply-templates>
to this:
<xsl:apply-templates select="Modules/module">
<xsl:sort select="level" data-type="number"/>
</xsl:apply-templates>

How can I group homogenous data in xsl?

Let's say we have following data:
<all>
<item id="1"/>
<item id="2"/>
...
<item id="N"/>
</all>
What is the most elegant, xslt-ish way to group those items?
For example, imagine we want a table with two cells in each row.
Off the top of my head I can imagine (not tested though)
in template, matching item, I can call this very item, selecting following-sibling.
But even in this case I should pass additional param, to make recursion finite.
As row-count can be variable .. am passing it as a param to the template .. :)
<?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="/all[node]">
<table>
<xsl:for-each select="node[1]">
<xsl:call-template name="whoaa">
<xsl:with-param name="count" select="'1'"/>
<xsl:with-param name="row_count" select="'10'"/>
<!--maximum row_count is set to 10 -->
</xsl:call-template>
</xsl:for-each>
</table>
</xsl:template>
<xsl:template name="whoaa">
<xsl:param name="count"/>
<xsl:param name="row_count"/>
<!--check if we have crossed row_count-->
<xsl:if test="not ($row_count < $count)">
<tr>
<td>
<xsl:value-of select="."/>
</td>
<td>
<!--copy next column-->
<xsl:for-each select="following-sibling::node[1]">
<xsl:value-of select="."/>
</xsl:for-each>
</td>
</tr>
<!--Select next row .. call the same template untill we reach (row_count > count)-->
<xsl:for-each select="following-sibling::node[2]">
<xsl:call-template name="whoaa">
<xsl:with-param name="count" select="$count+2"/>
<xsl:with-param name="row_count" select="$row_count"/>
</xsl:call-template>
</xsl:for-each>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
use position and mod, e.g.
<xsl:template match="/all">
<table>
<xsl:apply-templates name="item" mode="group"/>
</table>
</xsl:template>
<xsl:template match="item[position() mod 2=1]" mode="group">
<tr>
<td><xsl:apply-templates select="." mode="render"/></td>
<td><xsl:apply-templates select="following-sibling::item[1]" mode="render"/></td>
</tr>
</xsl:template>
<xsl:template match="item[position() mod 2=0]"></xsl:template>
<xsl:template match="item" mode="render">item: <xsl:value-of select="#id"/></xsl:template>

Show the header only once in a for-each

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="'
'"/>
</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.
<?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">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.
Just take <xsl:text>Header</xsl:text> out of for-each...
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>