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> </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