[rfc-i] Section structure, was: RFC editing tools

Nico Williams nico at cryptonector.com
Fri Dec 7 13:11:17 PST 2012


FYI, the XSLT 2.0 idiom I developed for <hN> style -> nested <section>
style is roughly as follows (taken from lyx2rfc, a bit simplified):

<xsl:template match="*[matches(name(), '^h[2-9]') and
ends-with(@class, 'section') and
    not(matches(normalize-space(string-join(text(), '')), '^(Normative
|Informative |)References$'))]">
    <xsl:element name="section">

        <!-- N is the integer in hN -->
        <xsl:variable name="N" select="substring-after(name(), 'h')
cast as xs:integer"/>
        <xsl:variable name="thisHN" select="name()"/>
        <!-- We refer to this <hN> in various XPath contexts below where
             current() will no longer be this <h2>, so we need to save it -->
        <xsl:variable name="cur_sect" select="current()"/>

        <xsl:attribute name="title"
            select="normalize-space(string-join(text(), ''))"/>

        <!-- Make sure there's an anchor -->
        <xsl:variable name="id"
            select="a[not(starts-with(@id, 'magicparlabel-'))]/@id"/>
        <xsl:attribute name="anchor"
            select="if (string-length($id) > 0) then $id else generate-id()"/>

        <!-- Handle the contents of just this section.  Ask for all
             siblings of this <hN> where the nodes we're looking for are
             NOT hN, and their preceding <hN> is this one. -->
        <xsl:apply-templates
            select="(following-sibling::*[not(matches(name(), '^h[2-9]')) and
                (preceding-sibling::*[matches(name(),
'^h[2-9]')])[last()] is $cur_sect])"/>

        <!-- Handle sub-sections of this section.  Ask for all sibling
             h3 (and h4) nodes of this h2 where their preceding h2 is
             this one.  -->

        <xsl:apply-templates
            select="following-sibling::*[matches(name(), '^h[2-9]') and
                (preceding-sibling::*[name() = $thisHN])[last()] is
$cur_sect and
                (substring-after(name(), 'h') cast as xs:integer = ($N + 1))]"/>

    </xsl:element>
</xsl:template>

The key expressions are:

        <xsl:apply-templates
            select="(following-sibling::*[not(matches(name(), '^h[2-9]')) and
                (preceding-sibling::*[matches(name(),
'^h[2-9]')])[last()] is $cur_sect])"/>

(to get the contents of *this* section) and:

        <xsl:apply-templates
            select="following-sibling::*[matches(name(), '^h[2-9]') and
                (preceding-sibling::*[name() = $thisHN])[last()] is
$cur_sect and
                (substring-after(name(), 'h') cast as xs:integer = ($N + 1))]"/>

(to get the sub-sections following this section's content).

The key XPath 2.0 feature used here is sequences, as seen in the
sub-expression "(preceding-sibling::*[...])[last()]", where I'm
getting an <hN>'s preceding parent <hN> and then check that it's the
same the current <hN> so as to select that child.

Nico
--


More information about the rfc-interest mailing list