my dog learned polymorphism*
The moose likes XML and Related Technologies and the fly likes Using variable to hold a boolean test Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Engineering » XML and Related Technologies
Bookmark "Using variable to hold a boolean test" Watch "Using variable to hold a boolean test" New topic
Author

Using variable to hold a boolean test

Jason Sroka
Greenhorn

Joined: Aug 09, 2001
Posts: 3

I am working on an XSLT translation that has a single,
complicated boolean function appear in multiple loops
(and therefore in multiple places within the XSLT
document). In order to make the document more robust,
specifically to avoid a future edit that updates the
boolean test in some of the locations it appears but
misses some others, I'd like to have a single declaration
of the boolean test that I can call in the various locations.
I attempted to do this using an xsl:variable:
<xsl:variable name="MatchSelect">not(./Name = preceding::AA_Entry/child::Name) and (./Name = following::AA_Entry/Name)</xsl:variable>
then referencing the variable in another location
as the test attribute of an xsl:if:
<xsl:if test="$MatchSelect">
but what I find is that the xsl:if conditional
ends up matching everything (the conditional
always evaluates to true).
Can anyone help me by telling me this approach definitely
won't work, that this should work and I must be making some
kind of syntax/dereferencing error (troubleshooting suggestions
welcome!), or that there's another approach to realizing this
functionality?
Guillaume Compagnon
Ranch Hand

Joined: Aug 09, 2001
Posts: 106
Hey!

Don't forget the scope of your variable:
Beginning of the validity of the variable
<xsl:variable name="MatchSelect">not(./Name = preceding::AA_Entry/child::Name) and (./Name = following::AA_Entry/Name)
...
<xsl:if test="$MatchSelect">
...
</xsl:variable>
End of the validity of the variable
That should be ok, if not , try to initialize your variable with false!!


---------<BR>Guillaume
Mapraputa Is
Leverager of our synergies
Sheriff

Joined: Aug 26, 2000
Posts: 10065
Hi Jason!
For one thing, your variable should be declared as:
<xsl:variable name="MatchSelect" select="not(./Name =preceding::AA_Entry/child::Name) and (./Name = following::AA_Entry/Name)"/>
How it is declared now, it simply has a string value of "not(./Name = preceding::AA_Entry..." (try to print its value with <xsl:value-of select="$MatchSelect"/> ) and if a string variable is not empty, <xsl:if test="$varName"> will always evaluate to true. Your XPath expression doesn't "work".
Next thing, what you will call from the various locations is the result of once performed test, not the test, applied to your current data. From your post I did not quite understand if it's what you need or not.
Regarding scope of variable: if you define your var as a top-level element, (not inside a template) it will be accessible from any place. If you place <xsl:if> inside var declaration, as Guillaume suggested, then the result of <xsl:if> element execution will be added as a part of var value, which may produce an interesting effect, of course. How useful - that's another question

Uncontrolled vocabularies
"I try my best to make *all* my posts nice, even when I feel upset" -- Philippe Maquet
Jason Sroka
Greenhorn

Joined: Aug 09, 2001
Posts: 3
Answering Mapraputa:
I see what you mean about why the string always evaluates to 'true' - thanks for that explanation!
As for scoping, I am indeed declaring this outside of any templates specifically in order to be able to reference it in multiple templates within the document, which is why the variable-scoping-change suggested by Guillame won't work in my case (I'd have to have multiple templates inside a variable).
But, to answer the question you ask, I am intending to use the string as the text of the test, as opposed to intending to have the string evaluated when the variable is declared (creating a true or false) and using the boolean variable later in the document. The solution you propose, in conjunction with where I evaluate the variable (outside of any templates) results in the variable being set to 'false', so that the test condition becomes always-false, which isn't what I'm looking for.
Let me try to provide a little more flesh around the problem:
<!-- here I declare the variable, creating a string -->
<xsl:variable name="UniqueNameTest"> not(./Name=preceding::AA_Entry/child::Name) and (./Name= following::AA_Entry/Name)
</xsl:variable>
<!-- here is one template I want to use it in for producing html -->
<xsl:template match="BigList" mode="HTML">
<xsl:for-each select="BigListEntry">
<!-- as I'm iterating through the list, apply the test to each element of the list -->
<xsl:if test="$UniqueNameTest">
An entry matched the unique name test condition.
</xsl:if>
</xsl:for-each>
</xsl:template>
<!-- here is another template I want to use it in for producing voicexml -->
<xsl:template match="BigList" mode="VoiceXML">
<xsl:for-each select="BigListEntry">
<!-- as I'm iterating through the list, apply the test to each element of the list -->
<xsl:if test="$UniqueNameTest">
An entry matched the unique name test condition.
</xsl:if>
</xsl:for-each>
</xsl:template>
So, in both cases where the variable appears as:
<xsl:if test="$UniqueNameTest">
I want it to be treated as if it was:
<xsl:if test="not(./Name=preceding::AA_Entry/child::Name) and (./Name= following::AA_Entry/Name)">
This is a simple framework that I'm hoping shows how I want to use this - define the test condition once (as the string value of a variable) and be able to reference that string to provide the test condition within multiple templates. This would allow me to edit the test condition string once (in the variable declaration) but have the test condition string be used in multiple places throughout the document.
I hope this makes it clearer - thanks for the answers so far and any future suggestions!
Mapraputa Is
Leverager of our synergies
Sheriff

Joined: Aug 26, 2000
Posts: 10065
Yes, now it's perfectly clear! It's perfectly clear that I misunderstood your requirements
However,
<xsl:if test="$UniqueNameTest">
will not work. Test condition will return true if UniqueNameTest is not empty and that's all. I do not think there is any way to interpret a string as an XPath expression in standard XSLT. Good news is that if you really want this effect, you can use somePrefix:evaluate() extension function, which your XSLT processor may support. Xalan and Saxon provide such function, I do not know about other processors...
Another approach is to use a template instead of a variable.
<xsl:template name="test">
<xsl:if test=" not(./Name=preceding::AA_Entry/child::Name) and (./Name= following::AA_Entry/Name)">yes</xsl:if>
</xsl:template>
then you call it as:
<xsl:template match="something" >
<xsl:variable name="currentTest">
<xsl:call-template name="test"/>
</xsl:variable>
<xsl:if test="$currentTest='yes'">
some code here
</xsl:if>
</xsl:template>
It doesn't looks too elegant to me , but it's all within standard XSLT, no extensions
Jason Sroka
Greenhorn

Joined: Aug 09, 2001
Posts: 3
You are one sly bartender, Mapraputa!!
Perhaps not an ideal solution, but I wouldn't be so quick to say it isn't elegant - and most importantly it worked
Thank you very much for your help,
-Jason
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: Using variable to hold a boolean test