xml to xml conversion using xslt - xslt

I need to pass the XML to third party system which can be understand by third party and parse it.
Below is my input xml which I created data by fetching from database.
<FIXML>
<Header>
<RequestID>ReqID8942</RequestID>
<RequestType>DocGen</RequestType>
<Version>10.6</Version>
<BankId>01</BankId>
<ChannelId>LOS</ChannelId>
</Header>
<Body>
<Data>
**<CorpAppLimitDetailsBO>
<ApprovedLimitHomeCCY>100.0</ApprovedLimitHomeCCY>
<ApprovedLimitCCY>INR</ApprovedLimitCCY>
<ApprovedLimit>100.0</ApprovedLimit>
<LimitClassification>ROOT</LimitClassification>
</CorpAppLimitDetailsBO>
<CorpAppLimitDetailsBO>
<ApprovedLimitHomeCCY>0.0</ApprovedLimitHomeCCY>
<ApprovedLimitCCY/>
<ApprovedLimit>500.0</ApprovedLimit>
<LimitClassification>CLASSIFICATION1</LimitClassification>
</CorpAppLimitDetailsBO>
<CorpAppLimitDetailsBO>
<ApprovedLimitHomeCCY>100.0</ApprovedLimitHomeCCY>
<ApprovedLimitCCY>INR</ApprovedLimitCCY>
<ApprovedLimit>100.0</ApprovedLimit>
<LimitClassification>CLASSIFICATION1</LimitClassification>
</CorpAppLimitDetailsBO>
<CorpAppProductDetailsBO>
<ProductCategory>3</ProductCategory>
</CorpAppProductDetailsBO>
<CorpAppProductDetailsBO>
<ProductCategory>1</ProductCategory>
</CorpAppProductDetailsBO>
<CorpAppProductDetailsBO>
<ProductCategory>2</ProductCategory>
</CorpAppProductDetailsBO>**
<TemplateDetails>
<Template>tempid001</Template>
</TemplateDetails>
<SelectedClauses>
<Clauses>
<Clause>clause1</Clause>
</Clauses>
<Clauses>
<Clause>clause2</Clause>
</Clauses>
<Clauses>
<Clause>clause3</Clause>
</Clauses>
</SelectedClauses>
<Distribution>
<Email>email1#domain.com,email2#domain.com,email3#domain.com</Email>
<Print>blrkec3030,blrkec3031</Print>
</Distribution>
</Data>
</Body>
</FIXML>
I want to convert this input XML to another XML format using XSLT.
Below is the format which I need,
<FIXML>
<Header>
<RequestID>ReqID8942</RequestID>
<RequestType>DocGen</RequestType>
<Version>10.6</Version>
<BankId>01</BankId>
<ChannelId>LOS</ChannelId>
</Header>
<Body>
<Data>
**<LimitDetails>
<Limit>
<ApprovedLimitHomeCCY>100.0</ApprovedLimitHomeCCY>
<ApprovedLimitCCY>INR</ApprovedLimitCCY>
<ApprovedLimit>100.0</ApprovedLimit>
<LimitClassification>ROOT</LimitClassification>
</Limit>
<Limit>
<ApprovedLimitHomeCCY>0.0</ApprovedLimitHomeCCY>
<ApprovedLimitCCY/>
<ApprovedLimit>500.0</ApprovedLimit>
<LimitClassification>CLASSIFICATION1</LimitClassification>
</Limit>
<Limit>
<ApprovedLimitHomeCCY>100.0</ApprovedLimitHomeCCY>
<ApprovedLimitCCY>INR</ApprovedLimitCCY>
<ApprovedLimit>100.0</ApprovedLimit>
<LimitClassification>CLASSIFICATION1</LimitClassification>
</Limit>
</LimitDetails>
<ProductDetails>
<Product>
<ProductCategory>3</ProductCategory>
</Product>
<Product>
<ProductCategory>1</ProductCategory>
</Product>
<Product>
<ProductCategory>2</ProductCategory>
</Product>
</ProductDetails>**
<TemplateDetails>
<Template>tempid001</Template>
</TemplateDetails>
<SelectedClauses>
<Clauses>
<Clause>clause1</Clause>
</Clauses>
<Clauses>
<Clause>clause2</Clause>
</Clauses>
<Clauses>
<Clause>clause3</Clause>
</Clauses>
</SelectedClauses>
<Distribution>
<Email>email1#domain.com,email2#domain.com,email3#domain.com</Email>
<Print>blrkec3030,blrkec3031</Print>
</Distribution>
</Data>
</Body>
</FIXML>
Please help me out as I have to complete the task in another 2 days of time.
I tried with below code and i m getting below outputs but rest of the tags for e.g. <FIXML> , <TemplateDetails> and etc is not coming as part of output xml.
xsl code below:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output indent="yes" /> <!-- This identity template copies the document -->
<xsl:template match="node() | #*">
<xsl:copy>
<xsl:apply-templates select="node() | #*" />
</xsl:copy>
</xsl:template>
<!--
This template will only match the 'CorpAppLimitDetailsBO'
nodes and modify them the way you want.
-->
<xsl:template match="/*">
<xsl:element name="LimitDetails">
<xsl:for-each select="//CorpAppLimitDetailsBO">
<xsl:element name="Limit">
<xsl:for-each select="*">
<xsl:copy-of select="." />
</xsl:for-each>
</xsl:element>
</xsl:for-each>
</xsl:element>
<xsl:element name="ProductDetails">
<xsl:for-each select="//CorpAppProductDetailsBO">
<xsl:element name="Product">
<xsl:for-each select="*">
<xsl:copy-of select="." />
</xsl:for-each>
</xsl:element>
</xsl:for-each>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
output.xml below:
<?xml version="1.0" encoding="UTF-8"?>
<LimitDetails>
<Limit>
<ApprovedLimitHomeCCY>100.0</ApprovedLimitHomeCCY>
<ApprovedLimitCCY>INR</ApprovedLimitCCY>
<ApprovedLimit>100.0</ApprovedLimit>
<LimitClassification>ROOT</LimitClassification>
</Limit>
<Limit>
<ApprovedLimitHomeCCY>0.0</ApprovedLimitHomeCCY>
<ApprovedLimitCCY/>
<ApprovedLimit>500.0</ApprovedLimit>
<LimitClassification>CLASSIFICATION1</LimitClassification>
</Limit>
<Limit>
<ApprovedLimitHomeCCY>100.0</ApprovedLimitHomeCCY>
<ApprovedLimitCCY>INR</ApprovedLimitCCY>
<ApprovedLimit>100.0</ApprovedLimit>
<LimitClassification>CLASSIFICATION1</LimitClassification>
</Limit>
</LimitDetails>
<ProductDetails>
<Product>
<ProductCategory>3</ProductCategory>
</Product>
<Product>
<ProductCategory>1</ProductCategory>
</Product>
<Product>
<ProductCategory>2</ProductCategory>
</Product>
</ProductDetails>
Note: The child tag(for e.g.ApprovedLimitHomeCCY....) which i present under BO's(for e.g. CorpAppLimitDetailsBO) tag are dynamic.I shouldnt hard code in xsl.I m new to XSLT. pls help me out.
Thanks Shil and Sean for your solution. both are perfect for my requirements. but i have one more doubt now.i m adding one more child tag <DBApplicantMiscDetails> under
<CorpAppProductDetailsBO>
Input xml:
<CorpAppProductDetailsBO>
<ProductCategory>2</ProductCategory>
<DBApplicantMiscDetails>
<APPLICANTMISCID>400000</APPLICANTMISCID>
<APPLICANTID>400030</APPLICANTID>
<MISCTYPE>APPLIED</MISCTYPE>
</DBApplicantMiscDetails>
</CorpAppProductDetailsBO>
Below is the output format which i expect.
<ProductDetails>
<Product>
<ProductCategory>2</ProductCategory>
<APPLICANTMISCID>400000</APPLICANTMISCID>
<APPLICANTID>400030</APPLICANTID>
<MISCTYPE>APPLIED</MISCTYPE>
</Product>
</ProductDetails>
Thanks again.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*" />
<xsl:key name="kDetails" match="*
[starts-with(name(),'CorpApp') and
substring(name(), string-length(name()) - 8) = 'DetailsBO']"
use="substring-before(name(),'DetailsBO')" />
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[*[key('kDetails',substring-before(name(),'DetailsBO'))]]">
<xsl:copy>
<xsl:apply-templates select="#*"/>
<xsl:apply-templates select="*[generate-id() =
generate-id(key('kDetails',
substring-before(name(),'DetailsBO'))[1])]" mode="group" />
<xsl:apply-templates select="*[not(
key('kDetails',substring-before(name(),'DetailsBO')))]
|comment()|processing-instruction()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*" mode="group">
<xsl:variable name="group-name" select="substring-after(substring-before(name(),'DetailsBO'),'CorpApp')" />
<xsl:element name="{$group-name}Details">
<xsl:for-each select="key('kDetails',substring-before(name(),'DetailsBO'))">
<xsl:element name="{$group-name}">
<xsl:apply-templates select="#*|node()"/>
</xsl:element>
</xsl:for-each>
</xsl:element>
</xsl:template>
</xsl:stylesheet>

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<xsl:apply-templates select="FIXML"/>
</xsl:template>
<xsl:template match="FIXML">
<FIXML>
<xsl:apply-templates select="Header"/>
<xsl:apply-templates select="Body"/>
</FIXML>
</xsl:template>
<xsl:template match="Header">
<xsl:copy-of select="."/>
</xsl:template>
<xsl:template match="Body">
<Body>
<xsl:apply-templates select="Data"/>
</Body>
</xsl:template>
<xsl:template match="Data">
<Data>
<LimitDetails>
<xsl:apply-templates select="CorpAppLimitDetailsBO"/>
</LimitDetails>
<ProductDetails>
<xsl:apply-templates select="CorpAppProductDetailsBO"/>
</ProductDetails>
<xsl:apply-templates select="TemplateDetails"/>
<xsl:apply-templates select="SelectedClauses"/>
<xsl:apply-templates select="Distribution"/>
</Data>
</xsl:template>
<xsl:template match="CorpAppLimitDetailsBO">
<Limit>
<xsl:copy-of select="child::*"/>
</Limit>
</xsl:template>
<xsl:template match="CorpAppProductDetailsBO">
<xsl:apply-templates select="ProductCategory"/>
</xsl:template>
<xsl:template match="ProductCategory">
<Product>
<xsl:copy-of select="."/>
</Product>
</xsl:template>
<xsl:template match="TemplateDetails">
<xsl:copy-of select="."/>
</xsl:template>
<xsl:template match="SelectedClauses">
<xsl:copy-of select="."/>
</xsl:template>
<xsl:template match="Distribution">
<xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml"/>
<xsl:template match="/">
<xsl:apply-templates select="FIXML"/>
</xsl:template>
<xsl:template match="FIXML">
<FIXML>
<xsl:apply-templates select="Header"/>
<xsl:apply-templates select="Body"/>
</FIXML>
</xsl:template>
<xsl:template match="Header">
<xsl:copy-of select="."/>
</xsl:template>
<xsl:template match="Body">
<Body>
<xsl:apply-templates select="Data"/>
</Body>
</xsl:template>
<xsl:template match="Data">
<Data>
<LimitDetails>
<xsl:apply-templates select="CorpAppLimitDetailsBO"/>
</LimitDetails>
<ProductDetails>
<xsl:apply-templates select="CorpAppProductDetailsBO"/>
</ProductDetails>
<xsl:apply-templates select="TemplateDetails"/>
<xsl:apply-templates select="SelectedClauses"/>
<xsl:apply-templates select="Distribution"/>
</Data>
</xsl:template>
<xsl:template match="CorpAppLimitDetailsBO">
<Limit>
<xsl:copy-of select="child::*"/>
</Limit>
</xsl:template>
<xsl:template match="CorpAppProductDetailsBO">
<Product>
<xsl:apply-templates select="ProductCategory"/>
<xsl:apply-templates select="DBApplicantMiscDetails"/>
</Product>
</xsl:template>
<xsl:template match="ProductCategory">
<xsl:copy-of select="."/>
</xsl:template>
<xsl:template match="DBApplicantMiscDetails">
<xsl:copy-of select="child::*"/>
</xsl:template>
<xsl:template match="TemplateDetails">
<xsl:copy-of select="."/>
</xsl:template>
<xsl:template match="SelectedClauses">
<xsl:copy-of select="."/>
</xsl:template>
<xsl:template match="Distribution">
<xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>

