XML merge nodes with XSLT -
i have xml file that:
<root> <scenario name="film1"> <case name="aaa"> <test name="test1">ok</test> </case> <case name="bbb"> <test name="test2">not ok</test> </case> <case name="aaa"> <test name="test3">not ok</test> </case> <case name="bbb"> <test name="test66">ok</test> </case> </scenario> </root> of course there more nodes scenario want group case each scenario. expect that:
<root> <scenario name="fil1"> <case name="aaa"> <test name="test1">ok</test> <test name="test3">not ok</test> </case> <case name="bbb"> <test name="test2">not ok</test> <test name="test66">ok</test> </case> </scenario> </root> i made xslt file:
<?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" exclude-result-prefixes="msxsl"> <xsl:output method="xml" indent="yes"/> <xsl:template match="root"> <xsl:copy> <xsl:apply-templates/> </xsl:copy> </xsl:template> <xsl:template match="scenario"> <scenario> <xsl:attribute name="name"> <xsl:value-of select="@name"/> </xsl:attribute> <xsl:apply-templates/> </scenario> </xsl:template> <xsl:template match ="case"> <case> <xsl:attribute name="name"> <xsl:value-of select="@name"/> </xsl:attribute> </case> </xsl:template> </xsl:stylesheet> do know should now?
you in question want group case each scenario. if have multiple scenario elements, , want group case elements within each such element, need make use of concatenated key:
<xsl:key name="case" match="case" use="concat(../@name, '|', @name)" /> this means if had 2 case elements same name, in different scenario elements, still grouped separately.
now, grouping, each case statement within scenario, need find case elements occur first in key given attributes. can done follows:
<xsl:apply-templates select="case[generate-id() = generate-id(key('case', concat(../@name, '|', @name))[1])]" /> to break down...
key('case', concat(../@name, '|', @name)) - gets elements same attributes
key('case', concat(../@name, '|', @name))[1] - gets first element of list
generate-id(key('case', concat(../@name, '|', @name))[1]) - generates unique id first element, can compared current element.
so, effectively, distinct elements. can items in "group" using key again
<xsl:for-each select="key('case', concat(../@name, '|', @name))"> try xslt
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/xsl/transform"> <xsl:key name="case" match="case" use="concat(../@name, '|', @name)" /> <xsl:output method="xml" indent="yes"/> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()" /> </xsl:copy> </xsl:template> <xsl:template match="scenario"> <xsl:copy> <xsl:apply-templates select="@*" /> <xsl:apply-templates select="case[generate-id() = generate-id(key('case', concat(../@name, '|', @name))[1])]" /> </xsl:copy> </xsl:template> <xsl:template match ="case"> <xsl:copy> <xsl:apply-templates select="@*" /> <xsl:for-each select="key('case', concat(../@name, '|', @name))"> <xsl:apply-templates /> </xsl:for-each> </xsl:copy> </xsl:template> </xsl:stylesheet> as mentioned in comments, definitive article on approach can found @ http://www.jenitennison.com/xslt/grouping/muenchian.html, worth reading it, , re-reading it, practising it, until understand it.
also, note use of identity transform, means don't have write template each specific element if want copy without changes.
Comments
Post a Comment