This is the mail archive of the xsl-list@mulberrytech.com mailing list .


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: nested block elements in xml -> html


Hi Michael,

>My templates transform this to an html fragment
>
><p class="myclass">
>  Text before list
>  <ol class="mylist">
>    <li>first item</li>
>    <li>second item</li>
>  </ol>
>  Text after list
></p>
>
>which looks fine, but isn't. In the xml, as my dtd allows, the
>list is nested within the p. But in html, the new ol block
>element
>implicitly closes the p element, so that the browser
>in effect rewrites to
>
><p class="myclass">
>  Text before list
></p>  <<=============== !!!!
>  <ol class="mylist">
>    <li>first item</li>
>    <li>second item</li>
>  </ol>
>  Text after list
></p>

A possible way around your problem is to actually produce valid HTML so
that the browser doesn't have to resort to guessing where the paragraph
ends.  In other words to produce:

<p class="myclass">
  Text before list
</p>
<ol class="mylist">
  <li>first item</li>
  <li>second item</li>
</ol>
<p class="myclass">
  Text after list
</p>

This would be fairly easy if the text before and after the list does not
contain any other markup (make a template matching p/text() which wraps
said text within a 'p' element).  I think it's more likely, though, that
you have emphasised text or something in there as well, and that you could
have several lists within a particular paragraph in your source document.
In other words, I'm testing with a source of:

<p>
 <em>Emphasised</em> text before lists
 <list>
   <item>first item, first list</item>
   <item>second item, first list</item>
 </list>
 Text between lists
 <list>
   <item>first item, second list</item>
   <item>second item, second list</item>
 </list>
 Text after lists
</p>

After some playing around, the best I can come up with is the following,
though there may be a simpler way.

First, generate the groups of text and elements that need to be put into
paragraphs together using keys.  The following xsl:key element groups
together all children of 'p' that are not called 'list' by indexing them
according to the unique id of the next sibling 'list' element.

  <xsl:key name="content" match="doc/p/node()[name() != 'list']"
    use="generate-id(following-sibling::list)" />

Now that we have them in groups, given a node we can generate a paragraph
that contains a copy of (to maintain existing HTML styling) all the nodes
in that group.  So first, we want to only look at nodes that are (a) the
first node in the paragraph; (b) the first node after a list; or (c) a list
(since we want to process them too!).  I could have selected those nodes
that appear first in the keyed groups, but I didn't because this way was
shorter.

  <xsl:template match="p">
    <xsl:apply-templates
      select="node()[1] |
              node()[name(preceding-sibling::node()[1]) = 'list'] |
              list" />
  </xsl:template>

Then, for those nodes that aren't lists, we want to take them, and all
other nodes in their group, and put them in a paragraph:

  <xsl:template match="p/node()[name() != 'list']">
    <p class="myclass">
      <xsl:apply-templates mode="copy"
        select="key('content', generate-id(following-sibling::list))" />
    </p>
  </xsl:template>

  <xsl:template match="node()" mode="copy">
    <xsl:copy-of select="." />
  </xsl:template>

This enables you to keep your existing template matching 'list', which
probably looks something like:

  <xsl:template match="list">
    <ol>
      <xsl:for-each select="item">
        <li><xsl:value-of select="." /></li>
      </xsl:for-each>
    </ol>
  </xsl:template>

I've tested this and it works with SAXON.

I hope this helps,

Jeni


Dr Jeni Tennison
Epistemics Ltd, Strelley Hall, Nottingham, NG8 6PE
Telephone 0115 9061301 • Fax 0115 9061304 • Email
jeni.tennison@epistemics.co.uk



 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]