Related

Transform nested child elements to single element

I need to convert a some basic XHTML output from an WYSIWYG editor to a proprietairy typesetting XML format using XSLT.
The typesetting format may contain multiple txt elements, each which can have bold, italic and underline boolean attributes.
Now I want to be able to convert nested combinations of <I>, <B> and <U> tags and convert them to this XML format. For example:
<block><b><i><u>BoldItalicUnderlined</u>BoldItalic</i>Bold</b></block>
To:
<txt bold="true" italic="true" underlined="true">BoldItalicUnderlined</txt>
<txt bold="true" italic="true" underlined="false">BoldItalicUnderlined</txt>
<txt bold="true" italic="false" underlined="false">Bold</txt>
Can this be done with XSLT?
So far I have:
<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xls="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common">
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="node()|#*" mode="mPass2">
<xsl:copy>
<xsl:apply-templates select="node()|#*" mode="mPass2"/>
</xsl:copy>
</xsl:template>
<xsl:template match="block">
<xsl:variable name="vrtfPass1Result">
<xsl:apply-templates/>
</xsl:variable>
<xsl:apply-templates mode="mPass2" select="ext:node-set($vrtfPass1Result)/*"/>
</xsl:template>
<xsl:template match="text()">
<txt underline="false" italic="false" bold="false" the-text="true">
<xsl:value-of select="."/>
</txt>
</xsl:template>
<xsl:template match="em|i">
<txt underline="false" italic="true" bold="false" the-italic="true">
<xsl:apply-templates/>
</txt>
</xsl:template>
<xsl:template match="strong|b">
<txt underline="false" italic="false" bold="true" the-bold="true">
<xsl:apply-templates/>
</txt>
</xsl:template>
<xsl:template match="u">
<txt underline="true" italic="false" bold="false" the-underline="true">
<xsl:apply-templates/>
</txt>
</xsl:template>
<xsl:template match="txt[txt]" mode="mPass2" name="txt">
<xsl:variable name="bold">
<xsl:value-of select="#bold"/>
</xsl:variable>
<xsl:for-each select="txt">
<xsl:apply-templates select="." mode="mPass2"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Which produces:
<txt underline="false" italic="false" bold="false">BoldItalicUnderlined</txt>
<txt underline="false" italic="false" bold="false">BoldItalic</txt>
<txt underline="false" italic="false" bold="false">Bold</txt>
Try this:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<xsl:apply-templates select="//text()"/>
</xsl:template>
<xsl:template match="text()[normalize-space()='']"/>
<xsl:template match="text()">
<text bold="{boolean(ancestor::b)}" italic="{boolean(ancestor::i)}" underlined="{boolean(ancestor::u)}">
<xsl:value-of select="."/>
</text>
</xsl:template>
</xsl:stylesheet>

