XPath expression to access each element of a string - xpath

This question may sound very basic; however, I have been trying to find some resources related to it.
Let's say there is a sequence of characters or strings:
let $abc := ('a', 'b', 'c', 'd', 'e', 'f')
return (for $i in $abc return $i)
Above query will give me individual elements of a sequence.
However, if I have only a single string, how to retrieve each element of it?
e.g. let $abc = "abc"
How to fetch 'a' from $abc, is there any $abc[0] as such to do so?

You can also use
for $char in string-to-codepoints($abc)!codepoints-to-string(.)
return ...

You can't access a string as an array in XQuery, but you can use substring:
let $abc := "abcd"
for $i in (1 to string-length($abc))
return substring($string, $i, 1)

Related

Perl: Using data from an anonymous hash

I am adding on to another developers code, we are both new to perl I am trying to take a list of IPs and run it through whois. I am unsure how to access the data in the anonymous hash, how do I use it?
He told me the data was stored inside one. This is the only instance I could find mentioning a hash:
## Instantiate a reference to an anonymous hash (key value pair)
my $addr = {};
The anonymous hash is the {} part. It returns a reference which can be stored in a scalar variable, like in your example:
my $addr = {};
To see the structure, you can print it with Data::Dumper:
use Data::Dumper;
print Dumper $addr;
It might show you something like:
$VAR1 = {
'c' => 1,
'a' => 2
};
You access the hash keys using the arrow operator:
print $addr->{"a"}
Like how you would access a regular hash, but with the arrow operator in between.
You can dereference the reference by putting a hash sigil in front
%$addr
# compare %addr %$addr
# hash hashref dereferenced
Here is an anonymous hash:
my $anon_hash = {
key1 => 'Value 1',
key2 => 'Value 2',
key3 => 'Value 3',
}
If you want to access an individual value:
my $value = $anon_hash->{key1};
say $anon_hash->{key2};
If you want to update an individual value:
$anon_hash->{key3} = 'New value 3';
If you want to add a new key/value pair:
$anon_hash->{key4} = 'Value 4';
You can also use all of the standard hash functions (e.g. keys()). You just need to "deference" your hash reference - which means putting a '%' in front of it.
So, for example, to print all the key/value pairs:
foreach my $key (keys %$anon_hash) {
say "$key : $anon_hash->{$_}";
}

How do I sort a Perl hash by keys numerically? [duplicate]

This question already has answers here:
How can I sort a hash's keys naturally?
(4 answers)
Closed 1 year ago.
My first question ... I have found many answers to other questions through search but I am failing to do so this time :-)
I want to generate a report that is sorted by a number that is embedded in a string from my input data. The report is being generate from elements of a perl hash where the same number is used as the hash key.
The output that I am currently getting is sorted like strings.
foreach my $num (sort keys %dir_map) {
$path = $paths{$num};
$name = $names{$num};
printf OUT ("%d %s %s\n",$num,$path,$name);
}
My input data looks like:
dist_14 randomString nameStringIwant RandomInteger AnotherRandomString
Which I am processing like:
while(<IN>) {
chomp;
my #header = split /\s+/;
my $header_length = $#header ;
if ( /dist_/ ) {
my $NumberStr = $header[0] ;
$justNumberStr =~ s/dist_//;
my $justNumber = sprintf("%d",$justNumberStr);
$names{$justNumber} = $header[2];
}
}
As you've discovered, Perl's sort will, by default, sort using a string comparison. To override that default behaviour, you need to provide a sort block.
foreach my $num (sort { $a <=> $b } keys %dir_map)
The sort block is given two of the elements from your list in the variables $a and $b. Your code should compare these two values and return a negative integer if $a comes before $b, a positive integer if $b comes before $a and zero if they sort in the same place. The "spaceship operator" (<=>) does exactly that for two numbers.
The FAQ How do I sort an array by (anything)?
might also be useful. You don't have an array, but your list of keys can be treated in the same way.

Insert multiple characters in string at once

