XSLT: "test" results confusion - xslt

I'm finding that while this test returns true:
test="string-length(foo) = 0"
However, for some reason, both of these tests are returning false:
test="foo = ''"
test="foo = null"
Any idea what might be going on? Is there some other state that foo could be in that would result in a 0 length, while still not being equal to '' or null?
Additionally - if I output:
X<xsl:value-of select="foo" />X
outputs: XX

If foo is an empty node-set then string(foo) is "", and string-length(foo) is zero, but foo = '' is false. XPath is full of surprises.
The explanation is that foo = "" doesn't mean string(foo) = "" as you might expect, but rather some $F in foo satisfies $F = "" (which you can write in full in XPath 2.0). And if foo is an empty set then the existential test is clearly false.

Well if you do test="foo = null" you compare the foo child element(s) of the context node to the null child element(s) of the context node.

Related

In vbscript can you use two possible conditions in an if statement? (OR)

An example would be:
If filter_purchase = 0 Or "" Then
SetDocVar "filter_purchase", "0"
Else
SetDocVar "filter_purchase", CStr(filter_purchase)
End If
But I get a 'Type Mismatch'. Would there be an easier way than doing Else IFs?
you have to explicitly state the condition for each OR. Please see below
If filter_purchase = 0 Or filter_purchase = "" Then
SetDocVar "filter_purchase", "0"
Else
SetDocVar "filter_purchase", CStr(filter_purchase)
End If
This should be the condition you want
If ((filter_purchase = 0) Or (filter_purchase = "")) Then
#agamike, I believe a single = is used for comparison in a vbs if not and not == link here
If you're just trying to test for an uninitialized variable then your If expression is actually redundant. All variables in VBScript are variants and all variants start out with a default value of 0/False/"". For example:
Dim v
If v = "" Then MsgBox "Empty string"
If v = 0 Then MsgBox "Zero"
If v = False Then MsgBox "False"
All three of these tests will pass. Note how you can compare a single variable against string, numeric, and boolean literals. Uninitialized variables have no type yet, so these kinds of comparisons are completely fine.
However, once you assign a value to the variable, you need to consider its type when making comparisons. For example:
Dim v
v = ""
If v = "" Then MsgBox "Empty String" ' Pass. "" = "".
If v = 0 Then MsgBox "Zero" ' Fail! Illegal comparison.
If v = False Then MsgBox "False" ' Fail! "" <> False.
Now that the variant has been defined as holding a string, it will need to be compared against other string types (literals or variables) or values that can be cast (either implicitly or explicitly) to a string.

Map strange behaviour

I have a map function as follows, which reads from an array of lines generated by a unix command.
my %versions = map {
if (m/(?|(?:^Patch\s(?(?=description).*?(\w+)\sPATCH).*?(\d+(?:\.\d+)+).*)|(?:^(OPatch)\s(?=version).*?(\d+(\.\d+)+)))/)
{ 'hello' => 'bye'; }
} #dbnode_versions;
print Dumper(\%versions); gives
$VAR1 = {
'' => undef,
'hello' => 'bye',
'bye' => ''
};
which I find extremely odd, as the hello and bye values should only get added if the regex is true. Anyone able to help me out?
Well, you have to consider what happens when the regex doesn't match, and the if is false. The if will evaluate to some value, although you shouldn't rely on the value of a statement.
Especially, if (cond) { expression } is roughly equivalent to cond and expression. This means that if the regex (our cond) will not match, we'll get a false value.
use Data::Dump;
dd [map { /foo(bar)/ and (hello => 'bye') } qw/foo foobar bar/];
What is your expected output? You may have thought ["hello", "bye"]. But actually, we get
["", "hello", "bye", ""]
because "" represents the false value returned by the regex match on failure.
If you want to return nothing in failure cases, you should explicitly return an empty list:
map { /foo(bar)/ ? (hello => 'bye') : () } qw/foo foobar bar/
or use grep, which filters a list for those elements that match a condition:
my %hash =
map { hello => 'bye' } # replace each matching element
grep { /foo(bar)/ } # filter for matching elements
qw/foo foobar bar/;
The %hash will them either be () or (hello => 'bye'), as each key can only occur once.

