14

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

rjzii
  • 14,236
  • 12
  • 79
  • 119

6 Answers6

21

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
  • 94,622
  • 24
  • 146
  • 218
  • +1 for the more formal explanation of *why* this is unnecessary and therefore impossible. – Tomalak Aug 21 '09 at 15:33
  • 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. – rjzii Aug 25 '09 at 05:26
12

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
  • 332,285
  • 67
  • 532
  • 628
  • Tomalak is correct. But, if your question was really if the variable has been set, then something like can test for a value. – dacracot Aug 19 '09 at 15:12
  • This tests if a variable *has a value*, which is, strictly speaking, something totally different. As soon as you can write `` and your stylesheet compiles, then the variable is set (i.e. "declared") - regardless of its value. – Tomalak Aug 19 '09 at 15:18
  • 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... – rjzii Aug 19 '09 at 17:27
  • ... 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. – rjzii Aug 19 '09 at 17:37
  • 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 Aug 19 '09 at 17:38
  • 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 Aug 19 '09 at 17:41
  • 1
    @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. – rjzii Aug 19 '09 at 17:51
  • 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. – rjzii Aug 19 '09 at 17:53
  • 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 `` would probably solve the issue. – Tomalak Aug 19 '09 at 17:58
  • @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. – rjzii Aug 19 '09 at 18:13
  • Sometimes I think that 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 Aug 19 '09 at 18:29
  • 1
    "It's declarative: nothing can exist unless you declare it" Depends on who you mean by 'You'. Using a system like Symphony CMS params can be generated for you to access in your templates. But in some circumstances are only generated when certain conditions are met. So actually there are situations in which you may need to check for the existance of a param before you can do anything with it. "Asking this question indicates that you did not fully grasp the key point of XSLT." Or perhaps that there are implementations you're not aware of? – Nathan Hornby Jul 25 '14 at 10:53
  • @Nathan I see what you mean, "implementations you're not aware of" is something to keep in mind. On the other hand, the main use case of XSLT is data-driven/declarative (=template matching), not imperative (=if/then/else), so the question "has this been defined yet" tends to arise only if you're doing it wrong, IMHO. – Tomalak Jul 25 '14 at 13:11
  • @Tomalak - Oh I agree, it's just frustrating when you're looking for an answer to a question only to be met with 'that isn't an issue', when you know that sometimes, it is :) Logic may not be the core of XSLT's purpose, but they put those operators in there for a reason, so it's hardly an unsupported facet of the language, or an unusual request. You could argue that even in PHP you should know if a variable is set or not, but we still have access to `isset` to help with cases where you don't. But tl;dr I agree that it's a specific use-case, and arguably bad practice. – Nathan Hornby Jul 25 '14 at 13:47
2

XSL variables are strictly scoped, so you can't access them in sibling nodes, only in children. If you are dealing with params, you can use a global <xsl:param />.

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

Félix Saparelli
  • 8,424
  • 6
  • 52
  • 67
StarSignLeo
  • 256
  • 1
  • 2
  • 9
  • 1
    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 Aug 19 '09 at 14:04
  • 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 Aug 19 '09 at 22:46
  • @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. – rjzii Aug 20 '09 at 11:53
  • 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 Aug 21 '09 at 04:02
  • @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. – rjzii Aug 21 '09 at 12:13
1

Best and fast idea to check value if it's exist is to check it length

<xsl:if test="string-length(value/to/check)=0">

</xsl:if>
pevik
  • 4,523
  • 3
  • 33
  • 44
Karol
  • 179
  • 1
  • 6
0

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
  • 138,757
  • 24
  • 193
  • 173
  • 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. – rjzii Aug 19 '09 at 13:23
  • 1
    @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 Aug 19 '09 at 15:05
  • @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. – rjzii Aug 19 '09 at 17:15
  • There are circumstances where the "just" in Tomalak's last sentence is pretty huge. For instance, a transform that could conceivably create 30 different

    elements, and that should emit an

    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

    . (The pattern at the end of my post didn't come out of nowhere.)

    – Robert Rossney Aug 21 '09 at 17:55
  • A param can be generated by the system (ala Symphony CMS), so kind of a redundant answer. It's completely implementation specific. – Nathan Hornby Jul 25 '14 at 10:50
  • @NathanHornby, if we go as far as reading the question, we notice "locally scoped variable" in there. – Michael Krelin - hacker Jul 25 '14 at 14:03
0

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 ;)

rjzii
  • 14,236
  • 12
  • 79
  • 119
Kieran Senior
  • 17,960
  • 26
  • 94
  • 138
  • 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. – rjzii Aug 19 '09 at 13:32
  • 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. – Kieran Senior Aug 19 '09 at 14:08
  • 2
    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 Aug 20 '09 at 17:57