As Janning said, what's happening is that an XSLT stylesheet (actually,
the XSLT processor) comes with built-in template rules which apply if
there's no explicit template rule for a given node. Then one solution,
if this creates problems, is to override these built-ins, as he sort of
Janning Vygen wrote:
> <xsl:template match="/">
> <xsl:apply-templates select="Contents"/>
However, you'll find that this also doesn't quite work. The
xsl:apply-templates element says to look for and apply any template
rules in effect for *children* of the current node. By using the select
attribute, you're saying to do so for only the specified child(ren), not
*all* children, of the current node.
In the above, the current node -- set by the match="/" -- is the source
tree's root node. That has exactly one child, the root ELEMENT named
"Book." The select attribute says to process only the child(ren) named
"Contents"; since the current node has no such children, the effect is
to suppress the output explicitly associated with ANY children of the
The simplest way to fix this is to replace the "/" match pattern with
"Book" -- because that element does indeed have a child named
"Contents." And by using an explicit select="Contents" attribute,
Janning has effectively suppressed the contents of the Title element,
which is one effect you sought.
But then the XSLT processor hits this in Janning's solution:
> <xsl:template match="Contents">
> <xsl:for-each select="Chapters">
> <xsl:apply-templates select = "Heading"/><hr></hr>
This template rule is not fired as a result of the earlier
xsl:apply-templates (for children of the root node), because (as I
explained) there are NO children of the root node named "Contents."
Rather, it's fired for the simplest of reasons -- because its match
pattern corresponds to the name of an element type in the source tree.
There's exactly one such element in your sample XML, so this template
rule will fire exactly once.
Unfortunately this template rule is just a little bit scrambled,
although it's headed in the right direction. The problem is the
xsl:apply-templates WITHIN the xsl:for-each. You don't need that. Just
do this instead:
The xsl:value-of element transfers text content from the source to the
result tree. The XPath expression used as the value of the select
attribute is relative to the context node, which (here) is the Chapters
element currently being processed by the xsl:for-each. That is, the
xsl:value-of gets the Heading CHILD of the current Chapters element, and
transfers it to the result tree. The rest of the template consists of
just a horizontal rule.
You'll find that there are still some problems with the stylesheet,
aside from the above:
(1) The correct namespace declaration for elements in the XSLT namespace is:
(2) Your xsl:stylesheet element also needs to include a version="1.0"
(3) You probably don't need the xsl:output element here, but if you want
to use it I suggest making the value of its method attribute value all
lowercase, e.g. method="html". (Some processors may forgive the
uppercase, even though it's not a legitimate value.)
After fixing all this up and running the code through the Saxon XSLT
processor, you get a result tree which looks like this (I added a title
element to the head, which helps confirm that the template rule for the
root Book element is firing correctly):
intro to Java
<hr>Creating First Java Program
<hr>Writing thread based applications
<hr>Socket Programming in JAVA
Which I think is what you were after.
John E. Simpson | "When I was a little kid we had a sand
http://www.flixml.org | box. It was a quicksand box. I was an
XML Q&A: www.xml.com | only child... eventually." (Steven Wright)