RE: [xsl] Grouping: XHTML inline, block and flow

Subject: RE: [xsl] Grouping: XHTML inline, block and flow
From: "Bjorndahl, Brad" <brad.bjorndahl@xxxxxxxxxxxxxxxx>
Date: Thu, 27 Mar 2008 11:13:52 -0400
Hi,

I can only respond to question 1. I have done something similar with DITA,
which also allows a mix of inline and block type elements.

First, though, I would not try to solve this problem in full generality
without XSLT 2.0. I'm just not brave enough.

Assuming you have resolved your problems with 2.0, this is how I handle the
mix:

1) Specify your inline elements in a global variable like this:
<xsl:variable name="inlineElts">
  <inline></inline> <!-- for text nodes -->
  <inline>b</inline>
  <inline>i</inline>
  <inline>sup</inline>
  <inline>sub</inline>
  .
  .
  .
</xsl:variable>


2) In templates that process mixed content, include, at the appropriate
point:
<xsl:call-template name="processMixedContent" >
.
</xsl:call-template>

In my case I also have
<xsl:call-template name="processNodes-note" >
<xsl:call-template name="processNodes-li_choice_dt" >
and so on for special cases, but they all work in a similar way.


3) Add the processMixedContent template:
<xsl:template name="processMixedContent"> . . .

in which you have a statement that groups inline and block elements like this
(and this is where 2.0 is important):

  <xsl:for-each-group select="child::node()"
group-adjacent="exists(index-of($inlineElts/inline,local-name()))">
    <xsl:for-each select=".">
      <xsl:choose>
        <xsl:when test="current-grouping-key() eq true()"> <!-- Process inline
elements  -->
          <xsl:for-each select="current-group()" >
        .
        .
        .
        <xsl:otherwise> <!-- Process block elements  -->
           <xsl:apply-templates select="current-group()">
        .
        .
        .


This works for me. I hope it's clear enough.
Brad


-----Original Message-----
From: Raka Gator [mailto:plogbil@xxxxxxxxx]
Sent: March 26, 2008 10:43 PM
To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
Subject: [xsl] Grouping: XHTML inline, block and flow

Hi people!

First post on the list for me. Please be gentle...

I've read the FAQ:s, I've read the guidelines. I've found endless information
about grouping but I still can't figure this one out.

I'm processing XHTML in order to generate ODF/ODT [1]. I'm no XSL guru and I'm
not aiming for a full-blown converter but I've used XSL now and then and
accomplished at least some usefull stuff the last years so I figured I'd try
something interesting now. I'm a programmer but I don't work with XML/XSL/HTML
professionally so this is purely recreational. :-)

But now I'm stuck. XHTML uses block- and inline-level types of elements (ie.
table and u respectiveley) for different layout purposes. But XHTML also mixes
them sometimes (I think the "mode" is called flow).

So I'm transforming an XHTML table. Every table cell can basically contain
almost any XHTML element, both block and inline types anyway. Let's say that
my XHTML table cell (<td>) looks like this, which seems to be correct (but
ugly):

<td>This is a <strong>wonderful</strong> table <p>but evil</p></td>

I'd like that transformed into something like this (omitting lots of
attributes for clarity):

<table:table-cell>
  <text:p>This is a <text:span text:style-name="bold">wonderful </text:span>
table</text:p>
  <text:p>but evil</text:p>
</table:table-cell>

I have two questions, one of which is not really XSL-related but anyway...

1. The first one is about grouping. As seen above, I need to group a text
   node, a <xhtml:strong> node and another text node and put them into a
   <text:p>. Then I need to transform the <xhtml:p> node into another
   <text:p> node. I have a messy and big stylesheet that manages all but
   these mixed cases. I've tried recursive and for-each variants but I get
   bitten by the fact that I need to test for... well... so much.

   The rest of the stylesheet is quite simple. I'm starting to think that
   I might need to use a completely separate stylesheet just to handle
   the tables and use modes or something.

   I'm not asking anyone to type a solution down. I'm just asking for
   some general advice. Maybe this is a huge task. It's just irritating
   that I'm completely stuck. I've read about xsl:key/xsl:generate-id tricks
but
   this gets messy with lots of corner cases. Is there a silver bullet? Done
   before but well kept secret? I've found tons of info on ODT->XHTML but
   not the other way around.

2. Does XSL provide some kind of mechanism by which I can relate a node to
   an entity name? I'm thinking about the "block/inline/flow" concept in
XHTML
   and looked at the DTD of HTML 4.01 [2] which I understand XHTML1.0 is
   based on. I'm basically finding myself writing lots of tests like
   "$ename = 'p' or $ename = 'ol' or...". A test if a node is a block node
   would be nice. Somehow...

I'm using xsltproc so I'm currently stuck with XSL 1.0. I realize that I could
benefit from using 2.0 but ran into some problems with saxonb9 when I tested
it earlier this week.


/Stefan

[1] http://www.oasis-open.org/committees/tc_home.php?wg_abbrev=office#odf11
[2] http://www.w3.org/TR/REC-html40/sgml/dtd.html#flow

Current Thread