This is the mail archive of the
xsl-list@mulberrytech.com
mailing list .
Re: Newbie needs xsl
- To: roshansharma at hotmail dot com
- Subject: Re: [xsl] Newbie needs xsl
- From: Jeni Tennison <mail at jenitennison dot com>
- Date: Thu, 22 Feb 2001 22:25:59 +0000
- CC: xsl-list <xsl-list at lists dot mulberrytech dot com>
- Organization: Jeni Tennison Consulting Ltd
- References: <a05001902b6bb20699206@[192.168.254.9]>
- Reply-To: xsl-list at lists dot mulberrytech dot com
Hi Rosh,
> Thanks, this has been a tutorial for me. A question in line with
> this scenario - how do you propose applying templates if an
> element (office) forms sub-node as given below?
The template I showed you before was:
<xsl:template match="customer_name">
<!-- Customer Name -->
<xsl:text>Customer Name: </xsl:text><xsl:value-of select="@id" />
<!-- Revenue -->
<xsl:text>
 Revenue: $</xsl:text>
<xsl:value-of select="@revenue div 100" />
<!-- Office 1 -->
<xsl:text>
 Office1: </xsl:text>
<xsl:value-of select="substring-before(@office1, ' ')" />
<xsl:text>sq feet</xsl:text>
<!-- Office 2 -->
<xsl:if test="@office2">
<xsl:text>
 Office2: </xsl:text>
<xsl:value-of select="substring-before(@office2, ' ')" />
<xsl:text>sq feet</xsl:text>
</xsl:if>
<!-- More Customers -->
<xsl:apply-templates />
</xsl:template>
This assumed that the size of Office1 and Office2 were stored as
attributes on the customer_name element, so it accessed those values
through the paths:
@office1
@office2
Now you have them as children of the customer_name element, so you
need to change the paths that tell the processor how to get the
relevant values. The offices are represented by elements called
'office_name' with their 'id' attribute specifying whether they are
'office1' or 'office2'. The size of each office is stored in the
'space' attribute on the 'office_name' element.
Building a location path is all about thinking about where you're
starting from (the 'customer_name' element) and how you can navigate
through the node tree to get to where you want to go.
The first step in your path is to get the 'office_name' children of
'customer_name' (i.e. of the current node). For that you need the
path:
office_name
To get 'office1' you want the office_name element whose id attribute
is equal to the string 'office1'. You use a predicate to filter a set
of nodes to get only the ones you want:
office_name[@id = 'office1']
Now you've got the relevant 'office_name' element, to get its size,
you want that office_name element's 'space' attribute. That's another
step:
office_name[@id = 'office1']/@space
Similarly, you can get the relevant value for office2 through:
office_name[@id = 'office2']/@space
You need to put these location paths into the original template. You
also need to change the template so that it only applies templates to
its child customer_name elements - if you don't specify what it should
apply templates to, xsl:apply-templates applies templates to *all*
children of the current node, so it'll apply templates to the
office_name elements as well.
So you need to change the template to:
<xsl:template match="customer_name">
<!-- Customer Name -->
<xsl:text>Customer Name: </xsl:text><xsl:value-of select="@id" />
<!-- Revenue -->
<xsl:text>
 Revenue: $</xsl:text>
<xsl:value-of select="@revenue div 100" />
<!-- Office 1 -->
<xsl:text>
 Office1: </xsl:text>
<xsl:value-of
select="substring-before(office_name[@id = 'office1']/@space, ' ')" />
<xsl:text>sq feet</xsl:text>
<!-- Office 2 -->
<xsl:if test="office_name[@id = 'office2']">
<xsl:text>
 Office2: </xsl:text>
<xsl:value-of
select="substring-before(office_name[@id = 'office2']/@space, ' ')" />
<xsl:text>sq feet</xsl:text>
</xsl:if>
<!-- More Customers -->
<xsl:apply-templates select="customer_name" />
</xsl:template>
If you want to get those details about the offices through applying
templates instead (which is a good idea if you don't know how many
offices there are going to be), then you can apply templates to all
the office_name elements:
<xsl:template match="customer_name">
<!-- Customer Name -->
<xsl:text>Customer Name: </xsl:text><xsl:value-of select="@id" />
<!-- Revenue -->
<xsl:text>
 Revenue: $</xsl:text>
<xsl:value-of select="@revenue div 100" />
<!-- Offices -->
<xsl:apply-templates select="office_name" />
<!-- More Customers -->
<xsl:apply-templates select="customer_name" />
</xsl:template>
And then create a template for the office_name elements that gives the
relevant output:
<xsl:template match="office_name">
<xsl:text>
 </xsl:text>
<xsl:value-of select="@id" />
<xsl:text>: </xsl:text>
<xsl:value-of
select="substring-before(@space, ' ')" />
<xsl:text>sq feet</xsl:text>
</xsl:template>
> The reason I am asking is that xerces complained on an attempt to
> apply-template again when the name matches "office_name" saying that
> apply-template can be used only once in one match (namely
> customer_name). Alternate attempt to call-template also did not
> work.
It would be a lot easier to work out what was wrong in your code if
you showed us what it looked like. Perhaps you've got an
xsl:apply-templates element within another xsl:apply-templates element
or something?
[By the way, your XML as shown still isn't well formed - you've got
attributes in the end tags of the elements.]
I hope that helps,
Jeni
---
Jeni Tennison
http://www.jenitennison.com/
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list