XSLT for-each namespace

I'm using a for-each in my XSLT template.
This is my example input XML:
<products>
<data>
<label_1>some_label1</label_1>
<label_2>some_label2</label_2>
<values>
<a>a</a>
<b>b</b>
</values>
</data>
<data>
<label_1>some_label1</label_1>
<label_2>some_label2</label_2>
<values>
<c>c</c>
<d>d</d>
</values>
</data>
</products>
Now based on my template:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns="http:/example.com/ns">
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="data">
<data>
<xsl:variable name="values" select="values" />
<xsl:for-each select="$values">
<xsl:apply-templates select="#*|node()" />
</xsl:for-each>
</data>
</xsl:template>
</xsl:stylesheet>
I get only <values></values> and that is ok for me.
That's my output:
<products>
<data>
<a>a</a>
<b>b</b>
</data>
<data>
<c>c</c>
<d>d</d>
</data>
</products>
What i need in my output is namespace like this:
<products>
<data>
<ns:a>a</ns:a>
<ns:b>b</ns:b>
</data>
<data>
<ns:c>c</ns:c>
<ns:d>d</ns:d>
</data>
</products>
So what i understand is "each element of values is applied by template". How can I add namespace ?
You can get output similar to what you show (albeit well-formed) by using:
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:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="data">
<xsl:copy>
<xsl:apply-templates select="values/*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="values/*">
<xsl:element name="ns:{local-name()}" namespace="http:/example.com/ns">
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Or, if you prefer:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns="http:/example.com/ns">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/products">
<products>
<xsl:for-each select="data">
<xsl:copy>
<xsl:for-each select="values/*">
<xsl:element name="ns:{local-name()}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:for-each>
</xsl:copy>
</xsl:for-each>
</products>
</xsl:template>
</xsl:stylesheet>
Replace http:/example.com/ns with your own namespace URI.
Credits
This answer follows the technique used in this SO answer to a similar problem.
Solution
Add namespace information to all descendants of specific elements. Augment the stylesheet by a template matching this set of nodes:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns="http://my.ns.uri"
>
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="data">
<data>
<xsl:variable name="values" select="values" />
<xsl:for-each select="$values">
<xsl:apply-templates select="#*|node()" />
</xsl:for-each>
</data>
</xsl:template>
<!--
Added template.
-->
<xsl:template match="data//*">
<xsl:element name="ns:{name()}" namespace="http://my.ns.uri">
<xsl:for-each select=".">
<xsl:apply-templates select="#*|node()" />
</xsl:for-each>
</xsl:element>
</xsl:template>
</xsl:stylesheet>

xml to xml transformation through XSLT

I want to convert one xml format to another xml format using XSLT .
Below is the input XML format that i need to transform to another XML format.
<FIXML>
<Header>
<RequestID>ReqID8942</RequestID>
<RequestType>DocGen</RequestType>
<Version>10.6</Version>
<BankId>01</BankId>
<ChannelId>LOS</ChannelId>
</Header>
<Body>
<Data>
<CorpAppLimitDetailsBO>
<ApprovedLimitHomeCCY>100.0</ApprovedLimitHomeCCY>
<ApprovedLimitCCY>INR</ApprovedLimitCCY>
<ApprovedLimit>100.0</ApprovedLimit>
<LimitClassification>ROOT</LimitClassification>
<DBApplicantMiscDetails>
<APPLICANTMISCID>400000</APPLICANTMISCID>
<APPLICANTID>400030</APPLICANTID>
<MISCTYPE>APPLIED</MISCTYPE>
</DBApplicantMiscDetails>
</CorpAppLimitDetailsBO>
</Data>
</Body>
</FIXML>
Below is the output format xml which i expect.
<FIXML>
<Header>
<RequestID>ReqID8942</RequestID>
<RequestType>DocGen</RequestType>
<Version>10.6</Version>
<BankId>01</BankId>
<ChannelId>LOS</ChannelId>
</Header>
<Body>
<Data>
<LimitDetails>
<Limit>
<ApprovedLimitHomeCCY>100.0</ApprovedLimitHomeCCY>
<ApprovedLimitCCY>INR</ApprovedLimitCCY>
<ApprovedLimit>100.0</ApprovedLimit>
<LimitClassification>ROOT</LimitClassification>
<APPLICANTMISCID>400000</APPLICANTMISCID>
<APPLICANTID>400030</APPLICANTID>
<MISCTYPE>APPLIED</MISCTYPE>
</Limit>
</Data>
</Body>
</FIXML>
I have tried with below code but dont know how to modify the code to inlcude DBApplicantMiscDetails details in output XML format.
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<xsl:apply-templates select="FIXML"/>
</xsl:template>
<xsl:template match="FIXML">
<FIXML>
<xsl:apply-templates select="Header"/>
<xsl:apply-templates select="Body"/>
</FIXML>
</xsl:template>
<xsl:template match="Header">
<xsl:copy-of select="."/>
</xsl:template>
<xsl:template match="Body">
<Body>
<xsl:apply-templates select="Data"/>
</Body>
</xsl:template>
<xsl:template match="Data">
<Data>
<LimitDetails>
<xsl:apply-templates select="CorpAppLimitDetailsBO"/>
</LimitDetails>
</Data>
</xsl:template>
<xsl:template match="CorpAppLimitDetailsBO">
<Limit>
<xsl:copy-of select="child::*"/>
</Limit>
</xsl:template>
</xsl:stylesheet>
The way you could probably approach this is to build upon the XSLT identity transform, which on its own just copies the nodes in your XML
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
You then add templates to match your special cases where you want to make changes (as opposed to written templates for elements you just want to copy). For example, to rename the CorpAppLimitDetailsBO to Limit you would do this
<xsl:template match="CorpAppLimitDetailsBO">
<Limit>
<xsl:apply-templates />
</Limit>
</xsl:template>
Removing the DBApplicationMiscDetails then becomes a straight-forward task
<xsl:template match="DBApplicantMiscDetails">
<xsl:apply-templates />
</xsl:template>
Here is the full XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="Data">
<Data>
<LimitDetails>
<xsl:apply-templates />
</LimitDetails>
</Data>
</xsl:template>
<xsl:template match="CorpAppLimitDetailsBO">
<Limit>
<xsl:apply-templates />
</Limit>
</xsl:template>
<xsl:template match="DBApplicantMiscDetails">
<xsl:apply-templates />
</xsl:template>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
When applied to your sample XML, the following is output
<FIXML>
<Header>
<RequestID>ReqID8942</RequestID>
<RequestType>DocGen</RequestType>
<Version>10.6</Version>
<BankId>01</BankId>
<ChannelId>LOS</ChannelId>
</Header>
<Body>
<Data>
<LimitDetails>
<Limit>
<ApprovedLimitHomeCCY>100.0</ApprovedLimitHomeCCY>
<ApprovedLimitCCY>INR</ApprovedLimitCCY>
<ApprovedLimit>100.0</ApprovedLimit>
<LimitClassification>ROOT</LimitClassification>
<APPLICANTMISCID>400000</APPLICANTMISCID>
<APPLICANTID>400030</APPLICANTID>
<MISCTYPE>APPLIED</MISCTYPE>
</Limit>
</LimitDetails>
</Data>
</Body>
</FIXML>

xml to xml transformation using xslt based on parent and child relationship

I need to transform my xml to another xml based on parent and child relationship.
Below is my source xml
<FIXML>
<Header>
<RequestID>ReqID8942</RequestID>
</Header>
<Body>
<Data>
<LimitDetails>
<LimitRefNo>L1</LimitRefNo>
<LimitClassification>ROOT</LimitClassification>
<ParentLimitRefNo></ParentLimitRefNo>
<ApprovedLimit>100.0</ApprovedLimit>
</LimitDetails>
<LimitDetails>
<LimitRefNo>L2</LimitRefNo>
<LimitClassification>ClASSIFICATION1</LimitClassification>
<ParentLimitRefNo>L1</ParentLimitRefNo>
<ApprovedLimit>200.0</ApprovedLimit>
</LimitDetails>
<LimitDetails>
<LimitRefNo>L3</LimitRefNo>
<LimitClassification>CLASSIFICATION2</LimitClassification>
<ParentLimitRefNo>L2</ParentLimitRefNo>
<ApprovedLimit>300.0</ApprovedLimit>
</LimitDetails>
<LimitDetails>
<LimitRefNo>L4</LimitRefNo>
<LimitClassification>CLASSIFICATION3</LimitClassification>
<ParentLimitRefNo>L3</ParentLimitRefNo>
<ApprovedLimit>400.0</ApprovedLimit>
</LimitDetails>
</Data>
</Body>
</FIXML>
Here,Child limits refers Parent limits based on ParentLimitRefNo. Parent limit is the one which has ParentLimitRefNo as empty.
Below is the xml which i need to produce based on source xml.
<FIXML>
<Header>
<RequestID>ReqID8942</RequestID>
</Header>
<Body>
<Data>
<LimitDetails>
<Limit>
<LimitRefNo>L1</LimitRefNo>
<LimitClassification>ROOT</LimitClassification>
<ParentLimitRefNo></ParentLimitRefNo>
<ApprovedLimit>100.0</ApprovedLimit>
<SubLimit>
<LimitRefNo>L2</LimitRefNo>
<LimitClassification>ClASSIFICATION1</LimitClassification>
<ParentLimitRefNo>L1</ParentLimitRefNo>
<ApprovedLimit>200.0</ApprovedLimit>
<SubLimit>
<LimitRefNo>L3</LimitRefNo>
<LimitClassification>CLASSIFICATION2</LimitClassification>
<ParentLimitRefNo>L2</ParentLimitRefNo>
<ApprovedLimit>300.0</ApprovedLimit>
<SubLimit>
<LimitRefNo>L4</LimitRefNo>
<LimitClassification>CLASSIFICATION3</LimitClassification>
<ParentLimitRefNo>L3</ParentLimitRefNo>
<ApprovedLimit>400.0</ApprovedLimit>
</SubLimit>
</SubLimit>
</SubLimit>
</Limit>
</LimitDetails>
</Data>
</Body>
Thanks in advance.
This XSLT 2.0 transformation (easy to convert to XSLT 1.0):
<xsl:stylesheet version="2.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="kLD" match="LimitDetails" use="ParentLimitRefNo"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Data">
<Data>
<LimitDetails>
<xsl:apply-templates
select="LimitDetails[not(ParentLimitRefNo/node())]"/>
</LimitDetails>
</Data>
</xsl:template>
<xsl:template match="LimitDetails">
<xsl:variable name="vSuf" select=
"if(ParentLimitRefNo/text())
then 'Sub'
else ()
"/>
<xsl:element name="{$vSuf}Limit">
<xsl:apply-templates select="node()|key('kLD', LimitRefNo)"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
when applied on the provided XML document:
<FIXML>
<Header>
<RequestID>ReqID8942</RequestID>
</Header>
<Body>
<Data>
<LimitDetails>
<LimitRefNo>L1</LimitRefNo>
<LimitClassification>ROOT</LimitClassification>
<ParentLimitRefNo></ParentLimitRefNo>
<ApprovedLimit>100.0</ApprovedLimit>
</LimitDetails>
<LimitDetails>
<LimitRefNo>L2</LimitRefNo>
<LimitClassification>ClASSIFICATION1</LimitClassification>
<ParentLimitRefNo>L1</ParentLimitRefNo>
<ApprovedLimit>200.0</ApprovedLimit>
</LimitDetails>
<LimitDetails>
<LimitRefNo>L3</LimitRefNo>
<LimitClassification>CLASSIFICATION2</LimitClassification>
<ParentLimitRefNo>L2</ParentLimitRefNo>
<ApprovedLimit>300.0</ApprovedLimit>
</LimitDetails>
<LimitDetails>
<LimitRefNo>L4</LimitRefNo>
<LimitClassification>CLASSIFICATION3</LimitClassification>
<ParentLimitRefNo>L3</ParentLimitRefNo>
<ApprovedLimit>400.0</ApprovedLimit>
</LimitDetails>
</Data>
</Body>
</FIXML>
produces the wanted, correct result:
<FIXML>
<Header>
<RequestID>ReqID8942</RequestID>
</Header>
<Body>
<Data>
<LimitDetails>
<Limit>
<LimitRefNo>L1</LimitRefNo>
<LimitClassification>ROOT</LimitClassification>
<ParentLimitRefNo/>
<ApprovedLimit>100.0</ApprovedLimit>
<SubLimit>
<LimitRefNo>L2</LimitRefNo>
<LimitClassification>ClASSIFICATION1</LimitClassification>
<ParentLimitRefNo>L1</ParentLimitRefNo>
<ApprovedLimit>200.0</ApprovedLimit>
<SubLimit>
<LimitRefNo>L3</LimitRefNo>
<LimitClassification>CLASSIFICATION2</LimitClassification>
<ParentLimitRefNo>L2</ParentLimitRefNo>
<ApprovedLimit>300.0</ApprovedLimit>
<SubLimit>
<LimitRefNo>L4</LimitRefNo>
<LimitClassification>CLASSIFICATION3</LimitClassification>
<ParentLimitRefNo>L3</ParentLimitRefNo>
<ApprovedLimit>400.0</ApprovedLimit>
</SubLimit>
</SubLimit>
</SubLimit>
</Limit>
</LimitDetails>
</Data>
</Body>
</FIXML>
Explanation:
Using and modifying the identity rule.
Using a key to specify all logical children of a LimitDetails from its LimitRefNo.
II. XSLT 1.0 solution:
This is an almost mechanical translation of the above transformation into XSLT 1.0 -- only the definition of the variable $vSuf is different:
<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="kLD" match="LimitDetails" use="ParentLimitRefNo"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Data">
<Data>
<LimitDetails>
<xsl:apply-templates
select="LimitDetails[not(ParentLimitRefNo/node())]"/>
</LimitDetails>
</Data>
</xsl:template>
<xsl:template match="LimitDetails">
<xsl:variable name="vSuf" select=
"concat('',
substring('Sub',1 div boolean(ParentLimitRefNo/text()))
)"/>
<xsl:element name="{$vSuf}Limit">
<xsl:apply-templates select="node()|key('kLD', LimitRefNo)"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
When applied to the same XML document (above), the same correct result is produced.
The use of keys surely is more elegant (see Dimitre Novatchevs solution), but this one takes the wanted changes in the structure into account (e.g. rename <LimitDetails /> to <SubLimit /> and placing the <Limit /> tag.):
<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="#*|node()">
<xsl:copy><xsl:apply-templates select="#*|node()" /></xsl:copy>
</xsl:template>
<xsl:template match="Data">
<xsl:copy>
<LimitDetails>
<Limit>
<xsl:apply-templates select=".//LimitDetails[./ParentLimitRefNo='']" />
</Limit>
</LimitDetails>
</xsl:copy>
</xsl:template>
<xsl:template match="LimitDetails">
<xsl:variable name="LimitRefNo" select="./LimitRefNo" />
<xsl:apply-templates select="#*|node()" />
<xsl:if test="../LimitDetails[./ParentLimitRefNo = $LimitRefNo]">
<SubLimit>
<xsl:apply-templates select="../LimitDetails[./ParentLimitRefNo = $LimitRefNo]" />
</SubLimit>
</xsl:if>
</xsl:template>
</xsl:transform>
Or as a modification of Dimitre's solution using keys:
<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="kLD" match="LimitDetails" use="ParentLimitRefNo"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Data">
<Data>
<LimitDetails>
<Limit>
<xsl:apply-templates select="LimitDetails[not(ParentLimitRefNo/node())]"/>
</Limit>
</LimitDetails>
</Data>
</xsl:template>
<xsl:template match="LimitDetails">
<xsl:apply-templates />
<xsl:if test="key('kLD', LimitRefNo)">
<SubLimit>
<xsl:apply-templates select="key('kLD', LimitRefNo)"/>
</SubLimit>
</xsl:if>
</xsl:template>
</xsl:stylesheet>

How to create a new list and tag nodes in it using xslt

I am transforming an XML to another using Identity Transformation and during this, based on a condition I want to tag few nodes in a new list.
Suppose, I have an XML like:
<nod>
<a>A</a>
<b>B</b>
<c><p>p1</p></c>
<c><p>p2</p></c>
<c><p>p3</p></c>
<c><p>p4</p></c>
</nod>
From this XML , I want to update name of 'nod' to 'newnod' and create an orderedlist for element 'c' ; so that output comes as:
<newnod>
<a>A</a>
<b>B</b>
<orderedlist>
<listitem><p>p1</p></listitem>
<listitem><p>p2</p></listitem>
<listitem><p>p3</p></listitem>
<listitem><p>p4</p></listitem> </orderedlist>
</newnod>
Can anybody please tell me how to do this.
Thanks !!!
Here is a true "push-style" solution:
<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:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/nod">
<newnod>
<xsl:apply-templates select="node()|#*"/>
</newnod>
</xsl:template>
<xsl:template match="c[1]">
<orderedlist>
<xsl:apply-templates mode="wrap"
select=".|following-sibling::c"/>
</orderedlist>
</xsl:template>
<xsl:template match="c" mode="wrap">
<listitem>
<xsl:apply-templates/>
</listitem>
</xsl:template>
<xsl:template match="c"/>
</xsl:stylesheet>
when this transformation is applied on the provided XML document:
<nod>
<a>A</a>
<b>B</b>
<c><p>p1</p></c>
<c><p>p2</p></c>
<c><p>p3</p></c>
<c><p>p4</p></c>
</nod>
the wanted, correct result is produced:
<newnod>
<a>A</a>
<b>B</b>
<orderedlist>
<listitem>
<p>p1</p>
</listitem>
<listitem>
<p>p2</p>
</listitem>
<listitem>
<p>p3</p>
</listitem>
<listitem>
<p>p4</p>
</listitem>
</orderedlist>
</newnod>
This produces the desired output for your example:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:template match="/nod">
<newnod>
<xsl:copy-of select="*[not( self::c )]"/>
<orderedlist>
<xsl:apply-templates select="c">
<xsl:sort/>
</xsl:apply-templates>
</orderedlist>
</newnod>
</xsl:template>
<xsl:template match="nod/c">
<listitem>
<xsl:copy-of select="node()"/>
</listitem>
</xsl:template>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Note that it might need some tweaking for your actual input. For example, the details of sorting. Or the sequence of a, b and c. And lump all c together or not? But it works for your sample.
You could use something like:
<xsl:template match="nod">
<newnod>
<xsl:copy-of select="a"/>
<xsl:copy-of select="b"/>
<orderedlist>
<xsl:for-each select="c">
<listitem><p><xsl:value-of select="."/></p></listitem>
</xsl:for-each>
</orderedlist>
</newnod>
</xsl:template>
Other approach is traversing the following axis like this:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()[1]|#*"/>
</xsl:copy>
<xsl:apply-templates select="following-sibling::node()[1]"/>
</xsl:template>
<xsl:template match="nod">
<newnod>
<xsl:apply-templates select="node()[1]|#*"/>
</newnod>
<xsl:apply-templates select="following-sibling::node()[1]"/>
</xsl:template>
<xsl:template match="c">
<orderedlist>
<xsl:call-template name="wrap"/>
</orderedlist>
<xsl:apply-templates select="following-sibling::node()[1]"
mode="search"/>
</xsl:template>
<xsl:template match="c" name="wrap" mode="wrap">
<listitem>
<xsl:apply-templates select="node()[1]|#*"/>
</listitem>
<xsl:apply-templates select="following-sibling::node()[1]"
mode="wrap"/>
</xsl:template>
<xsl:template match="node()" mode="wrap"/>
<xsl:template match="c" mode="search">
<xsl:apply-templates select="following-sibling::node()[1]"
mode="search"/>
</xsl:template>
<xsl:template match="node()" mode="search">
<xsl:apply-templates select="."/>
</xsl:template>
</xsl:stylesheet>
Or shorter (more "push style"):
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()[1]|#*"/>
</xsl:copy>
<xsl:apply-templates select="following-sibling::node()[1]"/>
</xsl:template>
<xsl:template match="nod">
<newnod>
<xsl:apply-templates select="node()[1]|#*"/>
</newnod>
<xsl:apply-templates select="following-sibling::node()[1]"/>
</xsl:template>
<xsl:template match="c">
<orderedlist>
<xsl:call-template name="wrap"/>
</orderedlist>
<xsl:apply-templates select="following-sibling::node()
[not(self::c)][1]"/>
</xsl:template>
<xsl:template match="c" name="wrap" mode="wrap">
<listitem>
<xsl:apply-templates select="node()[1]|#*"/>
</listitem>
<xsl:apply-templates select="following-sibling::node()[1]
/self::c"
mode="wrap"/>
</xsl:template>
</xsl:stylesheet>
Both output:
<newnod>
<a>A</a>
<b>B</b>
<orderedlist>
<listitem>
<p>p1</p>
</listitem>
<listitem>
<p>p2</p>
</listitem>
<listitem>
<p>p3</p>
</listitem>
<listitem>
<p>p4</p>
</listitem>
</orderedlist>
</newnod>
Note: Even with XSLT 2.0, some complex sequence processing are expressed better with this pattern.