My question concerns X/HTML as the transformation target, where "p"
is the lowest level block-level element, which admits no other
block-level element(s) as content, but the source is a model (like
DocBook, TEI, etc.) which allows (and has) a variety of block level
content in paragraphs.
The following snippets of XSLT 2.0 are what I've been using to
transform <tei:p> elements that contain <tei:list> or <tei:eg> into
XHTML. I do not claim (at all) that this is a good, let alone the
best way to do this, but rather only that it has been working for me.
---------
<!--
** This section contains all the code for moving <list>s and <eg>s that
** are nested inside <p>s to being the middle siblings of two <p>s. I.e.:
** | <p>Blah-blah-01
** | <eg>exampleA</eg>
** | Blah-blah-02
** | <eg>exampleB</eg>
** | Blah-blah-03</p>
** should be transformed into
** | <p>Blah-blah-01</p>
** | <pre>exampleA</pre>
** | <p>Blah-blah-02</p>
** | <pre>exampleB</pre>
** | <p>Blah-blah-03</p>
-->
<xsl:template match="in:p">
<!-- first handle content up to and including the last <eg> or <list>
inside me -->
<xsl:call-template name="eg-and-list-in-p"/>
<!-- Note that if there is no <eg> or <list>, the above template did
nothing. -->
<!-- So now we still need to handle the content from the last <eg> or
<list> -->
<!-- (exclusive of it) to the end-of-me, and all my content if there was no
-->
<!-- <eg> or <list>. So the first step is to select all such nodes and tuck
'em -->
<!-- in a variable. So this XPath selects all nodes that are not <eg> or
<list> -->
<!-- and do not have any <eg> or <list> following. Thus, if there is
neither -->
<!-- an <eg> nor a <list>, it selects all my child nodes. -->
<xsl:variable name="end-content"
select="node()[not(self::in:list or self::in:eg) and
not(following-sibling::in:list or following-sibling::in:eg)]"/>
<xsl:if test="$end-content">
<xsl:element name="p">
<xsl:apply-templates select="$end-content"/>
</xsl:element>
</xsl:if>
</xsl:template>
<xsl:template name="eg-and-list-in-p">
<!-- for each of my (this <p>'s) children <eg> or <list> ... -->
<xsl:for-each select="./in:eg|./in:list">
<!-- remember the <eg> or <list> before me (now "me" = current <eg> or
<list>) -->
<xsl:variable name="before-me"
select="preceding-sibling::node()[self::in:eg or self::in:list][1]"/>
<!--
** The content we want is everthing between it (previous <eg> or
** <list>, whichever it was) and me (the current <eg> or <list>).
** However, don't ask me exactly how this predicate works. While
** I understand each little piece, I think, I don't get the big
** picture, and I don't understand the detail of why the equality
** test could ever fail. It is modified from the incomparable Jeni
** Tennison's post to XSL-List of 2001-01-19T15:49Z "How to
** transform <BR> to </P><P>"
** (http://xslt.com/html/xsl-list/2001-01/msg00927.xhtml),
** which I found via Dave Pawson's awesomely helpful FAQ at
** http://www.dpawson.co.uk/xsl/index.xhtml
-->
<xsl:variable name="content"
select="preceding-sibling::node()
[not($before-me) or
generate-id(preceding-sibling::node()[self::in:eg or self::in:list][1])
=
generate-id($before-me)]" />
<!-- if there is any content ... -->
<xsl:if test="$content">
<!-- ... put it out in a <p> before we ... -->
<xsl:element name="p">
<xsl:apply-templates select="$content"/>
</xsl:element>
</xsl:if>
<!-- ... put current node (and its children) into the output tree. -->
<xsl:apply-templates select="."/>
</xsl:for-each>
</xsl:template>
---------
--~------------------------------------------------------------------
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>
--~--