Positional grouping using XSLT -
i have xml contain documents:
<document> <line id="0"> <field id="0"><![cdata[h:doc1]]></field> </line> <line id="1"> <field id="0"><![cdata[l:1]]></field> </line> <line id="2"> <field id="0"><![cdata[l:2]]></field> </line> <line id="3"> <field id="0"><![cdata[l:3]]></field> </line> <line id="4"> <field id="0"><![cdata[h:doc2]]></field> </line> <line id="5"> <field id="0"><![cdata[l:1]]></field> </line> </document>
h=header of document , l=line-item. in example whe have 2 h means 2 documents number doc1 , doc2. doc1 have 3 line items , doc2 have 1 line item.
how convert data using xslt version 1 result:
<documents> <document> <header> <number>doc1</number> </header> <line-item> <line-number>1</line-number> <line-number>2</line-number> <line-number>3</line-number> </line-item> </document> <document> <header> <number>doc2</number> </header> <line-item> <line-number>1</line-number> </line-item> </document> </documents>
this xslt 1.0 transformation:
<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="kfollowing" match="line[starts-with(field,'l:')]" use="generate-id(preceding-sibling::line [starts-with(field,'h:')] [1] )"/> <xsl:template match="/"> <documents> <xsl:apply-templates/> </documents> </xsl:template> <xsl:template match="line[starts-with(field,'h:')]"> <document> <header> <number><xsl:value-of select="substring-after(field,'h:')"/></number> <line-item> <xsl:apply-templates mode="ingroup" select= "key('kfollowing', generate-id())"/> </line-item> </header> </document> </xsl:template> <xsl:template match="line" mode="ingroup"> <line-number> <xsl:value-of select="substring-after(field,'l:')"/> </line-number> </xsl:template> <xsl:template match="text()"/> </xsl:stylesheet>
when applied on provided xml document:
<document> <line id="0"> <field id="0"><![cdata[h:doc1]]></field> </line> <line id="1"> <field id="0"><![cdata[l:1]]></field> </line> <line id="2"> <field id="0"><![cdata[l:2]]></field> </line> <line id="3"> <field id="0"><![cdata[l:3]]></field> </line> <line id="4"> <field id="0"><![cdata[h:doc2]]></field> </line> <line id="5"> <field id="0"><![cdata[l:1]]></field> </line> </document>
produces wanted, correct result:
<documents> <document> <header> <number>doc1</number> <line-item> <line-number>1</line-number> <line-number>2</line-number> <line-number>3</line-number> </line-item> </header> </document> <document> <header> <number>doc2</number> <line-item> <line-number>1</line-number> </line-item> </header> </document> </documents>
explanation: using keys conveniently specify , select complete group of adjacent "lines" following "header".
Comments
Post a Comment