How to do a single line If statement in VBScript for Classic-ASP?

The "single line if statement" exists in C# and VB.NET as in many other programming and script languages in the following format
lunchLocation = (dayOfTheWeek == "Tuesday") ? "Fuddruckers" : "Food Court";
does anyone know if there is even in VBScript and what's the extact syntax?
The conditional ternary operator doesn't exist out of the box, but it's pretty easy to create your own version in VBScript:
Function IIf(bClause, sTrue, sFalse)
If CBool(bClause) Then
IIf = sTrue
Else
IIf = sFalse
End If
End Function
You can then use this, as per your example:
lunchLocation = IIf(dayOfTheWeek = "Tuesday", "Fuddruckers", "Food Court")
The advantage of this over using a single line If/Then/Else is that it can be directly concatenated with other strings. Using If/Then/Else on a single line must be the only statement on that line.
There is no error checking on this, and the function expects a well formed expression that can be evaluated to a boolean passed in as the clause. For a more complicated and comprehensive answer see below. Hopefully this simple response neatly demonstrates the logic behind the answer though.
It's also worth noting that unlike a real ternary operator, both the sTrue and sFalse parameters will be evaluated regardless of the value of bClause. This is fine if you use it with strings as in the question, but be very careful if you pass in functions as the second and third parameters!
VBScript does not have any ternary operator.
A close solution in a single line and without using a user defined function, pure VBScript:
If dayOfTheWeek = "Tuesday" Then lunchLocation = "Fuddruckers" Else lunchLocation = "Food Court"
BTW, you can use JScript in Classic ASP if ternary opertor is so important to you.
edited 2017/01/28 to adapt to some of the non boolean condition arguments
Note: If all you need is to select an string based on an boolean value, please, use the code in the Polinominal's answer. It is simpler and faster than the code in this answer.
For a simple but more "flexible" solution, this code (the original code in this answer) should handle the usual basic scenarios
Function IIf( Expression, TruePart, FalsePart)
Dim bExpression
bExpression = False
On Error Resume Next
bExpression = CBool( Expression )
On Error Goto 0
If bExpression Then
If IsObject(TruePart) Then
Set IIf = TruePart
Else
IIf = TruePart
End If
Else
If IsObject(FalsePart) Then
Set IIf = FalsePart
Else
IIf = FalsePart
End If
End If
End Function
If uses the Cbool function to try to convert the passed Expression argument to a boolean, and accepts any type of value in the TrueValue and FalseValue arguments. For general usage this is fast, safe and fully complies to documented VBScript behaviour.
The only "problem" with this code is that the behaviour of the CBool is not fully "intuitive" for some data types, at least for those of us that constantly change between vbscript and javascript. While numeric values are coherent (a 0 is a False and any other numeric value is a True), non numeric types generate a runtime error (in previous code handled as false), except if it is a string with numeric content or that can be interpreted as true or false value in english or in the OS locale.
If you need it, a VBScript version "equivalent" to the ? javascript ternary operator is
Function IIf( Expression, TruePart, FalsePart )
Dim vType, bExpression
vType = VarType( Expression )
Select Case vType
Case vbBoolean : bExpression = Expression
Case vbString : bExpression = Len( Expression ) > 0
Case vbEmpty, vbNull, vbError : bExpression = False
Case vbObject : bExpression = Not (Expression Is Nothing)
Case vbDate, vbDataObject : bExpression = True
Case Else
If vType > 8192 Then
bExpression = True
Else
bExpression = False
On Error Resume Next
bExpression = CBool( Expression )
On Error Goto 0
End If
End Select
If bExpression Then
If IsObject( TruePart ) Then
Set IIf = TruePart
Else
IIf = TruePart
End If
Else
If IsObject( FalsePart ) Then
Set IIf = FalsePart
Else
IIf = FalsePart
End If
End If
End Function
BUT independently of the version used, be careful, you are calling a function, not using a ternary operator. Any code, or function call you put in TruePart of FalsePart WILL BE EXECUTED independently of the value of the condition. So this code
value = IIf( 2 > 3 , DoSomething(), DontDoSomething() )
WILL EXECUTE the two functions. Only the correct value will be returned to value var.
There's a weird trick possible (hi, Python!) for exact one-liner:
lunchLocation = array("Food Court", "Fuddruckers")(-(dayOfTheWeek = "Tuesday"))
The "magic" works because of a boolean operation specifics in VBScript.
True is actually -1 and False is 0, therefore we can use it as an index for array (just get rid of a minus). Then the first item of array will be a value for False condition and second item for True.
related to #MC_ND answer:
to execute only one function, you can do something like that:
If VarType(TruePart) = vbString and InStr(1,TruePart,"function:") = 1 then
IIf = GetRef(Mid(TruePart,10))()
Else
IIf = TruePart
End If
the same for the FalsePart, and call IIf() it like that:
value = IIf( 2 > 3 , "function:DoSomething", "function:DontDoSomething" )
and will call DoSomething() or DontDoSomething()

