While working on a new release, some syntax polishing took place
in the CVS version.
There were two commands with which I was so unsatisfied
that I decided to change them in a way that
may break some of the existing scripts.
Let me summarize the changes:
- the mapping expression can also be XPath,
or any other XSH2 argument expression, not just
Perl
- if Perl is used, it must be enclosed in braces,
as customary in XSH2.
- $_ is read-only and
the result is collected from the expression value
just like in Perl map.
- However, --in-place (:i) flag
was introduced to preserve the old behavior,
when the result is taken from $_.
This is useful for s///-like substitutions
with Perl code.
-
map does not rename elements anymore,
rename is used for that.
Instead, map operates on element's content
and the mapping expression may produce arbitrary nodes,
not just text.
Here is how the old syntax translates to the new one:
Old syntax | New syntax |
map { $_=uc } //text(); | map { uc } //text(); |
map $_=uc //text(); | map { uc } //text(); |
map s/foo/bar/ //text(); | map :i { s/foo/bar/ } //text(); |
map { $_='link' } //ref | rename link //ref; |
And here are some funny examples from the documentation
demonstrating the gained features:
Recompute column sums in the last row of row-oriented table:
map sum(/table/row[position()<last()]/
cell[count(xsh:current()/preceding-sibling::cell)+1])
/table/row[last()]/cell;
The following commands do all about the same:
wrap --inner Z //*;
map --reverse xsh:parse(concat("<Z>",xsh:serialize(node()),"</Z>")) //*;
map xsh:parse(concat("<Z>",xsh:serialize(node()),"</Z>")) { reverse xpath('//*') };
Feel free to protest, but I'm quite happy about the result.