Forgot to add the URL for the XSL list: http://www.mulberrytech.com/xsl/xsl-list/
Jay Bryant Bryant Communication Services robert frapples <[EMAIL PROTECTED]> 11/30/2004 03:09 PM Please respond to [EMAIL PROTECTED] To [EMAIL PROTECTED] cc Subject setting up tables differently based on existance of xml tags. (static variables, recursion, templates, and intrigue) Here's a (hopefully) interesting problem: (I've been editing this email every day. Every time I can't figure out how to do something, I come up with an alternate plan, assisted by a few people in #xml on irc.freenode.net. (Thank you Bebabo). I figured at this point I'd share my experiences. If you can think of better, faster, cleaner ways to do this, I'd love to hear from you.) source xml: <document> <field> <title>a</title> </field> <field> <title>b</title> <value/> <field> <title>c</title> <value/> </field> <field> <title>d</title> </field> <field> <title>e</title> <value/> </field> </document> What I want to happen is basically, for-each select="field", if <field> has a <value/> and the next <field> also has a value, have 4 cells in a row: field[n]/title, text , field[n+1]/title, 'text'. If <field> does not have a <value/> or if the next <field> does not have a <value/>, then have 2 cells: field[n]/title, and 'other text' with number-columns-spanned=3. My first thought was this: /-----------------------------------------------------------------------------------------\ . . . <xsl:variable name="col" select="''"/> <xsl:table-body> <xsl:for-each select="field"> <xsl:choose> <xsl:when test="value and not($col)"> <fo:table-row> <fo:table-cell><xsl:value-of select="title"/></fo:table-cell> <fo:table-cell>text</fo:table-cell> <xsl:variable name="col" select="'true'"/> </xsl:when> <xsl:when test="value and $col"> <fo:table-cell><xsl:value-of select="title"/></fo:table-cell> <fo:table-cell>text</fo:table-cell> </fo:table-row> <xsl:variable name="col" select="''"/> </xsl:when> <xsl:when test="not(value) and not($col)"> <fo:table-row> <fo:table-cell><xsl:value-of select="title"/></fo:table-cell> <fo:table-cell>other text</fo:table-cell> <fo:table-cell number-columns-spanned="2"/> </fo:table-row> </xsl:when> <xsl:when test="not(value) and $col"> <fo:table-cell number-columns-spanned="2"/> </fo:table-row> <fo:table-row> <fo:table-cell><xsl:value-of select="title"/></fo:table-cell> <fo:table-cell>other text</fo:table-cell> <fo:table-cell number-columns-spanned="2"/> </fo:table-row> <xsl:variable name="col" select="''"/> </xsl:when> </xsl:choose> </xsl:for-each> </fo:table-body> \---------------------------------------------------------------------------------------/ This obviously will not work, because XSLT does not allow variables to be reassigned. After reading extensively from O'Reilly's XSLT book and the w3c specs for XSLT and XPath, I decided I could achive my goal with recursive template matches. Here is what I arrived at: /----------------------------------------------------------------------------------------\ <xsl:stylesheet . . .> <xsl:template match="document"> . . . <fo:table-body> <xsl:apply-templates select="field[1]"> </fo:table-body> . . . </xsl:template> <!-- end template match="document" --> <xsl:template match="field"> <xsl:choose> <!-- When current <field> has <value/> and next <field> has <value/> --> <xsl:when test="value and following-sibling::field[1]/value"> <fo:table-row> <fo:table-cell> <!-- current title --> <fo:block><xsl:value-of select="title"/></fo:block> </fo:table-cell> <fo:table-cell> <fo:block>text</fo:block> </fo:table-cell> <fo:table-cell> <!-- next title --> <fo:block><xsl:value-of select="following-sibling::field[1]/title"/></fo:block> </fo:table-cell> <fo:table-cell> <fo:block>text</fo:block> </fo:table-cell> </fo:table-row> <!-- use this template for the next element (after the one previously referred to as 'next'. omitting the final '[1]' will cause this template to be processed remaining <field>, which results in very long files with lots of stuff i don't want. --> <xsl:apply-templates select="following-sibling::field[position() > 1][1]"/> </xsl:when> <!-- if not. . . --> <xsl:otherwise> <fo:table-row> <fo:table-cell> <fo:block><xsl:value-of select="title"/></fo:block> </fo:table-cell> <fo:table-cell number-columns-spanned="3"> <fo:block>other text</fo:block> </fo:table-cell> </fo:table-row> <!-- use this template for the next element. again, don't omit '[1]'. --> <xsl:apply-templates select="following-sibling::field[1]"/> </xsl:otherwise> </xsl:choose> </xsl:template> \------------------------------------------------------------------------------------/ This works great. Based on my understanding of the XSLT parsers, this is pretty memory intensive, as applying "following-sibling::field[1]" actually passes the remaining <field> nodes in <document> every time, leaving a lot of stuff in the stack. Is that correct? At any rate, any ideas on a better way to do this? (Other than a SAX parsing of the XML with a few variables and leaving an extra node in select <field>s.) --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]