How to display sub nodes in different node groups separately? - xslt-1.0

I am new with xslt. I am converting an XML file to a flat file. But the sub nodes values are shown together under every node group. How can I show them separately?
XML:
<list>
<group name="group1">
<item value="item1" />
<item value="item11" />
</group>
<group name="group2">
<item value="item2" />
<item value="item22" />
<item value="item222" />
</group>
</list>
XSLT:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ms="urn:schemas-microsoft-com:xslt">
<xsl:template match="/">
<xsl:for-each select="//list1/group">
<xsl:text>group name</xsl:text>
<xsl:value-of select="#name"/>
<!--item -->
<xsl:for-each select="//list1/group/item">
<xsl:text>item value</xsl:text>
<xsl:value-of select="#value" />
</xsl:for-each>
</xsl:for-each>
<xsl:apply-templates/>
</xsl:template>
</xsl:stylesheet>
Output:
group name group1
item value item1
item value item11
item value item2
item value item22
item value item22
group name group2
item value item1
item value item11
item value item2
item value item22
item value item22
Expected output:
group name group1
item value item1
item value item11
group name group2
item value item2
item value item22
item value item222

The main problem with your posted code is here:
<xsl:for-each select="//list1/group/item">
This will always select all item nodes in the entire XML document, starting from the root node and ignoring the current context.
Earlier, when you did:
<xsl:for-each select="//list1/group">
you were put in the context of group. From here, to process the item elements that are children of the current group, you should do simply:
<xsl:for-each select="item">

You'd better off using the xsl matching capabilities instead of "for-each"
Possible solution (selects all items and then outputs the parent's name and the item's value):
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ms="urn:schemas-microsoft-com:xslt">
<xsl:output method="text" omit-xml-declaration="yes" indent="no"/>
<xsl:template match="//list/group/item">
<xsl:text>group name: </xsl:text><xsl:value-of select="../#name"/><xsl:text>
</xsl:text>
<xsl:text>item value: </xsl:text><xsl:value-of select="#value" /><xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>

Following code check:-
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="group">
<xsl:text>group name</xsl:text>
<xsl:value-of select="#name"/>
<xsl:text>item value</xsl:text>
<xsl:value-of select="item/#value" />
</xsl:template>

Related

XSLT 1.0 Select Name field based on evaluation of Date and Time fields

