[XSL-LIST Mailing List Archive Home]
[By Thread]
[By Date]
RE: [xsl] empty element as an end-marker
Subject: RE: [xsl] empty element as an end-marker From: "Michael Kay" <mhk@xxxxxxxxx> Date: Fri, 28 Mar 2003 09:41:37 -0000 |
These problems are slightly tricky, and the exact details of the solution depend on the exact nature of the problem. A typical example of the problem is to convert <p> line1<br/> line2<br/> linen </p> to <p> <line>line1</line> <line>line2</line> <line>linen</line> </p> The best way to tackle this, provided that it doesn't exceed the recusion depth allowed by most processors (say 1000), is to use apply-templates recursing along the following-sibling axis. In simple cases the following works: <xsl:template match="p"> <p> <xsl:apply-templates select="child::text()[1]" mode="along"/> </p> </xsl:template> <xsl:template match="text()" mode="along"> <line><xsl:value-of select="."/></line> <xsl:apply-templates select="following-sibling::text()[1]" mode="along"/> </xsl:template> Unfortunately this isn't very robust. Some processors (wrongly) split text nodes when entity references are encountered, and all (rightly) split them when comments are encountered; also your text might have other elements such as <i> embedded in it. So a more robust technique is to match the br elements, and each time you hit a br, copy all the preceding siblings whose next br element is this one. This can be done as follows: <xsl:template match="br" mode="along"> <xsl:copy-of select="preceding-sibling::node() [generate-id(following-sibling::br[1])=generate-id(current())]"/> <xsl:apply-templates select="following-sibling::br[1]"/> </xsl:template> Then you have to mop up the last group of elements (the ones that have no following br element) which you can do in the parent template. This has O(n^n) performance and it can recurse deeply, so it isn't ideal. A more efficient solution is to treat it as a grouping problem. The sibling elements between two br elements constitute a group, the grouping key for this group is the generate-id() of the most recent br (or p) element. So you can use Muenchian grouping with the grouping key: <xsl:key name="k" match="p/node()" use="concat(generate-id(..), generate-id(preceding-sibling::br[1]"/> It's easier in XSLT 2.0. If you can use Saxon 7.4, try: <xsl:for-each-group select="child::node()" group-starting-with="br"> <line><xsl:copy-of select="current-group()"/></line> </xsl:for-each-group> Michael Kay Software AG home: Michael.H.Kay@xxxxxxxxxxxx work: Michael.Kay@xxxxxxxxxxxxxx > -----Original Message----- > From: owner-xsl-list@xxxxxxxxxxxxxxxxxxxxxx > [mailto:owner-xsl-list@xxxxxxxxxxxxxxxxxxxxxx] On Behalf Of > Vincent Neyt > Sent: 28 March 2003 00:09 > To: XSL-List@xxxxxxxxxxxxxxxxxxxxxx > Subject: [xsl] empty element as an end-marker > > > Hello, > > my problem is easily explained. This is the simple xml: > > <p>some text some text <pb/>more text more text</p> > > In my (html) output I need to process and reproduce the 'some > text' (ie. up to the <pb/>) without the 'more text'. (Of > course I also need to output just the 'more text' in another > instance.) I'm having some trouble with this. Also the 'some > text' contains tags which need to be processed by the stylesheet. > > Sorry if this problem has been solved before, I searched the > archives and FAQ's using 'empty elements' and didn't find > anything. Thanx in advance, Vincent > > > > 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] empty element as an end-marke, Vincent Neyt | Thread | Re: [xsl] empty element as an end-m, Vincent Neyt |
AW: [xsl] identifying elements by c, Daniel Brauer | Date | RE: [xsl] matching on multiple attr, Michael Kay |
Month |
Keywords