Subject: Re: [xsl] Creating new, distinct groups of ranges from an aggregation of individual ranges From: "Heiko Niemann kontakt@xxxxxxxxxxxxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> Date: Tue, 18 Nov 2014 13:02:33 -0000 |
Hi Michael, this would be my solution: <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> <xsl:output method="xml" encoding="UTF-8"/> <xsl:variable as="element()+" name="bounds"> <xsl:for-each select="/ranges/range"> <xsl:for-each select="tokenize(string(.), ',')"> <bor val="{normalize-space(tokenize(.,'-')[1])}"/> <eor val="{normalize-space(tokenize(.,'-')[2])}"/> </xsl:for-each> </xsl:for-each> </xsl:variable> <xsl:variable as="element()" name="grouped"> <grouped> <xsl:for-each-group select="$bounds" group-by="@val"> <xsl:sort select="@val"/> <xsl:sequence select="current-group()[1]"/> </xsl:for-each-group> </grouped> </xsl:variable> <xsl:variable as="element()" name="completed"> <completed> <xsl:for-each select="$grouped/*"> <xsl:copy> <xsl:copy-of select="@*"/> <xsl:choose> <xsl:when test="local-name() = 'bor'"> <xsl:attribute select="following-sibling::bor[1]/@val - 1" name="end"/> </xsl:when> <xsl:otherwise> <xsl:attribute select="preceding-sibling::eor[1]/@val + 1" name="beg"/> </xsl:otherwise> </xsl:choose> </xsl:copy> </xsl:for-each> </completed> </xsl:variable> <xsl:template match="/"> <result> <bounds> <xsl:copy-of select="$bounds"/> </bounds> <grouped> <xsl:copy-of select="$grouped/*"/> </grouped> <completed> <xsl:copy-of select="$completed/*"/> </completed> <ranges> <xsl:for-each-group group-starting-with="bor | eor[preceding-sibling::*[1]/local-name() eq 'eor']" select="$completed/*"> <xsl:variable name="bor" select="current-group()[local-name() eq 'bor'][1]"/> <xsl:variable name="eor" select="current-group()[local-name() eq 'eor'][1]"/> <range> <xsl:value-of separator="-"> <xsl:sequence select="($bor/@val, $eor/@beg, 'err')[1]"/> <xsl:sequence select="($eor/@val, $bor/@end, 'err')[1]"/> </xsl:value-of> </range> </xsl:for-each-group> </ranges> </result> </xsl:template> </xsl:stylesheet> With this input: <ranges> <range>150-202</range> <range>201-225</range> <range>201-204</range> <range>205-234</range> <range>226-234, 250-260</range> </ranges> You'll get this output (which includes the results of the different steps): <result> <bounds> <bor val="150"/> <eor val="202"/> <bor val="201"/> <eor val="225"/> <bor val="201"/> <eor val="204"/> <bor val="205"/> <eor val="234"/> <bor val="226"/> <eor val="234"/> <bor val="250"/> <eor val="260"/> </bounds> <grouped> <bor val="150"/> <bor val="201"/> <eor val="202"/> <eor val="204"/> <bor val="205"/> <eor val="225"/> <bor val="226"/> <eor val="234"/> <bor val="250"/> <eor val="260"/> </grouped> <completed> <bor val="150" end="200"/> <bor val="201" end="204"/> <eor val="202" beg=""/> <eor val="204" beg="203"/> <bor val="205" end="225"/> <eor val="225" beg="205"/> <bor val="226" end="249"/> <eor val="234" beg="226"/> <bor val="250" end=""/> <eor val="260" beg="235"/> </completed> <ranges> <range>150-200</range> <range>201-202</range> <range>203-204</range> <range>205-225</range> <range>226-234</range> <range>250-260</range> </ranges> </result> So I take four steps: 1) extract beginning/end of range; create bor/eor elements for each; unsorted/duplicates 2) remove duplicates and sort bounds (which leaves out that there might be a bor and a eor that have the same value, but you did not mention what to do in this case, can be added I guess) So now I have a sequence of bor and eor elements which do not alternate yet, this means I will have to include a eor element when a bor follows a bor and vice versa. This is solved in step 4. 3) adding attributes for 'possible' beginning and end: each bor gets an end-Attribute with the value of the next following bor minus 1; each eor gets a beg-Attribute with the next preceding eor plus 1; the first eor and the last bor will be blank for those attributes which is ok since I assume they won't be needed because there should be a bor at the beginning of the sequence and an eor at the end. Anyhow I don't know yet whether these attributes will be needed but it is possible. 4) grouping: group starting either with a bor or an eor preceded by an eor. So a group will either consist of a single bor, a single eor or of bor and eor. So the start of a range will either be the value (@val) of bor or - if bor is absent - the 'possible' beg of eor. Similar logic for the end of a range. Hopefully it's not to confusing. The code probably can be optimized (I would like to know whether I could get rid of local-name() e.g.). Heiko > Greetings, > I'm trying to use XSLT 2.0 to create a new set of grouped ranges based on > the overlap of an aggregation of a set of non-contiguous individual > ranges. Example: > Given a range of numbers as an individual set:1. <range>150-202</range>2. > <range>201-225</range>3. <range>201-204</range>4. <range>205-234</range>5. > <range>226-234, 250-260</range> > I'm trying to produce a new grouping based on the way the groups > overlap:150-200 (this is where <range> 1 starts and overlaps to 2 & > 3)201-202 (this is where 1 & 2 overlap, and group 1 ends)203-204 (this is > where 2 & 3 overlap and 3 ends)205-225 (this is where 4 starts and begins > to overlap with 5)226-234 (this is where 4 & 5 overlap and end for the > first part of 5)250-260 (this is where the second range in 5 exists) > The start and end point of the individual source ranges form the > boundaries. > I expect to end up with a string or variable structure > like:<finalrange><range>150-200</range><range>201-202</range>etc</finalrange>or: > <range start="150" end="200"/><range start="201" end="202"/>etc > Ultimately I have to format some content in XSLFO based on the XML's > participation in the "new" given range grouping. If you know aircraft > effectivity, this is what I am trying to group. > I've been using <xsl:sequence> to find all the numbers of a single range, > so I can do compares against individual numbers in the entire range, if > necessary. But, it seems like it may be easier to just work with the > boundaries: the start and end points and see if a value falls within it, > somehow, rather than iterating repetitively through enumerations of > sequences. > I've been searching the archives for a while and have found some evocative > possibilities from Dimitre Novatchev and Michael Kay, but I can't quite > find a way to work with the overlapping. I'm continuing to study their > ranging/grouping examples, but help would be appreciated! > Thanks,Michael Friedman
Current Thread |
---|
|
<- Previous | Index | Next -> |
---|---|---|
Re: [xsl] Creating new, distinct gr, Wolfgang Laun wolfga | Thread | Re: [xsl] Creating new, distinct gr, Paul Tyson phtyson@x |
Re: [xsl] Creating new, distinct gr, Wolfgang Laun wolfga | Date | Re: [xsl] Creating new, distinct gr, Paul Tyson phtyson@x |
Month |