I am newbie to XSLT.can you help me for xslt to achieve below output. In my input xml have duplicate nodes and i have to remove based on element (CustAccId) value should not be re-peat.
Inputxml :
<Main> <Request> <TypeInd>I</TypeInd> <CustAcctID>505665599</CustAcctID> <ServiceOrderID>1452653</ServiceOrderID> </Request> <Request> <TypeInd>O</TypeInd> <CustAcctID>2011395</CustAcctID> <ServiceOrderID>1452652</ServiceOrderID> </Request> <Request> <TypeInd>I</TypeInd> <CustAcctID>505665599</CustAcctID> <ServiceOrderID>1452653</ServiceOrderID> </Request> </Main>
Output XML :
<Main> <Request> <TypeInd>I</TypeInd> <CustAcctID>505665599</CustAcctID> <ServiceOrderID>1452653</ServiceOrderID> </Request> <Request> <TypeInd>O</TypeInd> <CustAcctID>2011395</CustAcctID> <ServiceOrderID>1452652</ServiceOrderID> </Request> Here is XSLt i tried but didn't work like it retrun duplicate request node <?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:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()" /> </xsl:copy> </xsl:template> <xsl:template match="/"> <xsl:if test="not(following::Request[CustAcctID=current()])"> <xsl:copy> <xsl:apply-templates select="@*|node()" /> </xsl:copy> </xsl:if> </xsl:template> </xsl:stylesheet>
You can remove the duplicate with following XSLT:
<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="*"/> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()" /> </xsl:copy> </xsl:template> <xsl:template match="Request[CustAcctID = following::Request/CustAcctID]"/> </xsl:stylesheet>
Output XML:
<?xml version="1.0" encoding="UTF-8"?> <Main> <Request> <TypeInd>O</TypeInd> <CustAcctID>2011395</CustAcctID> <ServiceOrderID>1452652</ServiceOrderID> </Request> <Request> <TypeInd>I</TypeInd> <CustAcctID>505665599</CustAcctID> <ServiceOrderID>1452653</ServiceOrderID> </Request> </Main>
The template matching all Request
nodes where the CustAcctID
matches the CustAcctID
of the following Request
will not produce any output for the matching Request
, so the duplicates will not be written.
Update for the advice in the comment by michael.hor257k: Another approach is to use Muenchian grouping:
<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="*"/> <xsl:key name="x" match="ServiceOrderID" use="." /> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()" /> </xsl:copy> </xsl:template> <xsl:template match="Request"> <xsl:for-each select="."> <xsl:if test="generate-id(ServiceOrderID) = generate-id(key('x', ServiceOrderID)[1])"> <xsl:copy> <xsl:apply-templates select="@*|node()" /> </xsl:copy> </xsl:if> </xsl:for-each> </xsl:template> </xsl:stylesheet>
which produces the same output XML but can be more efficient as you'll find described in detail in the article by Jeni Tennison http://www.jenitennison.com/xslt/grouping/muenchian.xml that michael.hor257k already recommended.
As additional reference for XSLT grouping you can have a look at http://www.dpawson.co.uk/xsl/sect2/N4486.html