virtual nesting of list using XSLT - list

I need nesting of list in the following manner, I have to create n-1 list wrappers, where n is the value of #virtual-nesting:
XML Doc:
<l virtual-nesting="3">
<li>
<lilabel/>
<p>
<text>Data used:</text>
</p>
</li>
</l>
Output Required:
<list>
<listitem>
<bodytext>
<list>
<listitem>
<label/>
<bodytext>
<p>
<text>Data used:</text>
</p>
</bodytext>
</listitem>
</list>
</bodytext>
</listitem>
</list>
XSLT Itried. As I am new to this:
<xsl:template match="l">
<xsl:choose>
<xsl:when test="#virtual-nesting">
<xsl:variable name="virtual"><xsl:value-of select="#virtual-nesting"/></xsl:variable>
<xsl:if test="$virtual>0">
<xsl:apply-templates select="generate-id(following-sibling::node()),#virtual-nesting-1"/>
</xsl:if>
<xsl:apply-templates select="li"/>
</xsl:when>
<xsl:otherwise>
<xsl:element name="list">
<xsl:apply-templates select="li"/> <!-- Template for list and lilabel is already created -->
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Kindly guide me through this.

Recursion is the key to creating nested structures in XSLT.
The following uses a recursive <xsl:template match="l"> with a $level parameter. This parameter defaults to #virtual-nesting - 1 and after that is decremented with every recursive step.
The template takes two different paths, depending on its value.
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="l">
<xsl:param name="level" select="#virtual-nesting - 1" />
<list>
<listitem>
<xsl:if test="$level <= 1">
<xsl:apply-templates />
</xsl:if>
<xsl:if test="$level > 1">
<bodytext>
<xsl:apply-templates select=".">
<xsl:with-param name="level" select="$level - 1" />
</xsl:apply-templates>
</bodytext>
</xsl:if>
</listitem>
</list>
</xsl:template>
<xsl:template match="li">
<label>
<xsl:apply-templates select="lilabel/node()" />
</label>
<bodytext>
<xsl:apply-templates select="node()[not(self::lilabel)]" />
</bodytext>
</xsl:template>
</xsl:transform>
Result:
<list>
<listitem>
<bodytext>
<list>
<listitem>
<label/>
<bodytext>
<p>
<text>Data used:</text>
</p>
</bodytext>
</listitem>
</list>
</bodytext>
</listitem>
</list>

Related

duplicate content in xsl

I am very new in xsl. I was trying to add the <quote> tag in between the <para>.tag. but the output printing twice.
Here is my xsl code
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:strip-space elements="*"/>
<xsl:template match="node()|#*" mode="pretrans">
<xsl:copy>
<xsl:copy-of select="#*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="p[count(child::node())=0]" mode="pretrans"/>
<xsl:template match="doc">
<poc>
<xsl:apply-templates/>
</poc>
</xsl:template>
<xsl:template match="text">
<chapter>
<xsl:variable name="pos" select="count(child::node()[#style='H5']/preceding-sibling::p)+1"/>
<xsl:apply-templates select="child::node()[position()<$pos]" mode="presec"/>
<section>
<xsl:variable name="nodesets" >
<xsl:apply-templates select="child::node()[position()>=$pos]" mode="pretrans"/>
</xsl:variable>
<xsl:apply-templates select="$nodesets" mode="postsec"/> <!---->
</section>
</chapter>
</xsl:template>
<xsl:template match="p" mode="presec">
<xsl:choose>
<xsl:when test="#style='H2'">
<title><xsl:apply-templates/></title>
</xsl:when>
<xsl:when test="#style='H4'">
<subdivision>
<title><xsl:apply-templates/></title>
</subdivision>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template match="p" mode="postsec">
<xsl:variable name="pos" select="count(preceding-sibling::p[#style='H5'][1]/preceding-sibling::p)+1"/>
<xsl:variable name="pos" select="count(preceding-sibling::p)+1"/>
<xsl:variable name="styleblock" select="count(preceding-sibling::p[#style='BlockStyle'][1]/preceding-sibling::p)+1"/>
<xsl:choose>
<xsl:when test="#style='H5'">
<title><xsl:apply-templates/></title>
</xsl:when>
<xsl:when test="count(child::node())=0"/>
<xsl:otherwise>
<paragraph>
<xsl:if test="#style='BlockStyle'">
<quotes>
<xsl:apply-templates/>
</quotes>
</xsl:if>
<xsl:apply-templates/>
</paragraph>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
expected output:
<poc>
<chapter>
<section>
<paragraph>
<quote>
Hi welcome to new year 2022
</quote>
Hi welcome to new year 2022
</paragraph>
</section>
</chapter>
</poc>
The message is printing twice.
can anyone help me in this.
Depending on your needs delete the first or the second
<paragraph>
<xsl:if test="#style='BlockStyle'">
<quotes>
<xsl:apply-templates/><!-- First -->
</quotes>
</xsl:if>
<xsl:apply-templates/><!-- Second -->
</paragraph>