I have XML form data coming in from a vendor app that allows me to select values for fields on the form by using this format.
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xsl:stylesheet version="1.0" xmlns="http://www.w3.org/1999/XSL/Transform" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<xsl:output method="text" /><xsl:template match="/"><xsl:apply-templates/></xsl:template>
<xsl:template match="DataSet/diffgr:diffgram/Forms">
<xsl:for-each select="Form">
<xsl:value-of select="FieldName1"/>
<xsl:value-of select="FieldName2"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
I can't see the XML, but I can surmise from this that all of the fields are siblings within the <form> and looks something like this:
<form>
<CosignerName1 value="John Doe"/>
<CosignerDate1 value="1/1/1970"/>
<CosignerTime1 value="8:46 PM"/>
<CosignerName2 value="Jane Smith"/>
<CosignerDate2 value="2/2/1972"/>
<CosignerTime2 value="11:46 AM"/>
...
<CosignerName12 value="Will Hunting"/>
<CosignerDate12 value="12/12/1982"/>
<CosignerTime12 value="1:00 AM"/>
</form>
<form>
<CosignerName1 value="Bill Thomas"/>
<CosignerDate1 value="5/5/2020"/>
<CosignerTime1 value="8:46 PM"/>
<CosignerName2 value="Bev Poole"/>
<CosignerDate2 value="6/6/2022"/>
<CosignerTime2 value="11:46 AM"/>
...
<CosignerName12 value="Bob Ross"/>
<CosignerDate12 value="12/12/1982"/>
<CosignerTime12 value="1:00 AM"/>
</form>
Known factors:
Each form has 12 cosigners, each with numbered field names i.e. CosignerName1, CosignerName2, etc.
Each named cosigner also has a CosignerDate and a CosignerTime field associated by number. i.e. CosignerName1 has CosignerDate1 and CosignerTime1 fields that, when combined, show when that user signed the form.
I am using the word 'idnum' in my code and in this question to refer to the number at the end of each label that shows they are part of a set i.e CosignerName1, CosignerDate1, and CosignerTime1 all share idnum=1
Goal: Identify and select only the most recent CosignerName, based on CosignerDate and CosignerTime.
To do this, I figure I need to:
Find the most recent CosignerDate/CosignerTime combination
Read the label of either of the identified fields to extract the idnum from the end
Use the idnum to to identify the correct CosignerName and output it
I have some pieces of the solution, but no way to bring them together:
Create a Timestamp
I can combine a set of CosignerDate[idnum] and CosignerTime[idnum] fields, then translate them into a timestamp. If I could create an array of these timestamps, then I could sort and find the most recent one, but as I understand it XSLT 1.0 doesn't have arrays. So I am not sure what to do with this.
<xsl:variable name="mm" select="substring-before(CosignerDate1,'/')" />
<xsl:variable name="mmyyyy" select="substring-after(CosignerDate1,'/')"/>
<xsl:variable name="dd" select="substring-before($mmyyyy,'/')" />
<xsl:variable name="yyyy" select="substring-after($mmyyyy,'/')" />
<xsl:variable name="ampm" select="substring-after(CosignerTime1,' ')" />
<xsl:variable name="time">
<xsl:choose>
<xsl:when test="$ampm = 'AM'">
<xsl:value-of select="number(translate(substring-before(CosignerTime1,' '),':',''))" />
</xsl:when>
<xsl:when test="$ampm = 'PM'">
<xsl:value-of select="number(translate(substring-before(CosignerTime1,' '),':',''))+number('1200')" />
</xsl:when>
</xsl:choose>
</xsl:variable>
<xsl:value-of select="concat('Timestamp:',$yyyy,$mm,$dd,$time)"/>
The code above outputs something like: Timestamp:202209191128
Get idnums
I can loop through all of the Cosigners and extract the identifying number shared by their labels.
<xsl:for-each select="*[starts-with(local-name(), 'CosignerName')]">
<xsl:variable name="idnum">
<xsl:value-of select="translate(local-name(),'CosignerName','')" />
</xsl:variable>
<xsl:value-of select="$idnum"/>
<xsl:value-of select="','"/>
</xsl:for-each>
This code above outputs something like: 1,4,7,12
But, this is where I get lost.
Failed Attempt
I tried something like the code below. The logic was to loop through each Cosigner name (12 iterations), get the idnum from the label, use that to get the CosignerDate and CosignerTime, create a timestamp, then sort the timestamps, if the timestamp we are looking at is the top one (most recent) then use the idnum to select the correct CosignerName and output it.
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xsl:stylesheet version="1.0" xmlns="http://www.w3.org/1999/XSL/Transform" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<xsl:output method="text" /><xsl:template match="/"><xsl:apply-templates/></xsl:template>
<xsl:template match="DataSet/diffgr:diffgram/Forms">
<xsl:for-each select="Form">
<xsl:for-each select="*[starts-with(local-name(), 'CosignerName')]">
<xsl:variable name="idnum">
<xsl:value-of select="translate(local-name(),'CosignerName','')" />
</xsl:variable>
<xsl:variable name="mm" select="substring-before(concat(CosignerDate,$idnum),'/')" />
<xsl:variable name="mmyyyy" select="substring-after(concat(CosignerDate,$idnum),'/')"/>
<xsl:variable name="dd" select="substring-before($mmyyyy,'/')" />
<xsl:variable name="yyyy" select="substring-after($mmyyyy,'/')" />
<xsl:variable name="ampm" select="substring-after(concat(CosignerTime,$idnum),' ')" />
<xsl:variable name="time">
<xsl:choose>
<xsl:when test="$ampm = 'AM'">
<xsl:value-of select="number(translate(substring-before(concat(CosignerTime,$idnum),' '),':',''))" />
</xsl:when>
<xsl:when test="$ampm = 'PM'">
<xsl:value-of select="number(translate(substring-before(concat(CosignerTime,$idnum),' '),':',''))+number('1200')" />
</xsl:when>
</xsl:choose>
</xsl:variable>
<xsl:variable name="timestamp" select="concat('Timestamp: ',$yyyy,$mm,$dd,$time)"/>
<xsl:sort select="$timestamp" data-type="number" order="descending"/>
<xsl:if test="position() = 1"><xsl:value-of select="."/></xsl:if>
</xsl:for-each>
<xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
This of course fails for several reasons:
the concat with the $idnum doesn't actually pull values from fields
the sort has to be the first thing in the for-each
the sort has to happen after all of the timestamps are created
the sorted list of timestamps still needs to reference which idnum they were generated from
Without being able to create an array of timestamps and idnums, I don't know how you can accomplish this.
Does anyone know how can I get at the CosignerName[idnum] that is correlated with the most recent CosignerDate[idnum]/CosignerTime[idnum]?
I believe you could just sort the CosignerNameX nodes by the individual components of their associated dates and times, as shown in the two other answers I linked to:
https://stackoverflow.com/a/59288030/3016153
https://stackoverflow.com/a/30631073/3016153
However, it might be more efficient - and certainly more readable - to do this in two steps:
Construct a dateTime value for each cosigner;
Find the cosigner with the most recent value.
Consider the following example:
XML
<DataSet xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
<diffgr:diffgram>
<Forms>
<form>
<CosignerName1 value="John Doe"/>
<CosignerDate1 value="1/1/1970"/>
<CosignerTime1 value="8:46 PM"/>
<CosignerName2 value="Jane Smith"/>
<CosignerDate2 value="2/2/1972"/>
<CosignerTime2 value="11:46 AM"/>
<CosignerName12 value="Will Hunting"/>
<CosignerDate12 value="12/12/1982"/>
<CosignerTime12 value="1:00 AM"/>
</form>
<form>
<CosignerName1 value="Bill Thomas"/>
<CosignerDate1 value="5/5/2020"/>
<CosignerTime1 value="8:46 PM"/>
<CosignerName2 value="Bev Poole"/>
<CosignerDate2 value="6/6/2022"/>
<CosignerTime2 value="11:46 AM"/>
<CosignerName12 value="Bob Ross"/>
<CosignerDate12 value="12/12/1982"/>
<CosignerTime12 value="1:00 PM"/>
</form>
</Forms>
</diffgr:diffgram>
</DataSet>
XSLT 1.0 + EXSLT node-set()
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1"
xmlns:exsl="http://exslt.org/common"
exclude-result-prefixes="diffgr exsl">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/DataSet">
<output>
<xsl:for-each select="diffgr:diffgram/Forms/form">
<xsl:variable name="datetimes">
<xsl:for-each select="*[starts-with(local-name(), 'CosignerName')]">
<!-- identify values -->
<xsl:variable name="i" select="substring-after(local-name(), 'CosignerName')" />
<xsl:variable name="date" select="../*[local-name()=concat('CosignerDate', $i)]/#value" />
<xsl:variable name="time" select="../*[local-name()=concat('CosignerTime', $i)]/#value" />
<!-- extract date components -->
<xsl:variable name="year" select="substring-after(substring-after($date, '/'), '/')" />
<xsl:variable name="month" select="substring-before($date, '/')" />
<xsl:variable name="day" select="substring-before(substring-after($date, '/'), '/')" />
<!-- extract time components -->
<xsl:variable name="hour12" select="substring-before($time, ':')" />
<xsl:variable name="minute" select="substring-before(substring-after($time, ':'), ' ')" />
<xsl:variable name="pm" select="contains($time,'PM')" />
<xsl:variable name="hour" select="$hour12 mod 12 + 12*$pm"/>
<!-- construct dateTime -->
<datetime cosigner="{#value}" index="{$i}">
<xsl:value-of select="$year"/>
<xsl:value-of select="format-number($month, '-00')"/>
<xsl:value-of select="format-number($day, '-00')"/>
<xsl:value-of select="format-number($hour, 'T00')"/>
<xsl:value-of select="format-number($minute, ':00')"/>
<xsl:text>:00</xsl:text>
</datetime>
</xsl:for-each>
</xsl:variable>
<!-- output -->
<form>
<xsl:for-each select="exsl:node-set($datetimes)/datetime">
<xsl:sort select="." data-type="text" order="descending"/>
<xsl:if test="position()=1">
<last-cosigner index="{#index}" dateTime="{.}" >
<xsl:value-of select="#cosigner"/>
</last-cosigner>
</xsl:if>
</xsl:for-each>
</form>
</xsl:for-each>
</output>
</xsl:template>
</xsl:stylesheet>
Result
<?xml version="1.0" encoding="UTF-8"?>
<output>
<form>
<last-cosigner index="12" dateTime="1982-12-12T01:00:00">Will Hunting</last-cosigner>
</form>
<form>
<last-cosigner index="2" dateTime="2022-06-06T11:46:00">Bev Poole</last-cosigner>
</form>
</output>
P.S. With a Microsoft processor you may need to change the namespace declaration:
xmlns:exsl="http://exslt.org/common"
to:
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
and then change the exsl prefix in lines #5 and #39 to msxsl.