Where as str[] will replace a character, str.insert will insert a character at a position. But it requires two lines of code:
str = "COSO17123456"
str.insert 4, "-"
str.insert 7, "-"
=> "COSO-17-123456"
I was thinking how to do this in one line of code. I came up with the following solution:
str = "COSO17123456"
str.each_char.with_index.reduce("") { |acc,(c,i)| acc += c + ( (i == 3 || i == 5) ? "-" : "" ) }
=> "COSO-17-123456
Is there a built-in Ruby helper for this task? If not, should I stick with the insert option rather than combining several iterators?
Use each to iterate over an array of indices:
str = "COSO17123456"
[4, 7].each { |i| str.insert i, '-' }
str #=> "COSO-17-123456"
You can uses slices and .join:
> [str[0..3], str[4..5],str[6..-1]].join("-")
=> "COSO-17-123456"
Note that the index after the first one (between 3 and 4) will be different since you are not inserting earlier insertion first. ie, more natural (to me anyway...)
You will insert at the absolute index of the original string -- not the moving relative index as insertions are made.
If you want to insert at specific absolute index values, you can also use ..each_with_index and control the behavior character by character:
str2 = ""
tgts=[3,5]
str.split("").each_with_index { |c,idx| str2+=c; str2+='-' if tgts.include? idx }
Both of the above create a new string.
String#insert returns the string itself.
This means you can chain the method calls, which can be a prettier and more efficient if you only have to do it a couple of times like in your example:
str = "COSO17123456".insert(4, "-").insert(7, "-")
puts str
COSO-17-123456
Your reduce version can be therefore more concisely written as:
[4,7].reduce(str) { |str, idx| str.insert(idx, '-') }
I'll bring one more variation to the table, String#unpack:
new_str = str.unpack("A4A2A*").join('-')
# or with String#%
new_str = "%s-%s-%s" % str.unpack("A4A2A*")

Counting occurrences of attributes in a sequence in XQuery

I have a sequence called $answer with the attributes I extracted from elements from an XML file. Inside $answer I have the following 3 attributes: 1, 3, 3 and another sequence of attributes called $p with: 1, 3
I tried to do this to get the number of occurrences by doing
for $x in $p
return count (index-of($x, $answer))
since I saw it as a solution in another posting but it gave me errors. What's the correct way to do this?
Do you want to sort all your attributes by its values? The group by statement might give you the expected results:
for $a in (attribute a {'A'}, attribute b {'B'}, attribute a {'A'})
group by $v := $a
return concat(count($a), ': ', $v)
Note, however, that your XQuery implementation needs to support XQuery 3.0.
You need to swap the arguments you passed to index-of():
for $x in $p
return count(index-of($answer, $x))
But a simpler way is to test for equality in a predicate:
for $x in $p
return count($answer[. eq $x])
which produces the same result for the given data.

How do I convert a Ruby string with brackets to an array?

I would like to convert the following string into an array/nested array:
str = "[[this, is],[a, nested],[array]]"
newarray = # this is what I need help with!
newarray.inspect # => [['this','is'],['a','nested'],['array']]
You'll get what you want with YAML.
But there is a little problem with your string. YAML expects that there's a space behind the comma. So we need this
str = "[[this, is], [a, nested], [array]]"
Code:
require 'yaml'
str = "[[this, is],[a, nested],[array]]"
### transform your string in a valid YAML-String
str.gsub!(/(\,)(\S)/, "\\1 \\2")
YAML::load(str)
# => [["this", "is"], ["a", "nested"], ["array"]]
You could also treat it as almost-JSON. If the strings really are only letters, like in your example, then this will work:
JSON.parse(yourarray.gsub(/([a-z]+)/,'"\1"'))
If they could have arbitrary characters (other than [ ] , ), you'd need a little more:
JSON.parse("[[this, is],[a, nested],[array]]".gsub(/, /,",").gsub(/([^\[\]\,]+)/,'"\1"'))
For a laugh:
ary = eval("[[this, is],[a, nested],[array]]".gsub(/(\w+?)/, "'\\1'") )
=> [["this", "is"], ["a", "nested"], ["array"]]
Disclaimer: You definitely shouldn't do this as eval is a terrible idea, but it is fast and has the useful side effect of throwing an exception if your nested arrays aren't valid
Looks like a basic parsing task. Generally the approach you are going to want to take is to create a recursive function with the following general algorithm
base case (input doesn't begin with '[') return the input
recursive case:
split the input on ',' (you will need to find commas only at this level)
for each sub string call this method again with the sub string
return array containing the results from this recursive method
The only slighlty tricky part here is splitting the input on a single ','. You could write a separate function for this that would scan through the string and keep a count of the openbrackets - closedbrakets seen so far. Then only split on commas when the count is equal to zero.
Make a recursive function that takes the string and an integer offset, and "reads" out an array. That is, have it return an array or string (that it has read) and an integer offset pointing after the array. For example:
s = "[[this, is],[a, nested],[array]]"
yourFunc(s, 1) # returns ['this', 'is'] and 11.
yourFunc(s, 2) # returns 'this' and 6.
Then you can call it with another function that provides an offset of 0, and makes sure that the finishing offset is the length of the string.

Resources