This is not entirely complicated, but staggering due to the extensive (but necessary) nested use of substring-before() and substring-after() .
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" > <xsl:key name="kObject" match="r/c" use=" concat(@id, '|', @value) " /> <xsl:key name="kTagByUid" match="r/c" use=" concat(@id, '|', substring-before(@value, '|')) " /> <xsl:key name="kTagByName" match="r/c" use=" concat(@id, '|', substring-before( @value, substring-after(substring-after(@value, '|'), '|') ) ) " /> <xsl:variable name="vTagId" select="/Container/DataHeader/c[@value='TAG'][1]/@id" /> <xsl:variable name="vInfoId" select="/Container/DataHeader/c[@value='Info'][1]/@id" /> <xsl:template match="Container"> <xsl:copy> <xsl:apply-templates mode="tag" select=" Data/Rows/r/c[@id=$vTagId][ generate-id() = generate-id(key('kObject', concat(@id, '|', @value))[1]) ] " /> </xsl:copy> </xsl:template> <xsl:template match="c" mode="tag"> <TestTag> <object UID="{@uid}" name="{@value}" /> <xsl:apply-templates mode="info" select=" key('kTagByUid', concat($vInfoId, '|', @value))[ generate-id() = generate-id( key( 'kTagByName', concat(@id, '|', substring-before( @value, substring-after(substring-after(@value, '|'), '|') ) ) )[1] ) ] " /> </TestTag> </xsl:template> <xsl:template match="c" mode="info"> <xsl:variable name="key" select="substring-before(@value, substring-after(substring-after(@value, '|'), '|'))" /> <xsl:variable name="name" select="substring-before(substring-after($key, '|'), '|')" /> <xsl:element name="{$name}"> <xsl:for-each select="key('kTagByName', concat(@id, '|', $key))"> <xsl:variable name="attrDef" select="substring-after(@value, $key)" /> <xsl:attribute name="{substring-before($attrDef, '|')}"> <xsl:value-of select="substring-after($attrDef, '|')" /> </xsl:attribute> </xsl:for-each> </xsl:element> </xsl:template> </xsl:stylesheet>
generates:
<Container> <TestTag> <object UID="TAuid1" name="uid1" /> <tag1 attr1="somevalue1" attr2="somevalue2"></tag1> <tag2 attr3="somevalue3"></tag2> </TestTag> <TestTag> <object UID="TAuid2" name="uid2" /> <tag1 attr1="somevalue4"></tag1> <tag2 attr3="somevalue5"></tag2> </TestTag> </Container>
Note that this does not take into account duplicate attribute definitions. If you have uid1|tag1|attr1|somevalue1 and later uid1|tag1|attr1|othervalue1 , then you will get one attribute: attr1="othervalue1" , because in <xsl:for-each> both will receive a turn, and the second wins (i.e. ends at the exit).
Perhaps for this, it will require another key and another Muenchian group, I am going to leave this as an exercise for the reader. Heh.;)