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() &gt; 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]

Reply via email to