[XSL-LIST Mailing List Archive Home] [By Thread] [By Date] [Recent Entries] [Reply To This Message] Re: Creating new, distinct groups of ranges from an a
Given this already normalized input:
<ranges> <range start="150" end="202" n="1"/> <range start="201" end="225" n="2"/> <range start="201" end="204" n="3"/> <range start="205" end="234" n="4"/> <range start="226" end="234" n="5"/> <range start="250" end="260" n="6"/> </ranges> I'm applying a two-pass transformation: <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> <xsl:output indent="yes"/> <xsl:template match="/ranges"> <xsl:variable name="pass1" as="element(pass1)"> <pass1> <!-- eliminates duplicate start/end attributes and creates a new range for each distinct start and end value: --> <xsl:for-each-group select="range/(@start|@end)" group-by="string-join((name(), .), '=')"> <xsl:sort select="." data-type="number"/> <range> <xsl:sequence select="."/> <!-- adds a start attribute to the end attribute iff the start attribute's value is smaller than the end attribute's: --> <xsl:sequence select="../@start[. < current()]"/> </range> </xsl:for-each-group> </pass1> </xsl:variable> <xsl:variable name="pass2" as="element(pass2)"> <pass2> <!-- Replaces the existing start attribute with the nearest value available, looking behind (template with xml:id="B" below). Ranges without an end attribute will be eliminated by virtue of the built-in template. Except for the first range (template with xml:id="A" below): If it doesn't have an end attribute, and if its start attribute is not equal to the next range's start attribute, the next suitable end attribute will be added. --> <xsl:apply-templates select="$pass1/range" mode="pass2"/> </pass2> </xsl:variable> <result> <xsl:sequence select="$pass1"/> <xsl:sequence select="$pass2"/> </result> </xsl:template> <xsl:template mode="pass2" xml:id="A" match="range[1][not(@start = following-sibling::*[1]/@start)]"> <xsl:copy> <xsl:copy-of select="@start"/> <xsl:attribute name="end" select="following-sibling::range[@start][1]/@start - 1"/> </xsl:copy> </xsl:template> <xsl:template match="range[@end]" mode="pass2" xml:id="B"> <xsl:copy> <xsl:attribute name="start" select="max((@start, preceding-sibling::*[@start][1]/@start, preceding-sibling::*[@end][1]/@end + 1))"/> <xsl:copy-of select="@end"/> </xsl:copy> </xsl:template> </xsl:stylesheet> to receive this result: <?xml version="1.0" encoding="UTF-8"?> <result> <pass1> <range start="150"/> <range start="201"/> <range end="202" start="150"/> <range end="204" start="201"/> <range start="205"/> <range end="225" start="201"/> <range start="226"/> <range end="234" start="205"/> <range start="250"/> <range end="260" start="250"/> </pass1> <pass2> <range start="150" end="200"/> <range start="201" end="202"/> <range start="203" end="204"/> <range start="205" end="225"/> <range start="226" end="234"/> <range start="250" end="260"/> </pass2> </result> It doesn't feel particularly elegant. It almost has a slightly imperative feel about it, and it might appear inefficient at first due to the selections along the sibling axes. But the processor will probably see that these lookups will stop after the first sibling and therefore I think it should be sufficient. You might want to test whether all fringe cases have been taken into account. For example, change the first range's end attribute to something less than 201. Gerrit On 18.11.2014 06:06, Michael Friedman sumarimike@xxxxxxxxxxx wrote: Greetings,
Registergericht / Commercial Register: Amtsgericht Leipzig Registernummer / Registration Number: HRB 24930 GeschC$ftsfC<hrer: Gerrit Imsieke, Svea Jelonek, Thomas Schmidt, Dr. Reinhard VC6ckler
|
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
|