xml - XSL 1.0 Format table splitting values -
i've sample xml input following:
<table name="table1"> <fields> <field name="field1" /> <field name="field2" /> <field name="field3" /> <field name="field4" /> </fields> <data> <row value="2,description1,a,aa" /> <row value="3,description2,b,bb" /> <row value="7,description3,c,cc" /> </data> </table> <table name="table2"> <fields> <field name="field7" /> <field name="field8" /> <field name="field9" /> </fields> <data> <row value="q,description7,a" /> <row value="w,description8,b" /> <row value="x,description9,c" /> </data> </table> please note can have many tables different number of fields row values contain exact number of fields required.
the expected result output this:
<listoftable1> <item> <field1>2</field1> <field2>description1</field2> <field3>a</field3> <field4>aa</field4> </item> <item> <field1>3</field1> <field2>description2</field2> <field3>b</field3> <field4>bb</field4> </item> <item> <field1>7</field1> <field2>description3</field2> <field3>c</field3> <field4>cc</field4> </item> </listoftable1> <listoftable2> <item> <field7>q</field7> <field8>description7</field8> <field9>a</field9> </item> <item> <field7>w</field7> <field8>description8</field8> <field9>b</field9> </item> <item> <field7>x</field7> <field8>description9</field8> <field9>c</field9> </item> </listoftable2> i can use strict xslt 1.0 unfortunately no external functions or reference
i've been using modified version of third solution suggested
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/xsl/transform"> <xsl:template match="//table"> <xsl:value-of disable-output-escaping="yes" select="concat('<listof',@name,'>')" /> <xsl:apply-templates /> <xsl:value-of disable-output-escaping="yes" select="concat('</listof',@name,'>')" /> </xsl:template> <xsl:template match="table/data/row"> <item> <xsl:call-template name="fldsplit"> <xsl:with-param name="f" select="@value" /> <xsl:with-param name="set" select="//fields/field" /> </xsl:call-template> </item> </xsl:template> <xsl:template name="fldsplit"> <xsl:param name="f" /> <xsl:param name="set"/> <xsl:variable name="bfc" select="substring-before($f,',')"/> <xsl:variable name="afc" select="substring-after($f,',')"/> <xsl:element name="{$set/@name}"> <xsl:choose> <xsl:when test="$bfc"> <xsl:value-of select="$bfc"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="$f"/> </xsl:otherwise> </xsl:choose> </xsl:element> <xsl:if test="$afc"> <xsl:call-template name="fldsplit"> <xsl:with-param name="f" select="$afc"/> <xsl:with-param name="set" select="$set/following-sibling::*" /> </xsl:call-template> </xsl:if> </xsl:template> </xsl:stylesheet> but have issue second table (or other add input), fields name repeat starting field1 while expect use specific fields each table parsed
this current output (wrong)
<?xml version="1.0" encoding="utf-8"?> <listoftable1> <item><field1>2</field1><field2>description1</field2><field3>a</field3><field4>aa</field4></item> <item><field1>3</field1><field2>descritpion2</field2><field3>b</field3><field4>bb</field4></item> <item><field1>7</field1><field2>description3</field2><field3>c</field3><field4>cc</field4></item> </listoftable1> <listoftable2> <item><field1>q</field1><field2>description7</field2><field3>a</field3></item> <item><field1>w</field1><field2>description8</field2><field3>b</field3></item> <item><field1>x</field1><field2>description9</field2><field3>c</field3></item> </listoftable2>
if can commas in row value ones separate fields (i.e. there's no "escape" mechanism "\,"), , there right number of fields in every row, recursive approach work. i'm assuming here there single root element named root enclosing table elements in order make input well-formed.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/xsl/transform" version="1.0"> <xsl:output method="xml" indent="yes" /> <xsl:template match="/"> <data> <xsl:apply-templates select="root/table" /> </data> </xsl:template> <xsl:template match="table"> <xsl:element name="listof{@name}"> <xsl:apply-templates select="data/row"/> </xsl:element> </xsl:template> <xsl:template match="row"> <!-- add trailing comma value don't lose last field --> <xsl:variable name="val" select="concat(@value, ',')" /> <item> <!-- use fields belong table --> <xsl:apply-templates select="../../fields/field[1]"> <xsl:with-param name="thisval" select="substring-before($val, ',')" /> <xsl:with-param name="rest" select="substring-after($val, ',')" /> </xsl:apply-templates> </item> </xsl:template> <xsl:template match="field"> <xsl:param name="thisval"/> <xsl:param name="rest"/> <xsl:element name="{@name}"> <xsl:value-of select="$thisval" /> </xsl:element> <xsl:apply-templates select="following-sibling::field[1]"> <xsl:with-param name="thisval" select="substring-before($rest, ',')" /> <xsl:with-param name="rest" select="substring-after($rest, ',')" /> </xsl:apply-templates> </xsl:template> </xsl:stylesheet> the trick here generate <field1> etc. elements applying templates field elements in turn. there's no need explicit conditionals (if or choose) because recursion automatically stop @ last field when following-sibling::field[1] no longer selects anything.
Comments
Post a Comment