Subject: Re: How would you add depth to this flat XML source? From: Jeni Tennison <Jeni.Tennison@xxxxxxxxxxxxxxxx> Date: Fri, 26 May 2000 11:46:06 +0100 |
Eric, >It seems to me that I can process each <firstitem> element and then apply >templates to all of the following-siblings that have their first <firstitem> >preceding-sibling equal to the current <firstitem>. But, a) I can't seem to get >the syntax right for this solution, b) this seems like an odd way to solve the >problem, and c) somebody probably knows an easier way. There are definitely other approaches (like you could use an xsl:for-each rather than applying templates), but your approach is an eminently reasonable one, and the biggest problem, the XPath expression, applies in both, so let's see if we can get the syntax working. I don't know how far you've got with it, so forgive me if I go through everything just in case! First you want to "process each <firstitem> element". You do that with a template matching that kind of element, so: <xsl:template match="firstitem"> ... </xsl:template> Second, and importantly, you *only* want to process those firstitem elements. That means that the template that matches whatever element your firstitems and items are children of has to only be applying templates to the firstitem. I'll assume that they're children of an 'items' element: <xsl:template match="items"> <xsl:apply-templates select="firstitem" /> </xsl:template> Third, you want to "apply templates to all of the following-siblings that have their first <firstitem> preceding-sibling equal to the current <firstitem>". Applying templates to a node list is easy: <xsl:apply-templates select="..." /> The thing that's difficult is generating the node list! Let's take it a step at a time: 1. "all of the following-siblings..." Actually, you're not interested in *all* of the following-sibling nodes, just in the 'item' elements. The XPath for that is: following-sibling::item In David Carlisle's human-speak, this is "all items that are following siblings". 2. "...that have..." Here you're narrowing the list you've got by putting an extra condition on it, so you use a predicate: following-sibling::item[...] 3. "...their first <firstitem> preceding-sibling..." or 'the first preceding-sibling that is a firstitem': preceding-sibling::firstitem[1] 4. "...the current <firstitem>..." This could be a little tricky because when we're in the predicate that we're currently in, the *context node* is an item. We want the *current node*, which we know is a firstitem (because that's what this template is matching on) and that we get using: current() 5. "...equal to..." Now we get into a bit of a murky area that I got confused by myself recently. We want to make sure that the *node* that is 'the first preceding-sibling that is a firstitem' is the same as the *node* that is 'the current node'. There are two ways of doing that: a. generate a unique identifier for the two nodes and compare them: generate-id(preceding-sibling::firstitem[1]) = generate-id(current()) b. make a set that is the union of the two nodes and see how many elements are in it - if they're the same node, then the answer is 1: count(preceding-sibling::firstitem[1] | current()) = 1 I'm going to use the first because it makes more sense to me. We have our XPath expression: following-sibling::item[generate-id(preceding-sibling::firstitem[1]) = generate-id(current())] So we slot that into our xsl:apply-templates, and put that into our firstitem-matching template: <xsl:template match="firstitem"> ... <xsl:apply-templates select="following-sibling::item[generate-id(preceding-sibling::firstitem[1]) = generate-id(current())]" /> ... </xsl:template> What have we forgotten? Oh yes, the output! For each 'firstitem', we want to have a 'list', with the first 'item' having the content of the 'firstitem' and the other 'item's being copies of the original ones. <xsl:template match="firstitem"> <list> <item><xsl:value-of select="." /></item> <xsl:apply-templates select="following-sibling::item[generate-id(preceding-sibling::firstitem[1]) = generate-id(current())]" /> </list> </xsl:template> <xsl:template match="item"> <xsl:copy-of select="." /> </xsl:template> I've tested the full stylesheet (below) in SAXON and it works. Hope that helps, Jeni ----8<---- <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output indent="yes" /> <xsl:template match="items"> <xsl:apply-templates select="firstitem" /> </xsl:template> <xsl:template match="firstitem"> <list> <item><xsl:value-of select="." /></item> <xsl:apply-templates select="following-sibling::item[generate-id(preceding-sibling::firstitem[1]) = generate-id(current())]" /> </list> </xsl:template> <xsl:template match="item"> <xsl:copy-of select="." /> </xsl:template> </xsl:stylesheet> ----8<---- XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
Current Thread |
---|
|
<- Previous | Index | Next -> |
---|---|---|
How would you add depth to this fla, Eric G. Bosch | Thread | Re: How would you add depth to this, Eric G. Bosch |
Re: XT and SAXON treats //ccc and /, Matt Sergeant | Date | Re: human-talk for "::", Juergen Hermann |
Month |