How to get sum of elements by it's position. I have below XML and wanted to get sum of DonneeRensCompl by position using XSLT

I have below code and wanted to get sum of DonneeRensCompl by it's position. Example Position1 = 3.60 (1.30+ 2.30 = 3.60) likewise for all possible positions.
<DATA_DS>
<R>
<Annee>2021</Annee>
<CaseRensCompl>
<CodeRensCompl>235</CodeRensCompl>
<DonneeRensCompl>1.30</DonneeRensCompl>
</CaseRensCompl>
<CaseRensCompl>
<CodeRensCompl>B-1</CodeRensCompl>
<DonneeRensCompl>10650.00</DonneeRensCompl>
</CaseRensCompl>
<CaseRensCompl>
<CodeRensCompl>RZ-RJ</CodeRensCompl>
<DonneeRensCompl>10650.00</DonneeRensCompl>
</CaseRensCompl>
</R>
<R>
<Annee>2021</Annee>
<CaseRensCompl>
<CodeRensCompl>235</CodeRensCompl>
<DonneeRensCompl>2.30</DonneeRensCompl>
</CaseRensCompl>
<CaseRensCompl>
<CodeRensCompl>RZ-CA</CodeRensCompl>
<DonneeRensCompl>10650.00</DonneeRensCompl>
</CaseRensCompl>
</R>
</DATA_DS>
If you don't know in advance the number of positions, then you must increment the position in a loop until there are no nodes in the current position:
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:template match="/DATA_DS">
<root>
<xsl:call-template name="sum-by-positions"/>
</root>
</xsl:template>
<xsl:template name="sum-by-positions">
<xsl:param name="i" select="1"/>
<xsl:variable name="cases" select="//CaseRensCompl[$i]" />
<xsl:if test="$cases">
<sum position="{$i}">
<xsl:value-of select="format-number(sum($cases/DonneeRensCompl), '#,##0.00')"/>
</sum>
<!-- recursive call -->
<xsl:call-template name="sum-by-positions">
<xsl:with-param name="i" select="$i + 1"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Applied to your input example, this will produce:
Result
<?xml version="1.0" encoding="UTF-8"?>
<root>
<sum position="1">3.60</sum>
<sum position="2">21,300.00</sum>
<sum position="3">10,650.00</sum>
</root>
To understand how this works, read this note in the XPath 1.0 specification:
NOTE: The location path //para[1] does not mean the same as the location path /descendant::para[1]. The latter selects the first descendant para element; the former selects all descendant para elements that are the first para children of their parents.

