tags:

views:

1411

answers:

6

When using XSLT how do you test to see if a locally scoped variable exists, or is this even possible?

+1  A: 

I don't think it's possible, but you're not likely to ever need it, because the variable doesn't exist unless you've declared it.

Michael Krelin - hacker
As it turns out, working with XSLT is a bit on the odd side as there are some things that aren't supported (e.g. for loops) and variables can only be set once and cannot be updated. As such, one of the ideas that has been floated around is using the existence of a variable as a flag to indicate if certain parts of the the transformation have run or not. Ideally you might just be able to do this by checking for the existence of something in the XML you are processing, but sometimes you don't have that option.
Rob
@hacker: +1. Basically the same thing I said. @Rob: I believe you have to let go of a bunch of "traditional" thinking patterns when you work with XSLT. You will also very likely not have to check whether certain parts of the transformation have run or not, because you can (declaratively) find out by checking if they *would* run or not. Want to find out if section X was created? Just check whether the *conditions* for creating section X are there.
Tomalak
@Tomalak - I am aware of that and the fact that we even had to look for a way of setting a flag variable is a sign that there is something wrong with the XML that is being generated.
Rob
There are circumstances where the "just" in Tomalak's last sentence is pretty huge. For instance, a transform that could conceivably create 30 different <p> elements, and that should emit an <h2> element first if it produces any. This is not only difficult but error-prone (and a maintenance nightmare) if you check all 30 conditions to determine whether or not to emit the <h2>. (The pattern at the end of my post didn't come out of nowhere.)
Robert Rossney
A: 

Check this out.

http://www.stylusstudio.com/xsllist/199911/post30020.html

StarSignLeo
I think that this answer might be the most helpful, but you're probably not getting any votes because you just threw up a link. Perhaps add a little explanation?
Kyle Walsh
Not in it for the votes but a little more explanation is a good idea. This was a question for google so I posted an answer from google.
StarSignLeo
@starsingleo - Two points to raise though. One is that the FAQ for the site says nothing is wrong with asking Google-able questions. Also, if you review the other answers and some of the discussion, the solutions that were coming back from hits on Google ended up being engine specific that may or may not work depending upon your circumstances. Thus, this means that other developers that come along in the future will also see that those solutions may or may not work and definitely are not best practice. This is information that would not be known from just Googling something.
Rob
All im saying is I copied the question straight into google and it was the first response. This post is now the first. But if you feel you need to mark me down for helping you out then that your choice.Maybe read the FAQ about marking down "If you post something that's off topic or incorrect". I believe that link is correct?
StarSignLeo
@StarSignLeo - I down voted you for two reasons, one is that your response was just a copy-paste of a link which doesn't really explain anything to someone coming into this question in the same way that the other answers do. However, more importantly, the link is explaining how to check to see if a declared variable has a value set for it, which is not the same as checking to see if a variable has been declared at all. As the other answers have shown, this is not posible in XSLT and if you are trying to do it, you might be doing something wrong or the XML you are working with is poorly formed.
Rob
A: 

If you have a variable, you can check it has something, or it "exists" by doing something like the following:

<xsl:choose>
    <xsl:when test="$myvar">
        This variable exists!
    </xsl:when>
    <xsl:otherwise>
        The variable doesn't exist :(
    </xsl:otherwise>
</xsl:choose>

As for its validity I cannot be certain. I will tell you however, that I do this in some of our systems at work ;)

Kezzer
Firefox 3.5.2 returns an error if "myvar" isn't already set. Perhaps something like this is implementation / XSLT version specific? I seem to recall that XSLT 2.0 has some neat functions that aren't available in a lot of XML engines.
Rob
I'm not entirely sure. Personally I don't think it should be done. This is an IE7-only system also, not sure if the browser causes any effects on it.
Kezzer
That doesn't test for the existence of a variable. That tests for the existence of an element named "myvar" under the context node.
Robert Rossney
+9  A: 

Asking this question indicates that you did not fully grasp the key point of XSLT. :-)

It's declarative: nothing can exist unless you declare it. You declare a variable, then it's there, you don't, then it's not.

Not once will there be the point where you have to wonder, while coding, if a certain variable exists.

XSLT has strict scoping rules, variables exist only within the scope of their parent element, (and not all elements can contain variables to begin with). Once you leave the parent element, the variable is gone.

So unless you specify your question/intent some more, the only valid answer is that the question is wrong. You cannot and do not need to check if a variable exists at run-time.

