In XSH2, like in Perl and XPath,
variable names are are prefixed
with a dollar sign ($).
Variables can
contain arbitrary Perl Scalar (string, number, array
reference, hash reference or an object reference). XPath
objects are transparently mapped to Perl objects via
XML::LibXML objects.
Values can be assigned to variables
either by simple assignments of the form
$variable = expression
,
where the right hand side is an expression, or by command
assignments of the form
$variable := command
,
where the right hand side is a XSH2 command, or by
capturing the output of some command with a variable
redirection of the following form:
command |> $variable;
XSH2 expressions are evaluated either by XPath
engine or by Perl (the latter only happens if the entire
expression is enclosed with braces
{...}
), and
both Perl and XPath can access all XSH2 variables
transparently (Perl expressions may even assign to them).
A simple simple expression consisting of a variable name
(e.g. $variable
) is always evaluated by the
XPath engine and the result is the content of the variable as
it appears to the XPath data model. Since in XPath object
cannot be void (undefined), XPath engine complains, if the
value of the variable is undefined. On the other hand,
expressions like {$variable}
are evaluated by
Perl, which results in the value of the variable as seen
by Perl.
Variables can also be used as macros for complicated XPath
expressions. Any occurrence of a substring of the form
${variable}
in an XPath expression is
interpolated to the value of $variable
(if
$variable
contains an object rather than a
string or number, then the object is cast to string first) before the
entire expression is evaluated. So, for example, if
${variable}
contains string
"chapter[title]
" (without the quotes), then
the XPath expression
//sect1/${variable}/para
interpolates to
//sect1/chapter[title]/para
prior
to evaluation.
To display the current value of a variable, use either print or (in case of a global variables - the distinction is discussed below) the command variables:
xsh>$b="my_document";
xsh>$file="${b}s.xml";
xsh>$f := open $file;
xsh>ls //$b[count(descendant::para)>10]
xsh>print $b
my_document xsh>variables
... $b='my_document'; ... $file='my_documents.xml'; ...
Variables can also serve as containers for documents and can be used to
store lists of nodes that result from evaluating an XPath
expression (a.k.a. XPath node-sets). This is especially useful
when a sequence of commands is to be performed on some fixed
set of nodes and repetitive evaluation of the same XPath
expression would be lengthy. XPath
node-sets are represented by
XML::LibXML::NodeList
Perl objects (which
is simply a array reference blessed to the above class, which
provides some simple operator overloading). In XPath, by a
node-set by definition can only contain a single copy of each
node and the nodes within a node-set are processed in the same
order as they appear in the XML document. Having XPath
node-sets represented by a list gives us the advantage of having
the possibility to process the list in a different order than
the one implied by the document (which is what happens
if a variable containing a node-list is evaluated by Perl
rather than XPath), see an example below.
xsh>$creatures = //creature[@status='alive']
# process creatures in the document order: xsh>foreach $creature print @name;
# process creatures in the reverse document order: xsh>foreach { reverse @$creature } print @name;
# append some more nodes to a node-list (using a variant of # a simple assignment) xsh>$creatures += //creature[@status='dead'];
# again, we can process creatures in order implied by the document: xsh>foreach $creature print @name;
# but we can also process first living and then dead creatures, # since this is how they are listed in $creature xsh>foreach {$creature} print @name;
# same as the above is xsh>foreach {@$creature} print @name;
XSH2 variables are either globally or lexically scoped. Global variables need not to be declared (they can be directly assigned to), whereas lexical variables must be declared using the command my. Global variable assignment may also be made temporal for the enclosing block, using local.
$var1 = "foo"; # a global variable requires no declaration local $var1 $var2 $var3; # localizes global variables $var1 = "bar"; # assignment to a localized variable is temporary local $var4 = "foo"; # localized assignment my $var1 $var $var3; # declares lexical variables my $var1 = "foo"; # lexical variable declaration with assignment
Lexical variables are only defined in the scope of current block or subroutine. There is no way to refer to a lexical variable form outside of the block it was declared in, nor from within a nested subroutine call. Of course, lexical variables can be referred to from nested blocks or Perl expressions (where they behave just like Perl's lexical variables).
On the other hand, global or localized XSH2 variables are just
Perl Scalar variables belonging to the
XML::XSH2::Map
namespace, which is also the
default namespace for any Perl code evaluated from XSH2 (so
there's no need to use this prefix explicitly in Perl expressions,
unless of course there is a lexical variable in the current
scope with the same).
Localizing a variable using the local
keyword makes all assignments to it occurring in the enclosing block
temporary. The variable itself remains global, only its
original value is restored at the end of the block that localized it.
In all above cases, it is possible to arbitrarily intermix XSH2 and Perl assignments:
xsh>ls //chapter[1]/title
<title>Introduction</title> xsh>$a=string(//chapter[1]/title)
xsh>perl { $b="CHAPTER 1: ".uc($a); }
xsh>print $b
CHAPTER 1: INTRODUCTION
Although all XSH2 variables are in fact Perl Scalars, it is still possible to store Perl Array or Hash value to a XSH2 variable via reference. The following example demonstrates using Perl Hashes to collect and print some simple racial statistics about the population of Middle-Earth:
my $races; foreach a:/middle-earth/creature { my $race=string(@race); perl { $races->{$race}++ }; } print "Middle-Earth Population (race/number of creatures)" print { map "$_/$races->{$_}\n" keys(%$races); };
variable assignment
specifying documents
expression argument type
temporarily assign new value to a variable
name of a sub-routine
XPath expression