When should comparator === be used over ==?

So I've been actively programming bot in school and work the past 5 years, but I never tried to find out the difference between == and ===.
I can see the difference of a comparator using a single =, it'll look at the value of the left handed variable through the loop, ex:
while($line = getrow(something))
So what's the difference between == and === in statements such as:
if ($var1 === $var2)
//versus
if ($var1 == $var2)
Likewise:
if ($var1 !== $var2)
//versus
if ($var1 != $var2)
I have always used double equals, I have never used tripple.
The languages I use are :php, vb.net, java, javascript, c/c++.
I'm interested in learning systematically what is going on in a tripple quote that is different than that of a double quote.
When should one be used over another? Thanks for appeasing to my curiosity :)
Typically, == looks at equality of value only. So, for instance...
5 == 5.0 //true
However, === also considers value and type (in the languages I am familiar with).
var five = 5;
var five_float = (float)5.0;
five === 5; //true - both int, both equal to 5
five_float === 5; //false - both equal 5 but one is an int and one is a float
FYI, the = operator (usually called the assignment operator) is used to set the value of the left side parameter to the right side. This is pretty obvious. However, in most languages, this will also return true if the assignment is successful. You want to avoid using = where you mean to use == (or ===) because it will look like a comparison, but it's not - and it will return true unexpectedly.
For instance, lets say you want to check if a number is equal to 10...
myNumber = 7;
if(myNumber = 10)
{
//will always be true and execute this code because myNumber will successfully
//be assigned the value of 10 instead of checking to see if the number is 10.
//oops!
}
A final note - this is true in PHP and JavaScript. I don't think there is a === operator in C++ or Java and == has a slightly different meaning as well.
$a === $b TRUE if $a is equal to $b, and they are of the same type. (introduced in PHP 4)
$a !== $b TRUE if $a is not equal to $b, or they are not of the same type. (introduced in PHP 4)
Reference
== will check the value only (equality operator), where === checks the data type as well (strict equality operator).
1 == '1' is true.
1 === '1' is false - the first is an Integer, the second is a String.
1 == true is true.
1 === true is false - the first is an Integer, the second is a Boolean.
Generally you want to use == (equality operator) but sometimes you want to make sure things are of certain types. I'm sure someone can provide an example, I can't think of one off the top of my head, but I've definitely used it.
In PHP and JavaScript (I'm not sure of other languages where the triple === syntax is valid) the difference is that === is a strict comparison. While == is loose. That means that === compares value and type, but == just compares value. A perfect example of this is the buggy PHP code below:
$str = 'Zebraman stole my child\'s pet lime!';
// Search for zebra man
if(strpos($str, 'Zebraman')){
echo 'The string contains "Zebraman"';
}else{
echo 'The string doesn\'t contain "Zebraman"';
}
Example Here
Since strpos($str, 'Zebraman') returns 0 (The index of the string Zebraman), and since 0 is falsy. That code will output The string doesn't contain "Zebraman". The correct code uses a strict comparison with false:
$str = 'Zebraman stole my child\'s pet lime!';
// Search for zebra man
if(strpos($str, 'Zebraman') !== false){
echo 'The string contains "Zebraman"';
}else{
echo 'The string doesn\'t contain "Zebraman"';
}
Example Here
See the PHP man page on strpos
I don't know if this holds true for all languages but in javascript the === stands for type comparison.
0 == false (true) 0 === false (false)
It is a common js error to not use the === when comparing a falsy value.
var a;
if(a) do something
(if a is zero the if will not get entered)

Powershell, how many replacements did you make?

I need to know how many replacements are made by Powershell when using either the -replace operator or Replace() method. Or, if that's not possible, if it made any replacements at all.
For example, in Perl, because the substitution operation returns the number of replacements made, and zero is false while non-zero is true in a boolean context, one can write:
$greeting = "Hello, Earthlings";
if ($greeting ~= s/Earthlings/Martians/) { print "Mars greeting ready." }
However with Powershell the operator and method return the new string. It appears that the operator provides some additional information, if one knows how to ask for it (e.g., captured groups are stored in a new variable it creates in the current scope), but I can't find out how to get a count or success value.
I could just compare the before and after values, but that seems entirely inefficient.
You're right, I don't think you can squeeze anything extra out of -replace. However, you can find the number of matches using Regex.Matches(). For example
> $greeting = "Hello, Earthlings"
> $needle = "l"
> $([regex]::matches($greeting, $needle)).Length # cast explicitly to an array
3
You can then use the -replace operator which uses the same matching engine.
After looking a little deeper, there's an overload of Replace which takes a MatchEvaluator delegate which is called each time a match is made. So, if we use that as an accumulator, it can count the number of replacements in one go.
> $count = 0
> $matchEvaluator = [System.Text.RegularExpressions.MatchEvaluator]{$count ++}
> [regex]::Replace("Hello, Earthlings","l",$matchEvaluator)
> $count
Heo, Earthings
3
Here a complete functional example which preserves the replacement behavior and count the number of matches
$Script:Count = 0
$Result = [regex]::Replace($InputText, $Regex, [System.Text.RegularExpressions.MatchEvaluator] {
param($Match)
$Script:Count++
return $Match.Result($Replacement)
})
None of the above answers are actually do replacement and working in recent PS versions:
James Kolpack - show how to count a removed regex (not replaced);
Kino101 - incomplete answer, variables not defined;
Annarfych - outdated answer, in recent PS version the evaluator count variable need to be global
Here is how you can do a replace and count it:
$String = "Hello World"
$Regex = "l|o" #search for 'l' or 'o'
$ReplaceWith = "?"
$Count = 0
$Result = [regex]::Replace($String, $Regex, { param($found); $Global:Count++; return $found.Result($ReplaceWith) })
$Result
$Count
Result in Powershell 5.1:
He??? W?r?d
5
Version of the script that actually does replace things and not null them:
$greeting = "Hello, earthlings. Mars greeting ready"
$counter = 0
$search = '\s'
$replace = ''
$evaluator = [System.Text.RegularExpressions.MatchEvaluator] {
param($found)
$counter++
Write-Output ([regex]::Replace($found, [regex] $search, $replace))
}
[regex]::Replace($greeting, [regex] $search, $evaluator);
$counter
->
> Hello,earthlings.Marsgreetingready
> 4