Subject: RE: [xsl] Formatting XSL for XML to CSV translation|
From: "Passin, Tom" <tpassin@xxxxxxxxxxxx>
Date: Thu, 18 Sep 2003 11:38:54 -0400
[ Stuart Jones] > For readability I would prefer the XSL file to look nicely > nested like this: > > <xsl:variable name="new_line" select="'
'"/> > <xsl:template match="/"> > > <xsl:for-each select="xml/rs:data/z:row"> > <xsl:value-of select="@field1"/>, > <xsl:value-of select="@field2"/>, > ... > <xsl:value-of select="@fieldn"/> > <xsl:value-of select="$new_line"/> > </xsl:for-each> > > </xsl:template> > > Unfortunately, this means that each value ends up on its own > line. Placing each element in one long line in the XSL solves > the problem but is hard to read (to say the least). > I often do it the following way - it seems odd at first, but is easy and effective - <xsl:value-of select="@field1" />,<xsl:value-of select="@field2" />, .... With that out of the way, I would not use your method at all. There is no need to enumerate all the fields. It seems that your row data is contained in attributes (next time, don't make us guess about that). If you do not name the fields, you remove the need to change the stylesheet if your data source design changes, and you make the styesheet simpler as well.. Suppose first that the only attributes in a row element are the actual data fields. Then 1) Include a statement like (assuming that the data are contained in a "row" element) - <xsl:apply-templates select='row'/> 2) Process the rows like this. For clarity I ignore the need to suppress the last trailing comma, then later I deal with it - <xsl:template match="row"> <xsl:apply-templates select='@*' mode='fields'/> <xsl:text> </xsl:text> <!-- or any other characters you want--> </xsl:template> <xsl:template match='@*' mode='fields'> <xsl:value-of select='.'/>, </xsl:template> The mode attribute acts as a safety feature to prevent other attributes from bring processed by the second template. 3) Suppress the last comma like this - <xsl:value-of select='.'/><xsl:if test='not(position() = last())'>,</xsl:if> See how easy it can be? Just let the processor do its job for you. There is one possible disadvantage to this method. The order of attributes cannot be guaranteed, so if the order is important, you would have to name the fields in the right order after all. However, the order should not be important because with a relational database, the field order is not significant either., and of course the data was serialized as attributes in the first place. You can always handle it in later processing if needed. Note that this method can work just as well when the data is contained in elements instead of attributes. Just remove the "@" characters and everything else will stay the same. If you have any other attributes in a row element that are not data fields (and whose names do not contain the string "field"), you can modify the select expression like this - <xsl:apply-templates select='@*[starts-with(name(),"field")]' mode='fields'/> Your approach is a typical procedural programming approach - go through the fields you want one by one, and put them into the right position. With xslt it is almost always better to take a different approach. The best approach is to choose the collection of nodes you want to operate on, and say what should happen to them in terms of what the result should look like. The processor will then apply your instructions to all the nodes you selected. This is called the "declarative" approach. Typically, the main problem becomes one of selecting the right collection of nodes, and sometimes, of grouping them into larger collections. Cheers, Tom P XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list