XSLT sort data in variable and save them to another variable

I have a problem. I have the following XML
<countryList>
<country>
<name>Afghanistan</name>
<population>29117000</population>
<area>654329</area>
</country>
<country>
<name>Albania</name>
<population>3195000</population>
<area>28748</area>
</country>
<country>
<name>Algeria</name>
<population>35423000</population>
<area>2381741</area>
</country>
<country>
<name>Andorra</name>
<population>84082</population>
<area>468</area>
</country>
</countryList>
I have one question. All I need to do is divide population/area and sort these divisions for each country. However, I tried this
<xsl:variable name="Podiel">
<xsl:value-of select="../population div ../area"/>
</xsl:variable>
<xsl:variable name="PodielPodiel">
<xsl:for-each select="$Podiel">
<xsl:sort select="." data-type="number" order="descending"/>
</xsl:for-each>
</xsl:variable>
but I still get error
The 'select' expression does not evaluate to a node set.
no result for data1.xml
Any help? I just want to know the maximum of all divisions.
Thanks.
Not sure whether the issue has been resolved, however for using node-set in XSLT 1.0, extension functions have to be used. Please refer to node-set extension for additional details on it's usage in XSLT 1.0.
If at all the country list in the input XML needs to be sorted on the value of population div area, the number() function can be used within <xsl:sort>. Declaring variables and calculating the additional values and then accessing the variable is not required.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:output method="xml" />
<xsl:strip-space elements="*" />
<!-- identity transform -->
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="countryList">
<xsl:copy>
<xsl:apply-templates select="country">
<xsl:sort select="number(population div area)" data-type="number" order="descending" />
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Output
<countryList>
<country>
<name>Andorra</name>
<population>84082</population>
<area>468</area>
</country>
<country>
<name>Albania</name>
<population>3195000</population>
<area>28748</area>
</country>
<country>
<name>Afghanistan</name>
<population>29117000</population>
<area>654329</area>
</country>
<country>
<name>Algeria</name>
<population>35423000</population>
<area>2381741</area>
</country>
</countryList>

