xsl-list
[Top] [All Lists]

Re: [xsl] Create Table

2010-04-06 20:24:14
bernie bonn wrote:

So I have my table built with all the source changes, now I want to
add a row with the 'diffs' for each change...


I'm pretty sure you meant to say you want to add a *column* with the
relevant diffs... ;-).


Off topic, I plan on using JavaScript to hide the diff detail unless
user wants to see it.


Not off-topic at all.  You want the new column to be optional, OK.  I'm
assuming you'll be calling this transformation from Javascript, rather
than an xml-stylesheet PI, if you want to present the user with options
for the <table> content, to keep the diffs transformation from
executing -- otherwise you could just toggle the column by setting a
<col> tag to display:none.

I added a global boolean parameter to the stylesheet, defaulting to
true and executing the code for transforming the optional column.  This
may be overridden easily when the transform is called by Javascript, in
any browser -- executing a stylesheet with a parameter is pretty
standard stuff.  With an xml-stylesheet PI, though, only mozilla has a
proprietary mechanism to allow parameter passing.


The challenge is after i have grabbed  the the File, version, date
etc for the first row,  I need to then somehow grab all the data
nodes where @field=diff, until the next node where @field!=diff, and
place it in the next row. Seems like a while loop, but I know those
don't exist. 


You just need to think upside-down, in terms of document order.
Instead of checking against some value for the *next* node, look for
patterns in *previous* nodes.  This makes recursive design easier,
IMHO.  Instead of looping through a set until some condition is met,
think in terms of selecting a set which meets certain criteria.

In this case, we need to select all the following-sibling data elements
with @section=diff before the next <tr> delimiter, but which don't have
a preceding-sibling where @section!=diff.  This is a two-step operation
which requires us to first identify a nodeset of all @section=diff
between the delimiters, by using <variable><copy-of/></variable>.

We can then perform operations against that variable of type=nodeset,
instead of the document as a whole.  This makes it easy to then
process only the data elements we're interested in.  If we're only
ever searching up the preceding-sibling axis, then we don't need to
account for end-of-parent-element, which is what I mean by thinking
upside-down.

Notice I've rolled the xsl:stylesheet @version up to '1.1'.  I don't
know the story on browser compatibility with XSLT 1.0 vs. 1.1, but I do
know that all XSLT-enabled browsers grok exslt:node-set(), so if my
code doesn't work in your target browser you can alter it to use exslt:
node-set() and it ought to work.

As I said before, XSLT 1 forces one to be clever.  I wouldn't normally
code a double-negative as I have here, but the key logic turned out to
be checking that something is not(!=).  It's a bit counter-intuitive,
which is why this response took so long -- I got totally stumped on it
until today.  Further comments in the XSLT code.


Sorry this is so muddled, let me know if you need clarifications.  
Thanks again,


The only apologizing needed here, is from whoever designed the XML
source language you're working with.  After receiving fifty lashes with 
a wet noodle.  Just sayin'.

-Eric

<?xml version='1.0' encoding='utf-8'?>
<interface-categories>
    <data lineId='1' section='diff' field='diff'>if (reportService = 
null)</data>
    <data lineId='2' section='diff' field='diff'>return false;</data>
    <data lineId='3' section='diff' field='diff'>return true;</data>
    <data lineId='4' section='changes' 
field='version'>\main\spr2010_apr_dev\2</data>
    <data lineId='5' section='changes' field='date'>20100310.102844</data>
    <data lineId='6' section='changes' field='user'>jryan</data>
    <data lineId='7' section='changes' field='cr_number'>602018</data>
    <data lineId='8' section='changes' field='comment'>fix for log 5960</data>
    <data lineId='9' section='diff' field='diff'>1296a1297,1298</data>
    <data lineId='11' section='diff' field='diff'>if !(reportService = 
null)</data>
    <data lineId='12' section='diff' field='diff'>return true;</data>
    <data lineId='13' section='diff' field='diff'>return false;</data>
    <data lineId='14' section='changes' field='file'>HistoryWages.java</data>
    <data lineId='15' section='changes' 
field='version'>\main\spr2009_apr_dev\2</data>
    <data lineId='16' section='changes' field='date'>20090310.102844</data>
    <data lineId='17' section='changes' field='cr_number'>602118</data>
    <data lineId='18' section='changes' field='comment'>fix for log 6950</data>
    <data lineId='19' section='diff' field='diff'>1293a1294,1295</data>
    <data lineId='21' section='diff' field='diff'>if (reportService != 
null)</data>
    <data lineId='22' section='diff' field='diff'>return bar;</data>
    <data lineId='23' section='diff' field='diff'>return foo;</data>
    <data lineId='29' section='Section1' 
field='URL'>[url]\\rnd-spbuild-1\...\index.html[/url]</data>
    <data lineId='30' section='diff' field='diff'>1012c1024</data>
    <data lineId='31' section='diff' 
