Can't figure out the correct parameters for this xsl:key example to work. What I want is to output the same xhtml with rate/name fields changed based on the data in root.xml.
XHMTL (main input)
<!DOCTYPE html>
<html lang="en">
<head>
<title>PZBank</title>
</head>
<body>
<table style="width:100%">
<tr>
<th align="left">Product #1</th>
<th align="left">Product #2</th>
<th align="left">Product #3</th>
</tr>
<tr>
<td name="name0">Whiz-bang</td>
<td name="name1">Ulitmate</td>
<td name="name2">Killer</td>
</tr>
<tr>
<td name="rate0">2.09</td>
<td name="rate1">1.99</td>
<td name="rate2">3.19</td>
</tr>
</table>
</body>
</html>
XML - root.xml
<root>
<dbu>
<product ord="0">
<name>Amazing</name>
<rate>4.5</rate>
</product>
</dbu>
<dbu>
<product ord="1">
<name>Incredible</name>
<rate>6.6</rate>
</product>
</dbu>
</root>
XSL
<xsl:stylesheet version="3.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
expand-text="yes">
<xsl:output method="html" omit-xml-declaration="yes" encoding="UTF-8" include-content-type="no"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:variable name="rooter" select="document('root.xml')"/>
<xsl:key name="krate" match="product/rate" use="/root/dbu/product[#ord]"/>
<xsl:key name="kname" match="name" use="#ord"/>
<xsl:template match="td[starts-with(#name,'rate')]/text()">
<xsl:variable name="ordv" select="substring-after(../#name,'rate')"/>
<xsl:for-each select="$rooter">
<xsl:value-of select="key('krate',$ordv)"/>
</xsl:for-each>
</xsl:template>
<xsl:template match="td[starts-with(#name,'name')]/text()">
{key('kname', substring-after(../#name, 'name'), $rooter)}
</xsl:template>
</xsl:stylesheet>
What is happening is the name/rate fields are blank in the output so obviously the xsl:key calls are incorrect. I have even tried 2 approaches: krate and kname but no luck. I have also tried a number of different #ord xpath strings on the xsl:key.
The root.xml is just a test version. In production it will be much more complex.
You could use your second approach for both. So try this:
<xsl:stylesheet version="3.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
expand-text="yes">
<xsl:output method="html" omit-xml-declaration="yes" encoding="UTF-8" include-content-type="no"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:strip-space elements="*" />
<xsl:variable name="rooter" select="document('root.xml')"/>
<xsl:key name="kord" match="/root/dbu/product" use="#ord"/>
<xsl:template match="td[starts-with(#name,'rate')]/text()">{key('kord', substring-after(../#name, 'rate'), $rooter)/rate}</xsl:template>
<xsl:template match="td[starts-with(#name,'name')]/text()">{key('kord', substring-after(../#name, 'name'), $rooter)/name}</xsl:template>
</xsl:stylesheet>
The xsl:strip-space removes the empty lines between the elements.
If you really need the xsl:for-each for rate, it could look like this:
<xsl:template match="td[starts-with(#name,'rate')]/text()">
<xsl:variable name="ordv" select="substring-after(../#name,'rate')"/>
<xsl:for-each select="$rooter">
<xsl:value-of select="key('kord',$ordv)/rate"/>
</xsl:for-each>
</xsl:template>
Its output is
<!DOCTYPE HTML><html lang="en">
<head>
<title>PZBank</title>
</head>
<body>
<table style="width:100%">
<tr>
<th align="left">Product #1</th>
<th align="left">Product #2</th>
<th align="left">Product #3</th>
</tr>
<tr>
<td name="name0">Amazing</td>
<td name="name1">Incredible</td>
<td name="name2"></td>
</tr>
<tr>
<td name="rate0">4.5</td>
<td name="rate1">6.6</td>
<td name="rate2"></td>
</tr>
</table>
</body>
</html>
Related
My XML input:
<result>
<objects name="wf1">
<object>
<qname>wf</qname>
<object_name>Nr 1</object_name>
<person_name>Anton</person_name>
</object>
<object>
<qname>wf</qname>
<object_name>Nr 2</object_name>
<person_name>Ben</person_name>
</object>
</objects>
<objects name="wf2">
<object>
<qname>wf</qname>
<object_name>Nr 2</object_name>
<person_name>Chris</person_name>
</object>
<object>
<qname>wf</qname>
<object_name>Nr 3</object_name>
<person_name>Dirk</person_name>
</object>
</objects>
</result>
Things to note
There are two blocks with information: wf1 and wf2
Both have an object with object_name = 'Nr 2'
All objects have qname = 'wf'
My XSLT:
<xsl:template match="/">
<xsl:call-template name="output_html" />
</xsl:template>
<xsl:template name="output_html">
<html>
<body >
<table>
<tr>
<th>Object name</th>
<th>Person name</th>
</tr>
<xsl:apply-templates select="result/objects/object[qname='wf']" />
</table>
</body>
</html>
</xsl:template>
<xsl:template match="object[*]">
<tr align="center" valign="top">
<td><xsl:value-of select="object_name"/></td>
<td><xsl:value-of select="person_name"/></td>
</tr>
</xsl:template>
Output:
Object name
Person name
Nr 1
Anton
Nr 2
Ben
Nr 2
Chris
Nr 3
Dirk
My wish:
I would like to see unique object names. If an object with a certain name appears in both wf1 and wf2 then only the one from wf2 should be shown.
So the desired output would be:
Object name
Person name
Nr 1
Anton
Nr 2
Chris
Nr 3
Dirk
The information "Ben" gets lost. That is fine.
Does anybody have ideas about how to achieve that in XSLT 1.0?
In XSLT 1.0, it would be best to adapt the Muenchian method to the current problem:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:key name="obj-by-name" match="object" use="object_name" />
<xsl:template match="/result">
<html>
<body >
<table>
<!-- header -->
<tr>
<th>Object name</th>
<th>Person name</th>
</tr>
<!-- for each distinct object_name -->
<xsl:for-each select="objects/object[count(. | key('obj-by-name', object_name)[1]) = 1]">
<tr>
<td>
<xsl:value-of select="object_name"/>
</td>
<td>
<!-- sort the group with wf2 on top -->
<xsl:for-each select="key('obj-by-name', object_name)">
<xsl:sort select="number(../#name='wf2')" data-type="number" order="descending"/>
<xsl:if test="position()=1">
<xsl:value-of select="person_name"/>
</xsl:if>
</xsl:for-each>
</td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
If <objects name="wf2"> will always come after <objects name="wf1">, then you can shorten this to:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:key name="obj-by-name" match="object" use="object_name" />
<xsl:template match="/result">
<html>
<body >
<table>
<!-- header -->
<tr>
<th>Object name</th>
<th>Person name</th>
</tr>
<!-- for each distinct object_name -->
<xsl:for-each select="objects/object[count(. | key('obj-by-name', object_name)[1]) = 1]">
<tr>
<td>
<xsl:value-of select="object_name"/>
</td>
<td>
<xsl:value-of select="key('obj-by-name', object_name)[last()]/person_name"/>
</td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
I have this structure in my xml:
<zoo>
<species name="bird" />
<animal name="crane" />
<animal name="duck" />
<species name="fish" />
<animal name="dolphin" />
<animal name="goldfish" />
</zoo>
which I want to transform into something like this:
<table>
<tr><td> <b>bird</b> </td></tr>
<tr><td> crane </td></tr>
<tr><td> duck </td></tr>
</table>
<table>
<tr><td> <b>fish</b> </td></tr>
<tr><td> dolphin </td></tr>
<tr><td> goldfish </td></tr>
</table>
How can I make this work? I tried using nested for:each'es, but that obviously doesn't work since the nodes are not nested.
Assuming an XSLT 2.0 processor like Saxon 9 or XmlPrime you can use for-each-group group-starting-with="species":
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="html" doctype-public="XSLT-compat" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
<xsl:template match="/">
<htmt>
<head>
<title>group-starting-with</title>
</head>
<body>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="zoo">
<xsl:for-each-group select="*" group-starting-with="species">
<table>
<xsl:apply-templates select="current-group()"/>
</table>
</xsl:for-each-group>
</xsl:template>
<xsl:template match="species">
<tr>
<th>
<xsl:value-of select="#name"/>
</th>
</tr>
</xsl:template>
<xsl:template match="animal">
<tr>
<td><xsl:value-of select="#name"/></td>
</tr>
</xsl:template>
</xsl:transform>
Online at http://xsltransform.net/nc4NzRc/1.
This transformable HTML5:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<table border="1">
<caption>Complex Table</caption>
<tbody>
<tr>
<th>Title</th>
<th>Volume</th>
<th>Chapter</th>
<th>Stds.</th>
<th>Dept.</th>
</tr>
<tr>
<td rowspan="6">STEM</td>
<td rowspan="1">1</td>
<td rowspan="2">1</td>
<td>1 to 10</td>
<td rowspan="2">Biology</td>
</tr>
<tr>
<td rowspan="1">2</td>
<td>20 to 30</td>
</tr>
<tr>
<td rowspan="1">3</td>
<td rowspan="1">2</td>
<td>40 to 60</td>
<td rowspan="1">Chemistry</td>
</tr>
<tr>
<td>4</td>
<td>3</td>
<td>70 to 80</td>
<td>Physics</td>
</tr>
<tr>
<td rowspan="4">5</td>
<td rowspan="1">4</td>
<td>80 to 120</td>
<td rowspan="1">Math</td>
</tr>
<tr>
<td rowspan="1">5</td>
<td>120 to 135</td>
<td rowspan="1">Geometry</td>
</tr>
</tbody>
</table>
<table border="1">
<caption>Simpler Table</caption>
<tbody>
<tr>
<th>Title</th>
<th>Volume</th>
<th>Chapter</th>
<th>Stds.</th>
<th>Dept.</th>
</tr>
<tr>
<td colspan="1" rowspan="3">Kinesiology</td>
<td>1</td>
<td>1</td>
<td>A to C</td>
<td>Strength</td>
</tr>
<tr>
<td>2</td>
<td>2 to 3</td>
<td>D to H</td>
<td>Agility</td>
</tr>
<tr>
<td>3</td>
<td>4</td>
<td>I to X</td>
<td>Flexibility</td>
</tr>
</tbody>
</table>
<table border="1">
<caption>Simplest Table</caption>
<tbody>
<tr>
<th>Title</th>
<th>Volume</th>
<th>Chapter</th>
<th>Stds.</th>
<th>Dept.</th>
</tr>
<tr>
<td>Skills</td>
<td>1</td>
<td>1</td>
<td>A to C</td>
<td>Keyboard</td>
</tr>
</tbody>
</table>
</body>
</html>
This desired output (if you view the rendered HTML, you can see the pattern of data wanted):
<?xml version="1.0" encoding="UTF-8"?>
<production>
<book title="STEM" volume="1"/>
<book title="STEM" volume="2"/>
<book title="STEM" volume="3"/>
<book title="STEM" volume="4"/>
<book title="STEM" volume="5"/>
<book title="Kinesiology" volume="1"/>
<book title="Kinesiology" volume="2"/>
<book title="Kinesiology" volume="3"/>
<book title="Skills" volume="1"/>
</production>
The not quite working transform:
<xsl:stylesheet
version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs">
<xsl:output method="xml" encoding="UTF-8" indent="yes" />
<xsl:template match="/">
<catalog>
<xsl:apply-templates/>
</catalog>
</xsl:template>
<xsl:template match="text()"/>
<!-- multi-volume edition -->
<xsl:template match="table">
<xsl:variable name="title" select="descendant::td[1]"/>
<xsl:variable name="context-td" select="."/>
<!-- the following needs work -->
<xsl:for-each select="descendant::tr/td[1][matches(.,'\d+$')]">
<book>
<xsl:attribute name="title" select="$title"/>
<xsl:attribute name="volume" select="."/>
</book>
</xsl:for-each>
</xsl:template>
<!-- single-volume edition -->
<xsl:template match="table[count(descendant::tr) < 3]">
<book>
<xsl:attribute name="title" select="descendant::td[1]"/>
<xsl:attribute name="volume" select="descendant::tr[2]/td[2]"/>
</book>
</xsl:template>
</xsl:stylesheet>
The xpath in for-each needs work. I've tried various axis but haven't found one that works across all use cases.
Couldn't this be simply:
XSLT 2.0
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="UTF-8" indent="yes" />
<xsl:template match="/">
<catalog>
<xsl:apply-templates select="html/body/table"/>
</catalog>
</xsl:template>
<xsl:template match="table">
<xsl:variable name="title" select="tbody/tr[2]/td[1]"/>
<xsl:for-each select="tbody/tr[2]/td[2] | tbody/tr[position() > 2]/td[1]">
<book>
<xsl:attribute name="title" select="$title"/>
<xsl:attribute name="volume" select="."/>
</book>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Oops, I see there is a problem with volume 5 of STEM being listed twice - hold on...
No, I don't see a simple solution to this. I suspect you'd have to drill down into the table's structure, taking preceding rowspans into consideration - somewhat similar to:
Please suggest for XSLT code for Table rowspan and colspan issues
Edit:
Ok, I believe this should work:
XSLT 2.0
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="UTF-8" indent="yes" />
<xsl:template match="/">
<catalog>
<xsl:apply-templates select="html/body/table"/>
</catalog>
</xsl:template>
<xsl:template match="table">
<xsl:apply-templates select="tbody/tr[2]/td[2]">
<xsl:with-param name="title" select="tbody/tr[2]/td[1]" tunnel="yes"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="td">
<xsl:param name="title" tunnel="yes"/>
<book>
<xsl:attribute name="title" select="$title"/>
<xsl:attribute name="volume" select="."/>
</book>
<xsl:variable name="rowspan" select="if(#rowspan) then #rowspan else 1" />
<xsl:apply-templates select="parent::tr/following-sibling::tr[number($rowspan)]/td[1]"/>
</xsl:template>
</xsl:stylesheet>
Test, applied to a modified input in the form of:
http://xsltransform.net/94hvTz1/2
I tried it with grouping:
<xsl:stylesheet
version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs">
<xsl:output method="xml" encoding="UTF-8" indent="yes" />
<xsl:template match="/">
<catalog>
<xsl:apply-templates select="//table"/>
</catalog>
</xsl:template>
<xsl:template match="table">
<xsl:for-each-group select="tbody/tr[position() gt 1]/td[1]" group-by="../../(tr[2]/td[2] | tr[position() gt 2]/td[1])">
<book title="{.}" volume="{current-grouping-key()}"/>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>
Would this help by any chance(little changes made to michael.hor257k's answer) :
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="UTF-8" indent="yes" />
<xsl:template match="/">
<catalog>
<xsl:apply-templates select="html/body/table"/>
</catalog>
</xsl:template>
<xsl:template match="table">
<xsl:variable name="title" select="tbody/tr[2]/td[1]"/>
<xsl:variable name="table-id" select="generate-id()"/>
<xsl:for-each select="tbody/tr[2]/td[2] | tbody/tr[position() > 2]/td[1]">
<xsl:variable name="curr-td" select="."/>
<xsl:if test="not(exists(following::tr[td[1][generate-id(../../..) = $table-id and . = $curr-td]]))">
<book>
<xsl:attribute name="title" select="$title"/>
<xsl:attribute name="volume" select="."/>
</book>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Here is my following xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- Edited by XMLSpy® -->
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<table border="1">
<tr bgcolor="#9acd32">
<th>Title</th>
<th>price</th>
</tr>
<xsl:for-each select="library/book/authors/author[first='Harry'and last='Potter'] ">
<tr>
<td><xsl:value-of select="title"/></td>
<td><xsl:value-of select="price"/></td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Below is my XSL stylesheet
<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- Edited by XMLSpy® -->
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<table border="1">
<tr bgcolor="#9acd32">
<th>Title</th>
<th>price</th>
</tr>
<xsl:for-each select="library/book/authors/author[first='Harry'and last='Potter'] ">
<tr>
<td><xsl:value-of select="title"/></td>
<td><xsl:value-of select="price"/></td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
I am unable to display title and price as they are the parent element and I'm giving condition to my child element. And I need to display information regarding my parents element.
You can get access to a parent node in your XPath expression using "../". For example:
<xsl:value-of select="../../title"/>
<xsl:value-of select="../../price"/>
In this case I'd be inclined to suggest that you use a predicate so the for-each operates over the book elements instead of the author ones:
<xsl:for-each select="library/book[authors/author[first='Harry'and last='Potter']] ">
This says "select all the book elements that have at least one author named Harry Potter".
Below is my input xml
<Record>
<Header>
<field1/>
</Header>
<Body>
<firstname>x1</firstname>
<lastname>y1</lastname>
<company>Test1</company>
<Body>
<Body>
<firstname>x2</firstname>
<lastname>y2</lastname>
<company></company>
<Body>
<Body>
<firstname>x3</firstname>
<lastname>y3</lastname>
<company>Test2</company>
<Body>
</Record>
I am trying to loop through body and check if the company value is blank,to output the corresponding first name and last name.This whole output,I am mapping to DATA on the target using xslt mapper.Can someone help me with the below code which is not working
<?xml version='1.0' ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns0="Namespace">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:variable name="NAME" select="/RecordSet/Body"/>
<xsl:variable name="break"><br></xsl:variable>
<xsl:variable name="tableB"><table Border="1" BorderColor="#000000" cellpadding="4" cellspacing="0" ></xsl:variable>
<xsl:variable name="tableE"></table></xsl:variable>
<xsl:variable name="trB"><tr></xsl:variable>
<xsl:variable name="trE"></tr></xsl:variable>
<xsl:variable name="tdB"><td></xsl:variable>
<xsl:variable name="tdE"></td></xsl:variable>
<xsl:variable name="nbsp"> </xsl:variable>
<xsl:variable name="thB"><tr BGCOLOR="#CCCCCC"></xsl:variable>
<xsl:template match="/">
<DATA>
<xsl:value-of select="$tableB"/>
<xsl:value-of select="$thB"/>
<xsl:value-of select="$tdB"/><B>FirstName</B>
<xsl:value-of select="$nbsp"/>
<xsl:value-of select="$tdE"/>
<xsl:value-of select="$tdB"/><B>LASTNAME </B>
<xsl:value-of select="$nbsp"/>
<xsl:value-of select="$tdE"/>
<xsl:value-of select="$trE"/>
<xsl:value-of select="$trB"/>
<xsl:for-each select="$NAME/Body[string-length(company) > 0]">
<xsl:value-of select="$tdB"/>
<xsl:value-of select="$MT_NAME/firstname"/>
<xsl:value-of select="$nbsp"/>
<xsl:value-of select="$tdE"/>
<xsl:value-of select="$tdB"/>
<xsl:value-of select="$MT_NAME/lastname"/>
<xsl:value-of select="$nbsp"/>
<xsl:value-of select="$tdE"/>
<xsl:if test="position() mod 2 = 0">
<xsl:value-of select="$trE"/>
</xsl:if>
</xsl:for-each>
<xsl:value-of select="$tableE"/>
</DATA>
The output should be
|FIRSTNAME|LASTNAME|
| X2 | Y2 |
The provided code doesn't produce HTML at all -- it produces strings -- one-dimensional text.
Also, AFAIK, DATA isn't an HTML element.
Also, the provided "XML" is severely malformed.
Here is an example how to produce an HTML table with XSLT:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*">
<table>
<thead>
<tr>
<td>First Name</td>
<td>Last Name</td>
<td>Company</td>
</tr>
</thead>
<xsl:apply-templates/>
</table>
</xsl:template>
<xsl:template match="Body">
<tr>
<xsl:apply-templates select="*"/>
</tr>
</xsl:template>
<xsl:template match="Body/*">
<td> </td>
</xsl:template>
<xsl:template match="Body/*[normalize-space()]">
<td><xsl:value-of select="."/></td>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the following XML document (the provided severely malformed text -- corrected):
<Record>
<Header>
<field1/>
<Body>
<firstname>x1</firstname>
<lastname>y1</lastname>
<company>Test1</company>
</Body>
<Body>
<firstname>x2</firstname>
<lastname>y2</lastname>
<company></company>
</Body>
<Body>
<firstname>x3</firstname>
<lastname>y3</lastname>
<company>Test2</company>
</Body>
</Header>
</Record>
A meaningful and sensible HTML table is produced:
<table>
<thead>
<tr>
<td>First Name</td>
<td>Last Name</td>
<td>Company</td>
</tr>
</thead>
<tr>
<td>x1</td>
<td>y1</td>
<td>Test1</td>
</tr>
<tr>
<td>x2</td>
<td>y2</td>
<td> </td>
</tr>
<tr>
<td>x3</td>
<td>y3</td>
<td>Test2</td>
</tr>
</table>
I have to take a guess at your requirements as they are not very well explained.
This XSLT 1.0 style-sheet...
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>
<xsl:strip-space elements="*" />
<xsl:template match="/">
<DATA>
<table Border="1" BorderColor="#000000" cellpadding="4" cellspacing="0">
<tr BGCOLOR="#CCCCCC">
<th>First name</th>
<th>Last name</th>
<th>Company</th>
</tr>
<xsl:apply-templates select="*/Body" />
</table>
</DATA>
</xsl:template>
<xsl:template match="Body">
<tr>
<td><xsl:value-of select="firstname" /></td>
<td><xsl:value-of select="lastname" /></td>
<td>
<xsl:choose>
<xsl:when test="company!=''" >
<xsl:value-of select="company" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat(firstname,' ',lastname)" />
</xsl:otherwise>
</xsl:choose>
</td>
</tr>
</xsl:template>
</xsl:stylesheet>
... when applied on this document...
<Record>
<Header>
<field1/>
</Header>
<Body>
<firstname>x1</firstname>
<lastname>y1</lastname>
<company>Test1</company>
</Body>
<Body>
<firstname>x2</firstname>
<lastname>y2</lastname>
<company/>
</Body>
<Body>
<firstname>x3</firstname>
<lastname>y3</lastname>
<company>Test2</company>
</Body>
</Record>
...will yield...
<DATA>
<table Border="1" BorderColor="#000000" cellpadding="4" cellspacing="0">
<tr BGCOLOR="#CCCCCC">
<th>First name</th>
<th>Last name</th>
<th>Company</th>
</tr>
<tr>
<td>x1</td>
<td>y1</td>
<td>Test1</td>
</tr>
<tr>
<td>x2</td>
<td>y2</td>
<td>x2 y2</td>
</tr>
<tr>
<td>x3</td>
<td>y3</td>
<td>Test2</td>
</tr>
</table>
</DATA>
Note
Notice that the middle record has a cell value of 'x2 y2' for Company as per stated requirements when the input Company is empty or missing.
Update
The input document is still badly malformed. In consideration of the OP's updated requirements, this XSLT 1.0 style-sheet...
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>
<xsl:strip-space elements="*" />
<xsl:template match="/">
<DATA>
<table Border="1" BorderColor="#000000" cellpadding="4" cellspacing="0">
<tr BGCOLOR="#CCCCCC">
<th>First name</th>
<th>Last name</th>
</tr>
<xsl:apply-templates select="*/Body[company='']" />
</table>
</DATA>
</xsl:template>
<xsl:template match="Body">
<tr>
<td><xsl:value-of select="firstname" /></td>
<td><xsl:value-of select="lastname" /></td>
</tr>
</xsl:template>
</xsl:stylesheet>
...when applied to the same input document as before, yields...
<DATA>
<table Border="1" BorderColor="#000000" cellpadding="4" cellspacing="0">
<tr BGCOLOR="#CCCCCC">
<th>First name</th>
<th>Last name</th>
</tr>
<tr>
<td>x2</td>
<td>y2</td>
</tr>
</table>
</DATA>