[XSL-LIST Mailing List Archive Home] [By Thread] [By Date] [Recent Entries] [Reply To This Message] Re: Grouping repeating elements
On Wed, 11 Jul 2001 11:57:07 +0100, Wendell wrote: >Hi Till, > >At 10:12 AM 7/11/01, Trevor wrote: >[snip] >>Have a template matching "name". >>In the body of this template create the target <person> element, >>copying the matched <name> element, e.g. using copy-of. >>To handle elements which always appear, use copy-of with >>following-sibling to get the *first* element after the name of the >>given type. Get this working first, and see that 'phil' ends up with >>age 28. Make sure everyone gets just one age! >>When you have that XPath right, you now have to add a condition that >>the node you find matches the current <name> node and not a later one. >>So, add a further condition that the <name> node before the one you >>have found is the same node as the one matched in your template: use >>preceding-sibling and generate-id(). >> >>Have a try at this yourself, if you get stuck ask again. > >And after you've got it working, ask again and we'll tell you about the >Advanced Technique using keys (the Topic of the Week) to simplify such >"levitation" problems (by which I mean making implicit structures explicit).... > >Cheers, >Wendell > I think what Wendell is referring to is that instead of writing this (tested with Saxon 6.0.2) (a) : <xsl:template match="name"> <person> <xsl:variable name="id" select="generate-id()" /> <xsl:copy-of select="."/> <xsl:copy-of select="following-sibling::firstname[1]"/> <xsl:copy-of select="following-sibling::age[1] [generate-id(preceding-sibling::name[1])=$id]" /> </person> </xsl:template> <xsl:template match="firstname|age" /> You can write (b): <xsl:key name="following-name" match="firstname|age" use="generate-id(preceding-sibling::name[1])" /> <xsl:template match="name"> <person> <xsl:copy-of select=".|key('following-name', generate-id())" /> </person> </xsl:template> </xsl:stylesheet> <xsl:template match="firstname|age" /> This is not exactly equivalent: - if your input contained <name/><age/><age/><name/>... then the key method copies both <age/> elements, while (a) copies only the first. This may or may not be what is needed. - the key method copies elements in the order they appear in the input document, rather than in an order you specify (this can be changed, but then you lose some of the brevity which is a main attraction of using keys) - if you are dealing with large documents, the performance characteristic of the first method is better, as long as you have a processor which takes the obvious short cut when it sees expressions like following-sibling::x[1]. If it doesn't, the key method is better, but you are likely in trouble with either approach. BTW you can get from (a) to (b) with some simple algebra. The core of method (a) is the expression: following-sibling::age[1] [generate-id(preceding-sibling::name[1])=$id] If there is at most one <age/> element between each <name/> then this is equivalent to: //age[generate-id(preceding-sibling::name[1])=$id] which is an example of a general form //pattern[f(.)=string-value] where f is a function returning a string. Whenever you see this you can rewrite it as: <xsl:key name="k" match="pattern" use="f(.)" /> and then key ('k', string-value) I hope somebody else enjoyed that too ;-) Regards, Trevor Nash -- Traditional training & distance learning, Consultancy by email Melvaig Software Engineering Limited voice: +44 (0) 1445 771 271 email: tcn@xxxxxxxxxxxxx XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
|
PURCHASE STYLUS STUDIO ONLINE TODAY!Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced! Download The World's Best XML IDE!Accelerate XML development with our award-winning XML IDE - Download a free trial today! Subscribe in XML format
|