xsl numbering with same elements next to

I need to format some xml data with the following structure
<list>
<item>
Test
</item>
<item>
Testt
</item>
<or-item>
TestOr
</or-item>
<or-item>
TestOrr
</or-item>
<item>
Testtt
</item>
<or-item>
TestOrrr
</or-item>
<item>
Testttt
</item>
</list>
with xsl:number the or-item must be formatted with the second level count on that position. I know it would be better to structure the or-item inside that item but the data is given like that.
I need a way to count the or-item next to the current or-item to calculate the numbering for xsl:number
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" version="1.1"
xmlns:axf="http://www.antennahouse.com/names/XSL/Extensions" xmlns:fn="http://www.w3.org/2005/xpath-functions">
<xsl:output encoding="UTF-8" method="html" indent="yes"/>
<xsl:template match="list">
<div>
<xsl:apply-templates/>
</div>
</xsl:template>
<xsl:template match="item">
<div>
<xsl:number count="item"/>
<xsl:value-of select="."/>
</div>
</xsl:template>
<xsl:template match="or-item">
<div style="padding-left: 10px">
<xsl:number value="count(//or-item)" format="a) "/>
<xsl:value-of select="."/>
</div>
</xsl:template>
</xsl:stylesheet>
Edit
I am using XSLT 1.1 with xsltproc on linux but 2.0 whould be possible if neccessary
As the target format is HTML, it seems you could rely on creating the appropriate nested HTML ordered lists by using xsl:for-each-group and group-starting-with="item":
<xsl:template match="list">
<ol>
<xsl:for-each-group select="*" group-starting-with="item">
<li>
<xsl:value-of select="."/>
<xsl:where-populated>
<ol>
<xsl:apply-templates select="tail(current-group())"/>
</ol>
</xsl:where-populated>
</li>
</xsl:for-each-group>
</ol>
</xsl:template>
<xsl:template match="or-item">
<li>
<xsl:value-of select="."/>
</li>
</xsl:template>
https://xsltfiddle.liberty-development.net/ejivJrM
That example uses some XSLT/XPath 3 stuff like were-populated and tail but in case that XSLT 2 compatility is needed then it could be replaced by <xsl:if test="subsequence(current-group(), 2)"><ol><xsl:apply-templates select="subsequence(current-group(), 2)"/></xsl:if>.
And of course the use of HTML ordered lists is not necessary, if needed/wanted you could just transform the input to nested divs with the used grouping approach and then in a second step use format-number as you seem to want to do:
<xsl:template match="list">
<xsl:variable name="nested-list">
<xsl:for-each-group select="*" group-starting-with="item">
<xsl:copy>
<xsl:value-of select="."/>
<xsl:copy-of select="tail(current-group())"/>
</xsl:copy>
</xsl:for-each-group>
</xsl:variable>
<div>
<xsl:apply-templates select="$nested-list"/>
</div>
</xsl:template>
<xsl:template match="item">
<div>
<xsl:number/>
<xsl:apply-templates/>
</div>
</xsl:template>
<xsl:template match="or-item">
<div style="padding-left: 10px">
<xsl:number format="a) "/>
<xsl:value-of select="."/>
</div>
</xsl:template>
https://xsltfiddle.liberty-development.net/ejivJrM/1
You can produce the expected output by simply adjusting the xsl:number instruction:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" encoding="utf-8"/>
<xsl:template match="/list">
<div>
<xsl:apply-templates/>
</div>
</xsl:template>
<xsl:template match="item">
<div>
<xsl:number/>
<xsl:value-of select="."/>
</div>
</xsl:template>
<xsl:template match="or-item">
<div style="padding-left: 10px">
<xsl:number level="any" from="item" format="a) "/>
<xsl:value-of select="."/>
</div>
</xsl:template>
</xsl:stylesheet>

