Apache – XSLT fop-0.95: problem with dyn:evaluate

apache-fopdynamicevaluatexslt

I've been struggling with some weird behavior of fop 0.95 (don't know if I'm doing
something wrong, or if there is a work around).

I have an auto generated XML as follows:

<projectteam>
 <projectname>Report Generation</projectname>
 <RoleTypes>
         <dev/>
         <qa/>
         <doc/>
 </RoleTypes>
 <member>
   <name>John</name>
   <dev>200</dev>
 </member>
 <member>
   <name>Max</name>
   <dev>60</dev>
 </member>
 <member>
   <name>Henry</name>
   <qa>80</qa>
 </member>
 <member>
   <name>Peter</name>
   <qa>40</qa>
 </member>
</projectteam>

(Note: This is a mocked up example, but I have a very similar need where I need
to generate reports at the end of a job with sevaral colums akin to roleTypes)

My goal is to display the above data in pdf as follows:

Name   | dev | qa  | doc |
--------------------------
John   | 100 |     |     |
Max    |  60 |     |     |
Henry  |     |  80 |     |
Peter  |     |  40 |     |

I used xsl:for-each to loop over RoleTypes/* elements to define table columns, and
then dynamically constructed XPath expression (using dyn:evaluate of exslt) to obtain
data for the cells that correspond to the roles (dev, qa, and doc).

My xsl stylesheet works as expected if I run it through a pre-processor (xsltproc)
to generate .fo, and then use fop to convert this .fo into a pdf.
But, when I use fop directly (i.e. single step: fop -xml blah.xml -xsl blah.xsl
-pdf out.pdf), I'm getting weird results – only the first column's data (i.e. the first
child element of 'RoleTypes', in this example – 'dev') and rest of the colums are blank.
I've also tried producing .fo first with fop itself (-foout option), and then using
fop to generate the pdf, but got the same result, i.e. data gets displayed only in the
column that corresponds to the first child element of RoleTypes element.
Is this a bug with fop (as it seems to recognize dyn:evaluate, but
doesn't do a complete job)?

I would really like to use the single step fop so that I wouldn't need
to deploy additional tools on the client box (like xsltproc etc).

Here's the critical segment of the stylesheet I've been using:

<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:fo="http://www.w3.org/1999/XSL/Format"
  xmlns:dyn="http://exslt.org/dynamic">

<xsl:template match="projectteam">
 ...
 <fo:table table-layout="fixed" width="100%">
  <fo:table-column column-width="3cm"/>
  <xsl:for-each select="RoleTypes/*">
   <fo:table-column column-width="1cm"/>
  </xsl:for-each>

  <fo:table-body>
  <xsl:for-each select="member">
   <xsl:variable name="Member" select="."/>
   <fo:table-row>
    <fo:table-cell>
     <fo:block> <xsl:value-of select="name"/></fo:block>
    </fo:table-cell>

    <xsl:for-each select="../RoleTypes/*">
     <xsl:variable name="roleName" select="concat('$Member/', name(.))"/>
     <fo:table-cell><fo:block>

     <!-- This is where the problem is with fop; although the same statement works fine with xsltproc?? -->

      <xsl:value-of select="dyn:evaluate($roleName)"/>
     </fo:block></fo:table-cell>
    </xsl:for-each>
   </fo:table-row>
  </xsl:for-each>
  </fo:table-body>
 </fo:table>
</xsl:template>
</xsl:stylesheet>

Thanks

Best Answer

This doesn't answer the general problem of using dyn:evaluate in FOP, but for this particular schema and problem, dynamic evaluation is not needed. You can use the name() function to match the node names. If you replace the inner loop of your example with:

                    <xsl:for-each select="../RoleTypes/*">
                        <xsl:variable name="roleName" select="name(.)"/>
                        <fo:table-cell><fo:block>
                            <xsl:value-of select="$Member/*[name()=$roleName]"/>
                        </fo:block></fo:table-cell>
                    </xsl:for-each>

You will get the output you wanted.

Related Topic