Re: [xsl] Passing variable number of parameters to xsl file

Subject: Re: [xsl] Passing variable number of parameters to xsl file
From: Peter Davis <pdavis152@xxxxxxxxx>
Date: Thu, 21 Mar 2002 01:07:25 -0800
On Wednesday 20 March 2002 23:51, Kim wrote:
> Hi, I need to be able to support a variable number of parameters.  I am
> currently using Xalan v2.2.
>
> For example, the user would invoke Xalan with parameters:
>
> 	-PARAM paramName1 paramValue1 -PARAM paramName2 paramValue2  ...
> -PARAM paramNameN paramValueN
> 	(specific example: -PARAM autobrand1 ford -PARAM autobrand2 lexus
> -PARAM tire1 goodyear -PARAM tire2 michellan)
>
> where N could be for example 1...500.
>

I'm afraid there is no way to do this using Xalan's standard command line 
tool.  It is not possible to specify the name of an xsl:param name 
dynamically.  What you are asking for is the functionality of an Array, and 
the way to use an Array in XSLT is to use a node-set.

You will have to write your own tool (or modify the source from Xalan's) to 
accept the parameters from the command line and use them to create a 
node-set.  I'm not sure exactly how to do this, but you can find 
documentation for the org.apache.xpath.NodeSet class at 
http://xml.apache.org/xalan-j/apidocs/index.html.  You could also check out 
Xalan's user/dev mailing list archives or ask someone over there.  Hopefully 
what I hacked out below could get you started.

A node-set can only contain nodes, which means you'll probably need to create 
your own element in order to contain the values.  To create an element, 
you'll have to get an instance of org.w3c.dom.Document.  I haven't tested it, 
but something like this might work:

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.apache.xpath.NodeSet;
import javax.xml.parsers.DocumentBuilderFactory;

public static void main(String[] args) {
...
Document d = 
DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();

NodeSet autobrands = new NodeSet();
NodeSet tires = new NodeSet();

// psuedocode: (wouldn't for(in) be nice? :->)
for(String autobrand in args) {
    Element e = d.createElement("autobrand");
    e.appendChild(d.createTextNode(autobrand));
    autobrands.addElement(e);
}

// repeat for tires

// create your transformer

transformer.setParameter("autobrands", autobrands);
transformer.setParameter("tires", tires);

// transform the document


You can then use the $autobrands and $tires params to iterate through the 
parameters like any other node-set.

<!-- node-sets that are collected and passed in through custom app -->
<xsl:param name="tires"/>
<xsl:param name="autobrands"/>

Note that you could modify the code above and only use one param that has 
different elements for autobrands and tires.  This might make some of the 
answers to your questions below easier, but it depends on what you need.

> Couple of Questions:
>
> 1) Is there a way to get the param count other than having it passed in
> as something like: -PARAM numParams 500?

Once you have the parameters, just use
<xsl:value-of select="count($autobrands/autobrand) + count($tires/tire)"/>

(and of course you could use the two count functions separately).

> 2) What I need to do is test a node's value against all of the
> parameter values passed in.  Note that for each invocation N could be:
> 0, 1, 2, ..500.
>
> I want to do something like:
>
> 	if (nodeValue match any of the paramValues of passed in)
> 	then
>   		doSomething();
> 	endif

The '=' operator, when given a single node on the left-hand side and a 
node-set on the right, will return true if any node in the node-set is equal 
to the single node.  So you could just do this:

<xsl:if test="$theNode = $autobrands/autobrand">
  doSomething
</xsl:if>

<xsl:if test="$theNode = $tires/tire">
  doSomething
</xsl:if>


>
> for each parameter "family" (ex. autobrand and tire mentioned above)
>
> without being forced to have a set of fixed static hardcoded test
> statements in the xsl like:
>
> 	if (nodeValue match $paramName1)
> 		doSomething()
> 	else if  (nodeValue match $paramName2)
> 		doSomething()
> 		...
> 	else if (nodeValue match $paramNameN)
> 		doSomething()
> 	endif
>
> where doSomething() is the exact same function for all
> nodeValue/paramValue matches.
>
> I have some ideas concerning using key, <xsl:choose>, <xsl:when>,
> temporary tree, <or> features, but am not sure which path is best to
> proceed on.

-- 
Peter Davis
A fox is a wolf who sends flowers.
		-- Ruth Weston

 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Current Thread