XSL 1.0 line breaks missing in output

I have an XML file for which I have to frame XSL so that my ETL job can process it. Here is what i need.
Input XML
<FS_Sub_Investment_Team>
<Report Name="REPORT">
<MeetTheTeamTableHeading Label="TEAM" />
<MeetTheTeamTable>
<Rows>
<Row ManagerData="ABC EFGHI XYZ" />
<Row ManagerData="ABC PQRST XYZ" />
</Rows>
</MeetTheTeamTable>
<MeetTheTeamNote></MeetTheTeamNote>
</Report>
</FS_Sub_Investment_Team>
Current XSL:
<xsl:template match="/">
<Bio>
<BioText>
<xsl:apply-templates select="//Row/#ManagerData" mode="concat"/>
</BioText>
</Bio>
</xsl:template>
Current Output :
<Bio><BioText>ABC EFGHI XYZABC PQRST XYZ</Bio></BioText>
My expected output is: With line break (or) with space between the two element values, please give me both solutions.
<Bio><BioText>ABC EFGHI XYZ
ABC PQRST XYZ</Bio></BioText>
Try:
<xsl:template match="/">
<Bio>
<BioText>
<xsl:for-each select="//Row">
<xsl:value-of select="#ManagerData" />
<xsl:if test="position()!=last()">
<xsl:text>
</xsl:text>
</xsl:if>
</xsl:for-each>
</BioText>
</Bio>
</xsl:template>
To insert a space instead of a new line, use:
<xsl:text> </xsl:text>
instead of:
<xsl:text>
</xsl:text>

A conditional sequence number for each order in xslt 1.0

