Subject: RE: [xsl] Wrapping consecutive similar elements inside a new pare nt element From: Stuart Brown <sbrown@xxxxxxxxxxx> Date: Fri, 14 Feb 2003 12:12:26 -0000 |
Hi Graham, What you want to do is select all the <p> elements which start with span, but whose immediate preceding siblings does not start with span. This selects the first element in the list. You then output the ul and handle the first list item. You then need to step down the following elements, each time handling them if they are another list item, and quitting the recursion if they are not. So: <!-- This template matches the a p with first child of span whose first preceding sibling is not a p with a first child of span, i.e. the first item in a list. --> <xsl:template match="p[*[1]/self::span][not(preceding-sibling::*[1][self::p][*[1]/self::sp an])]"> <!-- We output the ul element and process the first item --> <ul> <li><xsl:apply-templates/></li> <!-- We then call a template to check the following element (note we are still "within" the ul) --> <xsl:call-template name="followingItem"/> </ul> </xsl:template> <xsl:template name="followingItem"> <!-- This now moves the current node to the first following sibling IF it is a p AND it has a span (i.e. it is a list item) --> <xsl:for-each select="following-sibling::*[1][self::p][*[1]/self::span]"> <!-- Output the item, and call the template again. Note that when the condition fails (there is an ordinary p) the for-each of this template will not return a node and so the recursion will be exited as the recursive call is within the for-each --> <li><xsl:apply-templates/></li> <xsl:call-template name="followingItem"/> </xsl:for-each> </xsl:template> <xsl:template match="p"> <!-- Standard para --> <p><xsl:apply-templates/></p> </xsl:template> <xsl:template match="p[*[1]/self::span][preceding-sibling::*[1][self::p][*[1]/self::span]] "/> <!-- This prevents the subsequent list items being processed a second time outside of the ul --> Note that starts-with() only checks the text value of a node. If you want to check the first element child of a node use *[1]/self::myName as above (not myName[1], which returns the first myName whether or not it is the first child). Note also that I have assumed that a paragraph whose first child is span is always a list item (i.e. I have omitted the test for "-") for (relative) clarity of the XPaths. If you want to test for that as well, change the [*[1]/self::span] predicates to [starts-with(*[1]/self::span),'-')] wherever they occur. Hope that helps, Stuart > -----Original Message----- > From: Graham Hannington [mailto:Ghannington@xxxxxxx] > Sent: 14 February 2003 11:10 > To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx > Subject: [xsl] Wrapping consecutive similar elements inside a > new parent > element > > > I'm cleaning up HTML exported from Word documents. First, I > run Tidy again > the exported HTML, to convert it to well-formed XHTML, then I > transform it > with my own XSLT stylesheet. > > I need to convert (this is slightly simplified): > > > <p>Some paragraph that does not begin with a span element whose first > character is a hyphen.</p> > <p><span>-</span>List item</p> > <p><span>-</span>List item</p> > <p><span>-</span>List item</p> > <p><span>-</span>List item</p> > <p>Some paragraph that does not begin with a span element whose first > character is a hyphen.</p> > <p><span>-</span>List item</p> > <p><span>-</span>List item</p> > <p><span>-</span>List item</p> > <p><span>-</span>List item</p> > <p>Some paragraph that does not begin with a span element whose first > character is a hyphen.</p> > > > into this: > > > <p>Some paragraph that does not begin with a span element whose first > character is a hyphen.</p> > <ul> > <li>List item</li> > <li>List item</li> > <li>List item</li> > <li>List item</li> > </ul> > <p>Some paragraph that does not begin with a span element whose first > character is a hyphen.</p> > <ul> > <li>List item</li> > <li>List item</li> > <li>List item</li> > <li>List item</li> > </ul> > <p>Some paragraph that does not begin with a span element whose first > character is a hyphen.</p> > > > I'm afraid my attempts at this have been truly pitiful: > > > <xsl:template match="p[starts-with(span[1], '-')]"> > > <xsl:if > test="not(starts-with(preceding-sibling::p[1]/span[1], '-'))"> > <xsl:text><ul></xsl:text> > </xsl:if> > > <li> > <xsl:apply-templates /> > </li> > > <xsl:if > test="not(starts-with(following-sibling::p[1]/span[1], '-'))"> > <xsl:text></ul></xsl:text> > </xsl:if> > </xsl:template> > > > I know, I know: those <xsl:text><ul></xsl:text> bits > are a joke, they > don't produce the <ul> parent element. > > I've tried writing a template that uses <xsl:for-each>, but > that ends up > grabbing all following-sibling <p> elements that begin with > <span>-</span>. > I don't know how to stop the <xsl:for-each> at the first > non-matching <p> > element. > > Can anyone throw me an XSLT pearl? > > XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list > XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
Current Thread |
---|
|
<- Previous | Index | Next -> |
---|---|---|
[xsl] Wrapping consecutive similar , Graham Hannington | Thread | RE: [xsl] Wrapping consecutive simi, Yates, Danny (ANTS) |
RE: [xsl] Reference to variable can, Andrew Welch | Date | Re: [xsl] Reference to variable can, David Carlisle |
Month |