Tomalak
Tomalak is correct. But, if your question was really if the variable has been set, then something like <xsl:if test="sting-length($myVar)"> can test for a value.
dacracot
This tests if a variable *has a value*, which is, strictly speaking, something totally different. As soon as you can write `<xsl:if test="string-length($myVar)">` and your stylesheet compiles, then the variable is set (i.e. "declared") - regardless of its value.
Tomalak
To clarify things a bit since this is a bit more implementation specific as opposed to generic question, the current issue in the code is display a message of something is missing from the XML provided from the style sheet. The idea is to set a flag variable if something is output and later on display a different message if nothing was output. The only reason a flag came up is because the test condition as to if something is displayed or not is nested between a for-each and and a couple if statements. However, as it turns out, it looks like the fact that a flag variable even came up...
Rob
... is more of a sign that the XML isn't well designed than anything else. However, I am still curious to see if there is some "trick" that allows you to do it, similar to how the Muenchian Method is sometimes used.
Rob
This sounds a bit like you're tackling the problem from the wrong end (procdural thinking!). I'm sure there is a way to do what you want. Whether it is a nice/elegant way depends on what you have (input XML) and what you want (output format).
Tomalak
The main problem is that you cannot "set a flag" and check it elsewhere. The moment "flag" goes out of scope it's *gone*. (Besides, the Muenchian method is hardly a trick to do things like that - not sure why you mention it here.)
Tomalak
@Tomalak - Actually I've been working with XSLT for a couple of years now so I don't think it is so much a "looking at it from the wrong direction" issue, as the original format of the XML I was trying to work with was just *wrong*. So right now we are working on rewriting XML that was being generated and the XSLT is turning out to be extremely simple to write. There also seems to be a code smell here in that if you are doing something in XSLT that seems overly complicated, either you are doing it wrong, or the XML is structured wrong.
Rob
Also, the reason I mention the Muenchian method is that it is an example of a neat trick to use with XSLT and I'm just wondering if there trick for doing this in XSLT. Granted from what I have been reading it looks like it is not supported by design, but you never know what something might be able to do.
Rob
I see. Pardon my ignorance. ;-) The "code smell" part has my full ACK. Sometimes it is beneficial to think the whole thing over, instead of hammering on a small bit that refuses to work. In this case, I don't think there is a trick, because, frankly, there isn't a problem (or I am just not getting it). To me it still sounds like an `<xsl:if test="some xpath here">` would probably solve the issue.
Tomalak
@Tomalak - It might make more sense if I was able to share the production code, but I don't see how I can. However, the summary is multiple for-each statements that looped over most of the nodes in the XML followed by a couple nested if statements that navigated up and down the XML document. However, the XML is being rewritten and the new XSLT is much cleaner than what there used to be. So it seems like rewriting the XML was the best route to take as it is now much easier to work with than it was before.
Rob
Sometimes I think that <xsl:for-each> causes more problems than it solves, due to improper use. Most "for-each"s can (and should) be replaced by apply-templates, which can make things easier in the long run. Not knowing the complexity of your task, I am aware that this is pure theory. In any case all elegance is screwed once your XML input is nasty, at which point refactoring it as a first step may become your best option.
Tomalak
A good answer, @Tomalak! +1 from me.
Dimitre Novatchev
A: 

In any programming language you'll have exactly the same behavior.

Take C#. Trying to reference an undeclared variable name results in an error message. This is definetely a programmer error.

Why would it be necessary that XSLT behaves in a different way?

As for thinking about "before" and "later", or about a variable that would have more than one value in order to denote in which "state" we are -- this all is not allowed in XSLT by definition -- and exactly the absence of such "features" is what makes XSLT the nice and ellegant functional language it is.

Dimitre Novatchev
I'm inclined to disagree with *any* programming language having the same behavior as some languages will automatically create and set a default value upon the first encounter of a variable name. However, I definitely see your point in regards to the use of such a "feature" in a language pointing at something being wrong somewhere.
Rob
@Rob - The problem you have is that you are attempting to access a variable which is *out of scope*, in other words, which doesn't exist at all. All programming languages raise an error in this situation. BTW, it would not hurt to provide a sample (the minimum possible, but working) that demonstrates your problem. Then many people will be able to help.
Dimitre Novatchev
@Dimitre - As do you mean inside of the complied environment or in an interpreted environment? Some interpreted languages will actually create the variable for you in memory if you access it without prior declaration.
Rob
@Rob Even if this is supported by some interpreted language, in no way this is a good practice. The runtime environment may not be able to infer the type of the variable or could infer it incorrectly. Fraught with errors and inefficiency.
Dimitre Novatchev
@Dimitre - I agree with you in regards to it not being good practice, usually the need for it is a sign that something was written wrong, one way or another. Also, if you look at a language such as the older versions of Visual Basic, not using Option Explicit was considered a quick way to introduce bugs into an application due to on the fly variables.
Rob
+6  A: 

Considering the XSLT stylesheet as an XML DOM, a variable declaration element makes the variable visible to all following siblings and their descendants. This allows XSLT processors to statically analyze any XPath containing a variable reference to see if the variable exists; if the variable declaration exists on the preceding-sibling or ancestor axis, the variable reference is legal, otherwise it's not.

Note that this is entirely dependent on the structure of the XSLT, not the structure of the XML it's processing. The XSLT processor can and should produce an error if an XPath expression uses a variable that doesn't exist.

There's no way to check for this condition inside XSLT because this condition isn't legal within XSLT. The sitauation you described in your comment - "The idea is to set a flag variable if something is output and later on display a different message if nothing was output." - actually should result in a syntax error. For instance, if you do something like this:

<xsl:if test="some_condition">
   <!-- produce output here -->
   <xsl:variable name="flag">true</xsl:variable>
</xsl:if>
<!-- time passes -->
<xsl:if test="$flag='true'>
   <!-- wouldn't it be nice? -->
</xsl:if>

you'll get a syntax error: the second xsl:if element is neither a following sibling of the variable declaration nor one of their descendants.

Here's a technique I use a fair amount - this produces variable output based on a variety of different conditions that you don't want to re-check later:

<xsl:variable name="output">
   <xsl:if test="$condition1='true'">
      <p>condition1 is true</p>
   </xsl:if>
   <xsl:if test="$condition2='true'">
      <p>condition2 is true</p>
   </xsl:if>
   <xsl:if test="$condition3='true'">
      <p>condition3 is true</p>
   </xsl:if>
</xsl:variable>
<!-- we've produced the output, now let's actually *output* the output -->
<xsl:copy-of select="$output"/>
<!-- time passes -->
<xsl:if test="normalize-space($output) != ''">
   <p>This only gets emitted if $output got set to some non-empty value.</p>
</xsl:if>
Robert Rossney
+1 for the more formal explanation of *why* this is unnecessary and therefore impossible.
Tomalak
This seems to be a good answer to bring to the top as it also provides a better way of doing things if someone else has the same question.
Rob