Hey Ben,
Brutal honesty... gotta love it :)
The simplest way to both explain and to understand what apply-templates does is
as such. The following XML is a representation of circles, squares, and
triangles. Each shape has the ability to be one of three colors: red, yellow,
and blue. As such there is a possibility of 9 different combinations of of
colors and shapes. Youve been given the task to find all shapes that are yellow
and put them in the basket labeled yellow. One other thing: Im also going to
create a "Path" reference that represents the structure of the XML if which we
will first make a copy of its current state and then simply subtract from that
copy either a "/" or an element name and its following "/" seperator each time
we use the match attribute to match an element or attribute. This way we can
keep track of where we are in context to the overall XML structure.
The XML:
<shapes>
<shape type="triangle" color="red"/>
<shape type="triangle" color="yellow"/>
<shape type="triangle" color="blue"/>
<shape type="square" color="red"/>
<shape type="square" color="yellow"/>
<shape type="square" color="blue"/>
<shape type="circle" color="red"/>
<shape type="circle" color="yellow"/>
<shape type="circle" color="blue"/>
</shapes>
The XPath:
/shapes/shape
Keep in mind that unless we specify otherwise the last element specified in an
XPath statement will grab its attributes and children and pack them up for the
ride ahead of them.
Now we'll use XSLT to represent two things:
You (your job being to go through each shape, find those that are yellow, and
put them in the basket labeled yellow).
and
The basket labeled yellow
<xsl:template match="/">
<!-- this template represents you -->
<!-- because we used the match element to select the root of the tree structure
we make a copy of the above XPath -(minus) the first "/". So now we have
"shapes/shape" of which we make a mental copy of and take with us to look at
later -->
<!-- the following "apply-templates" element represents the mechanisms of
deciding which shapes match your job criteris and any other specific information
necessary to determine what to do with the shapes that have met your criteria.
The "select" attribute does basically what it sounds like... it selects XML
elements and/or attributes that match the instructions contained inside of it...
The following apply-templates element will pick out ALL shape elements who's
color is equal to yellow -->
<xsl:apply-templates select="shapes/shape[(_at_)color = 'yellow']" />
<!-- what we have just done is told the processor to take all elements (keep the
copy of the XPath in your head while writing the above statement to ensure you
use the right syntax to select the right elements and/or attributes) that have a
color attribute that is equal to yellow and then go through each template in the
XSLT tree structure and use the match attribute to find the closest match to
each selected element and stick that element (remember, its still packing the
attributes and its children right along with it) into the template whos match
attribute is the closest in describing that element, its attributes, and/or its
children. Our Result Tree Fragment of elements that have been selected by the
processor looks like this:
<shape type="triangle" color="yellow"/>
<shape type="square" color="yellow"/>
<shape type="circle" color="yellow"/>
Keep in mind that apply-templates is'nt going anywhere. It takes each element
and sends it out into the processors ether to be matched to its closest matching
template. When apply-templates has finished its list of elements the processor
then looks to the next element after apply-templates which in our case is
nothing, so the process as far as this template is concerned is done... well,
unless the closest match to an element is this template... then this template
has to decide what to do with the matching element in the same way it had to
decide what to do with all the elements that matched it the first time round
when "/" matched the root element of our XML tree.
So, lets go see what happened to all of the elements we just sent out of here...
-->
</xsl:template>
<xsl:template match="shape[(_at_)color = 'red']">
I am a red <xsl:value-of select="@shape"/>. <br/>
</xsl:template>
<xsl:template match="shape[(_at_)color = 'yellow']">
I am a yellow <xsl:value-of select="@shape"/>. <br/>
</xsl:template>
<xsl:template match="shape[(_at_)color = 'blue']">
I am a blue <xsl:value-of select="@shape"/>. <br/>
</xsl:template>
As should be fairly obvious each of the elements selected by the XPath contained
in the "select" attribute of the apply-templates element was passed into the
processors ether and matched against each templates match attribute. The match
attribute that best described the element at hand was then given the honor of
handling this element as it so pleased... in this case its pleasure what to
write to the output stream "I am a yellow " and then name of the shape contained
in the "shape" attribute. And if you remembered to make a copy of the XPath and
then subtracted the element (keep in memory a copy of its name, value, any
attributes, and its children but erase from our "frame of reference" the XPath
contained in the match attribute so that we can remember how to properly
reference any child elements and attributes as we continue through the process.
In this case the only thing we have left is the attributes so our frame of
reference is now empty... but if there were any children... say a child element
called "size"... then after subtracting "shape" and the following "/" seperator
from our frame of reference we have "size" as the remaining element(s) structure
referenced in your new copy of the XPath frame of reference... this is important
to remember if you decide that you want to use another apply-templates inside of
the "yellow" template and match all "size" elements to another template
somewhere in our tree structure... but for now we'll just leave it as is and
call the job complete.
So, after all is said and done by the matching "yellow" template our output
looks like:
I am a yellow triangle. <br/>
I am a yellow square. <br/>
I am a yellow circle. <br/>
Ok, thats the basics of apply-templates... I hope this helps in your
understanding!!!! I realize this was a REALLY basic way to describe things and
as such I should emphasize that I am in no way trying to make light of anything
or anybody... This is just the simplest way to describe how apply-temnplates
works and I have found that by using this or something similar to it people have
a tendency to immediatelly say "ah! got it! :)" and then are able to take it
from there...
Best of luck to you!
Regards,
<M:D/>
Ben Simkins wrote:
2. Transforming 'flat' structures to hierarchies:
....
Wrap the first apply-templates into a variable, use your processors
node-
set()
function (see your processors documentation on how to implment this)
to
convert
the result into a node-set and then apply-templates or for-each
through
the
resulting node-set using <xsl:number/> to accomplish the task
I'm supposed to be doing something else, but I just had to try this out
:)
Having 'learnt' XSL by cut and paste, I think I'm still at the stage
where I need subtitles.
I added xmlns:msxsl="urn:schemas-microsoft-com:xslt" to my
xsl:stylesheet declaration, and my first template now looks like this:
<xsl:template match="/">
<xsl:variable name="menus">
<xsl:apply-templates select="Menus"/>
</xsl:variable>
<xsl:for-each select="msxsl:node-set($menus)">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:attribute name="TOC">
<xsl:number level="multiple" format="1.1"/>
</xsl:attribute>
</xsl:copy>
</xsl:for-each>
</xsl:template>
Obviously, it doesn't work, otherwise I wouldn't be posting. I guess
what I don't understand is whether my for-each is for each node in the
nodeset. You suggested mayb using an apply-templates, but I don't
really understand how to do an apply templates which won't eat my other
menus upstream (ok, I'll be honest, I just don't understand
apply-templates ;)
Ben
--+------------------------------------------------------------------
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>
--+--