Subject: Re: [xsl] Newbie needs xsl From: Jeni Tennison <mail@xxxxxxxxxxxxxxxx> Date: Thu, 22 Feb 2001 22:25:59 +0000 |
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
Current Thread |
---|
|
<- Previous | Index | Next -> |
---|---|---|
Re:[xsl] Newbie needs xsl, by way of Mulberry T | Thread | Re: The top 10 limitations of XSLT , Clark C. Evans |
Re: Designs for XSLT functions (Was, Jeni Tennison | Date | Re: [xsl] Test for PCDATA, Jeni Tennison |
Month |