Variables


In the current version, XSH supports two types of variables: string (scalar) variables and node-list variables. Perl programmers that might miss some other kinds of variables (arrays or hashes) may use the support for interacting with Perl to access these types (see some examples below).

These two kinds of variables differ syntactically in the prefix: string variables are prefixed with a dollar sign ($) while node-list variables are prefixed with a percent sign (%).

String Variables

Every string variable name consists of a dollar sign ($) prefix and an id, that has to be unique among other scalar variables, e.g. $variable. Values are assigned to variables either by simple assignments of the form $variable = xpath or by capturing the output of some command with a variable redirection of the form command |> $variable.

String variables may be used in string expressions, XPath expressions, or even in perl-code as $id or ${id}. In the first two cases, variables act as macros in the sense that all variables occurences are replaced by the corresponding values before the expression itself is evaluated.

To display current value of a variable, use the print command, variables command or simply the variable name:

Example 1.

xsh> $b="chapter";
xsh> $file="${b}s.xml";
xsh> open f=$file;
xsh> ls //$b[count(descendant::para)>10]
xsh> print $b
chapter
xsh> $b
$b='chapter';
xsh> variables
$a='chapters.xml';
$b='chapter';

Node-list Variables

Every string variable name consists of a percent sign (%) prefix and an id, that has to be unique among other node-list variables, e.g. %variable.

Node-list variables can be used to store lists of nodes that result from evaluating an XPath. This is especially useful when several changes are performed on some set of nodes and evaluating the XPath expression repeatedly would take too long. Other important use is to remember a node that would otherwise be extremely hard or even impossible to locate by XPath expressions after some changes to the tree structure are made, since such an XPath cannot be predicted in advance.

Although node-list variables act just like XPath expressions that would result in the same node-list, for implementation reasons it is not possible to use node-list variables as parts of complex XPath expressions except for one case. They may be only used at the very beginning of an XPath expression. So while constructions such as %creatures[4], %creatures[@race='elf'], or %creatures/parents/father do work as expected, string(%creatures[2]/@name) //creature[%creatures[2]/@name=@name], or %creatures[@race='elf'][2] do not. In the first two cases it is because node-list variables cannot be evaluated in the middle of an XPath expression. The third case fails because this construction actually translates into a sequence of evaluations of self::*[@race='elf'][2] for each node in the %creatures node-list, which is not equivallent to the intended expression as the [2] filter does not apply to the whole result of %creatures[@race='elf'] at once but rather to the partial results.

Fortunatelly, it is usually possible to work around these unsupported constructions quite easily. This is typically done by introducing some more variables as well as using the foreach statement. The following example should provide some idea on how to do this:

Example 2.

# work around for $name=string(%creatures[2]/@name)
xsh> foreach %creatures[2] $name=string(@name)
# work around for ls //creature[%creatures[2]/@name=@name]
xsh> ls //creature[$name=@name]
# work around for ls %creatures[@race='elf'][2]
xsh> %elves = %creatures[@race='elf']
xsh> ls %elves[2]

Remember, that when a node is deleted from a tree it is at the same time removed from all node-lists it occurs in. Note also, that unlike string variables, node-list variables can not be (and are not intended to be) directly accessed from Perl code.

Accessing Perl Variables

All XSH string variables are usual Perl scalar variables from the XML::XSH::Map namespace, which is the default namespace for any Perl code evaluated from XSH. Thus it is possible to arbitrarily intermix XSH and Perl assignments:

Example 3.

xsh> ls //chapter[1]/title
<title>Introduction</title>
xsh> $a=string(//chapter[1]/title)
xsh> eval { $b="CHAPTER 1: ".uc($a); }
xsh> print $b
CHAPTER 1: INTRODUCTION

If needed, it is, however, possible to use any other type of Perl variables by means of evaluating a corresponding perl code. The following example demonstrates using Perl hashes to collect and print some simple racial statistics about the population of Middle-Earth:

Example 4.

foreach a:/middle-earth/creature { 
  $race=string(@race);
  eval { $races{$race}++ };
}
print "Middle-Earth Population (race/number of creatures)"
eval { 
  echo map "$_/$races{$_}\n",
    sort ($a cmp $b), keys(%races); 
};

Related Argument Types and Commands

assign
variable assignment
expression
string-like expression
id
identifier
local
temporarily assign new value to a variable
xpath
XPath expression