Reputation: 1144
I have a xpath 2.0 expression that implements a map/hash/associative_array:
if ($mykey eq 'key1') then 'val1'
else if ($mykey eq 'key2') then 'val2'
else if ($mykey eq 'key3') then 'val3'
else if ($mykey eq 'key4') then 'val4'
...
(same for 50 key/value pairs)
Is there a more compact way to do it? (the map is part of a longer xpath expression)
I have tried some tricks by assigning the sequence of pairs to a variable:
for $seq in ('key1', 'val1', 'key2', 'val2' ...) return
<some trick to access only keys and then the associated value>
but it doesn't assign the sequence to $seq
, it loops over each value in the sequence.
Update: Solved: I'm using proposal #1 by Jens Erat: Create an external xml with the mapping. For example, for this xml (cfg.xml):
<cfg>
<map>
<key1>val1</key1>
<key2>val2</key2>
<key3>val3</key3>
...
</map>
</cfg>
the xpath will be:
doc('cfg.xml')/cfg/map/*[ name() eq $mykey ]
Note: If key1, key2, etc start with a digit, just add a non digit char (for example "k") in the xml, and modify the xpath acordingly:
doc('cfg.xml')/cfg/map/*[ name() eq concat('k',$mykey) ]
Upvotes: 1
Views: 778
Reputation: 38662
Several proposals:
An obvious, but rather hacky-ish solution would be to use string manipulation, eg.
substring-after(('key1:val1', 'key2:val2')[starts-with(concat($key, ':'))], ':')
Using index-of
. In XQuery, you would do something like
let $seq := ('key1', 'val1', 'key2', 'val2')
let $key := 'key1'
return $seq[index-of($seq, $key) + 1]
But in XPath 2.0, no let
is allowed, and the for
hack doesn't work with sequences. You will have to repeat the sequence:
('key1', 'val1', 'key2', 'val2')[index-of(('key1', 'val1', 'key2', 'val2'), 'key1') + 1]
But then splitting into two sequences would probably be more reasonable:
('val1', 'val2')[index-of(('key1', 'key2'), 'key1')]
Upvotes: 1