Subject: [xsl] Re: OFFLIST: Re: XSLT to find missing characters? From: Dimitre Novatchev <dnovatchev@xxxxxxxxx> Date: Sun, 14 Jul 2002 01:23:00 -0700 (PDT) |
--- "Kirk Allen Evans" <kaevans at xmlandasp dot net> wrote: > Thank you all for your suggestions. > > As usual, the problem was only half-stated by the client. So, here > is > a > curveball. They want this to act kind of like a dynamic list box > where > they > can enter parts of a phrase. Kind of like the index search in MSDN > where > you type part of a phrase and it finds the next entry for you. A > more > precise requirement is that they want some kind of less-than or > greater-than > operator for strings. > > Given the corrected input XML (I had "Bud Lite" and "Budweiser" > ordered > incorrectly): > > <beers> > <beer name="Amstel Light"/> > <beer name="Bud Lite"/> > <beer name="Budweiser"/> > <beer name="Buffalo Beer"/> > <beer name="Buzz Beer"/> > <beer name="Cool Creek"/> > <beer name="Cooper's Reserve"/> > <beer name="Coors"/> > <beer name="Michelob"/> > <beer name="Miller Lite"/> > <beer name="Sam Adams"/> > </beers> > > The node list will be pre-sorted based on the name attribute. They > want to > enter "Bud" and get "Bud Lite", or "Budw" to get "Budweiser". If no > nodes > are found (like "Budx"), then the next node alphabetically is > returned > ("Buffalo Beer"). There is no limitation on the last match position > in > the > string. For instance, when working with "Budx", the third character > is > significant. When working with "Cooq", the fourth character is > significant > (and should return "Coors"). "Apqrstuvwxyz" makes the second > character > significant and would return "Bud Lite". > > Here is my first stab, modifying Dimitre's XPath solution with an > additional > union: > > ( > /*/*[starts-with(@name,$vStartPhrase)][1] > | > /*/*[contains(substring-after($vAlphabet, $vStartLetter), > substring(@name,1,1))][1] > )[1] > > | /*/*[1][contains(substring-before($vAlphabet, $vStartLetter ), > substring(/*/*[last()]/@name,1,1))] > > > My change works, but has a flaw in that "Buffalo Beer" is not > returned: > "Cool Creek" is. I asked if it would be OK to get the last node that > matches the first 2 letters (ie, "Buzz Beer"), they said no: the > business > case says that it should return "Buffalo Beer". > > I think I can conceive a solution using XSLT that uses the same > recursive > approach as the original post. But they want to implement this using > a > single XPath statement in order to shove the solution into their > existing > framework using MSXML and selectSingleNode. > > Kirk Hi Kirk, The first thing I'd do in your case would be to ask the customers to stick with specifying user requirements only and not to advise the implementors how to implement. I would not tell them that what they want is possible, given that certain additional assumptions are true, because the resulting "solution" is really ugly. In case we know the maximum length of the user-entered phrase and of the possible choices (lookup keywords), then we could normalise the user-enterd phrase and the lookup keywords to be of the same length by padding them with spaces. Then an XPath expression exists, that returns the first lookup keyword, which fully contains the user-entered phrase, or otherwise, the first lookup keyword, which is greater than the user-entered phrase. The solution matches characters to numbers, then constructs the difference between each pair of characters (kwd(n) - uphrase(n)), then constructs from these differences a number in a number system with base the number of different possible values for the characters used. The above is done between every lookup keyword and the user-enterd phrase, and the first lookup keyword, for which the result is positive, is returned. To illustrate with a simple example: source xml: <lookup> <kwd>abab </kwd> <kwd>acad </kwd> <kwd>baba </kwd> <kwd>baca </kwd> <kwd>caca </kwd> </lookup> Transformation: <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/> <xsl:variable name="vPhrase1" select="'aca '"/> <xsl:variable name="vPhrase2" select="'babd '"/> <xsl:template match="lookup"> <xsl:value-of select="concat('For ', $vPhrase1, ' found ')"/> <xsl:call-template name="lookup"> <xsl:with-param name="vPhrase" select="$vPhrase1"/> </xsl:call-template> <xsl:text>
</xsl:text> <xsl:value-of select="concat('For ', $vPhrase2, ' found ')"/> <xsl:call-template name="lookup"> <xsl:with-param name="vPhrase" select="$vPhrase2"/> </xsl:call-template> </xsl:template> <xsl:variable name="vChars" select="' abcd'"/> <xsl:template name="lookup"> <xsl:param name="vPhrase"/> <xsl:variable name="vCase1" select="/*/kwd [starts-with(., substring-before($vPhrase, ' '))][1]"/> <xsl:choose> <xsl:when test="$vCase1"> <xsl:value-of select="$vCase1"/> </xsl:when> <xsl:otherwise> <xsl:variable name="vCase2" select="/*/kwd [ ( string-length(substring-before($vChars, substring(.,1,1) ) ) - string-length(substring-before($vChars, substring($vPhrase, 1,1 ) ) ) ) * 125 + ( string-length(substring-before($vChars, substring(.,2,1) ) ) - string-length(substring-before($vChars, substring($vPhrase, 2,1 ) ) ) ) * 25 + ( string-length(substring-before($vChars, substring(.,3,1) ) ) - string-length(substring-before($vChars, substring($vPhrase, 3,1 ) ) ) ) * 5 + ( string-length(substring-before($vChars, substring(.,4,1) ) ) - string-length(substring-before($vChars, substring($vPhrase, 4,1 ) ) ) ) > 0 ][1]"/> <xsl:value-of select="$vCase2"/> </xsl:otherwise> </xsl:choose> </xsl:template> </xsl:stylesheet> When applied on the source xml above this transformation produces the following result: For aca found acad For babd found baca The result can be returned as a single XPath expression: $vCase1 | $vCase2 and this is really what your customers want. ===== Cheers, Dimitre Novatchev. http://fxsl.sourceforge.net/ -- the home of FXSL __________________________________________________ Do You Yahoo!? Yahoo! Autos - Get free new car price quotes http://autos.yahoo.com XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
Current Thread |
---|
|
<- Previous | Index | Next -> |
---|---|---|
[xsl] Creating an AFP print Stream , Bob McLaren | Thread | [xsl] Site Check, Joel Konkle-Parker |
OFFLIST: [xsl] Re: XSLT to find mis, Kirk Allen Evans | Date | [xsl] Site Check, Joel Konkle-Parker |
Month |