Hi, Max,
Slow day here, as I am waiting on a developer for a number of source
files. So I can answer your questions between rounds of extending my
XSL-based document production system to include JavaHelp output (in
addition to its current PDF and HTML output). Also, SST is generous with
regard to letting me contribute to the list.
Anywho, you've run into the common problem of needing to know the
structure of the source XML So, <xsl:value-of select="fName"/> won't find
anything unless the children (not grandchildren) of the current match
include fName nodes. I hesitate to mention this, but you can get there by
using select=".//fName". That returns the value of any descendant fName
element. I hesitate because // is bad practice in most cases (it exists
because it's needed in other cases, of course). The trouble with // is
that it can be very inefficient (especially at the root level) and can
return multiple nodes, which can either cause your XSLT processor to exit
with an error or produce garbage in your output. It's generally better to
specify the full path down to the node you want.
Assuming that you have many <directory> elements within some parent
element (I'll call it directories for demonstration purposes), you might
try a for-each kind of solution. So, if your source XML looks like this:
<directories>
<directory>
<!-- The structure you showed us earlier here -->
</directory>
<directory>
<!-- The structure you showed us earlier here -->
</directory>
<!-- and so on many times -->
</directories>
Then you could do something like this:
<xsl:template match="directories">
<table>
<xsl:for-each select="directory">
<!-- Reach down the tree to get the bits you need to insert as rows
-->
</xsl:for-each>
</table>
</xsl:template>
Mind you, <xsl:apply-templates/> would work just fine here and be
preferred (match and apply is XSLT's natural processing model), but I'm
guessing you have additional complexity that might make for-each more
workable.
I'm also guessing (would need a bigger sample of your data to be sure)
that you have a much deeper and nastier problem: grouping. I'm guessing
that you want to list all the folks in the Biology department together but
that your data is structured such that you have a listing for each person
rather than by department. If you are using an XSLT 2.0 processor (such as
Saxon), that's not too hard (xsl:for-each-group is your friend there). If
you're using XSLT 1.0, you can do it in several different ways. Exactly
which is easiest to understand and implement depends on the structure of
your source file.
HTH
Jay Bryant
Bryant Communication Services
(presently consulting at Synergistic Solution Technologies)
Max Bronsema <max(_dot_)bronsema(_at_)gmail(_dot_)com>
05/03/2005 11:23 AM
Please respond to
xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com
To
xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com
cc
Subject
Re: [xsl] Trouble creating a table with multiple named templates
Hi again Jay,
I hope I am not keeping you from doing your real consulting work :),
thank you for the code below. It works as you said it would. I had
butchered some XSL to get that same result before but ran into the
problem of it not going through the entire XML tree. The same thing is
happening here except your code is much much better. I am able to have
it work through the tree when I just list an element by it's name and
do not use XPATH.
Example
<td><xsl:value-of select="fName"/></td>
Alas, that only works if I use an XPATH location in the match portion
of the template tag.
Example
<template match="directory/staffOffice/Office">
Then it will iterate through the entire tree for that portion. Is this
caused by having the extra node staffOffice? What is the next step I
should try?
Oh, and Boone as I am refering to it is a building at the location of
where I work.
Thanks again,
Max
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="directory">
<table>
<tr>
<td><xsl:value-of select="staffOffice/Office/dptFull"/></td>
</tr>
<tr>
<td><xsl:value-of select="staffOffice/Office/Location"/></td>
<td><xsl:value-of select="staffTitle/Position/phone"/></td>
<!-- No fax or box in the sample, so skipped -->
</tr>
<tr>
<td>
<xsl:value-of
select="normalize-space(staffPersonal/Person/lName)"/>
<xsl:text>, </xsl:text>
<xsl:value-of
select="normalize-space(staffPersonal/Person/fName)"/>
</td>
<td><xsl:value-of select="staffTitle/Position/phone"/></td>
<td><xsl:value-of select="staffTitle/Position/pEmail"/></td>
<!-- No title in sample, so skipped -->
<td><xsl:value-of select="staffOffice/Office/Location"/></td>
</tr>
</table>
</xsl:template>
</xsl:stylesheet>
Produces this HTML fragment:
<table>
<tr>
<td>Biology</td>
</tr>
<tr>
<td>Boone</td>
<td>xxx-xxxx</td>
</tr>
<tr>
<td>last Name, first Name</td>
<td>xxx-xxxx</td>
<td>xyxy(_at_)tttt(_dot_)com</td>
<td>Boone</td>
</tr>
</table>
I used the normalize-space function to remove the trailing spaces on the
names. Otherwise, I got a space before the comma.
I'm sure your data is more complex, but I hope this small stylesheet
gives
you one idea for how to approach your problem. Other solutions exist.
If you run into trouble, let us know.
(That wouldn't be Boone, IA, would it?)
Jay Bryant
Bryant Communication Services
(presently consulting at Synergistic Solution Technologies)
--~------------------------------------------------------------------
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>
--~--
--~------------------------------------------------------------------
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>
--~--