Interacting with Perl and Shell

To allow more complex tasks to be achieved, XSH provides ways for interaction with the Perl programming language and the system shell.

Calling Perl

Perl is a language optimized for scanning arbitrary text files, extracting information from those text files, and printing reports based on that information. It's also a good language for many system management tasks. The language is intended to be practical (easy to use, efficient, and complete). XSH itself is written in Perl, so it is extremely easy to support this language as an extension to XSH.

Perl expressions or blocks of code can either be simply evaluated with the perl command, used to do quick changes to nodes of the DOM tree (see map command), used to provide list of strings to iterate over in a foreach loop, or to specify more complex conditions for if, unless, and while statements.

To prevent conflict between XSH internals and the evaluated perl code, XSH runs such code in the context of a special namespace XML::XSH::Map. As described in the section Variables, XSH string variables may be accessed and possibly assigned from Perl code in the most obvious way, since they actually are Perl variables defined in the XML::XSH::Map namespace.

The interaction between XSH and Perl actually works also the other way round, so that you may call back XSH from the evaluated Perl code. For this, Perl function xsh is defined in the XML::XSH::Map namespace. All parameters passed to this function are interpreted as XSH commands. To simplify evaluation of XPath expressions, another three functions: The first one, named count, returns the same value as would be printed by count command in XSH on the same XPath expression. The second function, named literal, returns the result of XPath evaluation as if the whole expression was wrapped with the XPath string() function. In other words, literal('doc:expression') returns the same value as count('doc:string(expression)'). The third function, named xml_list, returns the result of the XPath search as a XML string which is equivallent to the output of a ls on the same XPath expression (without indentation and without folding or any other limitation on the depth of the listing).

In the following examples we use Perl to populate the Middle-Earth with Hobbits whose names are read from a text file called hobbits.txt, unless there are some Hobbits in Middle-Earth already.

Example 5. Use Perl to read text files

unless (//creature[@race='hobbit']) {
  perl 'open $file, "hobbits.txt"';
  perl '@hobbits=<$file>';
  perl 'close $file';
  foreach { @hobbits } {
    insert element "<creature name='$__' race='hobbit'>"
      into m:/middle-earth/creatures;
  }
}

Example 6. The same code as a single Perl block

perl {
  unless (count(//creature[@race='hobbit'])) {
    open my $file, "hobbits.txt";
    foreach (<$file>) {
      xsh(qq{insert element "<creature name='$_' race='hobbit'>"
        into m:/middle-earth/creatures});
    }
    close $file;
  }
};

Writing your own XPath extension functions in Perl

XSH allows the user to extend the set of XPath functions by providing an extension function written in Perl. This can be achieved using the register-function command. The perl code implementing an extension function works as a usual perl routine accepting its arguments in @_ and returning the result. The following conventions are used:

The arguments passed to the perl implementation by the XPath engine are either simple scalars or XML::LibXML::NodeList objects, depending on the types of the XPath arguments. The implementation is responsible for checking the argument number and types. The implementation may use arbitrary XML::LibXML methods to process the arguments and return the result. (XML::LibXML perl module documentation can be found for example at http://search.cpan.org/author/PHISH/XML-LibXML-1.54/LibXML.pm).

The implementation SHOULD NOT, however, MODIFY the document. Doing so could not only confuse the XPath engine but result in an critical error (such as segmentation fault).

Calling XSH commands from extension function implementations is not currently allowed.

The perl code must return a single value, which can be of one of the following types: a simple scalar (a number or string), XML::LibXML::Boolean object reference (result is a boolean value), XML::LibXML::Literal object reference (result is a string), XML::LibXML::Number object reference (resulat is a float), XML::LibXML::Node (or derived) object reference (result is a nodeset consisting of a single node), or XML::LibXML::NodeList (result is a nodeset). For convenience, simple (non-blessed) array references consisting of XML::LibXML::Node objects can also be used for a nodeset result instead of a XML::LibXML::NodeList.

Calling the System Shell

In the interactive mode, XSH interprets all lines starting with a exclamation mark (!) as shell commands and invokes the system shell to interpret them (this is to mimic FTP command-line interpreters).

xsh> !ls -l
-rw-rw-r--    1 pajas    pajas        6355 Mar 14 17:08 Artistic
drwxrwxr-x    2 pajas    users         128 Sep  1 10:09 CVS
-rw-r--r--    1 pajas    pajas       14859 Aug 26 15:19 ChangeLog
-rw-r--r--    1 pajas    pajas        2220 Mar 14 17:03 INSTALL
-rw-r--r--    1 pajas    pajas       18009 Jul 15 17:35 LICENSE
-rw-rw-r--    1 pajas    pajas         417 May  9 15:16 MANIFEST
-rw-rw-r--    1 pajas    pajas         126 May  9 15:16 MANIFEST.SKIP
-rw-r--r--    1 pajas    pajas       20424 Sep  1 11:04 Makefile
-rw-r--r--    1 pajas    pajas         914 Aug 26 14:32 Makefile.PL
-rw-r--r--    1 pajas    pajas        1910 Mar 14 17:17 README
-rw-r--r--    1 pajas    pajas         438 Aug 27 13:51 TODO
drwxrwxr-x    5 pajas    users         120 Jun 15 10:35 blib
drwxrwxr-x    3 pajas    users        1160 Sep  1 10:09 examples
drwxrwxr-x    4 pajas    users          96 Jun 15 10:35 lib
-rw-rw-r--    1 pajas    pajas           0 Sep  1 16:23 pm_to_blib
drwxrwxr-x    4 pajas    users         584 Sep  1 21:18 src
drwxrwxr-x    3 pajas    users         136 Sep  1 10:09 t
-rw-rw-r--    1 pajas    pajas          50 Jun 16 00:06 test
drwxrwxr-x    3 pajas    users         496 Sep  1 20:18 tools
-rwxr-xr-x    1 pajas    pajas        5104 Aug 30 17:08 xsh

To invoke a system shell command or program from the non-interactive mode or from a complex XSH construction, use the exec command.

Since UNIX shell commands are very powerful tool for processing textual data, XSH supports direct redirection of XSH commands output to system shell command. This is very similarly to the redirection known from UNIX shells, except that here, of course, the first command in the pipe-line colone is an XSH command. Since semicolon (;) is used in XSH to separate commands, it has to be prefixed with a backslash if it should be used for other purposes.

Example 7. Use grep and less to display context of `funny'

xsh> ls //chapter[5]/para | grep funny | less

Example 8. The same on Windows 2000/XP systems

xsh> ls //chapter[5]/para | find "funny" | more

Related Argument Types and Commands

exec

execute a shell command

expression

string-like expression

lcd

change system working directory

map

quickly modify node value/data using Perl code

perl

evaluate in-line Perl code

perl-code

in-line code in Perl programming language

rename

quickly rename nodes with in-line Perl code