xsl-list
[Top] [All Lists]

RE: Building select-clause dynamically with parameters

2002-12-11 02:43:29

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(_dot_)H(_dot_)Kay(_at_)ntlworld(_dot_)com
work: Michael(_dot_)Kay(_at_)softwareag(_dot_)com 


 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