Re: [xsl] Transforming HTML to NITF

Subject: Re: [xsl] Transforming HTML to NITF
From: Jeni Tennison <mail@xxxxxxxxxxxxxxxx>
Date: Sat, 17 Feb 2001 12:35:29 +0000
Hi Adam,

>> I need to work with thos tags that  have the | beside them as a single
>> block so that I can wrap the entire thing in a <p> tag. Since I don't know
>> the placement or the order or even the frequency of such situations (there
>> is no reason why I couldn't have more blocks that need to be grouped
>> together). The solution needs to be general. 

Here's a single-pass solution that steps through the nodes one by one
to work out what to do. The first thing to do is get rid of all that
insignificant whitespace - otherwise you'll get lots of paragraphs
containing nothing but whitespace:

<xsl:strip-space elements="*" />

The next is to set the thing going with a body-matching template.
This creates a copy of the body and then starts the ball rolling by
applying templates to its first child:

<xsl:template match="body">
      <xsl:apply-templates select="node()[1]" />   

Now, if apply templates like this comes across something that you want
to keep as it is, then you just want to copy it before moving on to
the next node.  Here I've just listed the elements that you said were
valid directly under a body element:

<xsl:template match="p|table|ul|ol">
   <xsl:copy-of select="." />
   <xsl:apply-templates select="following-sibling::node()[1]" />

Now, when you come across something else, you want to create a p
element and place the next bunch of misfits inside it.  Creating the p
element is easy.  Inside it, I apply templates to the current node in
'copy' mode.  'copy' mode is my mode for copying the misfits and
moving on to the next.  Then I apply templates to the next sibling
that's one of the acceptable elements:

<xsl:template match="*|text()">
      <xsl:apply-templates select="." mode="copy" />
   <xsl:apply-templates select="following-sibling::*[self::p or self::table or self::ul or self::ol][1]" />

For 'copy' mode, I want to make a copy of the matched node, and then
move on to the next, but only if the next is a misfit node, not if
it's acceptable.  I could have done it with a big XPath, but it's a
bit clearer to use an xsl:if:

<xsl:template match="*|text()" mode="copy">
   <xsl:copy-of select="." />
   <xsl:if test="not(following-sibling::node()[1][self::p or self::table or self::ul or self::ol])">
      <xsl:apply-templates select="following-sibling::node()[1]" mode="copy" />

[Aside: I think that's the first time I've used a stepping-through
solution to one of these problems. Usually I use a Muenchian method,
keying on the preceding acceptable element. This way is actually a lot
smoother and easier to understand.]

As Mike suggested, you might want to do a two-pass solution in which
you essentially label the nodes that are 'misfits' as opposed to those
that are valid in the context.  That makes it a little easier to know
which node to move on to next.

I hope that helps,


Jeni Tennison

 XSL-List info and archive:

Current Thread