• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

Using variable to hold a boolean test

 
Greenhorn
Posts: 3
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

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?
 
Ranch Hand
Posts: 106
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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!!
 
Leverager of our synergies
Posts: 10065
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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
 
Jason Sroka
Greenhorn
Posts: 3
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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
Posts: 10065
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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
Posts: 3
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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
 
Don't get me started about those stupid light bulbs.
reply
    Bookmark Topic Watch Topic
  • New Topic