How to generate a sequence number with condition.
below is the input,in this <OrderLines> is unbounded element inside this <LineValue1> is there. if <LineValue1> is NULL then we have to ignore this <LineValue1> element and don't increment sequence number.The same way as <Item> is child element of <OrderLines>.If <ItemValue1> is Null then we have to ignore this element and don't increment the sequence number.otherwise we have to increment sequence number. like below output.
input:
<?xml version="1.0" encoding="UTF-8" ?>
<process xmlns="http://xmlns.oracle.com/JMS_TEST/JMS_Publish/JMSSendToQueue">
<OrderHeader><!-- unbounded -->
<HeaderValue1>HeaderValue11063</HeaderValue1>
<OrderLines><!-- unbounded -->
<LineValue1>LineValue11064</LineValue1>
<Linelevel>Linelevel1419</Linelevel>
<Linesyb>Linesyb1420</Linesyb>
<Item><!-- unbounded -->
<ItemValue1></ItemValue1><!-- if ItemValue1 is null then ignore the sequence number(don't increment) -->
<ItemLevel>ItemLevel1422</ItemLevel>
<Itemsyb>Itemsyb1423</Itemsyb>
<Element1><!-- unbounded -->
<ElementValue1>ElementValue11070</ElementValue1>
<ElementLevel>ElementLevel1428</ElementLevel>
<Elementsyb>Elementsyb1429</Elementsyb>
</Element1>
</Item>
<Item><!-- unbounded -->
<ItemValue1>Itemvalue123</ItemValue1>
<ItemLevel>ItemLevel1422</ItemLevel>
<Itemsyb>Itemsyb1423</Itemsyb>
<Element1><!-- unbounded -->
<ElementValue1>ElementValue11070</ElementValue1>
<ElementLevel>ElementLevel1428</ElementLevel>
<Elementsyb>Elementsyb1429</Elementsyb>
</Element1>
</Item>
</OrderLines>
<OrderLines>
<LineValue1></LineValue1><!-- if LineValue1 is null then ignore the sequence number(don't increment) -->
<Linelevel>Linelevel1419</Linelevel>
<Linesyb>Linesyb1420</Linesyb>
<Item>
<ItemValue1>ItemValue11067</ItemValue1>
<ItemLevel>ItemLevel1422</ItemLevel>
<Itemsyb>Itemsyb1423</Itemsyb>
<Element1>
<ElementValue1>ElementValue11070</ElementValue1>
<ElementLevel>ElementLevel1425</ElementLevel>
<Elementsyb>Elementsyb1426</Elementsyb>
</Element1>
</Item>
</OrderLines>
</OrderHeader>
</process>
output:
<?xml version = '1.0' encoding = 'UTF-8'?>
<process xmlns:ns1="http://xmlns.oracle.com/JMS_TEST/JMS_Publish/JMSSendToQueue">
<OrderHeader>
<HeaderValue1>1</HeaderValue1><!--sequence number starts from 1 -->
<OrderLines>
<LineValue1>2</LineValue1><!-- The LineValue1 is NOT NULL so increment the sequence number by '1'-->
<Linelevel>Linelevel1419</Linelevel>
<Linesyb>Linesyb1420</Linesyb>
<Item><!-- The ItemValue1 is NULL so don't increment the sequence number by '1' and ignore the ItemValue1-->
<ItemLevel>ItemLevel1422</ItemLevel>
<Itemsyb>Itemsyb1423</Itemsyb>
<Element1>
<ElementValue1>3</ElementValue1><!-- The ElementValue1 is NOT NULL so increment the sequence number by '1'-->
<ElementLevel>ElementLevel1428</ElementLevel>
<Elementsyb>Elementsyb1429</Elementsyb>
</Element1>
</Item>
<Item>
<ItemValue1>4</ItemValue1><!-- The ItemValue1 is NOT NULL so increment the sequence number by '1'-->
<ItemLevel>ItemLevel1422</ItemLevel>
<Itemsyb>Itemsyb1423</Itemsyb>
<Element1>
<ElementValue1>5</ElementValue1><!-- The ElementValue1 is NOT NULL so increment the sequence number by '1'-->
<ElementLevel>ElementLevel1428</ElementLevel>
<Elementsyb>Elementsyb1429</Elementsyb>
</Element1>
</Item>
</OrderLines>
<OrderLines>
<Item>
<ItemValue1>6</ItemValue1>
<ItemLevel>ItemLevel1422</ItemLevel>
<Itemsyb>Itemsyb1423</Itemsyb>
<Element1>
<ElementValue1>7</ElementValue1>
<ElementLevel>ElementLevel1428</ElementLevel>
<Elementsyb>Elementsyb1429</Elementsyb>
</Element1>
</Item>
</OrderLines>
</OrderHeader>
</process>
I tried the below xslt it is almost wrking ,but the issue is not ignoring the sequece number incase of above condition.
xslt:
<xsl:template match="/">
<process>
<xsl:for-each select="/process/OrderHeader">
<xsl:variable name="headerPosition">
<xsl:value-of select="position()"/>
</xsl:variable>
<xsl:variable name="headerVar">
<xsl:value-of select="
int(
count(/process/OrderHeader[position()<$headerPosition]//OrderLines)+
count(/process/OrderHeader[position()<$headerPosition]//OrderLines//Item)+
count(/process/OrderHeader[position()<$headerPosition]//OrderLines//Element1)+
position())"/>
</xsl:variable>
<OrderHeader>
<HeaderValue1>
<xsl:value-of select="$headerVar"/>
</HeaderValue1>
<xsl:for-each select="ns1:OrderLines">
<xsl:variable name="LinePos">
<xsl:value-of select="int(position())"/>
</xsl:variable>
<xsl:variable name="LineVar">
<xsl:value-of select="int(
$headerVar+
count(/process/OrderHeader[position()=$headerPosition]/OrderLines[position()<$LinePos]//Item)+
count(/process/OrderHeader[position()=$headerPosition]/OrderLines[position()<$LinePos]//Item//Element1)+
position())"/>
</xsl:variable>
<OrderLines>
<xsl:if test="LineValue1!=''">
<LineValue1>
<xsl:value-of select="$LineVar"/>
</LineValue1>
</xsl:if>
<xsl:for-each select="ns1:Item">
<xsl:variable name="ItemPos">
<xsl:value-of select="int(position())"/>
</xsl:variable>
<xsl:variable name="ItemVar">
<xsl:value-of select="int(
$LineVar+
count(/process/OrderHeader[position()=$headerPosition]/OrderLines[position()=$LinePos]//Item[position()<$ItemPos]//Element1)+
position())"/>
</xsl:variable>
<Item>
<xsl:if test="ItemValue1!=''">
<ItemValue1>
<xsl:value-of select="$ItemVar"/>
</ItemValue1>
</xsl:if>
<xsl:for-each select="Element1">
<Element1>
<ElementValue1>
<xsl:value-of select="$ItemVar+position()"/>
</ElementValue1>
</Element1>
</xsl:for-each>
</Item>
</xsl:for-each>
</OrderLines>
</xsl:for-each>
</OrderHeader>
</xsl:for-each>
</process>
</xsl:template>
Try this logic instead (I'm saying logic only because I am not sure of the namespaces present in your XML file)
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="process/OrderHeader/HeaderValue1">
<xsl:copy>
<xsl:value-of select="count(.) + count(preceding::HeaderValue1[.!=''])"/>
</xsl:copy>
</xsl:template>
<xsl:template match="process/OrderHeader/OrderLines/LineValue1">
<xsl:if test=". != ''">
<LineValue1>
<xsl:value-of select="count(.) + count(preceding::LineValue1[.!='']) + count(preceding::HeaderValue1[.!=''])"/>
</LineValue1>
</xsl:if>
</xsl:template>
<xsl:template match="process/OrderHeader/OrderLines/Item/ItemValue1">
<xsl:if test=".!=''">
<ItemValue1>
<xsl:value-of select="count(.) + count(preceding::ElementValue1[.!='']) + count(preceding::ItemValue1[.!='']) + count(preceding::LineValue1[.!='']) + count(preceding::HeaderValue1[.!=''])"/>
</ItemValue1>
</xsl:if>
</xsl:template>
<xsl:template match="process/OrderHeader/OrderLines/Item/Element1/ElementValue1">
<ElementValue1>
<xsl:value-of select="count(.) + count(preceding::ElementValue1[.!='']) + count(preceding::ItemValue1[.!='']) + count(preceding::LineValue1[.!='']) + count(preceding::HeaderValue1[.!=''])"/>
</ElementValue1>
</xsl:template>
</xsl:stylesheet>