RE: [xsl] Building select-clause dynamically with parameters

Subject: RE: [xsl] Building select-clause dynamically with parameters
From: "Michael Kay" <michael.h.kay@xxxxxxxxxxxx>
Date: Wed, 11 Dec 2002 09:43:29 -0000
> 
> I would like to pass some words into my XSL file which should 
> be used to build an XPath query in xsl:apply-templates.

This is something that's quite tricky to do in XPath 1.0, but much
easier in XPath 2.0. Since XPath 2.0 has taken some knocking on this
list recently, I'll show you the XPath 2.0 solution, which you can use
in Saxon 7.x today.

XPath 2.0 supports sequences of values, including sequences of strings.
You can supply a sequence of strings as a parameter, but for
convenience, let's assume you want to pass a single string, which makes
it easier to invoke from the command line.

So we declare the parameter:

<xsl:param name="query" as="xs:string"/>

and now we tokenize it into a sequence of strings:

<xsl:variable name="query-words" as="xs:string *"
   select="tokenize($query, ' ')"/>

Now we select the chapters containing this word:

<xsl:variable name="selected-chapters" as="element *"
   select="//chapter[some $w in $query-words satisfies
                     contains(string(.), $w)]"/>

If you want all the words to be present, just use "every" in place of
"some". It's also easy to extend this to eliminate chapters containing
excluded words.

The "as" attributes define the type of each variable. They are optional,
but I think it's good practice to include them because it helps to
document the stylesheet, it can trap programming errors, and the system
can sometimes use the information for optimization.

Michael Kay
Software AG
home: Michael.H.Kay@xxxxxxxxxxxx
work: Michael.Kay@xxxxxxxxxxxxxx 


 For 
> an example, the following works, but only for one word:
> 
>     <?xml version="1.0" encoding="ISO-8859-1"?>
>     <xsl:stylesheet version="1.0"
>     	xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; 	
> 
>     <xsl:param name="query"/>
> 
>     <xsl:template match="/">
>       <xsl:apply-templates 
> select="chapter[contains(descendant-or-self::*,$query)]"/>
>     </xsl:template>
> 
>     <xsl:template match="chapter | section">
>       <table>
>         <tr>
>           <td>&#160;</td>
>           <td>Found <xsl:value-of select="title"/>
>             <xsl:apply-templates 
> select="section[contains(descendant-or-self::*, $query)]"/>
>           </td>
>         </tr>
>       </table>
>     </xsl:template>
> 
>     </xsl:stylesheet>
> 
> I don't know how many words will be passed into the XSL file, 
> this should 
> be flexible.
> For example, If $query has the value "word1 word2", the only 
> chapters and 
> sections that
> should be selected by apply-templates are those which contain 
> word1 or 
> word2, I think
> in this case need I something like:
> 
>       <xsl:apply-templates 
> select="chapter[contains(descendant-or-self::*,'word1') or
>                                                              
> contains(descendant-or-self::*,'word2')]"/>
> 
> I tried to pass the whole string used by "select" as 
> parameter, but it does 
> not work.
> 
> Another thing is that I also have words that should be 
> excluded and that I 
> would like
> to pass a value into the XSL file that should define if it is 
> an AND or an 
> OR query to
> build something like:
> 
>       <xsl:apply-templates 
> select="chapter[contains(descendant-or-self::*,'word1') and
>                                                              
> contains(descendant-or-self::*,'word2') 
> and
>                                                              
> not(contains(descendant-or-self::*,'word3'))]"/>
> 
> Has anyone an idea how to do something like this? Or is it a better 
> solution to do this
> with Java DOM?
> 
> Thanks for help and greetings,
> 
> Marko
> 
> 
>  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