field='diff'>setMethod(row.getString('icpc_calc');</data>
    <data lineId='24' section='changes' field='file'>Wages.java</data>
    <data lineId='25' section='changes' field='date'>20080310.102844</data>
    <data lineId='26' section='changes' field='user'>ryanj</data>
    <data lineId='27' section='changes' field='cr_number'>602218</data>
    <data lineId='28' section='diff' field='diff'>1290a1291,1292</data>
</interface-categories>

<?xml version='1.0' encoding='utf-8'?>
<xsl:stylesheet version='1.1'
    xmlns='http://www.w3.org/1999/xhtml'
    xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
    <!-- call this stylesheet with diffs=false() to suppress the optional 
changeset column -->
    <xsl:param name='diffs' select='true()'/>
    <xsl:output omit-xml-declaration='no' method='xml' indent='yes' 
xml:space='default' encoding='utf-8'/>
    <xsl:template match='/'>
        <html xml:lang='en'>
            <head>
                <title>table example</title>
                <style 
type='text/css'>table{table-layout:fixed;width:auto}</style>
            </head>
            <body>
                <table width='0' summary='summary goes here for accessibility'>
                    <caption>caption goes here for accessibility</caption>
                    <thead>
                        <tr>
                            <th>Line #</th>
                            <th>File</th>
                            <th>Version</th>
                            <th>Date</th>
                            <th>User</th>
                            <th>CR Number</th>
                            <th>Comment</th>
                            <xsl:if 
test='$diffs'><th>Changeset</th></xsl:if><!-- optional column -->
                        </tr>
                    </thead>
                    <tfoot><!-- optional -->
                        <tr>
                            <th>Line #</th>
                            <th>File</th>
                            <th>Version</th>
                            <th>Date</th>
                            <th>User</th>
                            <th>CR Number</th>
                            <th>Comment</th>
                            <xsl:if 
test='$diffs'><th>Changeset</th></xsl:if><!-- optional column -->
                        </tr>
                    </tfoot>
                    <tbody>
                        <!-- find and throw the delimiters between groups of 
data elements, i.e. the last section=diff before a section=changes -->
                        <xsl:apply-templates 
select="//data[(_at_)section='diff']/following-sibling::data[(_at_)section='changes'][1]/preceding-sibling::data[1]"/>
                        <!-- the data elements between delimiters (or 
end-of-parent) make up the contents of each table row -->
                    </tbody>
                </table>
            </body>
        </html>
    </xsl:template>
    <xsl:template match='data'>
        <!-- catch the delimiting data elements and assign a group number based 
on delimiter occurrence number (position) -->
        <xsl:param name='i' select='position()'/>
        <!-- create a nodeset containing all non-section=changes data elements 
from here to the next delimiter (or end-of-parent), using xsl:variable 
*content* not @select -->
        <!-- if the count of the preceding delimiters is not equal to the 
current group number, the data element is not part of the current group -->
        <xsl:variable name='changeset'>
            <xsl:copy-of 
select="following-sibling::data[not(@section='changes') and 
count(preceding-sibling::data[(_at_)section='changes' and 
preceding-sibling::data[1]/@section='diff'])=$i]"/>
        </xsl:variable>
        <!-- handle all section=changes data elements from here to the next 
delimiter (or end-of-parent) using pull, to account for possible missing fields 
-->
        <!-- if the count of the preceding delimiters is not equal to the 
current group number, the data element is not part of the current group -->
        <tr>
            <th><xsl:value-of select='./@lineId+1'/></th>
            <td><xsl:value-of 
select="following-sibling::data[(_at_)field='file' and 
count(preceding-sibling::data[(_at_)section='diff']/following-sibling::data[(_at_)section='changes'][1])=$i][1]"/>&#160;</td>
            <td><xsl:value-of 
select="following-sibling::data[(_at_)field='version' and 
count(preceding-sibling::data[(_at_)section='diff']/following-sibling::data[(_at_)section='changes'][1])=$i][1]"/>&#160;</td>
            <td><xsl:value-of 
select="following-sibling::data[(_at_)field='date' and 
count(preceding-sibling::data[(_at_)section='diff']/following-sibling::data[(_at_)section='changes'][1])=$i][1]"/>&#160;</td>
            <td><xsl:value-of 
select="following-sibling::data[(_at_)field='user' and 
count(preceding-sibling::data[(_at_)section='diff']/following-sibling::data[(_at_)section='changes'][1])=$i][1]"/>&#160;</td>
            <td><xsl:value-of 
select="following-sibling::data[(_at_)field='cr_number' and 
count(preceding-sibling::data[(_at_)section='diff']/following-sibling::data[(_at_)section='changes'][1])=$i][1]"/>&#160;</td>
            <td><xsl:value-of 
select="following-sibling::data[(_at_)field='comment' and 
count(preceding-sibling::data[(_at_)section='diff']/following-sibling::data[(_at_)section='changes'][1])=$i][1]"/>&#160;</td>
            <!-- using dl markup for the name-value-pair semantics of line # - 
code, present the optional changeset column for this row, made up only of 
relevant @section=diffs from the source -->
            <!-- $changeset is a nodeset, to isolate the preceding-sibling 
check for @section!=diff to the current group instead of the entire source file 
-->
            <!-- the for-each @select chooses all data elements in the nodeset 
with @section=diff, only if their preceding-sibling axes witin the nodeset are 
clear of other @section values -->
            <xsl:if test='$diffs'>
                <td>
                    <dl>
                        <xsl:for-each 
select="$changeset//data[(_at_)section='diff' and 
not(preceding-sibling::data[(_at_)section!='diff'])]">
                            <dt><xsl:value-of select='./@lineId'/></dt>
                            <dd><xsl:copy-of select='./text()'/>&#160;</dd>
                        </xsl:for-each>
                    </dl>
                </td>
            </xsl:if>
        </tr>
    </xsl:template>
</xsl:stylesheet>

--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--

<Prev in Thread] Current Thread [Next in Thread>