Re: [xsl] Changing table output from horizontal to vertical

Subject: Re: [xsl] Changing table output from horizontal to vertical
From: "Mark" <mark@xxxxxxxxxxxx>
Date: Sun, 18 Sep 2011 14:56:33 -0700
Hi Brandon,
Got your message just as I posted the note that I figured it out myself. I finally realized what you said: position() is context sensitive and that let me move on. The second part of the problem (and I would have solved the whole mess earlier if I had recognized this) is the 'div' versus 'idiv' function. I was trying to use [$rowcount] as an integer when it actually was a real.


Mine is not so pretty, so let me look at yours.
Thanks for taking the time.
Mark

-----Original Message----- From: Brandon Ibach
Sent: Sunday, September 18, 2011 2:39 PM
To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
Subject: Re: [xsl] Changing table output from horizontal to vertical


Mark,

Here's a complete version of a "List" template, which also handles
iterating through all the present languages, building a table for
each.

Keep in mind that using something like "position()" inside of a
[predicate] gives the position of the context node being filtered by
the predicate.  If you want to use the position of the node that is
current outside the XPath expression, you generally need to save it to
a variable, first, and use that inside the predicate, as shown here.

<xsl:template match="List">
<xsl:for-each-group select="Item" group-by="@lang">
<xsl:variable name="group" select="current-group()"/>
<xsl:variable name="rowcount" select="ceiling(count($group) div 3)"/>
<table class="motif" lang="{@lang}">
<xsl:for-each select="$group[position() &lt;= $rowcount]">
<xsl:variable name="pos" select="position() - 1"/>
<tr>
<xsl:apply-templates select="$group[(position() - 1) mod
$rowcount = $pos]"/>
</tr>
</xsl:for-each>
</table>
</xsl:for-each-group>
</xsl:template>

-Brandon :)


On Sun, Sep 18, 2011 at 4:31 PM, Mark <mark@xxxxxxxxxxxx> wrote:
My first problem solved: the round() caused the extra row; did not realize I
had done that when I was trying to get rid of the decimal/integer problem.
Thus, my problem is specifying the entries for the second and third columns,
which I flat out do not understand. Can anyone point out my XPath error,
please? Or is it context? I have not a clue.


For the second column I tried many variation on the following with no
success (the full code is below):
<xsl:apply-templates select="../Item[@lang eq 'en'][position() +
$rowcount]"/>
Thanks,
Mark

-----Original Message----- From: Mark
Sent: Sunday, September 18, 2011 12:35 PM
To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
Subject: Re: [xsl] Changing table output from horizontal to vertical

Hi Liam,
Thanks for the code. I have a few problems. I am using XSLT2. First, I could
not specify the variable as="xs:integer"; the processor complained about the
raw value being a decimal. Second, the code gives me 10 rows, not 9, because
I am rounding up: this means I will have unnecessary blank cells. I know
that changing the +2 to a +1 will stop that, but I did not know why the +2
was in the expression in the first place. The most important issue is that I
do not know how to specify the second and third columns. My code (which only
gives me the first column with 10, not 9, cells), looks like this:


<xsl:variable name="rowcount" select="round((count(Item[@lang eq 'en']) + 2)
div 3)"/>
<table class="motif" lang="en">
<xsl:for-each select="Item[@lang eq 'en'][position()
&lt;=$rowcount]">
<tr>
<xsl:apply-templates select="."/>
<xsl:apply-templates select="../Item[@lang eq
'en'][position() + $rowcount]"/> <!-- Not working at all -->
<xsl:apply-templates select="../Item[@lang eq
'en'][position() + $rowcount + $rowcount]"/> <!-- Not working at all -->
</tr>
</xsl:for-each>
</table>
and the <Item> template:
<xsl:template match="Item">
<td>
<h4>
<xsl:element name="a">
<xsl:attribute name="href" select="@file"/>
<xsl:value-of select="@concept"/>
</xsl:element>
</h4>
</td>
</xsl:template>


Can you help clear this up for me?

-----Original Message----- From: Liam R E Quin
Sent: Sunday, September 18, 2011 10:16 AM
To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
Subject: Re: [xsl] Changing table output from horizontal to vertical

On Sun, 2011-09-18 at 09:50 -0700, Mark wrote:

Hi, I am using an XSLT template to produce an XHTML table.


Currently, the
stylesheet fills the table in a horizontal direction; I would like to fill
the table in a vertical direction.

Instead of thinking of filling a table, think of it as a mapping from the input tree to the output grid... Each output tr will start with the nth input item and then have the n + NRth item, then n + NR * 2, and so on, where NR is the number of rows (rounded up to the nearest integer if there's a partial row).

You can work out the total number of rows (I'd store it in an XSLT
variable for clarity) e.g. in the template for List you could do
<xsl:template match="List">
 <xsl:variable name="rowcount"
    select="(ncount(Item[@lang eq $langcode]) + 2) div 3"
    as="xs:integer" />
(if you are still in 1998 and XSLT 1, leave of the "as" attribute and
use = instead of eq)

 <!--* now you can map the Items to table cells. *-->
 <xsl:for-each
  select="Item[@lang eq $langcode][position() &lt;= $rowcount]">
  <xsl:apply-templates select="." />
 </xsl:for-each>
</xsl:template>

In this example $langcode is a global parameter to the stylesheet, but
to handle both languages make it a tunnel parameter, or in XSLT 1 make
it a literal parameter and add it as an argument to the List template,
or if List generates the tables, you could instead do,
 <xsl:for-each select="distinct-values(Item/@lang)">
  generate a table in here
 </xsl:for-each>
perhaps with an xsl:sort instruction in there :)

Liam

--
Liam Quin - XML Activity Lead, W3C, http://www.w3.org/People/Quin/
Pictures from old books: http://fromoldbooks.org/

Current Thread