[XSL-LIST Mailing List Archive Home]
[By Thread]
[By Date]
Hi Heiko & Michael,
On 19.11.2014 02:20, Heiko Niemann kontakt@xxxxxxxxxxxxxxxx wrote:
I emitted an xsl:message that would report any input token that doesnbt match '^\d{4}(\d{4})?$'. It might be a better idea to add terminate="yes" to that message instead of heuristically fixing the data, but Ibm not the one to make a call on this.
Youbre right, therebs still a bug. The matching pattern in the template with xml:id="A" should be changed from
match="range[1][not(@start = following-sibling::*[1]/@start)]"
to
match="range[1][not(@start = following-sibling::*[1]/(@start|@end))]"
Letbs see which other bugs are left uncovered by our anecdotal test cases. Ibm waiting for the FAA to knock on my door in order to investigate a future fatal incident caused by flaky XSLT codeb&
Ibm posting the complete revised code below. There are no templates in #default mode any more which should help in integrating the code. Ibve added a debug parameter. Apply aircrafts.xsl with debug=yes to get the intermediate stepsb results in /ranges/debug in the output.
Gerrit
----------------------
ranges.xsl
<xsl:param name="debug" select="'yes'"/>
<xsl:template match="ranges" mode="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>
<!-- Fill gaps with new ranges (Heikobs test case) -->
<xsl:apply-templates select="$pass1/range" mode="ranges_pass2"/>
</pass2>
</xsl:variable>
<xsl:variable name="pass3" as="element(pass3)">
<pass3>
<!-- 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="$pass2/range" mode="ranges_pass3"/>
</pass3>
</xsl:variable>
<ranges>
<xsl:if test="$debug = 'yes'">
<debug>
<xsl:sequence select="."/>
<xsl:sequence select="$pass1"/>
<xsl:sequence select="$pass2"/>
</debug>
</xsl:if>
<xsl:sequence select="$pass3/*"/>
</ranges>
</xsl:template>
<xsl:template mode="ranges_pass2"
match="range[@end]
[following-sibling::range[1]/@start > current()/@end + 1]
[following-sibling::range/@start < current()/@end]">
<xsl:copy-of select="."/>
<range start="{@end + 1}" end="{following-sibling::range[1]/@start - 1}"
inserted-in="pass2"/>
</xsl:template>
</xsl:stylesheet>
----------------------
aircrafts.xsl
<xsl:import href="ranges.xsl"/>
<xsl:param name="debug" select="'no'"/>
<xsl:template match="aircraft-range" mode="parse">
<xsl:for-each select="tokenize(., '\s+')">
<xsl:analyze-string select="." regex="^(\d{{4}})(\d{{4}})?$">
<xsl:matching-substring>
<range start="{number(regex-group(1))}" end="{number((regex-group(2)[normalize-space()], regex-group(1))[1])}"/>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:message select="'Could not parse ', ."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Re: [xsl] Creating new, distinct groups of ranges from an aggregation of individual ranges
Subject: Re: [xsl] Creating new, distinct groups of ranges from an aggregation of individual ranges From: "Imsieke, Gerrit, le-tex gerrit.imsieke@xxxxxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> Date: Wed, 19 Nov 2014 10:27:48 -0000 |
Hi Heiko & Michael,
On 19.11.2014 02:20, Heiko Niemann kontakt@xxxxxxxxxxxxxxxx wrote:
Hi Gerrit,
since my first name is not very international I listen to a whole range of names: from Heeeko to Hayoko. :)
Talking about ranges. I had the same question about 219, Michael clarified and since your code covers it already I would suggest Michael to follow your approach. They are similar anyhow.
I noticed two things though:
1) parsing the ranges does not cover missing leading zeros (if you e.g. add 8880889 to a aircraft-range it won't show in the result, 08880889 will); first I also looked at using analyze-string but dropped it so I use following code now (adjusted to the elements you use):
I emitted an xsl:message that would report any input token that doesnbt match '^\d{4}(\d{4})?$'. It might be a better idea to add terminate="yes" to that message instead of heuristically fixing the data, but Ibm not the one to make a call on this.
2) If you add e.g. 0200 to a list the result will show:
<pass3> <range start="200" end="200"/> <range start="200" end="200"/> <range start="201" end="204"/>
and if you add 0201 instead the result is:
<pass3> <range start="201" end="200"/> <range start="201" end="201"/> <range start="202" end="204"/>
Youbre right, therebs still a bug. The matching pattern in the template with xml:id="A" should be changed from
match="range[1][not(@start = following-sibling::*[1]/@start)]"
to
match="range[1][not(@start = following-sibling::*[1]/(@start|@end))]"
Letbs see which other bugs are left uncovered by our anecdotal test cases. Ibm waiting for the FAA to knock on my door in order to investigate a future fatal incident caused by flaky XSLT codeb&
Ibm posting the complete revised code below. There are no templates in #default mode any more which should help in integrating the code. Ibve added a debug parameter. Apply aircrafts.xsl with debug=yes to get the intermediate stepsb results in /ranges/debug in the output.
Gerrit
----------------------
ranges.xsl
<?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:param name="debug" select="'yes'"/>
<xsl:template match="ranges" mode="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>
<!-- Fill gaps with new ranges (Heikobs test case) -->
<xsl:apply-templates select="$pass1/range" mode="ranges_pass2"/>
</pass2>
</xsl:variable>
<xsl:variable name="pass3" as="element(pass3)">
<pass3>
<!-- 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="$pass2/range" mode="ranges_pass3"/>
</pass3>
</xsl:variable>
<ranges>
<xsl:if test="$debug = 'yes'">
<debug>
<xsl:sequence select="."/>
<xsl:sequence select="$pass1"/>
<xsl:sequence select="$pass2"/>
</debug>
</xsl:if>
<xsl:sequence select="$pass3/*"/>
</ranges>
</xsl:template>
<xsl:template match="range" mode="ranges_pass2"> <xsl:copy-of select="."/> </xsl:template>
<xsl:template mode="ranges_pass2"
match="range[@end]
[following-sibling::range[1]/@start > current()/@end + 1]
[following-sibling::range/@start < current()/@end]">
<xsl:copy-of select="."/>
<range start="{@end + 1}" end="{following-sibling::range[1]/@start - 1}"
inserted-in="pass2"/>
</xsl:template>
<xsl:template mode="ranges_pass3" xml:id="A" match="range[1][not(@start = following-sibling::*[1]/(@start|@end))]"> <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="ranges_pass3" 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>
----------------------
aircrafts.xsl
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="2.0">
<xsl:import href="ranges.xsl"/>
<xsl:param name="debug" select="'no'"/>
<xsl:template match="group[aircraft-range]"> <xsl:variable name="parse" as="element(ranges)"> <ranges> <xsl:apply-templates mode="parse"/> </ranges> </xsl:variable> <xsl:apply-templates select="$parse" mode="ranges"/> </xsl:template>
<xsl:template match="aircraft-range" mode="parse">
<xsl:for-each select="tokenize(., '\s+')">
<xsl:analyze-string select="." regex="^(\d{{4}})(\d{{4}})?$">
<xsl:matching-substring>
<range start="{number(regex-group(1))}" end="{number((regex-group(2)[normalize-space()], regex-group(1))[1])}"/>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:message select="'Could not parse ', ."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Current Thread |
---|
|
<- Previous | Index | Next -> |
---|---|---|
Re: [xsl] Creating new, distinct gr, Heiko Niemann kontak | Thread | Re: [xsl] Creating new, distinct gr, Michael Friedman sum |
[no subject], Unknown | Date | [xsl] Creating list using xslt, jaya k jayak_36@xxxx |
Month |
Keywords