This one ought to be extremely easy for experienced xslt-ers.

I have an html file, and in it are things like

<div class="ghoul"></div>
<div class="vampire></div>

and so on. In my stylesheet, I have different things to do with the div's depending on the class. So I have

<xsl:template match="div">
<xsl:choose>
<xsl:when test="@class='vampire'">
... do vampire stuff ..
</xsl:when>
<xsl:when test="@class='ghoul'">
... do ghoul stuff ..
</xsl>
</xsl:choose>
</xsl:template>

The idea is that I went the template to be applied differently to div's whose class is vampire than to those whose class is ghoul.

These matches do not happen at all. I can tell that because the framework in which I put the xslt file has debugging techniques available that prove it.

How do I separately match div's whose class is ghould and div's whose class is vampire?

Is it this what you've tried that didn't work?

<xsl:template match="div[@class='vampire']">
  ...
</xsl:template>
<xsl:template match="div[@class='ghoul']">
  ...
</xsl:template>

If so, do you have another template with:

<xsl:template match="div">
  ...
</xsl:template>

I had not yet tried what you suggested. A pity really, since it worked. Thank you for your assistance. Of course there is a follow-up question since, as always, solving one problem clears the way to the next problem which is soon stumbled upon. OK, we have what you suggested,

xsl:template match="div[@class='vampire']">
<xsl:apply-templates />
</xsl:template>

<xsl:template match="div[@class='ghoul']">
<xsl:apply-templates />
</xsl:template>

Outside of this template I have, among other things

<xsl:template match="//p">
...
</xsl:template>

This template picks up every <p> tag in the document. I want it to only pick up the <p> tags that are descendants of the <div class="vampire"> tag. I think I can come up with an ugly construction to solve this problem, but I am hoping there is a more straightforward, more aesthetic thing to do than what I have in mind. Is there?

Have you tried the decendant axis of xpath?.

If that does not work you can always use the @ caption command.

Have you tried the descendant axis of xpath?.

If that does not work you can always use the @ caption command.

Here is what I tried that gets me somewhere:

<xsl:template match="div[@class='vampire']//p">
<p:Para>
<xsl:apply-template />
</p>
</xsl:template>

There are several other html tags that I pick up the same way. They do get picked up. The problem is that so do several other div tags without the vampire attribute, but with other attributes that are irrelevant to me. I am at Witt's end.

This problem isn't complicated, but it's obvious we don't have the entire picture of what your transformation is trying to do. Why don't you provide a simple, stripped down input document. And the Target output document of what you want it to look like. Try and keep as simple as possible, but still at the root of your problem(s). Please use codeboxes as well.

I hope this gives you the entire picture, although I am making up what the task is really about since it is company proprietary, so we will pretend it is about vampires and ghouls.

My input file is an html file which comes in via an RSS feed.. I wish to get rid of all of the presentation material and just print the important paragraphs in my output. All of the important stuff for the output is contained within the

<div class="vampire">

tag. My task is to extract that text contained in <p> tags, <pre> tags, and <table> tags.

My approach was to start like this:<

<xsl:template match="/">
<xsl:apply-templates />
</xsl:template>

<!-- Block all the built-in templates so that only tags in the templates that we custom make are printed in the new file -->

<xsl:template match="*" priority="-1">
<xsl:apply-templates />
</xsl:template>

<xsl:template match="div[@class='vampire']//p">
<xsl:apply-templates />
</xsl:template>"


much etc. ...

The text in the <p> tags that lie in the div tags with their class attribute set to vampire do show up in th output, but so does the content of the div tags with their class attribute set to cuddlybinks.

What's going on, and how do I stop the descendants and contents of the wrong divs.

Alrighty, so in order t get to the tags that you want, I've constructed a MOCK XML document (like I wanted you to do) to help illustrate your problem.

The input document looks like this:

<html>
	<head>Head</head>
	<body>
		<h1>H1 Text</h1>
		<h2>First Group of Divs</h2>
		<div class="vampire">
			<p>First Vampire Text</p>
			<anothertag>
				<p>First Nested Vampire Text</p>
			</anothertag>
			<div class="werewolf">
				<p>First Werewolf Text</p>
				<div class="ghoul">
					<p>First Ghoul Text</p>
				</div>
			</div>
		</div>
		<h2>Second Group Group of Divs</h2>
		<div class="Werewolf">
			<p>First Werewolf Text</p>
			<div class="vampire">
				<p>Second Vampire Text</p>
			</div>
		</div>
	</body>
</html>

Ir order to get the "p" nodes that I want, I'm going to make use of the ancestor:: axis in the following xpath.

//p[ancestor::div[1][@class = 'vampire'] or ancestor::div[1][@class = 'ghoul']]

Which produces:

<p>First Vampire Text</p>
<p>First Nested Vampire Text</p>
<p>First Ghoul Text</p>
<p>Second Vampire Text</p>

This XPath basically means the the follow. Get me every "p" node in the document, whose FIRST ancestor is a "div" node that has a class of vampire or ghoul. The result of this even gets the 'First Nested Vampire Text'. Even though there's other tags between it and it's ancestor "div" node, it's still part of that "div".

The reason it gets the 'First Ghoul Text' is because the FIRST ancestor is of class 'ghoul'. Even though it has both a 'vampire' and 'werewolf' ancestor as well, the FIRST one what counts as part of that XPath.

Hopefully that works.

This was a truly great answer. I appreciate the time and effort you must have used to both show me a technique I didn't know and to show me what could happen in various situations related to what I said. So I tried it, of course. If only it had worked. I picked up everything that I was looking for, but I also picked up other stuff. There are two possible things that could have gone wrong. First of all, my tags are all really in namespaces. My html tags are all prefaced by html:, and they are all the tags in the file that I am transforming. The other possibility is that the framework I am in has changed all the documents in ways that screw up what you said. I am working in a framework of many programs being run, and I am fairly new here, so I don't really know what is going on yet. I worked out another, and far more time-consuming way to solve the problem that I had to solve and moved on, but I would still like to know if there were any syntax problems in what I did, or else anything wrong with the logic begind what I did. Someday I will get back to it.

No everything you did was fine. XML documents and their design and structure can become very complicated. Obviously the document you're trying to process isn't exactly the way your described it, or my solution (or a variation) would work correctly.

In order to solve this, I'd have to have a full understand of the design and structure of your input document along with your desired output. At that point you might as well start paying me as a consultant :)

Yes, of course. My company requires me to obscure what I am doing. It was only yesterday that I learned what the real input to my stylesheet looked like. The part I see is manipulated before it gets to the stylesheet. I have just began (maybe a month on and off mostly off) using XSLT and it ain't so easy. My beginners book is over 700 pages long, and while the pace is quite slow, there is still a lot of material in it. Even the local guru at my company couldn't solve some of the problems. I greatly appreciate the effort and time you have put in. They have opened up some areas of the XSLT to me that I was quite unaware of.

This article has been dead for over six months. Start a new discussion instead.