Re: Finding list items in XHTML
2002-11-14 14:39:54
Thanks again -- I've got it all working correctly now (I think -- I'll run
it on a few more test cases before I'm fully confident).
This was a great primer in grouping and making hierarchy out of flat files.
I'm starting to see uses for "mode" I hadn't before as well.
I gather from Michael Kay's book that I can also use modes to bring my
three passes into a single stylesheet -- right now I've got
three separate stylesheets and I've wrapped the whole procedure into a Perl
script. I may want the Perl wrapper anyway so I can
catch some errors for people who run the script later on, so that's OK, but
another day I'll no doubt want to explore using modes
more elegantly.
Thanks for all your wonderful help -- I really appreciate it.
At 12:40 PM 11/14/02, you wrote:
Hi Chris,
Okay, easy things first. Your current test looks like:
<xsl:if test="following-sibling::oeb:sublist[1]">
but it doesn't work. Translated into English, the XPath reads "the first
following sibling sublist", which gives a hint as to the problem: the test
is true if there is a (first) following sibling sublist. Which there
always is until you get to the end, hence your results.
Try:
<xsl:if test="following-sibling::*[1][self::oeb:sublist]">
which translates as "the first following sibling element, when it is
(itself) an oeb:sublist". That is, the node set returned by this
expression will contain a node only when the next sibling is a sublist.
What you want. (Try this and see, your results should look better.)
Okay, next thing. The technique you're adopting is basically
(a) test whether an <ol> is needed. It's needed when the next sibling is a
sublist. (We just did that.)
(b) if so, insert the <ol>
(c) inside the <ol>, collect the sublist elements we need, transforming
each into an <li>
Where (c) is getting nasty is in the algorithm to collect all the
sublists. This can be done in XPath. The thing is (and it takes some
experience to see this), the XPath you will need will be pretty nasty, and
essentially requires "keying" the sublists to the list they belong in
(which is what your variable identifying the paragraph is doing) ...
leading us to keys as a clean way to implement, leading us to the solution
you rejected as too complex! :->
Rather than undo all the logic here and re-engineer the grouping-by-keys
solution, since this looks good so far, let's just keep going. I'm going
to break down step (c):
(c) inside the <ol>
(c.1) if it's a sublist, include the first following sibling
(c.2) repeat (c.1) until the first following sibling is not a sublist
We can do this with a template, which we'll put into a special mode so as
not to confuse ourselves (since this isn't ordinary tree-traversal anymore):
<xsl:if test="following-sibling::*[1][self::oeb:sublist]">
<!-- we test to see whether we need an <ol> -->
<ol>
<!-- now we do our first sublist in our special mode -->
<xsl:apply-templates mode="listitem"
select="following-sibling::*[1][self::oeb:sublist]"/>
</ol>
</xsl:if>
and now our template:
<xsl:template match="oeb:sublist" mode="listitem">
<!-- make our item and include what's inside this sublist -->
<li>
<xsl:apply-templates/>
</li>
<!-- now do the same for the next immediate sibling that's a sublist
(if it's not, nothing will happen) -->
<xsl:apply-templates mode="listitem"
select="following-sibling::*[1][self::oeb:sublist]"/>
</xsl:template>
Notice what we have here is a recursive template that walks the tree
forward one node at a time, as long as the next sibling is a sublist,
making an item for each one it finds.
It's important for this to be in a mode since if we're not, this will
clash with the default depth-first tree-traversal and we'll get many
spurious list items as well as the ones we actually want. (We still need
the regular template for sublists to suppress them.)
I hope this helps. Note: this code is untested (though I've successfully
done this in the past).
Cheers,
Wendell
At 12:02 PM 11/14/2002, you wrote:
I seem to keep getting closer, but I'm not quite there yet, and I'm not
sure what to do next.
I've now got a first pass which takes my sublist items and surrounds them
with
<sublist>...</sublist>. So my input is like this:
***
<p class="hang-text-1"><span class="hang-text-2">➤ </span>Which of
the following features of the Mighty Vac are important to you? (Check all
that apply.)</p>
<sublist>Extra-long hose</sublist>
<sublist>Extra-long cord</sublist>
<sublist>Extra-high horsepower</sublist>
<sublist>Square head</sublist>
<sublist>Other <i>(Please specify)</i> ______________________</sublist>
<p class="hang-text-12"><span class="hang-text-2">➤ </span>How
would you rate the service you receive from Acme Industries? (Check one.)
Excellent</p>
<sublist>Good
Fair
Poor</sublist>
<p class="format-10">With closed-end questions, you must often give
directions to the respondent (such as
“Check one” or “Please rate from one to five, with five
being the best”).</p>
***
Yes, I know the second sublist didn't really come out right, but my input
isn't always perfect. That will have to be fixed downstream from me.
Now I'm trying to group the <sublist>s into an <ol> and to set up the <li>
for the main lists. In the third pass, I plan to group the <li>s for the
main lists.
I read the FAQ page cited above, and tried to implement some of it, but
frankly,
I'm not sure it all sunk in very well. I was able to make more sense of
Michael
Kay's discussion of grouping adjacent nodes on p. 496 of his book (2nd ed.),
so that's the path I'm trying to follow. However, I'm still off-course
somewhere.
Here's part of my stylesheet at present:
***
<xsl:template match="oeb:p[starts-with(.,'➤ ')]">
<li><xsl:apply-templates />
<xsl:if test="following-sibling::oeb:sublist[1]">
<xsl:text>
</xsl:text>
<ol>
<xsl:text>
</xsl:text>
<xsl:variable name="list-id"
select="generate-id(preceding-sibling::p[1])" />
<xsl:for-each
select="oeb:sublist[generate-id(preceding-sibling::p[1]) = $list-id]">
<li><xsl:value-of select="." /></li>
<xsl:text>
</xsl:text>
</xsl:for-each>
</ol>
<xsl:text>
</xsl:text>
</xsl:if>
</li>
</xsl:template>
<xsl:template match="oeb:sublist" />
<xsl:template match="oeb:span[.='➤ ']" />
***
What I'm trying to do is process the list items and the sublists of that
list item if there are any.
So my intended output for the above snippet of text would be
***
<li>Which of the following features of the Mighty Vac are important to
you? (Check all
that apply.)
<ol>
<li>Extra-long hose</li>
<li>Extra-long cord</li>
<li>Extra-high horsepower</li>
<li>Square head</li>
<li>Other <i>(Please specify)</i> ______________________</li>
</ol>
</li>
<li>How would you rate the service you receive from Acme Industries?
(Check one.)
Excellent
<ol>
<li>Good
Fair
Poor</li>
</ol>
</li>
<p class="format-10">With closed-end questions, you must often give
directions to the respondent (such as
“Check one” or “Please rate from one to five, with five
being the best”).</p>
***
However, I have several problems. First, the <xsl:if> turns out to be
true for EVERY occurrence where there
is a <sublist> anywhere further down in the document, so I get a lot of
empty <ol> tags where I don't want them.
Those stop occurring after the last <sublist> in the document. I need to
specify that the following-sibling is
immediately adjacent to the current node, but the [1] I inserted to try
to do that seems to pick the next occurrence
of <sublist> but not the next node. So my <xsl:if> isn't right.
Next, the stylesheet doesn't insert the <sublist> items into the place
where I expect them, so even when I do have
the <ol> tags in the right place, they don't have the content I was
trying to set up. My actual output looks like this:
***
<li>Which of the following features of the Mighty Vac are important to
you? (Check all
that apply.)
<ol>
</ol>
</li>
<li>How would you rate the service you receive from Acme Industries?
(Check one.)
Excellent
<ol>
</ol>
</li>
<p class="format-10">With closed-end questions, you must often give
directions to the respondent (such as
“Check one” or “Please rate from one to five, with five
being the best”).</p>
***
I think I understand why the <xsl:if> isn't working, but I don't know how
to fix it. I'm not sure why the second
problem is happening at all.
May I ask for a little more help? Thanks so much for all you've helped
with so far!
======================================================================
Wendell Piez
mailto:wapiez(_at_)mulberrytech(_dot_)com
Mulberry Technologies, Inc. http://www.mulberrytech.com
17 West Jefferson Street Direct Phone: 301/315-9635
Suite 207 Phone: 301/315-9631
Rockville, MD 20850 Fax: 301/315-8285
----------------------------------------------------------------------
Mulberry Technologies: A Consultancy Specializing in SGML and XML
======================================================================
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
--Chris
----------------------------------------------------------------------------------------
Texterity ~ XML and PDF ePublishing Services
----------------------------------------------------------------------------------------
Chris Loschen, XML Developer
Texterity, Inc.
144 Turnpike Road
Southborough, MA 01772 USA
tel: +1.508.804.3033
fax: +1.508.804.3110
email: loschen(_at_)texterity(_dot_)com
http://www.texterity.com/
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
|
|