xslt stylesheet structure

Structure

1. How to introduce structure
2. Nearest enclosing hx element
3. Markup internal to an element

1.

How to introduce structure

Wendell Piez


I'd start by elevating the value of that stylename attribute
to a real element type name, to get access to this
information more easily (since it's crucial.) So instead of

><p stylename="heading1" >
>  <string>More Money for All Amendment
>  </string>
></p>
><p stylename="section">
>  <string>1.(1)Clause 8 (1) (a) of the</string>
>  <string italic="on">More Money for All Amendment</string>
>  <string> is deleted and the following substituted:</string>
></p>

You have

><heading1>
>  <string>More Money for All Amendment
>  </string>
></heading1>
><section>
>  <string>1.(1)Clause 8 (1) (a) of the</string>
>  <string italic="on">More Money for All Amendment</string>
>  <string> is deleted and the following substituted:</string>
></section>

You can do this with <xsl:element
name="@stylename">...</xsl:element> elements. In general,
I think you'll gain quite a bit from pre-processing your
RTF-XML into something cleaner and more legible.


2.

Nearest enclosing hx element

Jeni Tennison

>  I am looking for the nearest enclosing <hx> element (h1 or h2).
>
> I need an Xpath expression that would give back h1 for the first <x/>
> element, and h2 for the second.
	

You can get the 'enclosing' elements with the ancestor:: axis. So you want to look along the ancestor:: axis and find any elements that are called h1 or h2:

  ancestor::h1 | ancestor::h2

or:

  ancestor::*[self::h1 or self::h2]

or, if you want any element whose name starts with 'h' and ends in a number, then:

  ancestor::*[starts-with(name(), 'h') and
              number(substring(name(), 2))]

and so on.

You want the nearest of these, which you can identify by studying its position in the document relative to the other nodes in the set. The first expression (ancestor::h1 | ancestor::h2) is a union of two node sets, so if you use a positional predicate on that, the positions will be judged in document order, and you want the last:

  (ancestor::h1 | ancestor::h2)[last()]

The other expressions are single steps, and the ancestor:: axis is a backwards axis, so any positional predicates will be assessed with the node set in reverse document order, and you need:

  ancestor::*[self::h1 or self::h2][1]

or:

  ancestor::*[starts-with(name(), 'h') and
              number(substring(name(), 2))][1]

3.

Markup internal to an element

Wendell Piez

Since I tackled a problem somewhat like yours back when in a project I distributed, I thought I'd post it.

Note that this recursive string-finding bit doesn't do a case-insensitive match, or make allowances for whitespace (which, judging from a cursory glance at your code, you apparently want). But it might give you a place to start.

Import this stylesheet into yours:


 <xsl:stylesheet version="1.0"
                  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 
 <!-- The 'segmentfunc' named template returns, for a given node,
       a text string with all occurrences of a given substring
       isolated by markup. The substring to be isolated must be
       passed to the template as the 'find' parameter: its markup
       is provided by another named template, 'displayfound' (to
       be provided in the main stylesheet).
 
       Wendell Piez, Mulberry Technologies, December 1999.      -->
 
 <xsl:template name="segmentfunc">
    <xsl:param name="procstring">
      <!-- the string to be processed. Trimmed recursively until
           all occurrences have been isolated and passed to
           'display'.                                           -->
      <xsl:value-of select="."/>
    </xsl:param>
    <xsl:choose>
      <xsl:when test="$find and contains($procstring, $find)">
        <xsl:value-of select="substring-before($procstring, $find)"/>
        <xsl:call-template name="displayfound"/>
        <xsl:call-template name="segmentfunc">
          <xsl:with-param name="procstring"
                        select="substring-after($procstring, $find)"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$procstring"/>
      </xsl:otherwise>
    </xsl:choose>
 </xsl:template>
 
 </xsl:stylesheet>
 
 <!-- and then, place a template such as this one in your main 
 stylesheet (to 
 provide your found string with markup in the output) -->
 
 <xsl:template name="displayfound">
    <!-- Providing markup for the found string. -->
    <xsl:param name="displaystring"/>
    <b>
      <xsl:value-of select="$find"/>
    </b>
 </xsl:template>
 
 (This one wraps your found string in a <b> element, assuming 
 that string is 
 identified in a global variable or parameter $find; do what you will.)