Wendell Piez wrote:
<xsl:apply-templates select=".//answers" />
Actually this should be "ancestor::*/answers", or
"ancestor::*[answers][1]/answers", shouldn't it?
".//answers" will search the subtree below the current node, rather
than look up the tree.
"ancestor::*/answers" will select answers elements from all ancestors;
"ancestor::*[answers][1]/answers" will select only the closest one. If
you think the latter expression is too opaque, you could also write
(ancestor::*/answers)[last()]
... and then try to explain that. :-)
Awe, yes, you are right of course! I always tell myself not to send out
technical messages in the middle of the night, even more so, not when
there's some beer around. But looking again now at his code, Steve
constructs one <div> element for each option element which is a child of
<questions> element. Which is interesting, because in his supplied
source, there isn't any at that level:
<questions>
<answers />
<question>
<answer>
<option>True</option>
<option>False</option>
</answer>
</question>
</questions>
which means that <xsl:template match="option" mode="q">... will never be
triggered by this snippet:
<xsl:template match="questions">
<xsl:apply-templates mode="q" select="option" />
<SNIP />
</xsl:template>
Following up the analysis, the <xsl:template match="answers" > contains
an xsl:if test="option" which can never be true either, considering the
sample source, the xsl:if encompassing the complete code block:
<xsl:template match="answers">
<xsl:param name="qKey" />
<xsl:if test="option">
.........
Steve, if you rewrite statements like that as this one above as:
<xsl:template match="answers[option]">
....
meaning: without the xsl:if completely, it will do the same and better.
You would benefit a great deal for clarity and you would much clearer
see and find where your code goes wrong. The way it is now it probably
doesn't output at all what you want. While rewriting, you will find the
problems and you can more easily fix them.
Wendell, considering the possible intent of Steve to wrap all output
inside one <div>, it is probably better if he does go back to using the
// syntax, but not in the way I proposed, but more like this (assuming
that the match="option" was a mistake from Steve, it doesn't even have
an @name, I replace it here with "section"):
<xsl:template match="section">
<div>
<span class="two"><label>
<xsl:value-of select="(@name | .)[1]" /> <!-- xslt 1.0
syntax now -->
</label></span>
<xsl:apply-template select=".//answers" />
</div>
</xsl:template>
<xsl:template match="answers[option]" >
<select>
<xsl:apply-templates select="option" />
</select>
</xsl:template>
<xsl:template match="option">
<option><xsl:value-of select="(@name | .)[1]" />
</xsl:template>
etc. etc. This roughly does the same as the whole structure that Steve
posted, but I left out the details (and some late-hour mistakes are
probably there: finders keepers). Steve, as you can see, you don't need
to test for the existence of a node before you use it. Just use
apply-templates, it does the "if"-ing for you.
Cheers,
-- Abel Braaksma