For a stylesheet I'm writing (actually for a set of them, each generating a different output format), I have the need to evaluate whether a certain value is present in a list of values. In this case, the value being tested is taken from an element's attribute. The list it is to be tested against comes from the invocation of the stylesheet, and is taken as a top-level <xsl:param>
(to be provided on the command-line when I call xsltproc
or a Saxon equivalent invocation). For example, the input value may be:
v0_01,v0_10,v0_99
while the attribute values will each look very much like one such value. (Whether a comma is used to separate values, or a space, is not important-- I chose a comma for now because I plan on passing the value via command-line switch to xsltproc
, and using a space would require quoting the argument, and I'm lazy-enough to not want to type the extra two characters.)
What I am looking for is something akin to Perl's grep
, wherein I can see if the value I currently have is contained in the list. It can be done with sub-string tests, but this would have to be clever so as not to get a false-positive (v0_01
should not match a string that contains v0_011
). It seems that the only non-scalar data-type that XSL/XSLT supports is a node-set. I suppose it's possible to convert the list into a set of text nodes, but that seems like over-kill, even compared to making a sub-string test with extra boundaries-checking to prevent false matches.
We can use the in-built python List method, count(), to check if the passed element exists in the List. If the passed element exists in the List, the count() method will show the number of times it occurs in the entire list. If it is a non-zero positive number, it means an element exists in the List.
Use the all() function to check if multiple values are in a list, e.g. if all(value in my_list for value in multiple_values): . The all() function will return True if all of the specified values are in the list and False otherwise.
There are various methods to access the elements of a list, but sometimes we may require to access element along with the index on which it is found. Let's see all the different way of accessing both index and value in a list.
We can use Python in operator to check if a string is present in the list or not. There is also a not in operator to check if a string is not present in the list.
Actually, using XPath string functions is the right way to do it. All you have to make sure is that you test for the delimiters as well:
contains(concat(',' $list, ','), concat(',', $value, ','))
would return a Boolean value. Or you might use one of these:
substring-before(concat('|,' $list, ',|'), concat(',', $value, ','))
or
substring-after(concat('|,' $list, ',|'), concat(',', $value, ','))
If you get an empty string as the result, $value
is not in the list.
EDIT:
@Dimitre's comment is correct: substring-before()
(or substring-after()
) would also return the empty string if the found string is the first (or the last) in the list. To avoid that, I added something at the start and the end of the list. Still contains()
is the recommended way of doing this.
In addition to the XPath 1.0 solution provided by Tomalak,
Using XPath 2.0 one can tokenize the list of values:
exists(tokenize($list, ',')[. = $value])
evaluates to true()
if and only if $value
is contained in the list of values $list
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With