xsl-list
[Top] [All Lists]

Re: [xsl] a table-of-contents for XHTML problem

2008-06-15 18:40:07
G Ken Holman <gkholman(_at_)cranesoftwrights(_dot_)com> writes:

At 2008-06-16 01:46 +0700, Ivan Shmakov wrote:

I wonder, what would be the simplest way to transform a sequence of
sibling nodes, e. g.:

...

into a nested list, like:

...

in XSLT 1.0?

The following conditions are assumed to be true:

* all the `hN' nodes are the children of a single `body' node;

* for any consequent elements `hN' and `hM', M <= 1 + N; the first
child of the `body' node is `h1'; i. e., it's assumed that, e. g.,
the following input could never happen:

<body>
  <h1>Foo</h1>
  <h3>Bar</h3>
</body>

Those criteria you state make this quite straightforward ... the
stylesheet below addresses these quite succinctly.  You don't mention
where you are having problems in your stylesheet so I'm not sure
where to advise.

        It seems that I've overlooked the `preceding-sibling' axis in
        the XPath specification (I've started to study XSLT a couple of
        days ago, so I'm not quite fluent in it.)

        What I've actually tried was to process each `body's child in a
        somewhat tricky manner, like:

  <xsl:template name="process-body-node">
    <xsl:param name="index" />
    <!-- pass more state here -->
    <xsl:variable name="body" select="/xhtml:html/xhtml:body" />
    <xsl:variable name="last" select="count($body)" />
    <xsl:if "$index &lt;= $last">
      <!-- ... do something with $body[position() = $index]... -->
      <!-- next iteration -->
      <xsl:call-template name="process-body-node">
        <xsl:with-param name="index" select="1 + $index" />
        <!-- pass even more state here -->
      </xsl:call-template>
    </xsl:if>
  </xsl:template>

        (Only that it has several `process-body-node' invocations, one
        for the inner nodes, and one for the ``siblings''.)

        I've got the program working, but it became quite large.

I don't think your indentation is significant so I didn't try to copy
the indentation in my solution.

This approach takes advantage of the ability to have multiple
declarations for the same key table.  This is different from
approaches I've taken in the past as I thought this might be far more
straightforward than trying to descend recursively ... since your
give the criterion that no levels of nesting are going to be missed
in the input.

I hope this helps.

        It surely will.  Thanks!

[...]

<?xml version="1.0" encoding="US-ASCII"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
                 version="1.0">

<xsl:output indent="yes"/>

<!--for each possible child, indicate who they are a child of-->
<xsl:key name="nested" match="h2"
use="generate-id(preceding-sibling::h1[1])"/>
<xsl:key name="nested" match="h3"
use="generate-id(preceding-sibling::h2[1])"/>
<xsl:key name="nested" match="h4"
use="generate-id(preceding-sibling::h3[1])"/>
<xsl:key name="nested" match="h5"
use="generate-id(preceding-sibling::h4[1])"/>
<xsl:key name="nested" match="h6"
use="generate-id(preceding-sibling::h5[1])"/>

        ... And it's a reverse axis...

[...]

</xsl:stylesheet>

[...]

--~------------------------------------------------------------------
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>
--~--

<Prev in Thread] Current Thread [Next in Thread>