How to resume xsl number count after nesting and while using level="any"

I am trying to have the <xsl:number/> resume its counter. However, since it is using level="any", it counts its previous sibling's child elements, which is undesirable.
Using the sample code below, everything looks correct except for the list items containing Three and Four. Those items are given the number counts of 5 and 6 because the counter is using the items nested within item Two instead of continuing from where item Two itself left off.
Sample Input XML:
<body>
<div class="list-wrapper">
<ol>
<li>One</li>
<li><span>Two</span>
<ol>
<li>AAA</li>
<li>BBB</li>
</ol>
<div class="list-wrapper">
<ol>
<li>CCC</li>
<li>DDD</li>
</ol>
<ol>
<li>EEE</li>
<li>FFF</li>
</ol>
</div>
<ol>
<li>GGG</li>
<li>HHH</li>
</ol>
</li>
</ol>
<ol>
<li>Three</li>
<li>Four</li>
</ol>
</div>
<div class="list-wrapper">
<ol>
<li>Five</li>
<li>Six</li>
</ol>
<ol>
<li>Seven</li>
<li>Eight</li>
</ol>
</div>
</body>
Sample Stylesheet:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="body">
<fo:root>
<xsl:apply-templates />
</fo:root>
</xsl:template>
<xsl:template match="div[#class='list-wrapper']">
<fo:list-block>
<xsl:apply-templates mode="list-wrapper" />
</fo:list-block>
</xsl:template>
<xsl:template match="ol" mode="list-wrapper">
<xsl:apply-templates mode="list-wrapper" />
</xsl:template>
<xsl:template match="li" mode="list-wrapper">
<fo:list-item>
<fo:list-item-label>
<xsl:number format="1." count="div[#class='list-wrapper']/ol/li" from="div[#class='list-wrapper']" level="any" />
</fo:list-item-label>
<fo:list-item-body>
<xsl:apply-templates />
</fo:list-item-body>
</fo:list-item>
</xsl:template>
<xsl:template match="ol">
<fo:list-block>
<xsl:apply-templates />
</fo:list-block>
</xsl:template>
<xsl:template match="li">
<fo:list-item>
<fo:list-item-label>
<xsl:number format="1."/>
</fo:list-item-label>
<fo:list-item-body>
<xsl:apply-templates />
</fo:list-item-body>
</fo:list-item>
</xsl:template>
</xsl:stylesheet>
Looks like I can get around the nesting problem by using an xsl:for-each to handle only the direct children of div[#class='list-wrapper'].
Now I can simply use position() to number each node as I require.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="body">
<fo:root>
<xsl:apply-templates />
</fo:root>
</xsl:template>
<xsl:template match="div[#class='list-wrapper']">
<fo:list-block>
<xsl:for-each select="ol/li">
<xsl:call-template name="process-ordered-list" />
</xsl:for-each>
</fo:list-block>
</xsl:template>
<xsl:template match="li">
<xsl:call-template name="process-ordered-list" />
</xsl:template>
<xsl:template name="process-ordered-list">
<fo:list-item>
<fo:list-item-label>
<xsl:number format="1." value="position()" />
</fo:list-item-label>
<fo:list-item-body>
<xsl:apply-templates />
</fo:list-item-body>
</fo:list-item>
</xsl:template>
<xsl:template match="ol">
<fo:list-block>
<xsl:apply-templates />
</fo:list-block>
</xsl:template>
</xsl:stylesheet>
I was able to simplify the template by replacing the for-each with an apply-templates.
This solution appears best.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="body">
<fo:root>
<xsl:apply-templates />
</fo:root>
</xsl:template>
<xsl:template match="div[#class='list-wrapper']">
<fo:list-block>
<xsl:apply-templates select="ol/li" />
</fo:list-block>
</xsl:template>
<xsl:template match="ol">
<fo:list-block>
<xsl:apply-templates />
</fo:list-block>
</xsl:template>
<xsl:template match="ol/li">
<fo:list-item>
<fo:list-item-label>
<xsl:number format="1." value="position()" />
</fo:list-item-label>
<fo:list-item-body>
<xsl:apply-templates />
</fo:list-item-body>
</fo:list-item>
</xsl:template>
</xsl:stylesheet>

replace xml value with sequentail numbers

Hi I have been trying to replace values in a certain tag with sequential numbers, I used position function, but it did not work.
Input xml:
<?xml version="1.0" encoding="UTF-8"?>
<Envelope>
<Header>
<User id="swarnai" />
<Request-Id id="592149819" />
<Type name="Request" />
<Application-Source version="8.1.1.10" name="Siebel" />
<Application-Destination version="1.2.2" name="EVA" />
<Outgo-Timestamp time="11:40:59" date="2015-08-04" />
<DealerCode>82536</DealerCode>
<Market>00000</Market>
</Header>
<Content>
<ClaimContext>
<ClaimControl>
<ClaimEntryFlag>3</ClaimEntryFlag>
<ClaimSaveFlag>1</ClaimSaveFlag>
</ClaimControl>
<Claim>
<DealerClaimNumber>1091871</DealerClaimNumber>
<WHC>WDD</WHC>
<FIN>2120026L020301</FIN>
<RegistrationNumber>JH07E2786</RegistrationNumber>
<FirstRegistrationDate>2012-11-29</FirstRegistrationDate>
<Mileage>14317</Mileage>
<MileageIndicator>0</MileageIndicator>
<RepairDate>2013-12-03</RepairDate>
<RegularlyMaintained>true</RegularlyMaintained>
<NoFirstRegDateInd>false</NoFirstRegDateInd>
<ClaimCurrencyId>EUR</ClaimCurrencyId>
<Taxi>false</Taxi>
<DamagePosition>
<DamageSeqNumber>1</DamageSeqNumber>
<WarrantyType>0</WarrantyType>
<DamageCode>0121504</DamageCode>
<OperationPosition>
<SeqNumber>1</SeqNumber>
<Opcode>02770501</Opcode>
<WorkingUnits>18</WorkingUnits>
<MainOperationCode>true</MainOperationCode>
<OperationText>OPERATIONS: FITTING FOR COOLANT CONNECTION TO CYLINDER</OperationText>
<PriceGroup>01</PriceGroup>
</OperationPosition>
</DamagePosition>
<DamagePosition>
<DamageSeqNumber>1</DamageSeqNumber>
<WarrantyType>0</WarrantyType>
<DamageCode>0121504</DamageCode>
<PartPosition>
<SeqNumber>1</SeqNumber>
<Quantity>10</Quantity>
<PartNumber>A6512001056</PartNumber>
<DamageCausingPart>true</DamageCausingPart>
<RetailPriceAmount>1499</RetailPriceAmount>
<Express>false</Express>
</PartPosition>
</DamagePosition>
<DamagePosition>
<DamageSeqNumber>1</DamageSeqNumber>
<WarrantyType>0</WarrantyType>
<DamageCode>0121504</DamageCode>
<PartPosition>
<SeqNumber>1</SeqNumber>
<Quantity>20</Quantity>
<PartNumber>A0009890825 10</PartNumber>
<DamageCausingPart>false</DamageCausingPart>
<RetailPriceAmount>1319</RetailPriceAmount>
<Express>false</Express>
</PartPosition>
</DamagePosition>
</Claim>
</ClaimContext>
</Content>
</Envelope>
In this xml within PartPosition/SeqNumber tag I want to replace or generate sequence of numbers in SeqNumber tag.
I tried below xslt:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="utf-8" indent="no"/>
<xsl:key name="Damage_Group" match="/Envelope/Content/ClaimContext/Claim/DamagePosition" use="DamageCode" />
<xsl:template match="Claim">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
<xsl:for-each select="DamagePosition[count(. | key('Damage_Group', DamageCode)[1]) = 1]">
<xsl:sort select="DamageCode" />
<DamagePosition>
<DamageSeqNumber>
<xsl:value-of select="position()" />
</DamageSeqNumber>
<DamageCode>
<xsl:value-of select="DamageCode" />
</DamageCode>
<WarrantyType><xsl:value-of select="WarrantyType" /></WarrantyType>
<xsl:for-each select="key('Damage_Group', DamageCode)">
<xsl:copy-of select="current()/PartPosition"/>
<xsl:copy-of select="current()/OperationPosition"/>
<xsl:copy-of select="current()/SubletPosition"/>
</xsl:for-each>
</DamagePosition>
</xsl:for-each>
</xsl:copy>
</xsl:template>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="DamagePosition">
</xsl:template>
</xsl:stylesheet>
but it is not giving me the desired output as below.
<?xml version="1.0" encoding="UTF-8"?>
<Envelope>
<Header>
<User id="swarnai" />
<Request-Id id="592149819" />
<Type name="Request" />
<Application-Source version="8.1.1.10" name="Siebel" />
<Application-Destination version="1.2.2" name="EVA" />
<Outgo-Timestamp time="12:15:47" date="2015-08-04" />
<DealerCode>82536</DealerCode>
<Market>00000</Market>
</Header>
<Content>
<ClaimContext>
<ClaimControl>
<ClaimEntryFlag>3</ClaimEntryFlag>
<ClaimSaveFlag>1</ClaimSaveFlag>
</ClaimControl>
<Claim>
<DealerClaimNumber>1091871</DealerClaimNumber>
<WHC>WDD</WHC>
<FIN>2120026L020301</FIN>
<RegistrationNumber>JH07E2786</RegistrationNumber>
<FirstRegistrationDate>2012-11-29</FirstRegistrationDate>
<Mileage>14317</Mileage>
<MileageIndicator>0</MileageIndicator>
<RepairDate>2013-12-03</RepairDate>
<RegularlyMaintained>true</RegularlyMaintained>
<NoFirstRegDateInd>false</NoFirstRegDateInd>
<ClaimCurrencyId>EUR</ClaimCurrencyId>
<Taxi>false</Taxi>
<DamagePosition>
<DamageSeqNumber>1</DamageSeqNumber>
<DamageCode>0121504</DamageCode>
<WarrantyType>0</WarrantyType>
<OperationPosition>
<SeqNumber>1</SeqNumber>
<Opcode>02770501</Opcode>
<WorkingUnits>18</WorkingUnits>
<MainOperationCode>true</MainOperationCode>
<OperationText>OPERATIONS: FITTING FOR COOLANT CONNECTION TO CYLINDER</OperationText>
<PriceGroup>01</PriceGroup>
</OperationPosition>
<PartPosition>
<SeqNumber>1</SeqNumber>
<Quantity>10</Quantity>
<PartNumber>A6512001056</PartNumber>
<DamageCausingPart>true</DamageCausingPart>
<RetailPriceAmount>1499</RetailPriceAmount>
<Express>false</Express>
</PartPosition>
<PartPosition>
<SeqNumber>2</SeqNumber>
<Quantity>20</Quantity>
<PartNumber>A0009890825 10</PartNumber>
<DamageCausingPart>false</DamageCausingPart>
<RetailPriceAmount>1319</RetailPriceAmount>
<Express>false</Express>
</PartPosition>
</DamagePosition>
</Claim>
</ClaimContext>
</Content>
</Envelope>
Any help is much appreciated.
Thanks
Firstly, instead of doing this, which copies the elements without further changes to it (or its descendants)
<xsl:copy-of select="current()/PartPosition"/>
<xsl:copy-of select="current()/OperationPosition"/>
<xsl:copy-of select="current()/SubletPosition"/>
You should you template matching instead, to allow you to write a template later on to change the sequence number
<xsl:apply-templates select="PartPosition"/>
<xsl:apply-templates select="OperationPosition"/>
<xsl:apply-templates select="SubletPosition"/>
Now, what you could do, is write a template that matches the various Sequence numbers and counts the preceding siblings for the same DamageCode. Something like this
<xsl:template match="PartPosition/SeqNumber">
<SeqNumber>
<xsl:variable name="DamageCode" select="../../DamageCode" />
<xsl:value-of select="count(../../preceding-sibling::*[PartPosition][DamageCode = $DamageCode]) + 1" />
</SeqNumber>
</xsl:template>
You could repeat the template for OperationPosition and SubletPosition too, although this would be quite repetitive. Alternatively, have a single generic template to match all three:
<xsl:template match="SeqNumber">
<SeqNumber>
<xsl:variable name="DamageCode" select="../../DamageCode" />
<xsl:variable name="Parent" select="name(..)" />
<xsl:value-of select="count(../../preceding-sibling::*[*[name() = $Parent]][DamageCode = $DamageCode]) + 1" />
</SeqNumber>
</xsl:template>
However, this is not necessarily that efficient, as it is not utilizing the key and so would have to check back through all preceding siblings to find a match.
Another solution would be to pass the position of the current DamagePosition in a parameter, and then use that in checking the key.
Try this XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" encoding="utf-8" indent="yes"/>
<xsl:key name="Damage_Group"
match="/Envelope/Content/ClaimContext/Claim/DamagePosition"
use="DamageCode"/>
<xsl:template match="Claim">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
<xsl:for-each select="DamagePosition[count(. | key('Damage_Group', DamageCode)[1]) = 1]">
<xsl:sort select="DamageCode"/>
<DamagePosition>
<DamageSeqNumber>
<xsl:value-of select="position()"/>
</DamageSeqNumber>
<DamageCode>
<xsl:value-of select="DamageCode"/>
</DamageCode>
<WarrantyType>
<xsl:value-of select="WarrantyType"/>
</WarrantyType>
<xsl:for-each select="key('Damage_Group', DamageCode)">
<xsl:apply-templates select="PartPosition">
<xsl:with-param name="Position" select="position()" />
</xsl:apply-templates>
<xsl:apply-templates select="OperationPosition">
<xsl:with-param name="Position" select="position()" />
</xsl:apply-templates>
<xsl:apply-templates select="SubletPosition">
<xsl:with-param name="Position" select="position()" />
</xsl:apply-templates>
</xsl:for-each>
</DamagePosition>
</xsl:for-each>
</xsl:copy>
</xsl:template>
<xsl:template match="DamagePosition/*">
<xsl:param name="Position" />
<xsl:copy>
<xsl:apply-templates select="#*|node()">
<xsl:with-param name="Position" select="$Position" />
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="SeqNumber">
<xsl:param name="Position" />
<SeqNumber>
<xsl:value-of select="count(key('Damage_Group', ../../DamageCode)[position() <= $Position][*[name() = name(current()/..)]])" />
</SeqNumber>
</xsl:template>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="DamagePosition" />
</xsl:stylesheet>

XSLT removing unnecessary element

i am trying to write an xslt code that will check whether the description element exist or not if it exist then it will show the description element but if it does not exist then it should not show the description element.but my code below still show element although there is no value in it.how can we code it so that it wont show out the description element if there is no description for a services.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="Service">
<xsl:element name="equipment">
<xsl:if test="description !='' ">
<xsl:value-of select="description" />
</xsl:if>
<xsl:if test="not(description)">
</xsl:if>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
as there is the an empty equipment element being returned.i want it to return only the first 2 equipment element that is not empty.
Updated solution is follows; please check
<xsl:template match="Services">
<xsl:for-each select="Service">
<xsl:if test="count(description) > 0 and description!=''">
<equipment>
<xsl:value-of select="description"/>
</equipment>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
<xsl:template match="/">
<xsl:apply-templates select="//Service"/>
</xsl:template>
<xsl:template match="Service">
<xsl:if test="description !='' ">
<xsl:element name="equipment">
<xsl:value-of select="description" />
</xsl:element>
</xsl:if>
</xsl:template>
or
<xsl:template match="/">
<xsl:apply-templates select="//Service"/>
</xsl:template>
<xsl:template match="Service">
<xsl:if test="child::description[text()]">
<xsl:element name="equipment">
<xsl:value-of select="description" />
</xsl:element>
</xsl:if>
</xsl:template>
Does this work for you?
<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- place <result /> as root to produce wellformed XML -->
<xsl:template match="/">
<result><xsl:apply-templates /></result>
</xsl:template>
<!-- rewrite those <Service /> that have a <description /> -->
<xsl:template match="Service[./description]">
<equipment><xsl:value-of select="description" /></equipment>
</xsl:template>
<!-- remove those who do not -->
<xsl:template match="Service[not(./description)]" />
</xsl:transform>