XSLT and numbers in attributes - templates

I have an xml-fragment like this:
<p rend="noIndent">eget <seg type="comStart" n="com123"/>kunde<seg type="comEnd" n="com123"/> der i Anledning af disse <seg type="comStart" n="com13"/>kunde<seg type="comEnd" n="com13"/> Smaadigte være at s</p>
I want to change the numbers in the n-attribut and make the numbers starts with 1. The values in the n-attribut shold be the same for each pair of comStat and comEnd in the type-attribute, ending up with this result:
<p rend="noIndent">eget <seg type="comStart" n="com1"/>havde<seg type="comEnd" n="com1"/> der i Anledning af disse <seg type="comStart" n="com2"/>kunde<seg type="comEnd" n="com2"/> Smaadigte være at s</p>
How do I match the corresponding n-attributs in xslt?
KSR

If there are always pairs you can simply create the number using xsl:number for the comStart element:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="3.0">
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="*[#type = ('comStart', 'comEnd')]/#n">
<xsl:attribute name="{name()}">n<xsl:number level="any" count="*[#type = 'comStart']"/></xsl:attribute>
</xsl:template>
</xsl:stylesheet>
http://xsltfiddle.liberty-development.net/eiQZDbm
respectively
<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="*[#type = 'comStart' or #type = 'comEnd']/#n">
<xsl:attribute name="{name()}">n<xsl:number level="any" count="*[#type = 'comStart']"/></xsl:attribute>
</xsl:template>
</xsl:stylesheet>
for XSLT 1 (http://xsltfiddle.liberty-development.net/eiQZDbm/1).

Related

Select various text in the same node and put them to different nodes

I want to Select various text in the same node and put them to different nodes in XSLT.
Input :
<p>The first para
<formula>formula text</formula> The second para
<list>List text</list>
The third para </p>
Desired output :
<pcom>The first para</pcom>
<formulai>formula text</formulai>
<pi>The second para</pi>
<listi>List text</listi>
<pi>The third para</pi>
Tried code :
<xsl:template match="p/text()[preceding-sibling::formula or preceding-sibling::list]">
<pi><xsl:apply-template/></pi>
</xsl:template>
<p>The first para</p> , <p>The second para</p> and <p>The third para</p> are text in same <p>. I want to tarns form them to seperate <pi>.
Those text preceding-sibling must be <formula> or <list>. If preceding-sibling not a <formula> or <list> then the output should be in <pcom>
How can I solve this? I am using XSLT 2.0
This should work for the given example:
<xsl:template match="p/text()">
<pcom>
<xsl:copy/>
</pcom>
</xsl:template>
<xsl:template match="p/text()[preceding-sibling::formula or preceding-sibling::list]">
<pi>
<xsl:copy/>
</pi>
</xsl:template>
However, the problem description is ambiguous. If you want to limit the pi element to text nodes whose immediately preceding sibling is formula or list, use:
<xsl:template match="p/text()[preceding-sibling::node()[1][self::formula or self::list]]">
<pi>
<xsl:copy/>
</pi>
</xsl:template>
<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:output method="xml" indent="yes"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="node()[ following-sibling::*[1][self::list] and preceding-sibling::*[1][self::formula] or preceding-sibling::*[1][self::list]]">
<pi>
<xsl:value-of select=" normalize-space(.)"/>
</pi>
</xsl:template>
<xsl:template match="node()[following-sibling::*[1][self::formula]]">
<pcom>
<xsl:value-of select="normalize-space(.)"/>
</pcom>
</xsl:template>
<xsl:template match="formula">
<formulai>
<xsl:value-of select="."/>
</formulai>
</xsl:template>
<xsl:template match="p">
<xsl:apply-templates/>
</xsl:template>
You may also try this.

Attempting to remove element and reorder elements in resulting document

I have the following XML and XSLT.
I am attempting to exclude the NotUsed2 element from the resulting document.
I need to reorder the resulting so that AutoTypesetInfo follows NotUsed3.
XML:
<?xml version="1.0" encoding="ISO-8859-1" standalone="no" ?>
<Plan xmlns="http://www.ccieurope.com/xmlns/CCIPlanner">
<Header>
<Update>0</Update>
<NewsPaper>Pub1</NewsPaper>
<Date>080818</Date>
<Zone>MAIN</Zone>
<Edition>1st</Edition>
<Pages>26</Pages>
<Section>A B C </Section>
<Number>08082018</Number>
<Format>
<Height>21.70i</Height>
<Width>9.87i</Width>
</Format>
<PrintingInfo/>
<Version/>
<Config/>
<Default/>
<FileFormat>2.0</FileFormat>
<IssueName/>
</Header>
<Page>
<PhysicalBook>A</PhysicalBook>
<BookPageNumber>1</BookPageNumber>
<Desk>A</Desk>
<SubDesk/>
<SpreadPage>0</SpreadPage>
<Status/>
<Deadline>0708182230</Deadline>
<PagePrintInfo/>
<Cmyk>CMYK</Cmyk>
<Spot1/>
<Spot2/>
<Spot3/>
<CyanFilm/>
<MagFilm/>
<YelFilm/>
<BlackFilm/>
<Spot1Film/>
<Spot2Film/>
<Spot3Film/>
<PageId>MAIN#F</PageId>
<TemplatePage>
<Content>c#FolioStandard#i#</Content>
<Layout></Layout>
</TemplatePage>
<ProdForm/>
<TextSourceDir/>
<TextSourcePage/>
<RunningPage/>
<CmyDeadline/>
<ColorGrp/>
<AdRules>1</AdRules>
<CustChar/>
<CustDate/>
<Active>1</Active>
<NoMaster>0</NoMaster>
<Cust2/>
<PageType>EditorialOnly</PageType>
<Cust4/>
<Cust5/>
<Cust6/>
<Cust7/>
<Cust8/>
<Cust9/>
<Cust10/>
<Desk2/>
<Desk2NewsHole/>
<Desk2Placement/>
<Cust11/>
<NotUsed2/>
<NotUsed3/>
<Ad>
<BookingNumber>12345</BookingNumber>
<Description>Desc1</Description>
<AdRelatedInfo> </AdRelatedInfo>
<FirstPubDate>080818</FirstPubDate>
<LastPubDate>080818</LastPubDate>
<Customer>Customer</Customer>
<AdColor>Proces</AdColor>
<AdWidth>710.9</AdWidth>
<AdHeight>144.0</AdHeight>
<MatType>EPS</MatType>
<AdType>0</AdType>
<AdPos>
<XPos>0.00</XPos>
<YPos>1404.03</YPos>
</AdPos>
<AdProdInfo/>
<AdNotUsed2/>
<AdNotUsed3/>
<AdCust1/>
<AdCust2/>
<AdCust3/>
</Ad>
<AutoTypesetInfo>0:5-60</AutoTypesetInfo></Page>
<Page>
<PhysicalBook>A</PhysicalBook>
<BookPageNumber>2</BookPageNumber>
<Desk>A</Desk>
<SubDesk/>
<SpreadPage>0</SpreadPage>
<Status/>
<Deadline>0708182230</Deadline>
<PagePrintInfo/>
<Cmyk>CMYK</Cmyk>
<Spot1/>
<Spot2/>
<Spot3/>
<CyanFilm/>
<MagFilm/>
<YelFilm/>
<BlackFilm/>
<Spot1Film/>
<Spot2Film/>
<Spot3Film/>
<PageId>MAIN#1</PageId>
<TemplatePage>
<Content>c#FolioStandard#i#</Content>
<Layout></Layout>
</TemplatePage>
<ProdForm/>
<TextSourceDir/>
<TextSourcePage/>
<RunningPage/>
<CmyDeadline/>
<ColorGrp/>
<AdRules>1</AdRules>
<CustChar/>
<CustDate/>
<Active>1</Active>
<NoMaster>0</NoMaster>
<Cust2/>
<PageType>Mixed</PageType>
<Cust4/>
<Cust5/>
<Cust6/>
<Cust7/>
<Cust8/>
<Cust9/>
<Cust10/>
<Desk2/>
<Desk2NewsHole/>
<Desk2Placement/>
<Cust11/>
<NotUsed2/>
<NotUsed3/>
<Ad>
<BookingNumber>152345</BookingNumber>
<Description>Description</Description>
<AdRelatedInfo> </AdRelatedInfo>
<FirstPubDate>080818</FirstPubDate>
<LastPubDate>080818</LastPubDate>
<Customer>Customer</Customer>
<AdColor>000K</AdColor>
<AdWidth>351.9</AdWidth>
<AdHeight>360.0</AdHeight>
<MatType>EPS</MatType>
<AdType>0</AdType>
<AdPos>
<XPos>0.00</XPos>
<YPos>1188.03</YPos>
</AdPos>
<AdProdInfo/>
<AdNotUsed2/>
<AdNotUsed3/>
<AdCust1/>
<AdCust2/>
<AdCust3/>
</Ad>
<Ad>
<BookingNumber>12345</BookingNumber>
<Description>Description</Description>
<AdRelatedInfo> </AdRelatedInfo>
<FirstPubDate>080818</FirstPubDate>
<LastPubDate>080818</LastPubDate>
<Customer>Customer</Customer>
<AdColor>Proces</AdColor>
<AdWidth>351.9</AdWidth>
<AdHeight>360.0</AdHeight>
<MatType>EPS</MatType>
<AdType>0</AdType>
<AdPos>
<XPos>358.99</XPos>
<YPos>1188.03</YPos>
</AdPos>
<AdProdInfo/>
<AdNotUsed2/>
<AdNotUsed3/>
<AdCust1/>
<AdCust2/>
<AdCust3/>
</Ad>
<AutoTypesetInfo>0:5-60</AutoTypesetInfo>
</Page>
</Plan>
XSL:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:cci="http://www.ccieurope.com/xmlns/CCIPlanner"
exclude-result-prefixes="msxsl cci"
>
<xsl:output indent="yes"/>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<!-- If element name match on NotUsed2, exclude from result -->
<xsl:template match="NotUsed2" />
</xsl:stylesheet>
Expected in the resulting Page node:
<Page>
<PhysicalBook>A</PhysicalBook>
<BookPageNumber>1</BookPageNumber>
<Desk>A</Desk>
<SubDesk/>
<SpreadPage>0</SpreadPage>
<Status/>
<Deadline>0708182230</Deadline>
<PagePrintInfo/>
<Cmyk>CMYK</Cmyk>
<Spot1/>
<Spot2/>
<Spot3/>
<CyanFilm/>
<MagFilm/>
<YelFilm/>
<BlackFilm/>
<Spot1Film/>
<Spot2Film/>
<Spot3Film/>
<PageId>MAIN#F</PageId>
<TemplatePage>
<Content>c#FolioStandard#i#</Content>
<Layout></Layout>
</TemplatePage>
<ProdForm/>
<TextSourceDir/>
<TextSourcePage/>
<RunningPage/>
<CmyDeadline/>
<ColorGrp/>
<AdRules>1</AdRules>
<CustChar/>
<CustDate/>
<Active>1</Active>
<NoMaster>0</NoMaster>
<Cust2/>
<PageType>EditorialOnly</PageType>
<Cust4/>
<Cust5/>
<Cust6/>
<Cust7/>
<Cust8/>
<Cust9/>
<Cust10/>
<Desk2/>
<Desk2NewsHole/>
<Desk2Placement/>
<Cust11/>
<NotUsed3/>
<AutoTypesetInfo>0:5-60</AutoTypesetInfo>
<Ad>
<BookingNumber>12345</BookingNumber>
<Description>Desc1</Description>
<AdRelatedInfo> </AdRelatedInfo>
<FirstPubDate>080818</FirstPubDate>
<LastPubDate>080818</LastPubDate>
<Customer>Customer</Customer>
<AdColor>Proces</AdColor>
<AdWidth>710.9</AdWidth>
<AdHeight>144.0</AdHeight>
<MatType>EPS</MatType>
<AdType>0</AdType>
<AdPos>
<XPos>0.00</XPos>
<YPos>1404.03</YPos>
</AdPos>
<AdProdInfo/>
<AdNotUsed2/>
<AdNotUsed3/>
<AdCust1/>
<AdCust2/>
<AdCust3/>
</Ad>
</Page>
I can't get the code to exclude the NotUsed2 element.
I'm not sure where to begin to tackle reordering the elements within nodes.
Any help would be appreciated.
Your NotUsed2 is not being removed because you have not accounted for the fact the element is in a default namespace in the XML. Your XSLT is looking for an element with no namespace.
You have declared the relevant namespace in your XSLT, so you just need to use the relevant prefix in the template match
<xsl:template match="cci:NotUsed2" />
For moving AutoTypesetInfo after NotUsed3 you should have a template that matches NotUsed3 where you can copy both the matched node, and the AutoTypesetInfo
<xsl:template match="cci:NotUsed3">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
<xsl:copy-of select="../cci:AutoTypesetInfo" />
</xsl:template>
You would also need a template to ensure the AutoTypesetInfo still doesn't get copied in its current position too
<xsl:template match="cci:AutoTypesetInfo" />
Try this XSLT
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:cci="http://www.ccieurope.com/xmlns/CCIPlanner"
exclude-result-prefixes="msxsl cci">
<xsl:output indent="yes"/>
<xsl:template match="#* | node()" name="identity">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<!-- If element name match on NotUsed2, exclude from result -->
<xsl:template match="cci:NotUsed2" />
<xsl:template match="cci:NotUsed3">
<xsl:call-template name="identity" />
<xsl:copy-of select="../cci:AutoTypesetInfo" />
</xsl:template>
<xsl:template match="cci:AutoTypesetInfo" />
</xsl:stylesheet>
This does assume NotUsed3 is always present. If not, change the last template to this to ensure the original AutoTypesetInfo is not removed in this case.
<xsl:template match="cci:AutoTypesetInfo[../cci:NotUsed3]" />
Try below XSLT.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:cci="http://www.ccieurope.com/xmlns/CCIPlanner"
exclude-result-prefixes="msxsl cci"
>
<xsl:output indent="yes"/>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<!-- If element name match on NotUsed2, exclude from result -->
<xsl:template match="*[local-name()='NotUsed2']" />
</xsl:stylesheet>

I need to define a xslt to combine couple of elements with separators for custom defined xsd types

I have couple of custom types which have 2, 3 or 4 childs. So wherever I get these childs I need to combine them into a single element which is the parent tag itself in the output XML. I tried but could not do due to lack of experience with xslt. Can any one help.
My input XML.
<PERSON>
<ID>194</ID>
<NAME>IKHAJA</NAME>
<DETAILS>
<NUMBER>100</NUMBER>
<Description />
<NUMBER01 />
<NUMBER02>Test</NUMBER02>
</DETAILS>
<STATUS>
<NUMBER>ACTIVE</NUMBER>
<Description>ACTIVE</Description>
<NUMBER01 />
<NUMBER02>ACTIVE</NUMBER02>
</STATUS>
<employer>
<ID>123456</ID>
<FNAME>EMPLOYER F NAME</FNAME>
<LNAME>EMPLOYER L NAME</LNAME>
</employer>
<PERSON_OFF>
<TYPE>
<NUMBER>41</NUMBER>
<Description>AMPLIFIERS</Description>
<NUMBER01>77</NUMBER01>
<NUMBER02 />
</TYPE>
<REPORT>
<NUMBER />
<Description />
<NUMBER01 />
<NUMBER02 />
</REPORT>
<SERIAL>111</SERIAL>
<ADDITIONAL_DESC>TEST</ADDITIONAL_DESC>
<KEY>5</KEY>
<CREATED_BY>Test Guy</CREATED_BY>
<CREATED_ON>2013-03-13T10:03:00</CREATED_ON>
<PERSON_OFF_ONE>
<BULK>
<NUMBER>98078</NUMBER>
<Description>BULK</Description>
<NUMBER01 />
<NUMBER02>8563</NUMBER02>
</BULK>
<CHECKED>Y</CHECKED>
</PERSON_OFF_ONE>
</PERSON_OFF>
</PERSON>
And my output XML should be like this:
<PERSON>
<ID>194</ID>
<NAME>IKHAJA</NAME>
<DETAILS>100;;;Test</DETAILS>
<STATUS>ACTIVE;ACTIVE;;ACTIVE</STATUS>
<employer>123456:EMPLOYER F NAME,EMPLOYER L NAME</employer>
<PERSON_OFF>
<TYPE>41;AMPLIFIERS;77;</TYPE>
<REPORT>;;;</REPORT>
<SERIAL>111</SERIAL>
<ADDITIONAL_DESC>TEST</ADDITIONAL_DESC>
<KEY>5</KEY>
<CREATED_BY>Test Guy</CREATED_BY>
<CREATED_ON>2013-03-13T10:03:00</CREATED_ON>
<PERSON_OFF_ONE>
<BULK>98078;BULK;;8563</BULK>
<CHECKED>Y</CHECKED>
</PERSON_OFF_ONE>
</PERSON_OFF>
</PERSON>
If you observe here details, status, bulk etc. are my custom types which have child nodes NUMBER, Description, NUMBER01, NUMBRER02. and I need to combine them with a separator ";" if they are empty or null just I will have ";;;" in my destination column as shown in REPORT field.
Also I have some fields of employer type like employer with childs ID, FNAME and LNAME and I should combine them as ID: FNAME, LNAME as shown in employer field.
I think if I know handling one custom type, I can handle the other types easily.
Can you please help? I already spent whole day on this and I need to do this very badly ASAP.
OP's comment to the answer by JLRishe:
It works if I list all of my custom types but, here I have so many
fields that are of my custom types. Instead of listing out all those
like "DETAILS | STATUS | TYPE | REPORT | BULK", is there any way to
merge fields of these.
This can be done easily, using the fact that all these possibly hundreds of parent elements have one of four children.
A minor adjustment to JLRishe's solution works with unlimited number of parent names:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[NUMBER|Description|NUMBER01|NUMBER02]">
<xsl:copy>
<xsl:apply-templates select="*" mode="delimit" />
</xsl:copy>
</xsl:template>
<xsl:template match="*[position() > 1]" mode="delimit">
<xsl:value-of select="concat(';', .)"/>
</xsl:template>
<xsl:template match="employer">
<xsl:copy>
<xsl:apply-templates select="*" mode="idlist" />
</xsl:copy>
</xsl:template>
<xsl:template match="ID" mode="idlist">
<xsl:value-of select="concat(., ':')" />
</xsl:template>
<xsl:template match="*[not(self::ID)][position() > 1]" mode="idlist">
<xsl:value-of select="concat(',', .)" />
</xsl:template>
</xsl:stylesheet>
As you see, this transformation doesn't mention at all any parent names such as DETAILS, STATUS, TYPE, REPORT, BULK, ..., etc.
and when applied on the provided XML document, produces the wanted, correct result:
<PERSON>
<ID>194</ID>
<NAME>IKHAJA</NAME>
<DETAILS>100;;;Test</DETAILS>
<STATUS>ACTIVE;ACTIVE;;ACTIVE</STATUS>
<employer>123456:EMPLOYER F NAME,EMPLOYER L NAME</employer>
<PERSON_OFF>
<TYPE>41;AMPLIFIERS;77;</TYPE>
<REPORT>;;;</REPORT>
<SERIAL>111</SERIAL>
<ADDITIONAL_DESC>TEST</ADDITIONAL_DESC>
<KEY>5</KEY>
<CREATED_BY>Test Guy</CREATED_BY>
<CREATED_ON>2013-03-13T10:03:00</CREATED_ON>
<PERSON_OFF_ONE>
<BULK>98078;BULK;;8563</BULK>
<CHECKED>Y</CHECKED>
</PERSON_OFF_ONE>
</PERSON_OFF>
</PERSON>
Please give this a try:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="DETAILS | STATUS | TYPE | REPORT | BULK">
<xsl:copy>
<xsl:apply-templates select="*" mode="delimit" />
</xsl:copy>
</xsl:template>
<xsl:template match="*[position() > 1]" mode="delimit">
<xsl:value-of select="concat(';', .)"/>
</xsl:template>
<xsl:template match="employer">
<xsl:copy>
<xsl:apply-templates select="*" mode="idlist" />
</xsl:copy>
</xsl:template>
<xsl:template match="ID" mode="idlist">
<xsl:value-of select="concat(., ':')" />
</xsl:template>
<xsl:template match="*[not(self::ID)][position() > 1]" mode="idlist">
<xsl:value-of select="concat(',', .)" />
</xsl:template>
</xsl:stylesheet>
When run on your sample input, the result is:
<PERSON>
<ID>194</ID>
<NAME>IKHAJA</NAME>
<DETAILS>100;;;Test</DETAILS>
<STATUS>ACTIVE;ACTIVE;;ACTIVE</STATUS>
<employer>123456:EMPLOYER F NAME,EMPLOYER L NAME</employer>
<PERSON_OFF>
<TYPE>41;AMPLIFIERS;77;</TYPE>
<REPORT>;;;</REPORT>
<SERIAL>111</SERIAL>
<ADDITIONAL_DESC>TEST</ADDITIONAL_DESC>
<KEY>5</KEY>
<CREATED_BY>Test Guy</CREATED_BY>
<CREATED_ON>2013-03-13T10:03:00</CREATED_ON>
<PERSON_OFF_ONE>
<BULK>98078;BULK;;8563</BULK>
<CHECKED>Y</CHECKED>
</PERSON_OFF_ONE>
</PERSON_OFF>
</PERSON>

Group/merge childs of same nodes in xml/xslt when repeating upper nodes

As an addition to my orginal post Group/merge childs of same nodes in xml/xslt I ran into the problem of having that structure repeated multiple times for different nodes (wihtin nodes higher in the hierarchy) e.g.,
<Collection>
<Questionnaire Name="Preferences" VersionID="3QW">
<Subject ID="2355">
<EventData Name="First Part">
<FormData Name="Past">
<GroupData ID="xxx" Key="4" Temp="yyy">
<ItemData ID="zzz" Value="3"/>
</GroupData>
<GroupData ID="xxx" Key="4" Temp="yyy">
<ItemData ID="qqq" Value="4"/>
</GroupData>
...
</FormData>
<FormData Name="Present">
<GroupData ID="yyy" Key="9" Temp="yyy">
<ItemData ID="www" Value="32"/>
</GroupData>
...
</FormData>
</EventData>
<EventData Name="SecondPart">
...
</EventData>
</Subject>
<Subject ID="9812">
...
</Subject>
</Questionnaire>
</Collection>
After trying variations on the suggestions I reveived and some other things I am stuck. I think it has something to do with multiple levels (and GroupData being spread over upper/grandparent nodes in which it will be a child) and then it possiblly does not have unique IDs anymore. So how can I get the childs of each GroupData node into one GroupData node (matched on ID and sometimes Key, since the latter is not always present)? Note: The same GroupData nodes (with corresponding attributes) must be merged into one GroupData node in each FormData node.
Here are two XSLT 1.0 solutions.
One solution is to take Dimite's solution from your first question, and just expand the key to include FormData...
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kGDByIdKey" match="FormData/GroupData"
use="concat(#ID, '+', #Key, '+', generate-id(..))"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match=
"FormData/GroupData
[generate-id()
=
generate-id(key('kGDByIdKey', concat(#ID, '+', #Key, '+', generate-id(..)))[1])
]">
<xsl:copy>
<xsl:apply-templates select=
"#*|key('kGDByIdKey', concat(#ID, '+', #Key, '+', generate-id(..)))/node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="GroupData"/>
</xsl:stylesheet>
Another solution moves the grouping test from the template match condition to the the invoking xsl:apply-templates in the parent FormData ...
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kGDByIdKey" match="FormData/GroupData" use="concat(#ID, '+', #Key)" />
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="FormData">
<xsl:copy>
<xsl:apply-templates select="
#* |
node()[not(self::GroupData)] |
GroupData[generate-id() =
generate-id(key('kGDByIdKey', concat(#ID, '+', #Key))[1])]"/>
</xsl:copy>
</xsl:template>
<xsl:template match="FormData/GroupData">
<xsl:copy>
<xsl:apply-templates select="#*|
key('kGDByIdKey', concat(#ID, '+', #Key))/node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="GroupData"/>
</xsl:stylesheet>
Both stylesheets assume that GroupData's parent is only ever FormData. Any GroupData which does not have a FormData parent is removed.

how to sort elements and group them based on unique element or ID, which has namespace

i have asked with the same question but not with the namespace
i have an xml like..this
<?xml version = '1.0' encoding = 'UTF-8'?>
<FinalDbGetUserId>
<FinalDbGetUserIdOutputCollection xmlns:ns0="http://xmlns.oracle.com/pcbpel/adapter/db/FinalDbGetUserId"
xmlns="http://xmlns.oracle.com/pcbpel/adapter/db/FinalDbGetUserId">
<ns0:USERUBSCRIBERS>
<ns0:USER_ID>237</ns0:USER_ID>
<ns0:BusinessEntity>
<ns0:NEVADA_BUSINESS_ID>NV0511201114</ns0:NEVADA_BUSINESS_ID>
<ns0:BUSINESS_ENTITY_ID>207</ns0:BUSINESS_ENTITY_ID>
</ns0:BusinessEntity>
</ns0:USERUBSCRIBERS>
<ns0:USERUBSCRIBERS>
<ns0:USER_ID>237</ns0:USER_ID>
<ns0:BusinessEntity>
<ns0:NEVADA_BUSINESS_ID>NV0511201119</ns0:NEVADA_BUSINESS_ID>
<ns0:BUSINESS_ENTITY_ID>212</ns0:BUSINESS_ENTITY_ID>
</ns0:BusinessEntity>
</ns0:USERUBSCRIBERS>
<ns0:USERUBSCRIBERS>
<ns0:USER_ID>237</ns0:USER_ID>
<ns0:BusinessEntity>
<ns0:NEVADA_BUSINESS_ID>NV0511201129</ns0:NEVADA_BUSINESS_ID>
<ns0:BUSINESS_ENTITY_ID>230</ns0:BUSINESS_ENTITY_ID>
</ns0:BusinessEntity>
</ns0:USERUBSCRIBERS>
</FinalDbGetUserIdOutputCollection>
</FinalDbGetUserId>
output should be like
<FinalDbGetUserId>
<FinalDbGetUserIdOutputCollection xmlns:ns0="http://xmlns.oracle.com/pcbpel/adapter/db/FinalDbGetUserId"
xmlns="http://xmlns.oracle.com/pcbpel/adapter/db/FinalDbGetUserId">
<ns0:USERUBSCRIBERS>
<ns0:USER_ID>237</ns0:USER_ID>
<ns0:BusinessEntity>
<ns0:NEVADA_BUSINESS_ID>NV0511201114</ns0:NEVADA_BUSINESS_ID>
<ns0:BUSINESS_ENTITY_ID>207</ns0:BUSINESS_ENTITY_ID>
</ns0:BusinessEntity>
<ns0:BusinessEntity>
<ns0:NEVADA_BUSINESS_ID>NV0511201119</ns0:NEVADA_BUSINESS_ID>
<ns0:BUSINESS_ENTITY_ID>212</ns0:BUSINESS_ENTITY_ID>
</ns0:BusinessEntity>
<ns0:BusinessEntity>
<ns0:NEVADA_BUSINESS_ID>NV0511201129</ns0:NEVADA_BUSINESS_ID>
<ns0:BUSINESS_ENTITY_ID>230</ns0:BUSINESS_ENTITY_ID>
</ns0:BusinessEntity>
</ns0:USERUBSCRIBERS>
</FinalDbGetUserIdOutputCollection>
</FinalDbGetUserId>
Following is the below xslt, that i was trying and not getting the desired result
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kuserID" match="USERUBSCRIBERS" use="USER_ID"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*">
<xsl:sort select="USER_ID" data-type="number"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match=
"USERUBSCRIBERS|USER_ID
|BusinessEntity"/>
<xsl:template match=
"USERUBSCRIBERS
[generate-id()
=
generate-id(key('kuserID', USER_ID)[1])
]">
<USERUBSCRIBERS>
<xsl:copy-of select="USER_ID"/>
<xsl:apply-templates mode="copy" select="key('kuserID',USER_ID)" />
</USERUBSCRIBERS>
</xsl:template>
<xsl:template match="USERUBSCRIBERS" mode="copy">
<BusinessEntity>
<xsl:apply-templates/>
</BusinessEntity>
</xsl:template>
</xsl:stylesheet>
i am getting the output same as input and there is no change.
may be i am doing mistake, but not getting what the mistake is .... trying to find it out
Define xmlns:ns0="http://xmlns.oracle.com/pcbpel/adapter/db/FinalDbGetUserId" on your xsl:stylesheet element, then use the prefix ns0 anywhere in your stylesheet where you match or select elements from that namespace e.g. <xsl:key name="kuserID" match="ns0:USERUBSCRIBERS" use="ns0:USER_ID"/> and <xsl:sort select="ns0:USER_ID" data-type="number"/>.